返回 DeepSeek-Reasonix
release-stable.test.sh
根目录 / scripts / release-stable.test.sh
1 #!/usr/bin/env bash
2 set -euo pipefail
3
4 repo_root="$(git rev-parse --show-toplevel)"
5 release_script="$repo_root/scripts/release-stable.sh"
6 test_root="$(mktemp -d "${TMPDIR:-/tmp}/reasonix-stable-tag-test.XXXXXX")"
7 cleanup() {
8 case "$test_root" in
9 */reasonix-stable-tag-test.*) rm -rf -- "$test_root" ;;
10 *) echo "refusing to clean unexpected test directory: $test_root" >&2 ;;
11 esac
12 }
13 trap cleanup EXIT
14
15 mkdir -p "$test_root/bin"
16 cat >"$test_root/bin/gh" <<'EOF'
17 #!/usr/bin/env bash
18 set -euo pipefail
19 if [ -n "${FAKE_ADVANCE_WORK:-}" ] && [ ! -e "$FAKE_ADVANCE_WORK/.advanced-by-fake-gh" ]; then
20 : >"$FAKE_ADVANCE_WORK/.advanced-by-fake-gh"
21 git -C "$FAKE_ADVANCE_WORK" add .advanced-by-fake-gh
22 git -C "$FAKE_ADVANCE_WORK" commit -q -m "advance main during CI"
23 git -C "$FAKE_ADVANCE_WORK" push -q origin main-v2
24 fi
25 if [ "${FAKE_GH_CONCLUSION:-success}" = pending ]; then
26 printf '[{"headSha":"%s","status":"in_progress","conclusion":""}]\n' "$FAKE_CANDIDATE"
27 else
28 printf '[{"headSha":"%s","status":"completed","conclusion":"%s"}]\n' \
29 "$FAKE_CANDIDATE" "${FAKE_GH_CONCLUSION:-success}"
30 fi
31 EOF
32 chmod +x "$test_root/bin/gh"
33
34 make_remote() {
35 local name="$1"
36 local work="$test_root/$name-work"
37 local remote="$test_root/$name.git"
38 git init -q --bare "$remote"
39 git init -q -b main-v2 "$work"
40 git -C "$work" config user.name test
41 git -C "$work" config user.email test@example.invalid
42 mkdir -p "$work/release-notes"
43 jq '.releases |= map(select(.version != "1.19.2"))' \
44 "$repo_root/release-notes/releases.json" >"$work/release-notes/releases.json"
45 git -C "$work" add release-notes/releases.json
46 git -C "$work" commit -q -m base
47 cp "$repo_root/release-notes/releases.json" "$work/release-notes/releases.json"
48 git -C "$work" add release-notes/releases.json
49 git -C "$work" commit -q -m "reviewed release notes"
50 git -C "$work" remote add origin "$remote"
51 git -C "$work" push -q origin main-v2
52 printf '%s\n' "$work"
53 }
54
55 success_work="$(make_remote success)"
56 success_sha="$(git -C "$success_work" rev-parse HEAD)"
57 (
58 cd "$success_work"
59 PATH="$test_root/bin:$PATH" FAKE_CANDIDATE="$success_sha" \
60 RELEASE_CI_WAIT_SECONDS=0 RELEASE_REMOTE=origin \
61 "$release_script" 1.19.2
62 )
63 for tag in v1.19.2 npm-v1.19.2 desktop-v1.19.2; do
64 [ "$(git ls-remote --tags --refs "$test_root/success.git" "refs/tags/$tag" | awk 'NR == 1 { print $1 }')" = "$success_sha" ]
65 done
66
67 # Advancing main after the atomic tag transaction must not invalidate the
68 # immutable Notes candidate selected by the protected relay.
69 git clone -q -b main-v2 "$test_root/success.git" "$test_root/success-control"
70 git -C "$test_root/success-control" config user.name test
71 git -C "$test_root/success-control" config user.email test@example.invalid
72 git -C "$test_root/success-control" commit --allow-empty -q -m "advance after tags"
73 git -C "$test_root/success-control" push -q origin main-v2
74 (
75 cd "$test_root/success-control"
76 GITHUB_OUTPUT="$test_root/success-control.out" RELEASE_REMOTE=origin \
77 RELEASE_TAG=v1.19.2 ALLOW_STABLE_RECOVERY=false \
78 "$repo_root/scripts/resolve-stable-release.sh"
79 )
80 grep -Eq '^sha='"$success_sha"'$' "$test_root/success-control.out"
81 (
82 cd "$success_work"
83 GITHUB_OUTPUT="$test_root/stale-control.out" RELEASE_REMOTE=origin \
84 RELEASE_TAG=v1.19.2 ALLOW_STABLE_RECOVERY=false \
85 "$repo_root/scripts/resolve-stable-release.sh"
86 )
87 grep -Eq '^sha='"$success_sha"'$' "$test_root/stale-control.out"
88
89 failure_work="$(make_remote failure)"
90 failure_sha="$(git -C "$failure_work" rev-parse HEAD)"
91 if (
92 cd "$failure_work"
93 PATH="$test_root/bin:$PATH" FAKE_CANDIDATE="$failure_sha" FAKE_GH_CONCLUSION=failure \
94 RELEASE_CI_WAIT_SECONDS=0 RELEASE_REMOTE=origin \
95 "$release_script" 1.19.2
96 ); then
97 echo "failed CI unexpectedly created release tags" >&2
98 exit 1
99 fi
100 [ -z "$(git ls-remote --tags --refs "$test_root/failure.git" 'refs/tags/*')" ]
101
102 # A later code commit is not the reviewed Notes merge and must never become the
103 # release candidate merely because it contains the older reviewed record.
104 stale_notes_work="$(make_remote stale-notes)"
105 git -C "$stale_notes_work" commit --allow-empty -q -m "later product change"
106 git -C "$stale_notes_work" push -q origin main-v2
107 stale_notes_sha="$(git -C "$stale_notes_work" rev-parse HEAD)"
108 if (
109 cd "$stale_notes_work"
110 PATH="$test_root/bin:$PATH" FAKE_CANDIDATE="$stale_notes_sha" \
111 RELEASE_CI_WAIT_SECONDS=0 RELEASE_REMOTE=origin \
112 "$release_script" 1.19.2
113 ); then
114 echo "candidate after the reviewed Notes commit unexpectedly created release tags" >&2
115 exit 1
116 fi
117 [ -z "$(git ls-remote --tags --refs "$test_root/stale-notes.git" 'refs/tags/*')" ]
118
119 # If main advances while exact-SHA CI is being checked, the no-op main-v2
120 # refspec makes the atomic push reject all three tags.
121 race_work="$(make_remote race)"
122 race_sha="$(git -C "$race_work" rev-parse HEAD)"
123 git clone -q -b main-v2 "$test_root/race.git" "$test_root/race-advance"
124 git -C "$test_root/race-advance" config user.name test
125 git -C "$test_root/race-advance" config user.email test@example.invalid
126 if (
127 cd "$race_work"
128 PATH="$test_root/bin:$PATH" FAKE_CANDIDATE="$race_sha" \
129 FAKE_ADVANCE_WORK="$test_root/race-advance" RELEASE_CI_WAIT_SECONDS=0 \
130 RELEASE_REMOTE=origin "$release_script" 1.19.2
131 ); then
132 echo "main-v2 advance during CI unexpectedly created release tags" >&2
133 exit 1
134 fi
135 [ -z "$(git ls-remote --tags --refs "$test_root/race.git" 'refs/tags/*')" ]
136 [ "$(git ls-remote "$test_root/race.git" refs/heads/main-v2 | awk 'NR == 1 { print $1 }')" != "$race_sha" ]
137
138 occupied_work="$(make_remote occupied)"
139 occupied_sha="$(git -C "$occupied_work" rev-parse HEAD)"
140 git -C "$occupied_work" tag v1.19.2
141 git -C "$occupied_work" push -q origin v1.19.2
142 if (
143 cd "$occupied_work"
144 PATH="$test_root/bin:$PATH" FAKE_CANDIDATE="$occupied_sha" \
145 RELEASE_CI_WAIT_SECONDS=0 RELEASE_REMOTE=origin \
146 "$release_script" 1.19.2
147 ); then
148 echo "occupied release identity unexpectedly passed" >&2
149 exit 1
150 fi
151 [ -z "$(git ls-remote --tags --refs "$test_root/occupied.git" refs/tags/npm-v1.19.2 refs/tags/desktop-v1.19.2)" ]
152
153 if "$release_script" 1.19.2-preview.1 >/dev/null 2>&1; then
154 echo "Preview version unexpectedly passed the Stable tag helper" >&2
155 exit 1
156 fi
157
158 echo "stable release tag helper tests: PASS"
159
159 lines BASH