Skip to content

ci(release): continuous delivery - every app change merged to main is released - #13

Merged
mbeczynski merged 1 commit into
mainfrom
ci/auto-release
Oct 6, 2026
Merged

mbeczynski merged 1 commit into
mainfrom
ci/auto-release

Conversation

@mbeczynski

Copy link
Copy Markdown
Contributor

Every merge to main that changes the app is released automatically. No hand-made tag, no release from a laptop.

What triggers a release: changes to mac-app/Sources|Resources, Package.swift/.resolved, mac-app/VERSION, launchd/, config/ or the cask template. Docs-only and test-only merges do not.

Version: mac-app/VERSION is the base. If it is not tagged yet, that is the release; otherwise the next patch (1.3.0 → 1.3.1 → …). Bump VERSION only for a minor or major release. The computed number is written into the build.

Also:

  • Run workflow on the Actions tab does the same.
  • A vX.Y.Z tag pushed by hand still works.
  • A cheap Linux job decides first, so a run with nothing to release costs no macOS minutes.
  • Publishing runs are serialised.
  • make-dmg is retried: the first v1.3.0 run failed on hdiutil: create failed - Resource busy, a known GitHub runner flake. The same step had passed three dry runs.

Checked locally against the real tags: main/dispatch → 1.3.1, tag v1.3.0 → 1.3.0, PR → 1.3.0 (dry), VERSION 1.4.0 → 1.4.0, an invalid VERSION → error.

🤖 Generated with Claude Code

… released

No tagging from a laptop. A merge to main that touches the app (sources,
resources, Package files, VERSION, launchd templates, config, the cask) is
released and tagged on that commit. The patch number is computed: the base
from mac-app/VERSION if it is not tagged yet, otherwise the next patch after
the highest tag of that major.minor (1.3.0 -> 1.3.1). It is written into the
build, so the app reports the released version. "Run workflow" does the
same; a hand-pushed vX.Y.Z tag still releases exactly that version.

A cheap Linux job decides first, so a run with nothing to release costs no
macOS minutes; publishing runs are serialised.

`hdiutil create` is retried: it failed the first v1.3.0 run with "Resource
busy", a known runner flake, after passing three dry runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mbeczynski
mbeczynski merged commit 844c4c4 into main Oct 6, 2026
4 checks passed
mbeczynski added a commit that referenced this pull request Oct 6, 2026
… is not (#14)

* fix(release): releases are built from a clean tree and say which file is not

v1.3.0 was released marked DIRTY-TREE with no clue why. And the patch
version step added in #13 wrote the computed version into mac-app/VERSION,
which would have marked every later release dirty too.

- build-app and make-dmg take the version from CM_RELEASE_VERSION when set;
  the workflow passes it instead of rewriting VERSION.
- build-app lists the uncommitted paths when the tree is dirty, and the
  workflow prints `git status` before building.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ci): build on macos-15, so releases use the pinned dependencies

swift-argument-parser 1.8.2 (pinned in Package.resolved) needs Swift 6. The
macos-14 runner has Swift 5.10, so it quietly resolved 1.7.2 and rewrote
Package.resolved: CI tested, and v1.3.0 shipped, a different dependency
than the repository pins - which is what the DIRTY-TREE marker was saying.

CI and releases now run on macos-15 (Swift 6), with the runner's default
Xcode, not a pinned one. A release also stops if the build changed any
tracked file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ci): lint with Homebrew's swift-format, not the one bundled with Xcode 16

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@mbeczynski
mbeczynski deleted the ci/auto-release branch October 6, 2026 08:49
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