Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ jobs:
- name: Validate release tag against workspace version (FR-002, FR-004, FR-010)
run: .github/scripts/validate-release-tag.sh "${GITHUB_REF_NAME}"

- name: Compute build identifier (FR-005)
# GITHUB_RUN_NUMBER.GITHUB_RUN_ATTEMPT -- deterministic, and
# (GITHUB_RUN_NUMBER, GITHUB_RUN_ATTEMPT) strictly increases
# across successful releases (SC-003). Exposed as a step output
# (not a job-level env var like TARGET) since it's produced by a
# script rather than a static value.
id: build_id
# A bare `echo "value=$(cmd)"` would swallow a failing `cmd`:
# the compound command's exit status is echo's, not the command
# substitution's, so GitHub Actions' default `bash -e {0}` (no
# `pipefail`) would never notice and the step would pass green
# with an empty value -- silently producing a malformed,
# unidentified release artifact instead of failing the job. A
# separate assignment does propagate the failure correctly.
run: |
build_id="$(.github/scripts/build-identifier.sh)"
echo "value=${build_id}" >> "$GITHUB_OUTPUT"

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
Expand All @@ -62,14 +80,24 @@ jobs:
run: cargo build --release -p iklo-cli --locked

- name: Package release binary (FR-003)
# Stages a target-triple-named copy under a dedicated dist/
# directory for T011 (checksums) and T012 (release creation) to
# consume. Per plan.md's Key Design Decision #7, the actual GitHub
# Release is created once, atomically, in T012 -- this step only
# prepares the asset; it does not create or upload to a Release.
# Stages a target-triple-and-build-identifier-named copy under a
# dedicated dist/ directory for T011 (checksums) and T012
# (release creation) to consume. Per plan.md's Key Design
# Decision #7, the actual GitHub Release is created once,
# atomically, in T012 -- this step only prepares the asset; it
# does not create or upload to a Release. BUILD_ID comes in via
# step-level env (a YAML value, not spliced into the run: script
# body), the same safe pattern as everywhere else in this file --
# GITHUB_RUN_NUMBER/GITHUB_RUN_ATTEMPT are GitHub-controlled, not
# attacker-influenced like a tag name, but there's no reason to
# treat step outputs differently from job-level env vars here.
env:
BUILD_ID: ${{ steps.build_id.outputs.value }}
run: |
mkdir -p dist
cp target/release/iklo "dist/iklo-${GITHUB_REF_NAME}-${TARGET}"
cp target/release/iklo "dist/iklo-${GITHUB_REF_NAME}-${TARGET}-${BUILD_ID}"

- name: Generate SHA-256 checksums (FR-012)
run: .github/scripts/generate-checksums.sh "dist/iklo-${GITHUB_REF_NAME}-${TARGET}"
env:
BUILD_ID: ${{ steps.build_id.outputs.value }}
run: .github/scripts/generate-checksums.sh "dist/iklo-${GITHUB_REF_NAME}-${TARGET}-${BUILD_ID}"
27 changes: 24 additions & 3 deletions specs/005-ci-release-versioning/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,9 @@ created with the packaged CLI binary attached.
atomic release-creation call, per plan.md's Key Design Decision #7 --
this task only stages the named artifact.
**Done 2026-08-13**: `release.yml` copies `target/release/iklo` to
`dist/iklo-${GITHUB_REF_NAME}-x86_64-unknown-linux-gnu` -- single
platform for now, per spec.md's Assumptions. Per plan.md's Key Design
`dist/iklo-${GITHUB_REF_NAME}-x86_64-unknown-linux-gnu` (later extended
with the build identifier in T015) -- single platform for now, per
spec.md's Assumptions. Per plan.md's Key Design
Decision #7, this step only *stages* the named artifact; it does not
create or upload to a GitHub Release -- the Release itself is created
atomically in T012, after checksums (T011) and release notes (T014)
Expand Down Expand Up @@ -298,8 +299,28 @@ progression and generated notes reflect `previous_tag..current_tag` commits.
T005's tag-selection logic), groups commits by conventional-commit intent
with a fallback bucket, and produces the release body text (FR-006,
FR-007, FR-009).
- [ ] **T015** [US3] Wire T006's build identifier into release metadata and
- [x] **T015** [US3] Wire T006's build identifier into release metadata and
artifact naming (FR-005).
**Done 2026-08-15**: `release.yml` gained a "Compute build identifier
(FR-005)" step right after tag validation, calling
`.github/scripts/build-identifier.sh` and exposing the result as a
step output (`steps.build_id.outputs.value`) -- a step output rather
than job-level `env` like `TARGET`, since it's computed by a script
rather than a static value. Threaded into artifact naming: the staged
binary and its checksum file are now
`dist/iklo-<tag>-<target>-<build-id>` (e.g.
`iklo-v0.1.0-x86_64-unknown-linux-gnu-42.1`), via `BUILD_ID` passed as
step-level `env` (a YAML value, not spliced into the `run:` script
body -- the same safe pattern used for the tag/target throughout this
file, even though `GITHUB_RUN_NUMBER`/`GITHUB_RUN_ATTEMPT` are
GitHub-controlled rather than attacker-influenced like a tag name).
"Release metadata" (the other half of FR-005) is completed by T012,
which will read the same `steps.build_id.outputs.value` when it
composes the atomic release-creation call -- not yet built. Verified
locally: built the real release binary, computed a build identifier
with `GITHUB_RUN_NUMBER=42 GITHUB_RUN_ATTEMPT=1` standing in for the
real env vars, staged and checksummed the correctly-named artifact,
confirmed `shasum -a 256 -c` reports `OK`.
- [ ] **T016** [US3] Verify SC-003/SC-004 end-to-end: two consecutive
release runs show a strictly increasing build identifier, and each
release's notes include exactly the commits since the previous tag (no
Expand Down