scripts/version.sh (new): emits ICCERY_RELEASE_TAG / MARKETING_VERSION / CURRENT_PROJECT_VERSION for eval. Tag = RELEASE_TAG env matching v[0-9]*, else git describe --tags --always --dirty --match 'v[0-9]*'. Marketing = first 3 numeric components of the tag core (v2.0.0.0-x → 2.0.0). Build = BUILD_NUMBER env override else git rev-list --count HEAD.
Hard-fail on mis-tag: a real v* release tag whose X.Y.Z ≠ project.yml's MARKETING_VERSION aborts packaging — marketing version always aligns with the released version.
project.yml: ICCERY_RELEASE_TAG build setting + "Stamp release tag" post-build phase writing Contents/Resources/ICCeryReleaseTag. A generated Info.plist cannot carry custom keys (INFOPLIST_KEY_* allowlist; ProcessInfoPlistFile runs after script phases), so the tag ships as a bundled resource — still before CodeSign.
package-release.sh: evals version.sh, passes the three as xcodebuild overrides, names DMGs ICCery-<tag>-<build>.dmg for tagged/described builds (plain release keeps ICCery-<ver>-<build>.dmg).
ArtefactFiles.appInfo(): About "Version:" = tag (marketing) — v2.0.0-pre2-grok (2.0.0); dedupes to v2.0.0 on an exact release tag; falls back to the plain version untagged. "Build:" = commit count (Apple: macOS CFBundleVersion must monotonically increase — unlike iOS it never resets per version).
CI twins: fetch-depth: 0 (shallow clones break git describe/rev-list), RELEASE_TAG: ${{ github.ref_name }}, and the build-for-testing leg stamps the same triple so mis-tags fail before packaging.
Tests: 7 new AppInfoTests — all 447 ICCeryCoreTests green locally.
xcodebuild test -scheme ICCery -only-testing:ICCeryCoreTests: 447/447 pass.
Release procedure after merge
Bump MARKETING_VERSION in project.yml on develop → merge develop → main → tag the release commit vX.Y.Z[-suffix] → push tag. CI builds + attaches ICCery-<tag>-<build>.dmg to the release.
Closes #189.
## What
- **`scripts/version.sh`** (new): emits `ICCERY_RELEASE_TAG` / `MARKETING_VERSION` / `CURRENT_PROJECT_VERSION` for `eval`. Tag = `RELEASE_TAG` env matching `v[0-9]*`, else `git describe --tags --always --dirty --match 'v[0-9]*'`. Marketing = first 3 numeric components of the tag core (`v2.0.0.0-x` → `2.0.0`). Build = `BUILD_NUMBER` env override else `git rev-list --count HEAD`.
- **Hard-fail on mis-tag**: a real `v*` release tag whose X.Y.Z ≠ `project.yml`'s `MARKETING_VERSION` aborts packaging — marketing version always aligns with the released version.
- **`project.yml`**: `ICCERY_RELEASE_TAG` build setting + "Stamp release tag" post-build phase writing `Contents/Resources/ICCeryReleaseTag`. A generated Info.plist cannot carry custom keys (`INFOPLIST_KEY_*` allowlist; `ProcessInfoPlistFile` runs after script phases), so the tag ships as a bundled resource — still before CodeSign.
- **`package-release.sh`**: evals version.sh, passes the three as `xcodebuild` overrides, names DMGs `ICCery-<tag>-<build>.dmg` for tagged/described builds (plain release keeps `ICCery-<ver>-<build>.dmg`).
- **`ArtefactFiles.appInfo()`**: About "Version:" = `tag (marketing)` — `v2.0.0-pre2-grok (2.0.0)`; dedupes to `v2.0.0` on an exact release tag; falls back to the plain version untagged. "Build:" = commit count (Apple: macOS `CFBundleVersion` must monotonically increase — unlike iOS it never resets per version).
- **CI twins**: `fetch-depth: 0` (shallow clones break `git describe`/`rev-list`), `RELEASE_TAG: ${{ github.ref_name }}`, and the `build-for-testing` leg stamps the same triple so mis-tags fail before packaging.
- **Tests**: 7 new `AppInfoTests` — all 447 ICCeryCoreTests green locally.
- **Docs**: README versioning section + env table, PREUAT DMG name, AGENTS.md, docs/21 About row.
## Verified locally
- `scripts/version.sh` matrix: describe, `v2.0.0`, `v2.0.0-pre2-grok`, `v2.0.0.0-prerelease-…`, branch name ignored, `BUILD_NUMBER` override; `v9.9.9`/`v2.x.0`/`v2.0-beta` → clear hard-fails.
- Debug build stamps `Contents/Resources/ICCeryReleaseTag` = `v2.0.0-dirty`; `codesign --verify` clean.
- `xcodebuild test -scheme ICCery -only-testing:ICCeryCoreTests`: 447/447 pass.
## Release procedure after merge
Bump `MARKETING_VERSION` in `project.yml` on `develop` → merge `develop` → `main` → tag the release commit `vX.Y.Z[-suffix]` → push tag. CI builds + attaches `ICCery-<tag>-<build>.dmg` to the release.
- scripts/version.sh resolves ICCERY_RELEASE_TAG / MARKETING_VERSION /
CURRENT_PROJECT_VERSION from RELEASE_TAG env or `git describe`; tag
builds hard-fail when the tag's X.Y.Z != project.yml MARKETING_VERSION
- build number = `git rev-list --count HEAD` (Apple: macOS
CFBundleVersion must monotonically increase, no per-version reset)
- tag ships as a bundled ICCeryReleaseTag resource — a generated
Info.plist can't carry custom keys (INFOPLIST_KEY_* allowlist, and
ProcessInfoPlistFile runs after script phases); About shows
"tag (marketing)", e.g. v2.0.0-pre2-grok (2.0.0)
- DMG named ICCery-<tag>-<build>.dmg for tagged/described builds
- CI twins: fetch-depth 0 + RELEASE_TAG env + stamped test builds
gronod
merged commit 14cd544e05 into develop2026-09-15 16:46:01 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #189.
What
scripts/version.sh(new): emitsICCERY_RELEASE_TAG/MARKETING_VERSION/CURRENT_PROJECT_VERSIONforeval. Tag =RELEASE_TAGenv matchingv[0-9]*, elsegit describe --tags --always --dirty --match 'v[0-9]*'. Marketing = first 3 numeric components of the tag core (v2.0.0.0-x→2.0.0). Build =BUILD_NUMBERenv override elsegit rev-list --count HEAD.v*release tag whose X.Y.Z ≠project.yml'sMARKETING_VERSIONaborts packaging — marketing version always aligns with the released version.project.yml:ICCERY_RELEASE_TAGbuild setting + "Stamp release tag" post-build phase writingContents/Resources/ICCeryReleaseTag. A generated Info.plist cannot carry custom keys (INFOPLIST_KEY_*allowlist;ProcessInfoPlistFileruns after script phases), so the tag ships as a bundled resource — still before CodeSign.package-release.sh: evals version.sh, passes the three asxcodebuildoverrides, names DMGsICCery-<tag>-<build>.dmgfor tagged/described builds (plain release keepsICCery-<ver>-<build>.dmg).ArtefactFiles.appInfo(): About "Version:" =tag (marketing)—v2.0.0-pre2-grok (2.0.0); dedupes tov2.0.0on an exact release tag; falls back to the plain version untagged. "Build:" = commit count (Apple: macOSCFBundleVersionmust monotonically increase — unlike iOS it never resets per version).fetch-depth: 0(shallow clones breakgit describe/rev-list),RELEASE_TAG: ${{ github.ref_name }}, and thebuild-for-testingleg stamps the same triple so mis-tags fail before packaging.AppInfoTests— all 447 ICCeryCoreTests green locally.Verified locally
scripts/version.shmatrix: describe,v2.0.0,v2.0.0-pre2-grok,v2.0.0.0-prerelease-…, branch name ignored,BUILD_NUMBERoverride;v9.9.9/v2.x.0/v2.0-beta→ clear hard-fails.Contents/Resources/ICCeryReleaseTag=v2.0.0-dirty;codesign --verifyclean.xcodebuild test -scheme ICCery -only-testing:ICCeryCoreTests: 447/447 pass.Release procedure after merge
Bump
MARKETING_VERSIONinproject.ymlondevelop→ mergedevelop→main→ tag the release commitvX.Y.Z[-suffix]→ push tag. CI builds + attachesICCery-<tag>-<build>.dmgto the release.