Skip to content

Commit 7468cd6

Browse files
committed
ci: consolidate release-pipeline bash into tested Go
1 parent ba97d49 commit 7468cd6

66 files changed

Lines changed: 5292 additions & 2071 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ scripts/
6262
prepare-helm-values/ # Values preparation/merging
6363
vault-secret-mapper/ # Vault-to-K8s secret mapping
6464
camunda-core/ # Shared Go packages (scenario resolution, kube client)
65-
values-injector/ # Values injection utility
65+
release-tools/ # Release-pipeline CLI (image set, Harbor tags, release notes, values injection)
6666
6767
test/
6868
integration/scenarios/ # Cross-version integration test scenarios

.github/workflows/chart-build-dev.yaml

Lines changed: 85 additions & 197 deletions
Large diffs are not rendered by default.

.github/workflows/chart-promote-rc.yaml

Lines changed: 66 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -74,57 +74,45 @@ jobs:
7474
app_id: ${{ env.GH_APP_ID_DISTRO_CI }}
7575
private_key: ${{ env.GH_APP_PRIVATE_KEY_DISTRO_CI }}
7676

77+
# "Parse dev tag" runs before the commit SHA is known, so build release-tools
78+
# here. The binary in /tmp survives the later checkout-at-SHA.
79+
- name: Checkout for tooling
80+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
81+
82+
- name: Install tools for tooling
83+
uses: ./.github/actions/install-tool-versions
84+
with:
85+
tools: |
86+
golang
87+
88+
- name: Build release-tools
89+
run: cd scripts/release-tools && go build -o /tmp/release-tools .
90+
7791
- name: Parse dev tag
7892
id: parse
7993
env:
8094
HARBOR_API: "https://${{ env.HARBOR_REGISTRY }}/api/v2.0"
8195
HARBOR_REPO: "projects/${{ env.HARBOR_PROJECT }}/repositories/camunda-platform"
8296
run: |
8397
input_tag="${{ inputs.dev-tag }}"
84-
85-
# Check if it's a rolling tag format: {major}-dev-latest
98+
99+
# A rolling tag ({major}-dev-latest) needs the artifact's tag list to
100+
# resolve to a concrete {version}-dev-{sha}; fetch it for resolve-tag.
101+
tags_args=()
86102
if [[ "$input_tag" =~ ^[0-9]+-dev-latest$ ]]; then
87103
echo "::notice::Rolling tag detected: ${input_tag}, resolving to actual dev tag..."
88-
89-
# Query Harbor API to get all tags for this artifact
90-
tags_response=$(curl -sf "${HARBOR_API}/${HARBOR_REPO}/artifacts/${input_tag}/tags" \
104+
curl -sf "${HARBOR_API}/${HARBOR_REPO}/artifacts/${input_tag}/tags" \
91105
-u "${HARBOR_REGISTRY_USER}:${HARBOR_REGISTRY_PASSWORD}" \
92-
--retry 3 --retry-delay 5 --retry-all-errors)
93-
94-
if [[ -z "$tags_response" || "$tags_response" == "null" ]]; then
95-
echo "::error::Rolling tag ${input_tag} not found in Harbor"
96-
exit 1
97-
fi
98-
99-
# Find the actual dev tag (format: {version}-dev-{sha})
100-
dev_tag=$(echo "$tags_response" | jq -r '.[].name | select(test("^[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z0-9]+)?-dev-[a-f0-9]+$"))' | head -1)
101-
102-
if [[ -z "$dev_tag" ]]; then
103-
echo "::error::Could not find actual dev tag for rolling tag ${input_tag}"
104-
exit 1
105-
fi
106-
107-
echo "::notice::Resolved rolling tag ${input_tag} to: ${dev_tag}"
108-
else
109-
dev_tag="$input_tag"
106+
--retry 3 --retry-delay 5 --retry-all-errors > /tmp/dev-tags.json
107+
tags_args=(--tags-file /tmp/dev-tags.json)
110108
fi
111-
112-
echo "resolved_tag=${dev_tag}" | tee -a $GITHUB_OUTPUT
113-
114-
# Validate format: {version}-dev-{sha}
115-
if [[ ! "$dev_tag" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?-dev-[a-f0-9]+$ ]]; then
116-
echo "::error::Invalid dev tag format. Expected: {version}-dev-{sha} (e.g., 13.4.0-dev-abc1234)"
117-
exit 1
118-
fi
119-
120-
# Extract version (everything before -dev-)
121-
version="${dev_tag%-dev-*}"
122-
echo "version=${version}" | tee -a $GITHUB_OUTPUT
123-
124-
# Extract SHA (everything after -dev-)
125-
sha="${dev_tag##*-dev-}"
126109
127-
# Resolve short SHA to full 40-char commit SHA.
110+
# Resolve + validate the dev tag; emit resolved_tag/version/chart_major/
111+
# rc_tag/rc_latest_tag to $GITHUB_OUTPUT. The short commit SHA is printed
112+
# to stdout and expanded to the full SHA below.
113+
sha=$(/tmp/release-tools resolve-tag --kind dev --input-tag "$input_tag" "${tags_args[@]}")
114+
115+
# Resolve short SHA to full 40-char commit SHA (GitHub API stays glue).
128116
# actions/checkout treats short SHAs as branch/tag names and fails.
129117
if [[ ${#sha} -lt 40 ]]; then
130118
echo "::notice::Short SHA detected (${sha}); resolving via GitHub API..."
@@ -142,14 +130,6 @@ jobs:
142130
fi
143131
144132
echo "sha=${sha}" | tee -a $GITHUB_OUTPUT
145-
146-
# Extract chart major (first number of version)
147-
chart_major="${version%%.*}"
148-
echo "chart_major=${chart_major}" | tee -a $GITHUB_OUTPUT
149-
150-
# RC tag format
151-
echo "rc_tag=${version}-rc" | tee -a $GITHUB_OUTPUT
152-
echo "rc_latest_tag=${chart_major}-rc-latest" | tee -a $GITHUB_OUTPUT
153133
154134
- name: Checkout at commit SHA
155135
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -165,18 +145,16 @@ jobs:
165145
fi
166146
167147
- name: Login to Harbor
168-
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
169-
with:
170-
registry: ${{ env.HARBOR_REGISTRY }}
171-
username: ${{ env.HARBOR_REGISTRY_USER }}
172-
password: ${{ env.HARBOR_REGISTRY_PASSWORD }}
148+
run: |
149+
# Retrying registry login; harbor_helm_pull below also re-auths on 401.
150+
source "${GITHUB_WORKSPACE}/scripts/harbor-retry.sh"
151+
harbor_login
173152
174153
- name: Install tools
175154
uses: ./.github/actions/install-tool-versions
176155
with:
177156
tools: |
178157
helm
179-
yq
180158
181159
- name: Pull and validate dev package
182160
id: package
@@ -200,28 +178,11 @@ jobs:
200178
echo "✅ Dev package exists: ${package_file}"
201179
echo "package_file=${package_file}" | tee -a $GITHUB_OUTPUT
202180
203-
# Extract Camunda version from Chart.yaml inside the package
181+
# Extract camunda_version (appVersion, .x-stripped), chart_dir_id, the
182+
# component-image-versions annotation and has_image_overrides from the
183+
# package's Chart.yaml → $GITHUB_OUTPUT.
204184
tar -xzf "${package_file}" camunda-platform/Chart.yaml -O > /tmp/Chart.yaml
205-
camunda_version=$(yq '.appVersion' /tmp/Chart.yaml | sed 's/.x//')
206-
207-
echo "camunda_version=${camunda_version}" | tee -a $GITHUB_OUTPUT
208-
echo "chart_dir_id=${camunda_version}" | tee -a $GITHUB_OUTPUT
209-
210-
# Extract component image versions from annotation (added by dev build)
211-
image_versions=$(yq '.annotations."camunda.io/component-image-versions" // ""' /tmp/Chart.yaml)
212-
if [[ -n "${image_versions}" ]]; then
213-
echo "image_versions<<EOF" >> $GITHUB_OUTPUT
214-
echo "${image_versions}" >> $GITHUB_OUTPUT
215-
echo "EOF" >> $GITHUB_OUTPUT
216-
fi
217-
218-
# Check if image overrides were used during dev build
219-
image_overrides=$(yq '.annotations."camunda.io/imageOverrides" // ""' /tmp/Chart.yaml)
220-
if [[ -n "${image_overrides}" ]]; then
221-
echo "has_image_overrides=true" >> $GITHUB_OUTPUT
222-
else
223-
echo "has_image_overrides=false" >> $GITHUB_OUTPUT
224-
fi
185+
/tmp/release-tools chart-metadata --chart-yaml /tmp/Chart.yaml
225186
226187
- name: Install release-please
227188
run: npm i release-please -g
@@ -276,58 +237,25 @@ jobs:
276237
GH_TOKEN: ${{ steps.generate-github-token.outputs.token }}
277238
run: |
278239
set -euo pipefail
279-
240+
280241
chart_version="${{ steps.parse.outputs.version }}"
281242
app_version="${{ steps.package.outputs.camunda_version }}"
282243
head_ref="${{ steps.release-please.outputs.head_ref }}"
283-
package_file="${{ steps.package.outputs.package_file }}"
284-
chart_path="charts/camunda-platform-${app_version}"
285-
286-
echo "Extracting images from dev package for version-matrix.json"
287-
288-
# Extract the chart from the package
289-
mkdir -p /tmp/rc-chart
290-
tar -xzf "${package_file}" -C /tmp/rc-chart
291-
292-
# Build layered values args (same approach as generate-version-matrix.sh)
293-
scenario_dir="${chart_path}/test/integration/scenarios/chart-full-setup"
294-
helm_values_args=""
295-
for layer_file in \
296-
"${scenario_dir}/values/base.yaml" \
297-
"${scenario_dir}/values/identity/keycloak.yaml" \
298-
"${scenario_dir}/values/persistence/elasticsearch.yaml"; do
299-
if [[ -f "${layer_file}" ]]; then
300-
helm_values_args="${helm_values_args} --values ${layer_file}"
301-
fi
302-
done
303-
304-
# Get images using helm template on the extracted package
305-
chart_images=$(
306-
helm template --skip-tests camunda /tmp/rc-chart/camunda-platform \
307-
${helm_values_args} 2>/dev/null |
308-
tr -d "\"'" | awk '/image:/{gsub(/^(camunda|bitnami)/, "docker.io/&", $2); printf "%s\n", $2}' |
309-
sort | uniq
310-
)
311-
chart_images_json=$(echo -e "$chart_images" | jq -R | jq -sc)
312-
313-
# Checkout release-please branch to update version-matrix.json
244+
245+
# Update version-matrix.json on the release-please branch.
314246
git fetch origin "${head_ref}"
315247
git checkout "${head_ref}"
316-
317-
# Update version-matrix.json
248+
318249
version_matrix_file="version-matrix/camunda-${app_version}/version-matrix.json"
319-
mkdir -p "$(dirname "${version_matrix_file}")"
320-
test -f "${version_matrix_file}" || echo '[]' > "${version_matrix_file}"
321-
322-
# Remove existing entry for this version if present, then add new one
323-
updated_json=$(cat "${version_matrix_file}" | \
324-
jq --arg ver "${chart_version}" 'map(select(.chart_version != $ver))' | \
325-
jq --arg ver "${chart_version}" --argjson imgs "${chart_images_json}" \
326-
'. + [{"chart_version": $ver, "chart_images": $imgs}]')
327-
328-
echo "${updated_json}" > "${version_matrix_file}"
329-
330-
# Check if there are changes to commit
250+
251+
# Write the matrix entry from the camunda.io/chart-images annotation in
252+
# the package's Chart.yaml (extracted to /tmp/Chart.yaml above).
253+
/tmp/release-tools update-matrix \
254+
--chart-yaml /tmp/Chart.yaml \
255+
--chart-version "${chart_version}" \
256+
--matrix-file "${version_matrix_file}"
257+
258+
# Commit + push if changed.
331259
if git diff --quiet "${version_matrix_file}"; then
332260
echo "::notice::No changes to version-matrix.json"
333261
else
@@ -338,90 +266,36 @@ jobs:
338266
git push origin "${head_ref}"
339267
echo "::notice::Updated version-matrix.json on release-please branch"
340268
fi
341-
342-
# Switch back to original checkout
269+
270+
# Switch back to original checkout.
343271
git checkout "${{ steps.parse.outputs.sha }}"
344-
rm -rf /tmp/rc-chart
345272
346273
- name: Add RC tags to Harbor package
347274
env:
348275
HARBOR_API: "https://${{ env.HARBOR_REGISTRY }}/api/v2.0"
349276
HARBOR_REPO: "projects/${{ env.HARBOR_PROJECT }}/repositories/camunda-platform"
350277
run: |
351278
set -euo pipefail
352-
# harbor_curl bakes in auth + --retry 3 --retry-delay 5 --retry-all-errors
353-
# with -sf, so HTTP 4xx/5xx (incl. transient 401) trigger retries.
354-
source "${GITHUB_WORKSPACE}/scripts/harbor-retry.sh"
355-
356-
# Get artifact digest from dev tag
357-
echo "Getting digest for dev tag: ${{ steps.parse.outputs.resolved_tag }}"
358-
digest=$(harbor_curl "${HARBOR_API}/${HARBOR_REPO}/artifacts/${{ steps.parse.outputs.resolved_tag }}" \
359-
| jq -r '.digest')
360-
361-
if [[ -z "$digest" || "$digest" == "null" ]]; then
362-
echo "::error::Failed to get digest for dev tag"
363-
exit 1
364-
fi
279+
# Point {version}-rc and {major}-rc-latest at the dev artifact's digest,
280+
# idempotently (no-op if already there, else move). Untagging uses the
281+
# deleteTag endpoint (DELETE .../tags/{tag}) so only the tag is removed,
282+
# never the shared artifact. Auth is HARBOR_REGISTRY_USER/PASSWORD (env).
283+
api="${HARBOR_API}"
284+
repo="${HARBOR_REPO}"
285+
286+
# Digest of the dev artifact the RC tags should point at.
287+
digest=$(/tmp/release-tools harbor-tag digest --api "$api" --repo "$repo" \
288+
--ref "${{ steps.parse.outputs.resolved_tag }}")
365289
echo "Digest: ${digest}"
366290
367-
# Helpers for idempotent tagging.
368-
tag_digest() {
369-
local tag_name="$1"
370-
harbor_curl "${HARBOR_API}/${HARBOR_REPO}/artifacts/${tag_name}" \
371-
| jq -r '.digest // empty' || true
372-
}
373-
374-
delete_tag_if_exists() {
375-
local tag_name="$1"
376-
echo "Removing existing tag if present: ${tag_name}"
377-
harbor_curl -X DELETE "${HARBOR_API}/${HARBOR_REPO}/artifacts/${tag_name}" || true
378-
}
379-
380-
add_or_update_tag() {
381-
local tag_name="$1"
382-
local must_move="$2" # true for rolling tags
383-
384-
existing_digest="$(tag_digest "${tag_name}")"
385-
if [[ -n "${existing_digest}" ]]; then
386-
if [[ "${existing_digest}" == "${digest}" ]]; then
387-
echo "✅ Tag already present and up-to-date: ${tag_name} -> ${digest}"
388-
return 0
389-
fi
390-
391-
if [[ "${must_move}" == "true" ]]; then
392-
echo "ℹ️ Tag exists but points elsewhere; will move: ${tag_name} (${existing_digest} -> ${digest})"
393-
else
394-
echo "ℹ️ Tag exists but points elsewhere; will overwrite: ${tag_name} (${existing_digest} -> ${digest})"
395-
fi
396-
delete_tag_if_exists "${tag_name}"
397-
fi
291+
# RC version tag — reruns safe (overwrite if it points elsewhere).
292+
/tmp/release-tools harbor-tag ensure --api "$api" --repo "$repo" \
293+
--digest "${digest}" --tag "${{ steps.parse.outputs.rc_tag }}"
398294
399-
echo "Adding tag: ${tag_name}"
400-
http_code="$(harbor_curl -o /tmp/harbor-tag.json -w "%{http_code}" \
401-
-X POST "${HARBOR_API}/${HARBOR_REPO}/artifacts/${digest}/tags" \
402-
-H "Content-Type: application/json" \
403-
-d "{\"name\": \"${tag_name}\"}" || true)"
295+
# RC rolling latest tag — always move to the selected digest.
296+
/tmp/release-tools harbor-tag ensure --api "$api" --repo "$repo" \
297+
--digest "${digest}" --tag "${{ steps.parse.outputs.rc_latest_tag }}" --move
404298
405-
if [[ "${http_code}" != "201" && "${http_code}" != "200" && "${http_code}" != "409" ]]; then
406-
echo "::error::Failed to add tag: ${tag_name} (HTTP ${http_code})"
407-
exit 1
408-
fi
409-
410-
# If Harbor returned conflict (409), verify whether the tag now exists and points to the desired digest.
411-
final_digest="$(tag_digest "${tag_name}")"
412-
if [[ "${final_digest}" != "${digest}" ]]; then
413-
echo "::error::Tag '${tag_name}' does not point to expected digest after update."
414-
echo "::error::Expected: ${digest}; got: ${final_digest:-<missing>}"
415-
exit 1
416-
fi
417-
}
418-
419-
# Add RC version tag (make reruns safe: overwrite if already exists)
420-
add_or_update_tag "${{ steps.parse.outputs.rc_tag }}" "false"
421-
422-
# Add RC rolling latest tag (always move to the selected digest)
423-
add_or_update_tag "${{ steps.parse.outputs.rc_latest_tag }}" "true"
424-
425299
echo "✅ RC tags added successfully"
426300
427301
- name: Summary

.github/workflows/chart-release-chores.yaml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ jobs:
5555
tools: |
5656
git-cliff
5757
golang
58-
gomplate
5958
helm
6059
helm-ct
6160
yq
@@ -112,14 +111,19 @@ jobs:
112111
run: git pull --rebase --autostash .
113112
- name: Generate version matrix
114113
run: |
115-
make helm.repos-add
116-
for chartPath in "${CHANGED_CHARTS}"; do
117-
# Extract app version (e.g., 8.8 from charts/camunda-platform-8.8)
118-
appVersion=$(echo "$chartPath" | sed 's|charts/camunda-platform-||')
119-
CAMUNDA_VERSION=$appVersion make -e release.generate-version-matrix-released
120-
chartPath=$chartPath make -e release.generate-version-matrix-index
121-
chartPath=$chartPath make -e release.generate-version-matrix-unreleased
114+
set -euo pipefail
115+
make install.release-tools
116+
make helm.dependency-update chartPath="${CHANGED_CHARTS}"
117+
for chartPath in ${CHANGED_CHARTS}; do
118+
app="${chartPath#charts/camunda-platform-}"
119+
chartVersion="$(yq .version "$chartPath/Chart.yaml")"
120+
release-tools update-matrix \
121+
--chart "$chartPath" \
122+
--chart-version "$chartVersion" \
123+
--matrix-file "version-matrix/camunda-$app/version-matrix.json"
124+
release-tools version-matrix --readme "$app" --chart-version "$chartVersion"
122125
done
126+
release-tools version-matrix --index
123127
# We use git-chglog to generate the release notes and release-please
124128
# doesn't have an option to disable the generation of CHANGELOG.md files.
125129
# https://github.com/googleapis/release-please/issues/2007

0 commit comments

Comments
 (0)