Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
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
21 changes: 21 additions & 0 deletions .github/scripts/build-identifier.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Computes the deterministic build identifier for a release run (FR-005):
# GITHUB_RUN_NUMBER.GITHUB_RUN_ATTEMPT, both required to be present and
# numeric so "strictly increase" can later be evaluated numerically as the
# pair (GITHUB_RUN_NUMBER, GITHUB_RUN_ATTEMPT) (SC-003).
set -euo pipefail

run_number="${GITHUB_RUN_NUMBER:-}"
run_attempt="${GITHUB_RUN_ATTEMPT:-}"

if [ -z "$run_number" ] || [ -z "$run_attempt" ]; then
echo "error: GITHUB_RUN_NUMBER and GITHUB_RUN_ATTEMPT must both be set" >&2
exit 1
fi

if ! [[ "$run_number" =~ ^[0-9]+$ ]] || ! [[ "$run_attempt" =~ ^[0-9]+$ ]]; then
echo "error: GITHUB_RUN_NUMBER ('$run_number') and GITHUB_RUN_ATTEMPT ('$run_attempt') must both be base-10 integers" >&2
exit 1
fi

echo "${run_number}.${run_attempt}"
70 changes: 70 additions & 0 deletions .github/scripts/tests/test-build-identifier.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
# Fixture-based tests for build-identifier.sh (T006, Constitution I). Run
# manually:
# bash .github/scripts/tests/test-build-identifier.sh
set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
script="$script_dir/../build-identifier.sh"

pass=0
fail=0

check_eq() {
local desc="$1" expected="$2" actual="$3"
if [ "$expected" == "$actual" ]; then
pass=$((pass + 1))
else
fail=$((fail + 1))
echo "FAIL: $desc (expected '$expected', got '$actual')"
fi
}

assert_fail() {
local desc="$1"; shift
if "$@" >/dev/null 2>&1; then
fail=$((fail + 1))
echo "FAIL (expected failure but succeeded): $desc"
else
pass=$((pass + 1))
fi
}

out="$(GITHUB_RUN_NUMBER=42 GITHUB_RUN_ATTEMPT=1 bash "$script")"
check_eq "basic case" "42.1" "$out"

out="$(GITHUB_RUN_NUMBER=1 GITHUB_RUN_ATTEMPT=3 bash "$script")"
check_eq "retry attempt" "1.3" "$out"

assert_fail "missing GITHUB_RUN_NUMBER fails" env -u GITHUB_RUN_NUMBER GITHUB_RUN_ATTEMPT=1 bash "$script"
assert_fail "missing GITHUB_RUN_ATTEMPT fails" env -u GITHUB_RUN_ATTEMPT GITHUB_RUN_NUMBER=1 bash "$script"
assert_fail "non-numeric run number fails" env GITHUB_RUN_NUMBER=abc GITHUB_RUN_ATTEMPT=1 bash "$script"
assert_fail "non-numeric run attempt fails" env GITHUB_RUN_NUMBER=1 GITHUB_RUN_ATTEMPT=abc bash "$script"
assert_fail "negative number fails (not base-10 unsigned per FR-005)" env GITHUB_RUN_NUMBER=-1 GITHUB_RUN_ATTEMPT=1 bash "$script"

# Numeric-pair ordering sanity (SC-003's "strictly increasing" comparison
# basis, (GITHUB_RUN_NUMBER, GITHUB_RUN_ATTEMPT)) -- not exercised by the
# script itself, but documents the contract callers must use rather than
# lexicographic string comparison: run-number is the primary key, and a
# tie is broken by attempt (a same-run retry still counts as "later").
a_run=9; a_attempt=9
Comment thread
rsenna marked this conversation as resolved.
b_run=10; b_attempt=1
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
if [ "$a_run" -lt "$b_run" ]; then
pass=$((pass + 1))
else
fail=$((fail + 1))
echo "FAIL: numeric run-number comparison sanity check"
fi

a_run=5; a_attempt=1
b_run=5; b_attempt=2
if [ "$a_run" -eq "$b_run" ] && [ "$a_attempt" -lt "$b_attempt" ]; then
pass=$((pass + 1))
else
fail=$((fail + 1))
echo "FAIL: same-run-number, attempt-breaks-tie sanity check"
fi

echo "----"
echo "pass=$pass fail=$fail"
[ "$fail" -eq 0 ]
5 changes: 4 additions & 1 deletion specs/005-ci-release-versioning/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,13 @@ shared by both release publishing (US2) and versioning/notes (US3).
Also implements `previous_release_tag` selection (FR-011): nearest
reachable prior SemVer tag via `git describe --tags --match "v[0-9]*"
--abbrev=0 <current_tag>^`.
- [ ] **T006** Implement build-identifier computation: deterministic
- [x] **T006** Implement build-identifier computation: deterministic
`GITHUB_RUN_NUMBER.GITHUB_RUN_ATTEMPT` (FR-005), evaluated numerically as
`(GITHUB_RUN_NUMBER, GITHUB_RUN_ATTEMPT)` for "strictly increasing" checks
(SC-003).
**Done 2026-07-30**: `.github/scripts/build-identifier.sh`, with fixture
tests under `.github/scripts/tests/test-build-identifier.sh` covering
missing/non-numeric env vars, not just the happy path.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

**Checkpoint**: Version/tag validation and build-identifier logic available
for both release publishing and notes generation.
Expand Down