Skip to content

Install with Homebrew from a tap of our own #151

Open

Description

@abashev

Why

Installing the formatter on a Mac or a Linux machine today means picking a file from the release page, making it executable, renaming it and moving it onto the PATH, and doing it again for every release, as the Command line page describes. With Homebrew it is one command, and brew upgrade keeps it current.

Upstream users ask for exactly this. palantir#1259 wants brew install palantir-java-format, so that AI coding tools and editors built on VS Code can call the formatter without Gradle's start-up time, and palantir#1116 asks for a CLI binary that editors such as Neovim can run. palantir-java-format publishes its native images to Maven Central only: its GitHub releases carry no files, and homebrew/core has no formula for it. We already ship the binaries, so only the install step is missing.

Proposal

A tap, openjavaformat/homebrew-tap, with one formula, Formula/open-java-format.rb, that installs the native binary of the latest release:

Platform Release file
macOS, Apple silicon open-java-format-macos_aarch64
macOS, Intel open-java-format-macos_x86-64
Linux x86-64 open-java-format-linux-glibc_x86-64
Linux AArch64 open-java-format-linux-glibc_aarch64

The formula picks the file with on_macos/on_linux and on_arm/on_intel, checks it against the checksum in the release's checksums_sha256.txt and installs it as bin/open-java-format. It depends on nothing, since the binary needs no JDK, and its test do block formats a small class and compares the output.

brew install openjavaformat/tap/open-java-format
open-java-format --version

A formula rather than a cask: Homebrew downloads a formula with curl, so the binary gets no quarantine flag, which matters because the macOS binaries are not notarized. Formulae work on Linux too.

Keeping it current

The same shape as follow-releases.yml in openjavaformat/open-java-format-action and openjavaformat/docs. An hourly workflow in the tap compares the latest release with the formula's version. When they differ, it writes the new version and the four checksums from checksums_sha256.txt, installs and tests the formula on a macOS and a Linux runner, and commits as github-actions[bot]. It needs nothing but the tap's own GITHUB_TOKEN.

JReleaser, which release.yml already runs, has a Homebrew packager. It would update the tap from inside the release workflow, though: before the draft release is published, while its download links still answer 404, and with a token that can push to another repository. Following published releases from the tap avoids both.

homebrew/core later

Not possible yet, for two reasons:

  • Notability. A new package needs at least 30 forks, 30 watchers or 75 stars, three times that when the project submits it itself. The repository has 34 stars today. Being a fork is no obstacle: a separately named fork may be accepted when it meets the other requirements.
  • No native binary. A core formula must build from source or install platform-independent output such as Java bytecode. It would install the runnable jar with depends_on "openjdk", the way homebrew/core packages google-java-format.

To decide

  • Only the latest version? A new minor version can change the output (see Versions), and brew upgrade takes it. brew pin open-java-format holds a version on one machine, and projects pin theirs in Gradle, Maven or the action anyway. Versioned formulae such as open-java-format@21.1 can follow if someone needs them.

Done when

  • brew install openjavaformat/tap/open-java-format installs the latest release on macOS (Apple silicon and Intel) and Linux (x86-64 and AArch64), and brew test passes on each;
  • a new release reaches the tap within the hour, without a hand edit;
  • the Command line page offers brew install before the manual download, and About lists the tap.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions