feat(cli): publish no-JRE jar bundle + Homebrew-core formula for amy

Enable distributing the `amy` CLI via Homebrew-core (mainline formulae).
Homebrew-core builds in a network-sandboxed env, so a from-source Gradle
build can't resolve Maven deps there; the accepted pattern for JVM tools is a
pre-built no-JRE jar bundle + `depends_on "openjdk"`. installDist already
produces exactly that (bin/amy + lib/*.jar, no bundled runtime).

- create-release.yml: publish `amy-<version>-jvm.tar.gz` (the installDist tree)
  as a release asset on the linux leg. Pure JVM bytecode, so one
  platform-independent artifact serves every OS.
- packaging/homebrew/amy.rb: reference formula (depends_on openjdk, livecheck
  for BrewTestBot auto-bumps, `amy --help` smoke test). Not consumed by any
  build here — it's the artifact to submit to Homebrew/homebrew-core.
- BUILDING.md: homebrew-core submission runbook; note that the desktop app is
  already on mainline Homebrew (homebrew/cask); document name-collision and
  pre-built-jar review caveats.
- asset-name.sh: document the jvm bundle naming exception.

Verified locally: :cli:installDist builds with only a JDK (no Android SDK),
and the extracted bundle runs via JAVA_HOME (`amy --help` exits 0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sso31DfSF9B6EFCVkEqWD
This commit is contained in:
Claude
2026-06-18 00:14:09 +00:00
parent c81dbb0127
commit f24fc10212
4 changed files with 116 additions and 0 deletions
+17
View File
@@ -321,6 +321,23 @@ jobs:
source scripts/asset-name.sh
collect_cli_assets "${{ matrix.family }}" "${{ matrix.arch }}" "${{ steps.ver.outputs.version }}" dist
# Homebrew-core ships a no-JRE jar bundle and depends_on "openjdk" — it
# cannot use the jlink tarball above (bundled runtime) nor build from
# source (its sandbox blocks Gradle's Maven downloads). installDist
# (bin/amy + lib/*.jar, no runtime/) is exactly that bundle. It is pure
# JVM bytecode, so one platform-independent asset serves every OS; we cut
# it on the linux leg only. amyImage depends on installDist, so the
# cli/build/install/amy tree already exists here.
- name: Package no-JRE jvm bundle for Homebrew (linux leg only)
if: matrix.family == 'linux'
run: |
set -euo pipefail
VER="${{ steps.ver.outputs.version }}"
SRC="cli/build/install/amy"
test -x "$SRC/bin/amy"
( cd "$SRC" && tar czf "$OLDPWD/dist/amy-${VER}-jvm.tar.gz" bin lib )
echo "Collected: dist/amy-${VER}-jvm.tar.gz"
- name: Enforce CLI size budget (200 MB per asset)
run: |
set -euo pipefail
+45
View File
@@ -360,6 +360,51 @@ The cask filename is `amethyst-nostr` (not `amethyst` — that's taken by a
tiling window manager). After the first PR is merged, `bump-homebrew.yml`
auto-submits new version bumps on each stable release.
> **The desktop app is already on mainline Homebrew.** `homebrew/cask` *is* the
> mainline cask repo — GUI apps live in homebrew-**cask**, CLIs in
> homebrew-**core**; both are "mainline." A private tap is only the *fallback*
> if Homebrew ever rejects the (now signed + notarized) cask.
### Homebrew-core formula for the `amy` CLI (one-time initial PR)
The CLI goes to **homebrew-core** (mainline formulae), not homebrew-cask —
casks are for GUI apps. homebrew-core builds in a **network-sandboxed**
environment, so a from-source Gradle build can't resolve its Maven
dependencies there. Instead the formula downloads the pre-built **no-JRE jar
bundle** `amy-<version>-jvm.tar.gz` (published by `create-release.yml`) and
`depends_on "openjdk"`. The reference formula lives at
[`packaging/homebrew/amy.rb`](packaging/homebrew/amy.rb).
To submit:
```bash
# 1. Grab the published asset's sha256
curl -fsSL -o amy-jvm.tar.gz \
https://github.com/vitorpamplona/amethyst/releases/download/v1.12.1/amy-1.12.1-jvm.tar.gz
shasum -a 256 amy-jvm.tar.gz
# 2. Fill the url + sha256 into packaging/homebrew/amy.rb, then open the PR
brew create --set-name amy --tap homebrew/core \
https://github.com/vitorpamplona/amethyst/releases/download/v1.12.1/amy-1.12.1-jvm.tar.gz
# (paste the reference formula body, run `brew audit --new amy`,
# `brew install --build-from-source amy`, `brew test amy`, then PR it.)
```
Caveats that the maintainer must weigh before submitting:
- **Name collision.** `amy` may already exist in homebrew-core — check with
`brew search amy` first. If taken, fall back to `amethyst-cli`.
- **Pre-built-jar scrutiny.** homebrew-core prefers source builds; downloading
a jar bundle is an accepted-but-reviewed pattern for JVM tools. Be ready to
justify it (sandboxed Gradle can't fetch Maven deps).
- **Bundle size.** The bundle is ~70 MB today because `:commons` leaks
Compose/Skiko jars onto the CLI classpath. Trimming that (a `:commons`
core/ui split) would shrink it and smooth review — tracked as a follow-up.
After the formula merges, the `livecheck` block lets homebrew-core's BrewTestBot
auto-open version-bump PRs on each stable release — no token or workflow on our
side (unlike the cask/winget bumps).
### Winget (one-time initial submission)
```bash
+47
View File
@@ -0,0 +1,47 @@
# Reference Homebrew formula for `amy`, the Amethyst CLI.
#
# This file is NOT consumed by any build in this repo. It is the artifact you
# submit to Homebrew/homebrew-core (`brew bump-formula-pr` / a new-formula PR).
# Once accepted, homebrew-core's copy is the source of truth; keep this in sync
# for reference and to make version bumps a copy-paste.
#
# Why a pre-built jar bundle instead of building from source:
# homebrew-core builds inside a network sandbox, so a Gradle build cannot
# resolve its Maven dependencies there. The accepted pattern for JVM tools is
# to download a pre-built, no-JRE jar bundle and depend on the system openjdk.
# We publish exactly that as `amy-<version>-jvm.tar.gz` (bin/amy + lib/*.jar,
# no bundled runtime) from .github/workflows/create-release.yml.
#
# Before submitting: replace the version in the url and the sha256 with the
# values for the actual published release asset:
# curl -fsSL -o amy-jvm.tar.gz \
# https://github.com/vitorpamplona/amethyst/releases/download/vX.Y.Z/amy-X.Y.Z-jvm.tar.gz
# shasum -a 256 amy-jvm.tar.gz
class Amy < Formula
desc "Command-line Nostr client from the Amethyst project"
homepage "https://github.com/vitorpamplona/amethyst"
url "https://github.com/vitorpamplona/amethyst/releases/download/v1.12.1/amy-1.12.1-jvm.tar.gz"
sha256 "REPLACE_WITH_RELEASE_ASSET_SHA256"
license "MIT"
# Lets homebrew-core's BrewTestBot auto-open version-bump PRs when a new
# stable GitHub release appears.
livecheck do
url :stable
strategy :github_latest
end
depends_on "openjdk"
def install
# Tarball top level is bin/ and lib/ (the Gradle installDist layout).
libexec.install Dir["*"]
# Wrapper on PATH that pins JAVA_HOME to Homebrew's openjdk so amy runs
# regardless of the user's own Java setup.
(bin/"amy").write_env_script libexec/"bin/amy", JAVA_HOME: Formula["openjdk"].opt_prefix
end
test do
assert_match "Amethyst command-line interface", shell_output("#{bin}/amy --help 2>&1")
end
end
+7
View File
@@ -32,6 +32,13 @@
# amy-1.08.0-linux-x64.tar.gz
# amy-1.08.0-linux-x64.deb
# amy-1.08.0-linux-x64.rpm
#
# One CLI asset breaks the family/arch shape on purpose: the no-JRE jar bundle
# for Homebrew-core is pure JVM bytecode (no bundled runtime), so a single
# platform-independent artifact serves every OS:
# amy-1.08.0-jvm.tar.gz
# It is packaged inline in create-release.yml (linux leg), not via the helpers
# below, since it has no <family>/<arch> dimension.
set -euo pipefail