-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrelease
More file actions
executable file
·244 lines (220 loc) · 8.02 KB
/
Copy pathrelease
File metadata and controls
executable file
·244 lines (220 loc) · 8.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#!/usr/bin/env bash
# Repository-owned release policy guard for the Base Bash v2 release line.
release_usage() {
cat >&2 <<'EOF'
Usage:
scripts/release <check|plan|notes|refs|publish> --version <version> [options]
Allowed release identifiers:
2.0.0-alpha.N
2.0.0-beta.N
2.0.0-rc.N
2.0.0
N must be a positive integer without leading zeroes. Real publication remains
locked until the verified-artifact and pre-GA release-candidate gates are
complete.
The refs command is a read-only preflight that fails closed when the candidate
tag already exists locally or on origin.
EOF
}
release_error() {
printf 'ERROR: %s\n' "$*" >&2
}
release_version_kind() {
local version="${1-}"
local prerelease_re='^2[.]0[.]0-(alpha|beta|rc)[.]([1-9][0-9]*)$'
if [[ "$version" == "2.0.0" ]]; then
printf 'ga\n'
return 0
fi
if [[ "$version" =~ $prerelease_re ]]; then
printf 'prerelease\n'
return 0
fi
return 1
}
release_check_tag_refs() {
local repo_root="$1"
local tag_name="$2"
local remote_refs=""
local git_status
if ! command -v git >/dev/null 2>&1; then
release_error "Git is required to inspect release tag '$tag_name'."
return 1
fi
if git -C "$repo_root" show-ref --verify --quiet "refs/tags/$tag_name"; then
release_error "Release tag '$tag_name' already exists in the local repository."
release_error "Remove only a confirmed stale local ref before retrying; never retag a published release."
return 1
else
git_status=$?
if ((git_status != 1)); then
release_error "Unable to inspect the local release tag '$tag_name' (git status $git_status)."
return 1
fi
fi
if ! remote_refs="$(git -C "$repo_root" ls-remote --tags origin "refs/tags/$tag_name" 2>/dev/null)"; then
release_error "Unable to inspect release tag '$tag_name' on origin; refusing to continue."
return 1
fi
if [[ -n "$remote_refs" ]]; then
release_error "Release tag '$tag_name' already exists on origin."
release_error "Published tags are immutable; choose a new policy-compliant release identifier."
return 1
fi
printf 'Release tag %s is absent locally and on origin.\n' "$tag_name"
}
main() {
local canonical_manifest
local command="${1-}"
local manifest_value=""
local version=""
local version_kind=""
local dry_run=0
local index
local release_driver="${BASE_BASH_RELEASE_BASECTL:-basectl}"
local script_dir repo_root
local -a arguments=("$@")
local -a delegated_arguments=()
local seen_dry_run=0
local seen_format=0
local seen_manifest=0
local seen_version=0
local seen_yes=0
case "$command" in
check|plan|notes|refs|publish)
;;
""|-h|--help|help)
release_usage
return 2
;;
*)
release_error "Unknown release command '$command'."
release_usage
return 2
;;
esac
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" || return 1
repo_root="$(cd -- "$script_dir/.." && pwd -P)" || return 1
canonical_manifest="$repo_root/base_manifest.yaml"
if [[ ! -f "$canonical_manifest" ]]; then
release_error "Canonical release manifest was not found at '$canonical_manifest'."
return 1
fi
index=1
while ((index < ${#arguments[@]})); do
case "${arguments[$index]}" in
--version)
if ((seen_version)); then
release_error "Option '--version' may be provided only once."
return 2
fi
seen_version=1
index=$((index + 1))
if ((index >= ${#arguments[@]})) || [[ -z "${arguments[$index]}" ]]; then
release_error "Option '--version' requires an argument."
return 2
fi
version="${arguments[$index]}"
;;
--manifest)
if ((seen_manifest)); then
release_error "Option '--manifest' may be provided only once."
return 2
fi
seen_manifest=1
index=$((index + 1))
if ((index >= ${#arguments[@]})) || [[ -z "${arguments[$index]}" ]]; then
release_error "Option '--manifest' requires an argument."
return 2
fi
manifest_value="${arguments[$index]}"
if [[ "$manifest_value" != "base_manifest.yaml" &&
"$manifest_value" != "./base_manifest.yaml" &&
"$manifest_value" != "$canonical_manifest" ]]; then
release_error "Release operations must use the canonical manifest at '$canonical_manifest'."
return 1
fi
;;
--format)
if [[ "$command" != "check" ]]; then
release_error "Option '--format' is only supported by release check."
return 2
fi
if ((seen_format)); then
release_error "Option '--format' may be provided only once."
return 2
fi
seen_format=1
index=$((index + 1))
if ((index >= ${#arguments[@]})) || [[ -z "${arguments[$index]}" ]]; then
release_error "Option '--format' requires an argument."
return 2
fi
;;
--dry-run)
if [[ "$command" != "publish" ]]; then
release_error "Option '--dry-run' is only supported by release publish."
return 2
fi
if ((seen_dry_run)); then
release_error "Option '--dry-run' may be provided only once."
return 2
fi
seen_dry_run=1
dry_run=1
;;
--yes)
if [[ "$command" != "publish" ]]; then
release_error "Option '--yes' is only supported by release publish."
return 2
fi
if ((seen_yes)); then
release_error "Option '--yes' may be provided only once."
return 2
fi
seen_yes=1
;;
-h|--help)
release_usage
return 0
;;
*)
release_error "Unknown release $command option '${arguments[$index]}'."
return 2
;;
esac
index=$((index + 1))
done
if [[ -z "$version" ]]; then
release_error "Release commands require --version."
return 2
fi
version_kind="$(release_version_kind "$version")" || {
release_error "Version '$version' is outside the Base Bash v2.0.0 release line."
release_error "Use 2.0.0-alpha.N, 2.0.0-beta.N, 2.0.0-rc.N, or 2.0.0."
return 1
}
if [[ "$command" == "refs" ]]; then
release_check_tag_refs "$repo_root" "v$version"
return $?
fi
if [[ "$command" == "publish" && "$dry_run" -eq 0 ]]; then
release_check_tag_refs "$repo_root" "v$version" || return $?
if [[ "$version_kind" == "prerelease" ]]; then
release_error "Publishing $version is locked until verified release artifacts and provenance land in #233."
else
release_error "Publishing v2.0.0 GA is locked until the #214 pre-GA gates and #240 RC rehearsal are complete."
fi
release_error "Use 'publish --dry-run' to inspect the guarded plan without changing GitHub state."
return 1
fi
delegated_arguments=("$@")
if ((seen_manifest == 0)); then
delegated_arguments+=(--manifest "$canonical_manifest")
fi
(
cd -- "$repo_root" || exit 1
"$release_driver" release "${delegated_arguments[@]}"
)
}
main "$@"