Skip to content

Commit bb07242

Browse files
Stop future releases from denying Homebrew and npm.
Why: The tag-driven release notes still said the release was not a Homebrew formula or npm package, and the workflow never attached the npm tarball. The spec-only front-door suite also fetched live GitHub, so agent verify could fail on rate limits or a stale tap. Changed: release.yml packages and attaches simbroker-<version>.tgz and rewrites the release notes. The live tap compare moves to scripts/sync_homebrew_tap.sh --check-remote. Front-door tests stay offline and pin the new release.yml contract. Verification: npm run agent:verify -- --profile spec-only --paths .github/workflows/release.yml,docs/test/front-door.test.mjs,scripts/sync_homebrew_tap.sh,spec/build-and-test.md,CHANGELOG.md --session-dir task-sessions/20260819-homebrew-p2-review node --test docs/test/front-door.test.mjs Affected: .github/workflows/release.yml docs/test/front-door.test.mjs scripts/sync_homebrew_tap.sh spec/build-and-test.md CHANGELOG.md Refs: #12 spec/build-and-test.md Session: task-sessions/20260819-homebrew-p2-review
1 parent fdbd070 commit bb07242

5 files changed

Lines changed: 67 additions & 29 deletions

File tree

.github/workflows/release.yml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Publish the Alpha CLI tarball when a version tag is pushed.
2-
# After merge, create the matching tag (example: v0.1.0-alpha.1).
3-
# This workflow does not build or attach the macOS app.
1+
# Publish the Alpha CLI tarball and the packable npm CLI when a version
2+
# tag is pushed. After merge, create the matching tag (example:
3+
# v0.1.0-alpha.1). This workflow does not build or attach the macOS app.
44
name: Release CLI
55

66
on:
@@ -13,7 +13,7 @@ permissions:
1313

1414
jobs:
1515
release:
16-
name: attach CLI tarball
16+
name: attach CLI and npm packages
1717
runs-on: ubuntu-latest
1818
timeout-minutes: 30
1919
steps:
@@ -38,8 +38,10 @@ jobs:
3838
npm run test:client
3939
npm run test:harness-adoption
4040
41-
- name: Package CLI tarball
42-
run: npm run package:cli
41+
- name: Package CLI tarball and npm CLI
42+
run: |
43+
npm run package:cli
44+
npm run package:npm
4345
4446
- name: Create GitHub Release
4547
env:
@@ -48,13 +50,15 @@ jobs:
4850
version="$(node -p "require('./package.json').version")"
4951
asset="artifacts/cli/simulator-broker-${version}-cli.tar.gz"
5052
checksum="${asset}.sha256"
53+
npm_asset="artifacts/npm/simbroker-${version}.tgz"
5154
prerelease_args=()
5255
if [[ "$version" == *alpha* || "$version" == *beta* || "$version" == *rc* ]]; then
5356
prerelease_args+=(--prerelease)
5457
fi
5558
gh release create "${GITHUB_REF_NAME}" \
5659
--title "Simulator Broker ${GITHUB_REF_NAME}" \
57-
--notes "Alpha CLI tarball. Extract it and run \`./bin/simbroker --help\`. Node.js 20 or newer is required. macOS and Xcode are still required to create and run iOS Simulators. This release is not a Homebrew formula, notarized app, or npm package. See CHANGELOG.md." \
60+
--notes "Alpha CLI. Install with \`brew install fiveonecode/simulator-broker/simbroker\` or \`npm install -g\` the attached \`simbroker-${version}.tgz\`. Node.js 20 or newer is required. macOS and Xcode are still required to create and run iOS Simulators. A signed, notarized operator app is not attached. See CHANGELOG.md." \
5861
"${prerelease_args[@]}" \
5962
"$asset" \
60-
"$checksum"
63+
"$checksum" \
64+
"$npm_asset"

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
from the signed, notarized GitHub Release zip `Simulator-Broker-<version>.zip`
1818
when that zip is attached.
1919
- Packable npm CLI `packages/simbroker` (`npm run package:npm`) with a `bin`
20-
field. The repo-root package stays private.
20+
field. The repo-root package stays private. Tag-driven
21+
`.github/workflows/release.yml` attaches that tarball and no longer
22+
claims the release is not a Homebrew formula or npm package.
2123

