Skip to content

Commit fd73380

Browse files
committed
fix(ci): bootstrap empty Glean channel from Nightly
1 parent 443bca3 commit fd73380

2 files changed

Lines changed: 223 additions & 15 deletions

File tree

.github/scripts/calculate-nightly-release-tag.sh

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ CHART_OCI_REF="${CHART_OCI_REF:-oci://registry.composio.io/composio-rodent/night
66
RELEASE_CHANNEL_NAME="${RELEASE_CHANNEL_NAME:-${NIGHTLY_CHANNEL_NAME:-Nightly}}"
77
RELEASE_CHANNEL_ID="${RELEASE_CHANNEL_ID:-}"
88
TAG_CALCULATION_MODE="${TAG_CALCULATION_MODE:-standard}"
9+
SEED_CHANNEL_NAME="${SEED_CHANNEL_NAME:-}"
10+
SEED_CHANNEL_ID="${SEED_CHANNEL_ID:-}"
11+
SEED_CHART_OCI_REF="${SEED_CHART_OCI_REF:-}"
912

1013
require_cmd() {
1114
if ! command -v "$1" >/dev/null 2>&1; then
@@ -31,7 +34,8 @@ write_output() {
3134
}
3235

3336
chart_name_from_ref() {
34-
basename "${CHART_OCI_REF}"
37+
local chart_oci_ref="$1"
38+
basename "${chart_oci_ref}"
3539
}
3640

3741
resolve_replicated_app_id() {
@@ -64,32 +68,29 @@ resolve_replicated_app_id() {
6468

6569
resolve_release_channel() {
6670
local app_id="$1"
71+
local channel_name="$2"
72+
local expected_channel_id="$3"
6773
local channels_json total_count channel_id current_version release_sequence
6874

6975
channels_json="$(
7076
curl -fsSLG "https://api.replicated.com/vendor/v3/app/${app_id}/channels" \
71-
--data-urlencode "channelName=${RELEASE_CHANNEL_NAME}" \
77+
--data-urlencode "channelName=${channel_name}" \
7278
--header "Accept: application/json" \
7379
--header "Authorization: ${REPLICATED_API_TOKEN}"
7480
)"
7581

7682
total_count="$(echo "${channels_json}" | jq -r '.totalCount // (.channels | length)')"
7783
if [[ "${total_count}" != "1" ]]; then
78-
echo "${RELEASE_CHANNEL_NAME} channel was not found in Replicated channels API response" >&2
84+
echo "${channel_name} channel was not found in Replicated channels API response" >&2
7985
exit 1
8086
fi
8187

8288
channel_id="$(echo "${channels_json}" | jq -r '.channels[0].id // .channels[0].channelId // empty')"
8389
current_version="$(echo "${channels_json}" | jq -r '.channels[0].currentVersion // empty')"
8490
release_sequence="$(echo "${channels_json}" | jq -r '.channels[0].releaseSequence // .channels[0].currentReleaseSequence // empty')"
8591

86-
if [[ -n "${RELEASE_CHANNEL_ID}" && "${channel_id}" != "${RELEASE_CHANNEL_ID}" ]]; then
87-
echo "${RELEASE_CHANNEL_NAME} channel ID mismatch: expected ${RELEASE_CHANNEL_ID}, got ${channel_id:-<empty>}" >&2
88-
exit 1
89-
fi
90-
91-
if [[ -z "${current_version}" || "${current_version}" == "null" ]]; then
92-
echo "${RELEASE_CHANNEL_NAME} channel response did not include currentVersion" >&2
92+
if [[ -n "${expected_channel_id}" && "${channel_id}" != "${expected_channel_id}" ]]; then
93+
echo "${channel_name} channel ID mismatch: expected ${expected_channel_id}, got ${channel_id:-<empty>}" >&2
9394
exit 1
9495
fi
9596

@@ -101,15 +102,16 @@ resolve_release_channel() {
101102
}
102103

103104
pull_release_values() {
104-
local chart_version="$1"
105+
local chart_oci_ref="$1"
106+
local chart_version="$2"
105107
local chart_name pull_root chart_dir
106108

107109
require_cmd helm
108110

109-
chart_name="$(chart_name_from_ref)"
111+
chart_name="$(chart_name_from_ref "${chart_oci_ref}")"
110112
pull_root="$(mktemp -d)"
111113

112-
helm pull "${CHART_OCI_REF}" --version "${chart_version}" --untar --untardir "${pull_root}" >/dev/null
114+
helm pull "${chart_oci_ref}" --version "${chart_version}" --untar --untardir "${pull_root}" >/dev/null
113115

114116
chart_dir="${pull_root}/${chart_name}"
115117
if [[ ! -f "${chart_dir}/values.yaml" ]]; then
@@ -207,6 +209,7 @@ calculate_next_glean_tag() {
207209
main() {
208210
local date_ist app_id channel_json channel_id current_version release_sequence
209211
local values_file base_tag base_tags base_count suffix_tag new_tag glean_tags
212+
local seed_channel_json values_source_name values_source_version values_source_ref
210213

211214
require_cmd jq
212215

@@ -216,6 +219,9 @@ main() {
216219
current_version=""
217220
release_sequence=""
218221
suffix_tag=""
222+
values_source_name="local file"
223+
values_source_version=""
224+
values_source_ref=""
219225

220226
if [[ -n "${RELEASE_VALUES_FILE:-}" ]]; then
221227
values_file="${RELEASE_VALUES_FILE}"
@@ -225,11 +231,41 @@ main() {
225231
require_cmd curl
226232

227233
app_id="$(resolve_replicated_app_id)"
228-
channel_json="$(resolve_release_channel "${app_id}")"
234+
channel_json="$(
235+
resolve_release_channel "${app_id}" "${RELEASE_CHANNEL_NAME}" "${RELEASE_CHANNEL_ID}"
236+
)"
229237
channel_id="$(echo "${channel_json}" | jq -r '.id // empty')"
230238
current_version="$(echo "${channel_json}" | jq -r '.currentVersion // empty')"
231239
release_sequence="$(echo "${channel_json}" | jq -r '.releaseSequence // empty')"
232-
values_file="$(pull_release_values "${current_version}")"
240+
241+
values_source_name="${RELEASE_CHANNEL_NAME}"
242+
values_source_version="${current_version}"
243+
values_source_ref="${CHART_OCI_REF}"
244+
245+
if [[ -z "${current_version}" || "${current_version}" == "null" ]]; then
246+
if [[ "${TAG_CALCULATION_MODE}" != "glean" ]]; then
247+
echo "${RELEASE_CHANNEL_NAME} channel response did not include currentVersion" >&2
248+
exit 1
249+
fi
250+
251+
require_env SEED_CHANNEL_NAME
252+
require_env SEED_CHANNEL_ID
253+
require_env SEED_CHART_OCI_REF
254+
255+
seed_channel_json="$(
256+
resolve_release_channel "${app_id}" "${SEED_CHANNEL_NAME}" "${SEED_CHANNEL_ID}"
257+
)"
258+
values_source_version="$(echo "${seed_channel_json}" | jq -r '.currentVersion // empty')"
259+
if [[ -z "${values_source_version}" || "${values_source_version}" == "null" ]]; then
260+
echo "${SEED_CHANNEL_NAME} seed channel response did not include currentVersion" >&2
261+
exit 1
262+
fi
263+
264+
values_source_name="${SEED_CHANNEL_NAME}"
265+
values_source_ref="${SEED_CHART_OCI_REF}"
266+
fi
267+
268+
values_file="$(pull_release_values "${values_source_ref}" "${values_source_version}")"
233269
fi
234270

235271
case "${TAG_CALCULATION_MODE}" in
@@ -276,6 +312,7 @@ main() {
276312
echo "${RELEASE_CHANNEL_NAME} channel id: ${channel_id:-not resolved}"
277313
echo "${RELEASE_CHANNEL_NAME} current chart version: ${current_version:-not resolved}"
278314
echo "${RELEASE_CHANNEL_NAME} release sequence: ${release_sequence:-not resolved}"
315+
echo "Chart values source: ${values_source_name} ${values_source_version:-not resolved}"
279316
echo "Base image tag used for increment: ${base_tag:-none}"
280317
echo "Suffix image tag used for increment: ${suffix_tag:-none}"
281318
echo "Calculated release tag: ${new_tag}"

.github/scripts/tests/calculate-nightly-release-tag-test.sh

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,153 @@ fail() {
1010
exit 1
1111
}
1212

13+
assert_output() {
14+
local file="$1"
15+
local key="$2"
16+
local expected="$3"
17+
local actual
18+
19+
actual="$(awk -F= -v key="${key}" '$1 == key { print substr($0, index($0, "=") + 1) }' "${file}" | tail -n1)"
20+
[[ "${actual}" == "${expected}" ]] \
21+
|| fail "${key}: expected ${expected:-<empty>}, got ${actual:-<empty>}"
22+
}
23+
24+
write_fake_api_tools() {
25+
local bin_dir="$1"
26+
27+
mkdir -p "${bin_dir}"
28+
cat >"${bin_dir}/curl" <<'EOF'
29+
#!/usr/bin/env bash
30+
set -euo pipefail
31+
32+
case "$*" in
33+
*"/vendor/v3/apps"*)
34+
printf '%s' '{"apps":[{"id":"app-id","slug":"composio-rodent","name":"Composio Rodent"}]}'
35+
;;
36+
*"channelName=Glean-Stable"*)
37+
printf '%s' '{"totalCount":1,"channels":[{"id":"3GwShNBOwcf13Bs7i5pfn3N8TDh","releaseSequence":0}]}'
38+
;;
39+
*"channelName=Nightly"*)
40+
if [[ "${FAKE_API_SCENARIO:-bootstrap}" == "bootstrap" ]]; then
41+
printf '%s' '{"totalCount":1,"channels":[{"id":"397k1WtPrJ1J56bhb70SfeKGcxL","currentVersion":"0.2.140","releaseSequence":238}]}'
42+
else
43+
printf '%s' '{"totalCount":1,"channels":[{"id":"397k1WtPrJ1J56bhb70SfeKGcxL","releaseSequence":0}]}'
44+
fi
45+
;;
46+
*)
47+
echo "unexpected curl arguments: $*" >&2
48+
exit 1
49+
;;
50+
esac
51+
EOF
52+
53+
cat >"${bin_dir}/helm" <<'EOF'
54+
#!/usr/bin/env bash
55+
set -euo pipefail
56+
57+
printf '%s\n' "$*" >> "${FAKE_HELM_LOG}"
58+
untar_dir=""
59+
while (( $# > 0 )); do
60+
if [[ "$1" == "--untardir" ]]; then
61+
untar_dir="$2"
62+
break
63+
fi
64+
shift
65+
done
66+
67+
if [[ -z "${untar_dir}" ]]; then
68+
echo "fake helm did not receive --untardir" >&2
69+
exit 1
70+
fi
71+
72+
mkdir -p "${untar_dir}/composio"
73+
cat >"${untar_dir}/composio/values.yaml" <<'EOF_VALUES'
74+
apollo:
75+
image:
76+
tag: r20260729_04
77+
EOF_VALUES
78+
EOF
79+
80+
chmod +x "${bin_dir}/curl" "${bin_dir}/helm"
81+
}
82+
83+
assert_empty_glean_uses_nightly_seed() {
84+
local tmp_dir output_file helm_log
85+
86+
tmp_dir="$(mktemp -d)"
87+
output_file="${tmp_dir}/github-output"
88+
helm_log="${tmp_dir}/helm-log"
89+
write_fake_api_tools "${tmp_dir}/bin"
90+
91+
if ! PATH="${tmp_dir}/bin:${PATH}" \
92+
FAKE_API_SCENARIO=bootstrap \
93+
FAKE_HELM_LOG="${helm_log}" \
94+
RELEASE_TAG_DATE=20260730 \
95+
REPLICATED_APP=composio-rodent \
96+
REPLICATED_API_TOKEN=test-token \
97+
RELEASE_CHANNEL_NAME=Glean-Stable \
98+
RELEASE_CHANNEL_ID=3GwShNBOwcf13Bs7i5pfn3N8TDh \
99+
CHART_OCI_REF=oci://registry.composio.io/composio-rodent/glean-stable/composio \
100+
TAG_CALCULATION_MODE=glean \
101+
SEED_CHANNEL_NAME=Nightly \
102+
SEED_CHANNEL_ID=397k1WtPrJ1J56bhb70SfeKGcxL \
103+
SEED_CHART_OCI_REF=oci://registry.composio.io/composio-rodent/nightly/composio \
104+
GITHUB_OUTPUT="${output_file}" \
105+
bash "${SCRIPT}" >"${tmp_dir}/stdout" 2>"${tmp_dir}/stderr"; then
106+
sed 's/^/ /' "${tmp_dir}/stderr" >&2
107+
fail "empty Glean channel did not bootstrap"
108+
fi
109+
110+
assert_output "${output_file}" replicated_current_version ""
111+
assert_output "${output_file}" release_tag "r20260729_04-p20260730_01"
112+
grep -Fq \
113+
'pull oci://registry.composio.io/composio-rodent/nightly/composio --version 0.2.140' \
114+
"${helm_log}" || fail "empty Glean channel did not pull the Nightly seed chart"
115+
116+
rm -rf "${tmp_dir}"
117+
}
118+
119+
assert_api_release_tag_fails() {
120+
local name="$1"
121+
local mode="$2"
122+
local channel_name="$3"
123+
local channel_id="$4"
124+
local seed_name="$5"
125+
local seed_id="$6"
126+
local seed_ref="$7"
127+
local scenario="$8"
128+
local expected_error="$9"
129+
local tmp_dir chart_ref
130+
131+
tmp_dir="$(mktemp -d)"
132+
write_fake_api_tools "${tmp_dir}/bin"
133+
chart_ref="oci://registry.composio.io/composio-rodent/nightly/composio"
134+
if [[ "${mode}" == "glean" ]]; then
135+
chart_ref="oci://registry.composio.io/composio-rodent/glean-stable/composio"
136+
fi
137+
138+
if PATH="${tmp_dir}/bin:${PATH}" \
139+
FAKE_API_SCENARIO="${scenario}" \
140+
FAKE_HELM_LOG="${tmp_dir}/helm-log" \
141+
RELEASE_TAG_DATE=20260730 \
142+
REPLICATED_APP=composio-rodent \
143+
REPLICATED_API_TOKEN=test-token \
144+
RELEASE_CHANNEL_NAME="${channel_name}" \
145+
RELEASE_CHANNEL_ID="${channel_id}" \
146+
CHART_OCI_REF="${chart_ref}" \
147+
TAG_CALCULATION_MODE="${mode}" \
148+
SEED_CHANNEL_NAME="${seed_name}" \
149+
SEED_CHANNEL_ID="${seed_id}" \
150+
SEED_CHART_OCI_REF="${seed_ref}" \
151+
bash "${SCRIPT}" >"${tmp_dir}/stdout" 2>"${tmp_dir}/stderr"; then
152+
fail "${name}: script unexpectedly succeeded"
153+
fi
154+
155+
grep -Fq "${expected_error}" "${tmp_dir}/stderr" \
156+
|| fail "${name}: expected error was not emitted"
157+
rm -rf "${tmp_dir}"
158+
}
159+
13160
assert_release_tag() {
14161
local name="$1"
15162
local mode="$2"
@@ -146,4 +293,28 @@ mercury:
146293
tag: r20260730_01
147294
'
148295

296+
assert_empty_glean_uses_nightly_seed
297+
298+
assert_api_release_tag_fails \
299+
"empty standard channel remains invalid" \
300+
standard Nightly 397k1WtPrJ1J56bhb70SfeKGcxL \
301+
"" "" "" empty-standard \
302+
"Nightly channel response did not include currentVersion"
303+
304+
assert_api_release_tag_fails \
305+
"empty Glean seed remains invalid" \
306+
glean Glean-Stable 3GwShNBOwcf13Bs7i5pfn3N8TDh \
307+
Nightly 397k1WtPrJ1J56bhb70SfeKGcxL \
308+
oci://registry.composio.io/composio-rodent/nightly/composio \
309+
empty-seed \
310+
"Nightly seed channel response did not include currentVersion"
311+
312+
assert_api_release_tag_fails \
313+
"mismatched Glean seed channel id is rejected" \
314+
glean Glean-Stable 3GwShNBOwcf13Bs7i5pfn3N8TDh \
315+
Nightly wrong-seed-id \
316+
oci://registry.composio.io/composio-rodent/nightly/composio \
317+
bootstrap \
318+
"Nightly channel ID mismatch"
319+
149320
echo "calculate-nightly-release-tag tests passed"

0 commit comments

Comments
 (0)