src/control-plane-services/admin-token-issuer-proxy/v1.1.2 #372
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
| # SPDX-FileCopyrightText: Copyright (c) NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # | |
| # When a service release is published, open a pull request moving the charts | |
| # that deploy it to that version. | |
| # | |
| # This is the first hop of the service to chart to stack cascade. The second is | |
| # stack-pin-bump.yml: merging this pull request does not by itself move the | |
| # stack, because a chart version only reaches the stack once the chart is | |
| # released. Cutting that chart release stays a human decision, and publishing | |
| # it is what triggers the stack bump. | |
| # | |
| # Which charts deploy the released service is declared, not derived; see | |
| # tools/ci/chart-service-edge for why deriving it is wrong. A service whose | |
| # charts have not declared the edge yet bumps nothing and says so. | |
| name: chart version bump | |
| on: | |
| release: | |
| types: [published] | |
| # Manual entry point for re-running a release whose bump did not land, and | |
| # for exercising the job without cutting a tag. | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: >- | |
| Service release tag, for example | |
| src/control-plane-services/notary/v1.9.0 | |
| required: true | |
| permissions: | |
| contents: read | |
| concurrency: | |
| # One bump at a time. Several releases landing together refresh the same | |
| # pull request rather than racing on the same files. | |
| group: chart-version-bump | |
| cancel-in-progress: false | |
| jobs: | |
| bump: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| # The default for a release event is the tagged commit, but the pull | |
| # request targets the default branch. Bumping the tag's tree would | |
| # carry whatever the chart looked like then onto a branch cut from | |
| # today's main. | |
| ref: ${{ github.event.repository.default_branch }} | |
| # Full history: the pull request title is derived from every bump | |
| # commit on the shared branch, which needs the merge base with main. | |
| fetch-depth: 0 | |
| - uses: actions/setup-go@v5 | |
| with: | |
| # Derived from the anchor, never a literal: tools/ci/check-go-version | |
| # fails any workflow that pins one. | |
| go-version-file: tools/go-toolchain/go.mod | |
| - name: Test the chart release tools | |
| # The bumper rewrites version fields in shipped charts, and the edge | |
| # audit decodes the same ownership declarations. Exercise both schemas | |
| # before either tool acts on a release. | |
| run: | | |
| go test -C tools/chart-version-bumper ./... | |
| go test -C tools/chart-service-edge ./... | |
| - name: Test the commit type helper | |
| # It decides the semver step of the chart release this bump causes. | |
| run: bash tools/ci/test-release-bump-type | |
| - name: Select the tag | |
| id: tag | |
| env: | |
| # Through env like every other step here. A release tag is chosen by | |
| # whoever pushes it, so expanding it into the script body is the | |
| # standard Actions injection shape. | |
| INPUT_TAG: ${{ github.event.inputs.tag }} | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| run: | | |
| set -euo pipefail | |
| tag="${INPUT_TAG:-${RELEASE_TAG}}" | |
| echo "tag=${tag}" >> "${GITHUB_OUTPUT}" | |
| # Chart releases move stack pins, which is stack-pin-bump.yml's job. | |
| # Everything else is a service release and is this job's business: | |
| # a tag that names no known service fails below rather than here, so | |
| # a service missing from the release metadata is visible. | |
| case "${tag}" in | |
| deploy/helm/*/v*) echo "applies=false" >> "${GITHUB_OUTPUT}" | |
| echo "${tag} is a chart release; stack-pin-bump.yml handles it" ;; | |
| */v*) echo "applies=true" >> "${GITHUB_OUTPUT}" ;; | |
| *) echo "applies=false" >> "${GITHUB_OUTPUT}" | |
| echo "${tag} is not a subtree release tag; nothing to do" ;; | |
| esac | |
| - name: Check the chart to service edges | |
| if: steps.tag.outputs.applies == 'true' | |
| # Report-only. Runs here so the undeclared charts are listed in the same | |
| # log as a bump that reached fewer charts than someone expected. | |
| run: tools/ci/chart-service-edge --audit | |
| - name: Check out the bump branch | |
| if: steps.tag.outputs.applies == 'true' | |
| env: | |
| BRANCH: chore/chart-version-bumps | |
| BASE_BRANCH: ${{ github.event.repository.default_branch }} | |
| run: | | |
| set -euo pipefail | |
| # The bump is applied ON the pull request branch, not on the default | |
| # branch and moved across afterwards. Bumping first and stashing the | |
| # result over a checkout collides whenever the branch already carries | |
| # a bump for the same chart, and a swallowed stash conflict either | |
| # drops that earlier bump or commits conflict markers. Starting here | |
| # also makes the run idempotent: the bumper sees the current value and | |
| # reports "already <version>". | |
| # | |
| # The shared branch is rebased onto the default branch first, as the | |
| # stack workflow does. Its tree can predate the tools this run needs | |
| # (the bumper's "bump:" line, release-bump-type), and a stale branch | |
| # would either fail or fall back to a patch commit for a minor bump. | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| tools/ci/prepare-stack-pin-branch "${BRANCH}" "${BASE_BRANCH}" | |
| - name: Apply the bump | |
| id: bump | |
| if: steps.tag.outputs.applies == 'true' | |
| env: | |
| # Through env, never expanded into the script body: a tag is chosen by | |
| # whoever pushes it, and ${{ }} interpolation into a run: block is the | |
| # standard Actions injection shape. | |
| TAG: ${{ steps.tag.outputs.tag }} | |
| run: | | |
| set +e | |
| set -uo pipefail | |
| # +e, deliberately. GitHub invokes this as `bash -e`, and the bumper | |
| # exits 3 when a chart's appVersion and image tag disagree even though | |
| # it still applied every chart it could move safely. Aborting here | |
| # would throw those away and leave the refusal as the only outcome. | |
| tools/ci/chart-version-bumper \ | |
| --tag "${TAG}" --write >/tmp/bump.out 2>/tmp/refusals | |
| status=$? | |
| cat /tmp/bump.out | |
| cat /tmp/refusals >&2 | |
| # The exit code, not whether stderr is empty. SystemExit writes its | |
| # message to stderr too, so an unresolvable tag looks exactly like a | |
| # refused chart there. 3 means the charts that could move did; any | |
| # other non-zero means nothing moved and the run should stop. | |
| if [ "${status}" -ne 0 ] && [ "${status}" -ne 3 ]; then | |
| echo "bumper failed (exit ${status}); no chart was changed" >&2 | |
| exit "${status}" | |
| fi | |
| if [ "${status}" -eq 3 ]; then | |
| { | |
| echo "refused<<CHART_BUMP_REFUSALS" | |
| cat /tmp/refusals | |
| echo "CHART_BUMP_REFUSALS" | |
| } >> "${GITHUB_OUTPUT}" | |
| fi | |
| # Scoped to the same paths the commit below stages. Repo-wide, any | |
| # unrelated modification in the workspace would set changed=true and | |
| # the commit would then abort with nothing staged. | |
| if git diff --quiet -- deploy/helm; then | |
| echo "changed=false" >> "${GITHUB_OUTPUT}" | |
| echo "no chart moved" | |
| else | |
| echo "changed=true" >> "${GITHUB_OUTPUT}" | |
| git --no-pager diff --stat -- deploy/helm | |
| fi | |
| # The largest semver step any chart took, reported by the bumper as | |
| # "bump: <level>". Empty when nothing moved. | |
| echo "level=$(sed -n 's/^bump: //p' /tmp/bump.out | tail -n 1)" >> "${GITHUB_OUTPUT}" | |
| - name: Open or refresh the pull request | |
| if: steps.bump.outputs.changed == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.NV_GITHUB_TOKEN || github.token }} | |
| TAG: ${{ steps.tag.outputs.tag }} | |
| LEVEL: ${{ steps.bump.outputs.level }} | |
| REFUSED: ${{ steps.bump.outputs.refused }} | |
| SERVER_URL: ${{ github.server_url }} | |
| REPO: ${{ github.repository }} | |
| BASE_BRANCH: ${{ github.event.repository.default_branch }} | |
| run: | | |
| set -euo pipefail | |
| branch="chore/chart-version-bumps" | |
| git add deploy/helm | |
| # The commit type carries the semver step of the service release | |
| # into the chart release. tools/ci/github-release feeds RELEASE_RULES | |
| # to semantic-release: fix cuts a patch, feat a minor, "!" a major, | |
| # and chore cuts nothing (which would stop the cascade here, since a | |
| # published chart release is what triggers stack-pin-bump.yml). A | |
| # service that moved a minor therefore moves its chart a minor, and | |
| # one step later the stack, instead of every bump reading as a patch. | |
| type="$(tools/ci/release-bump-type for-level "${LEVEL}")" | |
| case "${type}" in | |
| *!) subject="${type%!}(charts)!: bump for ${TAG}" ;; | |
| *) subject="${type}(charts): bump for ${TAG}" ;; | |
| esac | |
| # Separate -m flags rather than an embedded multi-line string: the | |
| # continuation lines of one would have to sit at column zero, which | |
| # ends the YAML block scalar this script lives in. | |
| if [ "${type}" = 'feat!' ]; then | |
| git commit \ | |
| -m "${subject}" \ | |
| -m "Opened by the chart version bump workflow on release of ${TAG}." \ | |
| -m "BREAKING CHANGE: ${TAG} is a major release of the service this chart deploys." | |
| else | |
| git commit \ | |
| -m "${subject}" \ | |
| -m "Opened by the chart version bump workflow on release of ${TAG}." | |
| fi | |
| git push --force-with-lease origin "${branch}" | |
| # The pull request squashes to one commit, so its title has to carry | |
| # the largest step among every bump accumulated on the branch. | |
| pr_type="$(tools/ci/release-bump-type for-branch "origin/${BASE_BRANCH}")" | |
| case "${pr_type}" in | |
| *!) title="${pr_type%!}(charts)!: bump chart versions for released services" | |
| breaking="BREAKING CHANGE: a pinned service moved to a new major version." ;; | |
| *) title="${pr_type}(charts): bump chart versions for released services" | |
| breaking="" ;; | |
| esac | |
| notes="" | |
| if [ -n "${REFUSED}" ]; then | |
| notes="$(printf '%s\n' \ | |
| "" \ | |
| "Some charts were not bumped:" \ | |
| "" \ | |
| '```' \ | |
| "${REFUSED}" \ | |
| '```' \ | |
| "" \ | |
| "A chart is refused when its \`appVersion\` and image tag disagree, or when the tag is floating. Reconciling those two fields is a decision, so it is left to a person rather than resolved during an automated bump.")" | |
| fi | |
| body="$(printf '%s\n' \ | |
| "Opened by \`.github/workflows/chart-version-bump.yml\` when \`${TAG}\` was published." \ | |
| "" \ | |
| "The released tag identifies the version and source tree, so this is a direct update rather than a lookup of the newest published image." \ | |
| "" \ | |
| "Merging this does not move the self-managed stack. A chart version reaches the stack only once the chart itself is released, and publishing that chart release is what triggers \`stack-pin-bump.yml\`." \ | |
| "" \ | |
| "Release notes: ${SERVER_URL}/${REPO}/releases/tag/${TAG}" \ | |
| "${notes}" \ | |
| "" \ | |
| "If this pull request sits unmerged, later service releases add their bumps to the same branch, so merging it applies all of them." \ | |
| "" \ | |
| "Github commit:" \ | |
| "${title}" \ | |
| "${breaking}" \ | |
| "")" | |
| # gh api, not `gh pr edit`. Against this repository `gh pr edit` fails | |
| # with "Projects (classic) is being deprecated ... | |
| # (repository.pullRequest.projectCards)", because it queries project | |
| # cards it does not need. The REST endpoint has no such dependency. | |
| number="$(gh api "repos/${REPO}/pulls?head=${REPO%%/*}:${branch}&state=open" -q '.[0].number')" | |
| if [ -n "${number}" ] && [ "${number}" != "null" ]; then | |
| jq -n --arg t "${title}" --arg b "${body}" '{title: $t, body: $b}' \ | |
| | gh api -X PATCH "repos/${REPO}/pulls/${number}" --input - >/dev/null | |
| echo "refreshed pull request #${number}" | |
| else | |
| gh pr create --base main --head "${branch}" \ | |
| --title "${title}" \ | |
| --body "${body}" | |
| fi | |
| - name: Surface refusals | |
| if: steps.bump.outputs.refused != '' | |
| # Last, so it does not stop the safe bumps from being opened. A chart | |
| # that wanted a bump and could not take one is a finding, and a green | |
| # run would bury it. | |
| env: | |
| # Via env, not ${{ }} interpolation: expanding it into the script body | |
| # is the standard Actions injection shape, even for text this | |
| # repository produced. | |
| REFUSED: ${{ steps.bump.outputs.refused }} | |
| run: | | |
| echo "::error::charts refused the bump:" | |
| printf '%s\n' "${REFUSED}" | |
| exit 1 |