Retag stable lcm-bricks latest → M<major>-bom1 #26
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "LCM: Retag stable image to major version" | |
| run-name: "Retag stable lcm-bricks ${{ inputs.tag }} → M<major>-${{ inputs.cluster }}" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Stable image tag to retag (e.g. 3.7.106), or "latest" to resolve the newest promoted version' | |
| required: true | |
| default: 'latest' | |
| type: string | |
| cluster: | |
| description: 'Target cluster to retag image to it' | |
| required: true | |
| type: choice | |
| options: | |
| - "na1" | |
| - "ca2" | |
| - "perf1" | |
| - "bom1" | |
| - "syd1" | |
| - "na3" | |
| - "eu1" | |
| - "fra1" | |
| - "all-clusters" | |
| dry-run: | |
| description: 'Dry-run only — print crane commands without executing' | |
| required: true | |
| default: true | |
| type: boolean | |
| concurrency: | |
| group: ${{ github.workflow }} | |
| cancel-in-progress: false | |
| jobs: | |
| retag-stable: | |
| name: Retag stable/${{ inputs.tag }} to major version | |
| runs-on: | |
| group: infra1-runners-arc | |
| labels: runners-small | |
| permissions: | |
| id-token: write | |
| contents: read | |
| env: | |
| INFRA_REPO_URL: ${{ secrets.ECR_URL }} | |
| images: "lcm-bricks lcm-bricks-nextversion" | |
| clusters: "na1 ca2 perf1 bom1 syd1 na3 eu1 fra1" | |
| steps: | |
| - name: Get required Vault secrets | |
| uses: hashicorp/vault-action@v3 | |
| with: | |
| url: ${{ secrets.VAULT_ADDRESS }} | |
| method: jwt | |
| path: jwt/github | |
| role: ecr-push | |
| secrets: | | |
| secret/data/v3/int/ecr/infra1-user-ecr-rw aws_ecr_access_key | AWS_ACCESS_KEY ; | |
| secret/data/v3/int/ecr/infra1-user-ecr-rw aws_ecr_secret_key | AWS_SECRET_KEY ; | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| aws-access-key-id: ${{ env.AWS_ACCESS_KEY }} | |
| aws-secret-access-key: ${{ env.AWS_SECRET_KEY }} | |
| aws-region: us-east-1 | |
| - name: Login to Amazon ECR | |
| uses: aws-actions/amazon-ecr-login@v2 | |
| with: | |
| mask-password: 'true' | |
| - name: Retag images | |
| id: retag | |
| env: | |
| TAG: ${{ inputs.tag }} | |
| DRY_RUN: ${{ inputs.dry-run }} | |
| CLUSTER: ${{ inputs.cluster }} | |
| run: | | |
| set -euo pipefail | |
| images=( ${{ env.images }} ) | |
| clusters=( ${{ env.clusters }} ) | |
| target_cluster="${CLUSTER}" | |
| if [[ "${target_cluster}" != "all-clusters" && " ${clusters[*]} " != *" ${target_cluster} "* ]]; then | |
| echo "::error::Unknown cluster '${target_cluster}'. Configured clusters: ${clusters[*]}" | |
| exit 1 | |
| fi | |
| # the image carries its own version (LABEL bricks_version, fed by BRICKS_VERSION | |
| # at build time), so 'latest' resolves without parsing mutable tag names | |
| resolve_version() { | |
| local ref=$1 version | |
| version=$(crane config "${ref}" | jq -r '.config.Labels.bricks_version // empty') | |
| if [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| # stderr: this runs inside $(...), stdout is reserved for the version | |
| echo "::error::cannot resolve a version from ${ref} (bricks_version label = '${version:-<missing>}')" >&2 | |
| return 1 | |
| fi | |
| printf '%s' "${version}" | |
| } | |
| crane_tag() { | |
| local src=$1 tag=$2 | |
| if [ "${DRY_RUN}" == 'true' ]; then | |
| echo "[dry-run] crane tag ${src} ${tag}" | |
| else | |
| crane tag "${src}" "${tag}" | |
| echo "Tagged ${src} → ${tag}" | |
| fi | |
| } | |
| resolved_summary="" | |
| for image in "${images[@]}"; do | |
| version="${TAG}" | |
| # retag from the concrete version tag: traceable, and immune to latest | |
| # moving underneath the run. Only checked when resolving latest — an | |
| # explicit older tag (rollback) is expected to differ from latest. | |
| if [[ "${TAG}" == 'latest' ]]; then | |
| version=$(resolve_version "${INFRA_REPO_URL}/stable/${image}:latest") | |
| echo "Resolved stable/${image}:latest → ${version}" | |
| if [[ "$(crane digest "${INFRA_REPO_URL}/stable/${image}:${version}")" \ | |
| != "$(crane digest "${INFRA_REPO_URL}/stable/${image}:latest")" ]]; then | |
| echo "::error::stable/${image}:latest and :${version} are different digests — refusing to retag" | |
| exit 1 | |
| fi | |
| fi | |
| major="${version%%.*}" | |
| src="${INFRA_REPO_URL}/stable/${image}:${version}" | |
| if [[ "${target_cluster}" == "all-clusters" ]]; then | |
| for cluster in "${clusters[@]}"; do | |
| crane_tag "${src}" "M${major}-${cluster}" | |
| done | |
| else | |
| crane_tag "${src}" "M${major}-${target_cluster}" | |
| fi | |
| resolved_summary+="${image}=${version} " | |
| done | |
| echo "resolved_summary=${resolved_summary% }" >> "$GITHUB_OUTPUT" | |
| - name: Summary | |
| env: | |
| TAG: ${{ inputs.tag }} | |
| CLUSTER: ${{ inputs.cluster }} | |
| RESOLVED: ${{ steps.retag.outputs.resolved_summary }} | |
| run: | | |
| set -euo pipefail | |
| clusters=( ${{ env.clusters }} ) | |
| if [[ "${CLUSTER}" == 'all-clusters' ]]; then | |
| targets="${clusters[*]}" | |
| else | |
| targets="${CLUSTER}" | |
| fi | |
| { | |
| echo "## LCM stable retag" | |
| echo "" | |
| echo "| | |" | |
| echo "|---|---|" | |
| echo "| **Requested tag** | \`${TAG}\` |" | |
| echo "| **Resolved version(s)** | \`${RESOLVED}\` |" | |
| echo "| **Major tag pattern** | \`M<major>-<cluster>\` |" | |
| echo "| **Retagged cluster(s)** | \`${targets}\` |" | |
| echo "| **Dry-run** | \`${{ inputs.dry-run }}\` |" | |
| } >> "$GITHUB_STEP_SUMMARY" |