2224
## [0.1.0-alpha.1] - 2026-08-18
2325

docs/test/front-door.test.mjs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,16 @@ test("release workflow packages the CLI tarball on version tags", () => {
174174

175175
assert.ok(release.includes("tags:"));
176176
assert.ok(release.includes("npm run package:cli"));
177+
assert.ok(release.includes("npm run package:npm"));
178+
assert.ok(release.includes("artifacts/npm/simbroker-${version}.tgz"));
177179
assert.ok(release.includes("gh release create"));
178180
assert.ok(release.includes("--prerelease"));
179181
assert.equal(release.includes("test:app"), false);
182+
assert.equal(
183+
release.replace(/\s+/g, " ").includes("This release is not a Homebrew formula, notarized app, or npm package."),
184+
false,
185+
"future release notes must not deny Homebrew and npm",
186+
);
180187
});
181188

182189
test("issue forms cover install failure, bug, and feature and state Alpha limits", () => {
@@ -238,11 +245,12 @@ test("status and contributing point strangers at issue forms, not later-sequence
238245
assert.ok(readme.includes("issues/new/choose"));
239246
});
240247

241-
test("Homebrew one-liner is documented against the homebrew-simulator-broker tap", async () => {
248+
test("Homebrew one-liner is documented against the homebrew-simulator-broker tap", () => {
242249
const readme = readRepoFile("README.md");
243250
const gettingStarted = readRepoFile("docs/getting-started.md");
244251
const structure = readRepoFile("spec/project-structure.md");
245252
const changelog = readRepoFile("CHANGELOG.md");
253+
const syncScript = readRepoFile("scripts/sync_homebrew_tap.sh");
246254

247255
for (const body of [readme, gettingStarted, structure, changelog]) {
248256
assert.ok(
@@ -255,22 +263,10 @@ test("Homebrew one-liner is documented against the homebrew-simulator-broker tap
255263
);
256264
}
257265

258-
const repoResponse = await fetch("https://api.github.com/repos/fiveonecode/homebrew-simulator-broker", {
259-
headers: { "User-Agent": "simulator-broker-front-door-test" },
260-
});
261-
assert.equal(
262-
repoResponse.status,
263-
200,
264-
"fiveonecode/homebrew-simulator-broker must exist for the brew one-liner",
265-
);
266-
const formulaResponse = await fetch(
267-
"https://raw.githubusercontent.com/fiveonecode/homebrew-simulator-broker/main/Formula/simbroker.rb",
268-
{ headers: { "User-Agent": "simulator-broker-front-door-test" } },
269-
);
270-
assert.equal(formulaResponse.status, 200, "tap must publish Formula/simbroker.rb on main");
271-
const formula = await formulaResponse.text();
272-
assert.ok(formula.includes("class Simbroker"));
273-
assert.ok(formula.includes("simulator-broker-0.1.0-alpha.1-cli.tar.gz"));
266+
assert.ok(syncScript.includes("--check-remote"));
267+
assert.ok(syncScript.includes("cmp -s"));
268+
assert.ok(syncScript.includes("--max-time"));
269+
assert.ok(syncScript.includes("Formula/simbroker.rb"));
274270
});
275271

276272
test("sync_homebrew_tap.sh copies Formula and Casks into a tap checkout", () => {

scripts/sync_homebrew_tap.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,34 @@ repo_root="$(cd "$(dirname "$0")/.." && pwd)"
66
usage() {
77
cat <<'EOF'
88
Usage: bash scripts/sync_homebrew_tap.sh --tap-dir <path>
9+
bash scripts/sync_homebrew_tap.sh --check-remote
910
1011
Copy Formula/ and Casks/ from this checkout into a clone of
1112
fiveonecode/homebrew-simulator-broker. Refuses to delete tap files when
1213
this tree has no Formula/simbroker.rb.
1314
15+
--check-remote compares this checkout's Formula/simbroker.rb to the
16+
published tap formula. It is optional and is not part of spec-only.
17+
1418
Options:
1519
--tap-dir <path> Existing checkout of fiveonecode/homebrew-simulator-broker
20+
--check-remote Compare local Formula/simbroker.rb to the live tap
1621
-h, --help Show this help text.
1722
EOF
1823
}
1924

2025
tap_dir=""
26+
check_remote=0
2127
while [[ $# -gt 0 ]]; do
2228
case "$1" in
2329
--tap-dir)
2430
tap_dir="$2"
2531
shift 2
2632
;;
33+
--check-remote)
34+
check_remote=1
35+
shift
36+
;;
2737
-h|--help)
2838
usage
2939
exit 0
@@ -36,6 +46,30 @@ while [[ $# -gt 0 ]]; do
3646
esac
3747
done
3848

49+
if [[ "$check_remote" -eq 1 ]]; then
50+
if [[ ! -f "$repo_root/Formula/simbroker.rb" ]]; then
51+
echo "This tree has no Formula/simbroker.rb." >&2
52+
exit 1
53+
fi
54+
remote_url="https://raw.githubusercontent.com/fiveonecode/homebrew-simulator-broker/main/Formula/simbroker.rb"
55+
remote_tmp="$(mktemp "${TMPDIR:-/tmp}/simbroker-tap-formula.XXXXXX")"
56+
cleanup_remote() {
57+
rm -f "$remote_tmp"
58+
}
59+
trap cleanup_remote EXIT
60+
if ! curl --fail --silent --show-error --max-time 15 -A "simulator-broker-sync-homebrew-tap" \
61+
-o "$remote_tmp" "$remote_url"; then
62+
echo "Could not fetch live tap formula from $remote_url" >&2
63+
exit 1
64+
fi
65+
if ! cmp -s "$repo_root/Formula/simbroker.rb" "$remote_tmp"; then
66+
echo "Live tap Formula/simbroker.rb does not match this checkout. Run scripts/sync_homebrew_tap.sh --tap-dir <tap> and push the tap." >&2
67+
exit 1
68+
fi
69+
echo "Live tap formula matches this checkout."
70+
exit 0
71+
fi
72+
3973
if [[ -z "$tap_dir" ]]; then
4074
usage >&2
4175
exit 1

spec/build-and-test.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ A first extracted implementation slice now exists:
4141
`brew install fiveonecode/simulator-broker/simbroker` clones
4242
`fiveonecode/homebrew-simulator-broker`. `scripts/sync_homebrew_tap.sh`
4343
copies `Formula/` and `Casks/` into a tap checkout only when
44-
`Formula/simbroker.rb` exists
44+
`Formula/simbroker.rb` exists. `--check-remote` compares this tree to
45+
the published tap formula and is not part of `spec-only`
4546
- `scripts/package_npm.sh` (`npm run package:npm`) packs `packages/simbroker`
4647
with a `bin` field; the repo-root package stays `private`
4748
- `Casks/simulator-broker.rb` installs `Simulator Broker.app` from
@@ -53,8 +54,9 @@ A first extracted implementation slice now exists:
5354
app snapshot must inject the fixture `simctl` adapter. The default
5455
public-surface scan reads index blobs only for dirty or missing worktree
5556
files so a clean checkout does not spawn one `git cat-file` per file.
56-
- tagged versions such as `v0.1.0-alpha.1` attach the CLI tarball to a GitHub
57-
Release through `.github/workflows/release.yml`
57+
- tagged versions such as `v0.1.0-alpha.1` attach the CLI tarball and the
58+
packable `simbroker-<version>.tgz` to a GitHub Release through
59+
`.github/workflows/release.yml`
5860
- local-debug portable bundle support through a zip bundle plus package-smoke verification of the bundled install path and installed-app launch proof
5961
- a separate Release distribution packaging path that requires operator-supplied signing inputs, runs `codesign` plus `spctl`, optionally notarizes with `notarytool`, and writes a readiness summary JSON
6062
- executable `agent-harness/` changes now route through the implementation

0 commit comments

Comments
 (0)