Skip to content

chore: add a just release recipe that starts the Xcode Cloud build - #151

Merged
keinstn merged 1 commit into
mainfrom
chore/release-recipe
Jul 30, 2026
Merged

chore: add a just release recipe that starts the Xcode Cloud build#151
keinstn merged 1 commit into
mainfrom
chore/release-recipe

Conversation

@keinstn

@keinstn keinstn commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Why

The Xcode Cloud workflow started on any change to app/pubspec.yaml. That file carries two unrelated concerns — the version and the dependency list — so the trigger was only an approximation of "the version changed".

Measured over the repo's history: 13 of the 47 commits touching app/pubspec.yaml changed no version line. Each one built an unchanged build number, which App Store Connect rejects as a duplicate. A 28% false-trigger rate produces recurring red builds, and red builds you learn to ignore are the real cost.

Xcode Cloud start conditions are path matchers and cannot read a file's contents, so no automatic trigger can express "only when the version: line changed". The workflow is now manual-start only (already changed in App Store Connect), and the build is started explicitly through the App Store Connect API.

What changed

  • justfile — a release recipe that bumps the version, commits that one path, pushes, and starts the build via asc xcode-cloud run.
  • CLAUDE.mdasc added to one-time host setup, plus a Releasing section.
  • app/ios/ci_scripts/ci_post_clone.sh — the comment still claimed a pubspec change triggers a release. Comment only; no behaviour change.
just release        # 1.0.0+48 -> 1.0.0+49  (same version, next build)
just release 1.0.1  # 1.0.0+48 -> 1.0.1+49  (new App Store version)

Design notes

Every guard runs before the first mutation — invalid semver, not on main, uncommitted pubspec.yaml, asc missing. A failure after the push would otherwise leave a version bump behind with no build to go with it.

The commit names its path explicitly rather than using -a, so unrelated work in the tree is never swept in. The build number always increments, including across a marketing-version change, so it stays monotonic within any version.

Alternatives considered and rejected: a git-tag trigger (the version was bumped 34 times in 10 days — tags would stop meaning "release"), building on every merge (builds should be explicit), and a mirrored version.txt watched by Xcode Cloud (keeping two files in sync is procedural discipline, not a guarantee, and on drift the build would archive a stale number). Triggering from GitHub Actions is feasible and would detect the version line exactly, but was rejected on security-vs-benefit: the repo is public, an App Store Connect API key is team-scoped, and there is no automation gain since the version is bumped from a terminal anyway.

Verification

  • just analyze — no issues
  • just test791 passed
  • just functions-check, just functions-test8 passed
  • Recipe guards exercised directly: invalid semver, non-main branch, and a valid semver on a non-main branch all exit non-zero without touching pubspec.yaml
  • Bump arithmetic verified against a copy of the real pubspec.yaml: 1.0.0+481.0.0+49, and with an argument → 1.0.1+49 / 2.0.0+49
  • asc xcode-cloud run itself was verified live before this PR — a Developer-role key started build run 49, so the API path works

Not verified end to end: just release has never been run to completion, because doing so pushes a commit and starts a real build. The mutating half (sed, commit, push, asc) is composed of pieces verified separately rather than as one run.

🤖 Generated with Claude Code

The Xcode Cloud workflow used to start on any change to app/pubspec.yaml.
That file carries two unrelated concerns: 13 of the 47 commits touching it
changed only dependencies, and each one built an unchanged build number that
App Store Connect rejects as a duplicate. Recurring red builds train you to
ignore red builds.

Xcode Cloud start conditions match paths and cannot read file contents, so no
automatic trigger can express "only when the version line changed". The
workflow is now manual-start only and `just release` starts the build through
the App Store Connect API instead, which makes the trigger exact.

The recipe bumps the version, commits that one path, pushes, and starts the
build. Every guard runs before the first mutation so a failure cannot leave a
version bump behind with no build to go with it. An optional argument sets a
new marketing version; the build number always increments.

Also documents asc as one-time setup and corrects the ci_post_clone.sh comment
that still described the old pubspec-change trigger.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@keinstn
keinstn merged commit 3b82b35 into main Jul 30, 2026
2 checks passed
@keinstn
keinstn deleted the chore/release-recipe branch July 30, 2026 02:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant