From dde0a7d542da20f567f1323885afa3e2e8cd5f00 Mon Sep 17 00:00:00 2001 From: majidkhan07 Date: Thu, 20 Aug 2026 18:01:51 +0530 Subject: [PATCH 1/2] fix(ci): point the devnet deploy at the app-chart values files --- .github/scripts/detect-config-changes.sh | 36 ++++++++---- .github/workflows/docker-build-release.yml | 65 +++++++++++++++------- 2 files changed, 69 insertions(+), 32 deletions(-) diff --git a/.github/scripts/detect-config-changes.sh b/.github/scripts/detect-config-changes.sh index d231ac1..658fba9 100755 --- a/.github/scripts/detect-config-changes.sh +++ b/.github/scripts/detect-config-changes.sh @@ -21,12 +21,15 @@ # comment_file markdown report to post on the PR (written when true) set -euo pipefail -# Helm values files the deploy job bumps — keep in sync with FILES in -# docker-build-release.yml. Top-level key = file name minus "-values.yml". -VALUES_FILES=( - canton-middleware-api-values.yml - canton-indexer-values.yml - canton-middleware-values.yml +# Services the deploy job bumps, as ||. +# One app-chart values.yaml per folder under DIR. None of the three fields is derivable +# from the others: canton-middleware's Deployment is canton-bridge-relayer, and +# canton-middleware-api's image is canton-erc20-api. +# Keep in sync with the table in docker-build-release.yml. +SERVICES=( + 'canton-middleware-api|canton-middleware-api|ghcr.io/chainsafe/canton-erc20-api' + 'canton-indexer|canton-indexer|ghcr.io/chainsafe/canton-indexer' + 'canton-middleware|canton-bridge-relayer|ghcr.io/chainsafe/canton-middleware' ) # Paths that can break a deploy when the Helm values are stale: per-package @@ -54,11 +57,22 @@ sanitize() { printf '%s' "$1" | tr -cd 'A-Za-z0-9._-' | cut -c1-64; } # baseline to diff against. TAG_REPORT="" TAG_VALUES=() -for f in "${VALUES_FILES[@]}"; do - key="${f%-values.yml}" - tag=$(yq e ".[\"${key}\"].image.tag" "${DIR}/${f}" 2>/dev/null) || tag="" - [ "${tag}" = "null" ] && tag="" - TAG_REPORT="${TAG_REPORT}${key}: $(sanitize "${tag:-missing}"); " +for entry in "${SERVICES[@]}"; do + IFS='|' read -r svc dep imgrepo <<< "${entry}" + # This layout holds the image as one string; the tag is what follows the last colon. + image=$(yq e ".deployments[\"${dep}\"].spec.template.spec.containers[0].image" \ + "${DIR}/${svc}/values.yaml" 2>/dev/null) || image="" + [ "${image}" = "null" ] && image="" + # Only trust a tag whose repository is the one we expect, and require the tag to be + # present. A repository mismatch means the values file was pointed elsewhere, and an + # untagged image has no baseline at all -- in either case treating what follows the + # colon as a tag would be wrong. Matching on "repo:" rather than stripping the suffix + # is deliberate: ${image%:*} returns the whole string when there is no colon. + case "${image}" in + "${imgrepo}":?*) tag="${image##*:}" ;; + *) tag="" ;; + esac + TAG_REPORT="${TAG_REPORT}${svc}: $(sanitize "${tag:-missing}"); " TAG_VALUES+=("${tag}") done diff --git a/.github/workflows/docker-build-release.yml b/.github/workflows/docker-build-release.yml index 9b6c9df..cf91ab2 100644 --- a/.github/workflows/docker-build-release.yml +++ b/.github/workflows/docker-build-release.yml @@ -133,8 +133,10 @@ jobs: # the Helm values against the config diff posted as a PR comment. if: github.event_name == 'push' && github.ref == 'refs/heads/main' && inputs.tag == '' env: - # Directory in infra-kubernetes holding the devnet Helm values files - DIR: definitions/canton/validator-dev1 + # Parent of the per-service app-chart values folders in infra-kubernetes. These + # services are managed by ArgoCD; their old definitions/ blocks still exist but are + # `enabled: false`, so writing there merges green and deploys nothing. + DIR: clusters/dev/apps/canton steps: - name: Compute image tag id: version @@ -167,21 +169,37 @@ jobs: SRC: .src run: .src/.github/scripts/detect-config-changes.sh - # Each service maps to a Helm values file in infra-kubernetes whose - # top-level key matches the Helm release name. Add a service here to - # have it bumped and deployed to devnet automatically on every main push. + # Each service is one folder under DIR holding a values.yaml. The table is + # ||, and none of the three is derivable + # from the others: canton-middleware's Deployment is canton-bridge-relayer, and + # canton-middleware-api's image is canton-erc20-api. Add a service here to have it + # bumped and deployed to devnet automatically on every main push. Keep in sync with + # SERVICES in .github/scripts/detect-config-changes.sh. - name: Update image tags for all services env: VERSION: ${{ steps.version.outputs.version }} run: | - while IFS='|' read -r key file; do - [ -z "$key" ] && continue - echo "Bumping ${key} -> ${VERSION} in ${file}" - yq e ".[\"${key}\"].image.tag = env(VERSION)" -i "${DIR}/${file}" + set -euo pipefail + while IFS='|' read -r svc dep imgrepo; do + [ -z "$svc" ] && continue + f="${DIR}/${svc}/values.yaml" + echo "Bumping ${svc} (${dep}) -> ${imgrepo}:${VERSION}" + # This layout holds the image as one string, not repository + tag. + yq e ".deployments[\"${dep}\"].spec.template.spec.containers[0].image = \"${imgrepo}:${VERSION}\"" -i "${f}" + + # These values files embed a config file verbatim inside an ExternalSecret, + # complete with external-secrets {{ }} placeholders. Fail if yq rewrote + # anything beyond the image line rather than committing a silent reformat. + CHANGED=$(git diff --numstat -- "${f}" | awk '{print $1"/"$2}') + if [ "${CHANGED}" != "1/1" ]; then + echo "::error::expected exactly one line changed in ${f}, got ${CHANGED:-nothing}" + git diff -- "${f}" + exit 1 + fi done <<'EOF' - canton-middleware-api|canton-middleware-api-values.yml - canton-indexer|canton-indexer-values.yml - canton-middleware|canton-middleware-values.yml + canton-middleware-api|canton-middleware-api|ghcr.io/chainsafe/canton-erc20-api + canton-indexer|canton-indexer|ghcr.io/chainsafe/canton-indexer + canton-middleware|canton-bridge-relayer|ghcr.io/chainsafe/canton-middleware EOF - name: Create signed commit and open PR @@ -195,9 +213,9 @@ jobs: COMMENT_FILE: ${{ steps.config.outputs.comment_file }} run: | FILES=( - canton-middleware-api-values.yml - canton-indexer-values.yml - canton-middleware-values.yml + canton-middleware-api/values.yaml + canton-indexer/values.yaml + canton-middleware/values.yaml ) BRANCH="cd/devnet-canton-services-${VERSION}" COMMIT_MSG="chore(devnet): deploy canton services ${VERSION}" @@ -218,13 +236,18 @@ jobs: # re-run). Everything after this block always runs, so a re-run # repairs a missing PR, label, or comment instead of exiting early. ALL_MATCH=true - for f in "${FILES[@]}"; do - KEY="${f%-values.yml}" - BRANCH_TAG=$(gh api "repos/${REPO}/contents/${DIR}/${f}?ref=${BRANCH}" \ + while IFS='|' read -r svc dep imgrepo; do + [ -z "$svc" ] && continue + BRANCH_IMAGE=$(gh api "repos/${REPO}/contents/${DIR}/${svc}/values.yaml?ref=${BRANCH}" \ -H "Accept: application/vnd.github.raw" 2>/dev/null \ - | yq e ".[\"${KEY}\"].image.tag" - 2>/dev/null || echo "") - [ "$BRANCH_TAG" = "$VERSION" ] || ALL_MATCH=false - done + | yq e ".deployments[\"${dep}\"].spec.template.spec.containers[0].image" - \ + 2>/dev/null || echo "") + [ "$BRANCH_IMAGE" = "${imgrepo}:${VERSION}" ] || ALL_MATCH=false + done <<'EOF' + canton-middleware-api|canton-middleware-api|ghcr.io/chainsafe/canton-erc20-api + canton-indexer|canton-indexer|ghcr.io/chainsafe/canton-indexer + canton-middleware|canton-bridge-relayer|ghcr.io/chainsafe/canton-middleware + EOF if [ "$ALL_MATCH" = "true" ]; then echo "Branch already at tag ${VERSION} for all services, skipping commit" else From 9c7fd73200c01c22203936c567c36bf2f35e6e5e Mon Sep 17 00:00:00 2001 From: majidkhan07 Date: Thu, 20 Aug 2026 18:38:54 +0530 Subject: [PATCH 2/2] chore(ci): trim comments to what the code does not already say --- .github/scripts/detect-config-changes.sh | 15 +++++---------- .github/workflows/docker-build-release.yml | 20 +++++++------------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/.github/scripts/detect-config-changes.sh b/.github/scripts/detect-config-changes.sh index 658fba9..e0d11cc 100755 --- a/.github/scripts/detect-config-changes.sh +++ b/.github/scripts/detect-config-changes.sh @@ -21,10 +21,8 @@ # comment_file markdown report to post on the PR (written when true) set -euo pipefail -# Services the deploy job bumps, as ||. -# One app-chart values.yaml per folder under DIR. None of the three fields is derivable -# from the others: canton-middleware's Deployment is canton-bridge-relayer, and -# canton-middleware-api's image is canton-erc20-api. +# ||, one values.yaml per folder under DIR. +# All three are needed: names do not follow from each other. # Keep in sync with the table in docker-build-release.yml. SERVICES=( 'canton-middleware-api|canton-middleware-api|ghcr.io/chainsafe/canton-erc20-api' @@ -59,15 +57,12 @@ TAG_REPORT="" TAG_VALUES=() for entry in "${SERVICES[@]}"; do IFS='|' read -r svc dep imgrepo <<< "${entry}" - # This layout holds the image as one string; the tag is what follows the last colon. image=$(yq e ".deployments[\"${dep}\"].spec.template.spec.containers[0].image" \ "${DIR}/${svc}/values.yaml" 2>/dev/null) || image="" [ "${image}" = "null" ] && image="" - # Only trust a tag whose repository is the one we expect, and require the tag to be - # present. A repository mismatch means the values file was pointed elsewhere, and an - # untagged image has no baseline at all -- in either case treating what follows the - # colon as a tag would be wrong. Matching on "repo:" rather than stripping the suffix - # is deliberate: ${image%:*} returns the whole string when there is no colon. + # Require the expected repository and a present tag; either being wrong means there is + # no baseline. Matched on "repo:" rather than ${image%:*}, which returns the whole + # string when there is no colon. case "${image}" in "${imgrepo}":?*) tag="${image##*:}" ;; *) tag="" ;; diff --git a/.github/workflows/docker-build-release.yml b/.github/workflows/docker-build-release.yml index cf91ab2..774ffb7 100644 --- a/.github/workflows/docker-build-release.yml +++ b/.github/workflows/docker-build-release.yml @@ -133,9 +133,7 @@ jobs: # the Helm values against the config diff posted as a PR comment. if: github.event_name == 'push' && github.ref == 'refs/heads/main' && inputs.tag == '' env: - # Parent of the per-service app-chart values folders in infra-kubernetes. These - # services are managed by ArgoCD; their old definitions/ blocks still exist but are - # `enabled: false`, so writing there merges green and deploys nothing. + # Parent of the per-service app-chart values folders in infra-kubernetes DIR: clusters/dev/apps/canton steps: - name: Compute image tag @@ -169,12 +167,10 @@ jobs: SRC: .src run: .src/.github/scripts/detect-config-changes.sh - # Each service is one folder under DIR holding a values.yaml. The table is - # ||, and none of the three is derivable - # from the others: canton-middleware's Deployment is canton-bridge-relayer, and - # canton-middleware-api's image is canton-erc20-api. Add a service here to have it - # bumped and deployed to devnet automatically on every main push. Keep in sync with - # SERVICES in .github/scripts/detect-config-changes.sh. + # ||. All three are needed: a Deployment's + # name need not match its folder, nor its image its service. Add a service here to + # have it deployed on every main push; keep in sync with SERVICES in + # .github/scripts/detect-config-changes.sh. - name: Update image tags for all services env: VERSION: ${{ steps.version.outputs.version }} @@ -184,12 +180,10 @@ jobs: [ -z "$svc" ] && continue f="${DIR}/${svc}/values.yaml" echo "Bumping ${svc} (${dep}) -> ${imgrepo}:${VERSION}" - # This layout holds the image as one string, not repository + tag. yq e ".deployments[\"${dep}\"].spec.template.spec.containers[0].image = \"${imgrepo}:${VERSION}\"" -i "${f}" - # These values files embed a config file verbatim inside an ExternalSecret, - # complete with external-secrets {{ }} placeholders. Fail if yq rewrote - # anything beyond the image line rather than committing a silent reformat. + # These files embed a config file verbatim inside an ExternalSecret, and a yq + # reformat of it would pass the infra repo's linters. Fail instead. CHANGED=$(git diff --numstat -- "${f}" | awk '{print $1"/"$2}') if [ "${CHANGED}" != "1/1" ]; then echo "::error::expected exactly one line changed in ${f}, got ${CHANGED:-nothing}"