chore: release 2.15.9 (#852) #476
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: Release Please | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| finalize_tag: | |
| description: Existing release tag to sign and update, for example v2.15.1 | |
| required: false | |
| push: | |
| branches: | |
| - main | |
| - "release-[0-9]*.[0-9]*" | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| env: | |
| # arduino/setup-task and actions4gh/setup-gh (both latest) still | |
| # declare node20; opt in to the 2026-06-16 node24 default early. | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| jobs: | |
| validate-release-ref: | |
| name: Validate Release Ref | |
| runs-on: ubuntu-26.04 | |
| steps: | |
| - name: Allow only release refs | |
| run: | | |
| if [[ "${GITHUB_REF_NAME}" == "main" || "${GITHUB_REF_NAME}" =~ ^release-[0-9]+\.[0-9]+$ ]]; then | |
| exit 0 | |
| fi | |
| echo "::error::Release Please can only run on main or release-X.Y branches. Current ref: ${GITHUB_REF_NAME}" | |
| exit 1 | |
| release-please: | |
| needs: [validate-release-ref] | |
| if: ${{ github.event_name != 'workflow_dispatch' || inputs.finalize_tag == '' }} | |
| runs-on: ubuntu-26.04 | |
| outputs: | |
| release_created: ${{ steps.release.outputs.release_created }} | |
| tag_name: ${{ steps.release.outputs.tag_name }} | |
| version: ${{ steps.release.outputs.version }} | |
| major: ${{ steps.release.outputs.major }} | |
| minor: ${{ steps.release.outputs.minor }} | |
| patch: ${{ steps.release.outputs.patch }} | |
| prs_created: ${{ steps.release.outputs.prs_created }} | |
| prs: ${{ steps.release.outputs.prs }} | |
| steps: | |
| - uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0 | |
| id: release | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| target-branch: ${{ github.ref_name }} | |
| config-file: ${{ github.ref_name == 'main' && 'release-please-config.json' || 'release-please-config-maintenance.json' }} | |
| manifest-file: .release-please-manifest.json | |
| preview-release-notes: | |
| name: Preview Release Notes | |
| needs: [release-please] | |
| if: ${{ needs.release-please.outputs.prs_created == 'true' && needs.release-please.outputs.release_created != 'true' }} | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| uses: ./.github/workflows/release-notes-engine.yml | |
| with: | |
| checkout_ref: ${{ fromJSON(needs.release-please.outputs.prs)[0].headBranchName }} | |
| preview_pr_number: ${{ fromJSON(needs.release-please.outputs.prs)[0].number }} | |
| secrets: | |
| SYNC_APP_PRIVATE_KEY: ${{ secrets.SYNC_APP_PRIVATE_KEY }} | |
| create-maintenance-branch: | |
| name: Create Maintenance Branch | |
| needs: [release-please] | |
| if: >- | |
| ${{ | |
| github.ref_name == 'main' && | |
| needs.release-please.outputs.release_created == 'true' && | |
| needs.release-please.outputs.patch == '0' | |
| }} | |
| runs-on: ubuntu-26.04 | |
| permissions: | |
| contents: write | |
| env: | |
| TAG_NAME: ${{ needs.release-please.outputs.tag_name }} | |
| MAJOR: ${{ needs.release-please.outputs.major }} | |
| MINOR: ${{ needs.release-please.outputs.minor }} | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Create branch for patch releases | |
| run: | | |
| branch="release-${MAJOR}.${MINOR}" | |
| if git ls-remote --exit-code --heads origin "${branch}" >/dev/null 2>&1; then | |
| echo "${branch} already exists" | |
| exit 0 | |
| fi | |
| git fetch --depth=1 origin "refs/tags/${TAG_NAME}:refs/tags/${TAG_NAME}" | |
| sha=$(git rev-list -n 1 "${TAG_NAME}") | |
| git push origin "${sha}:refs/heads/${branch}" | |
| build: | |
| name: "${{ matrix.component }} (${{ matrix.platform }})" | |
| needs: [release-please] | |
| if: ${{ always() && (needs.release-please.outputs.release_created == 'true' || inputs.finalize_tag != '') }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| component: [core, jobservice, registryctl, exporter, portal, registry, trivy-adapter] | |
| platform: | |
| - linux/amd64 | |
| - linux/arm64 | |
| runs-on: ubuntu-26.04 | |
| permissions: | |
| contents: read | |
| env: | |
| REGISTRY_ADDRESS: ${{ vars.REGISTRY_ADDRESS || '8gears.container-registry.com' }} | |
| REGISTRY_PROJECT: ${{ vars.REGISTRY_PROJECT || '8gcr' }} | |
| RELEASE_VERSION: ${{ needs.release-please.outputs.version }} | |
| TAG_NAME: ${{ needs.release-please.outputs.tag_name || inputs.finalize_tag }} | |
| steps: | |
| - name: Prepare | |
| id: prepare | |
| run: | | |
| platform=${{ matrix.platform }} | |
| echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV" | |
| if [ "${{ matrix.component }}" = "trivy-adapter" ]; then | |
| echo "image_name=trivy-adapter" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "image_name=harbor-${{ matrix.component }}" >> "$GITHUB_OUTPUT" | |
| fi | |
| if [ -n "$BUILDX_HOST" ]; then | |
| echo "BUILDX_HOST=$BUILDX_HOST" >> "$GITHUB_ENV" | |
| fi | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| ref: ${{ needs.release-please.outputs.tag_name || inputs.finalize_tag }} | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Install Task | |
| uses: arduino/setup-task@b91d5d2c96a56797b48ac1e0e89220bf64044611 # v2.0.0 | |
| with: | |
| version: 3.x | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Install jj | |
| env: | |
| JJ_VERSION: "0.44.0" | |
| run: | | |
| if command -v jj >/dev/null 2>&1; then | |
| jj --version | |
| exit 0 | |
| fi | |
| case "$(uname -m)" in | |
| x86_64|amd64) arch="x86_64" ;; | |
| aarch64|arm64) arch="aarch64" ;; | |
| *) | |
| echo "::error::Unsupported architecture: $(uname -m)" | |
| exit 1 | |
| ;; | |
| esac | |
| curl -fsSL "https://github.com/jj-vcs/jj/releases/download/v${JJ_VERSION}/jj-v${JJ_VERSION}-${arch}-unknown-linux-musl.tar.gz" -o /tmp/jj.tar.gz | |
| mkdir -p /tmp/jj-extract | |
| tar -xzf /tmp/jj.tar.gz -C /tmp/jj-extract | |
| sudo install -m 755 /tmp/jj-extract/jj /usr/local/bin/jj | |
| rm -rf /tmp/jj.tar.gz /tmp/jj-extract | |
| jj --version | |
| # Root Taskfile evaluation reads Go cache paths, even for apply-patches. | |
| - name: Setup Go | |
| uses: ./.github/actions/setup-go-cached | |
| with: | |
| go-version-file: src/go.mod | |
| go-sum-path: src/go.sum | |
| - name: Generate GitHub App token | |
| id: app-token | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| app-id: ${{ vars.SYNC_APP_ID }} | |
| private-key: ${{ secrets.SYNC_APP_PRIVATE_KEY }} | |
| owner: container-registry | |
| repositories: 8gcr | |
| permission-contents: read | |
| - name: Apply commercial patches | |
| env: | |
| PATCHES_TOKEN: ${{ steps.app-token.outputs.token }} | |
| run: task apply-patches | |
| - name: Load versions | |
| run: | | |
| grep -E '^[A-Z_]+=' versions.env >> "$GITHUB_ENV" | |
| echo "RELEASE_VERSION=${RELEASE_VERSION:-${TAG_NAME#v}}" >> "$GITHUB_ENV" | |
| - name: Generate API code | |
| if: ${{ contains(fromJSON('["core","jobservice","registryctl","exporter","registry","trivy-adapter"]'), matrix.component) }} | |
| run: task build:gen-apis | |
| - name: Compile Go binary | |
| if: ${{ contains(fromJSON('["core","jobservice","registryctl","exporter","registry","trivy-adapter"]'), matrix.component) }} | |
| run: task build:binary:${{ matrix.component }}:${{ env.PLATFORM_PAIR }} GIT_COMMIT="${GITHUB_SHA:0:8}" | |
| - name: Compile image helper binaries | |
| env: | |
| COMPONENT: ${{ matrix.component }} | |
| PLATFORM_PAIR: ${{ env.PLATFORM_PAIR }} | |
| run: | | |
| task build:binary:lprobe:${PLATFORM_PAIR} | |
| if [ "${COMPONENT}" = "trivy-adapter" ]; then | |
| task build:binary:trivy:${PLATFORM_PAIR} | |
| fi | |
| - uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 | |
| if: env.BUILDX_HOST == '' | |
| - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| with: | |
| driver: ${{ env.BUILDX_HOST && 'remote' || '' }} | |
| endpoint: ${{ env.BUILDX_HOST }} | |
| - name: Log in to registry | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY_ADDRESS }} | |
| username: ${{ vars.REGISTRY_USERNAME }} | |
| password: ${{ secrets.REGISTRY_PASSWORD }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 | |
| with: | |
| context: . | |
| file: dockerfile/${{ matrix.component }}.dockerfile | |
| platforms: ${{ matrix.platform }} | |
| build-args: | | |
| ALPINE_VERSION=${{ env.ALPINE_VERSION }} | |
| LPROBE_VERSION=${{ env.LPROBE_VERSION }} | |
| NGINX_VERSION=${{ env.NGINX_VERSION }} | |
| BUN_VERSION=${{ env.BUN_VERSION }} | |
| GO_VERSION=${{ env.GO_VERSION }} | |
| DISTRIBUTION_VERSION=${{ env.DISTRIBUTION_VERSION }} | |
| TRIVY_VERSION=${{ env.TRIVY_VERSION }} | |
| TRIVY_BASE_IMAGE_VERSION=${{ env.TRIVY_BASE_IMAGE_VERSION }} | |
| HARBOR_SCANNER_TRIVY_VERSION=${{ env.HARBOR_SCANNER_TRIVY_VERSION }} | |
| tags: ${{ env.REGISTRY_ADDRESS }}/${{ env.REGISTRY_PROJECT }}/${{ steps.prepare.outputs.image_name }} | |
| outputs: type=image,push-by-digest=true,name-canonical=true,push=true | |
| - name: Export digest | |
| run: | | |
| mkdir -p "${{ runner.temp }}/digests" | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "${{ runner.temp }}/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: digest-${{ matrix.component }}-${{ env.PLATFORM_PAIR }} | |
| path: ${{ runner.temp }}/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge: | |
| name: "Merge ${{ matrix.component }}" | |
| needs: [release-please, build] | |
| if: ${{ always() && needs.build.result == 'success' && (needs.release-please.outputs.release_created == 'true' || inputs.finalize_tag != '') }} | |
| strategy: | |
| matrix: | |
| component: [core, jobservice, registryctl, exporter, portal, registry, trivy-adapter] | |
| runs-on: ubuntu-26.04 | |
| permissions: | |
| contents: read | |
| env: | |
| REGISTRY_ADDRESS: ${{ vars.REGISTRY_ADDRESS || '8gears.container-registry.com' }} | |
| REGISTRY_PROJECT: ${{ vars.REGISTRY_PROJECT || '8gcr' }} | |
| VERSION: ${{ needs.release-please.outputs.version }} | |
| TAG_NAME: ${{ needs.release-please.outputs.tag_name || inputs.finalize_tag }} | |
| RELEASE_BRANCH: ${{ github.ref_name }} | |
| steps: | |
| - name: Prepare BuildKit | |
| id: prepare | |
| run: | | |
| if [ "${{ matrix.component }}" = "trivy-adapter" ]; then | |
| echo "image_name=trivy-adapter" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "image_name=harbor-${{ matrix.component }}" >> "$GITHUB_OUTPUT" | |
| fi | |
| if [ -n "$BUILDX_HOST" ]; then | |
| echo "BUILDX_HOST=$BUILDX_HOST" >> "$GITHUB_ENV" | |
| fi | |
| - name: Download digests | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: ${{ runner.temp }}/digests | |
| pattern: digest-${{ matrix.component }}-* | |
| merge-multiple: true | |
| - name: Log in to registry | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY_ADDRESS }} | |
| username: ${{ vars.REGISTRY_USERNAME }} | |
| password: ${{ secrets.REGISTRY_PASSWORD }} | |
| - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | |
| with: | |
| driver: ${{ env.BUILDX_HOST && 'remote' || '' }} | |
| endpoint: ${{ env.BUILDX_HOST }} | |
| - name: Create manifest list and push | |
| working-directory: ${{ runner.temp }}/digests | |
| env: | |
| IMAGE: ${{ env.REGISTRY_ADDRESS }}/${{ env.REGISTRY_PROJECT }}/${{ steps.prepare.outputs.image_name }} | |
| run: | | |
| # shellcheck disable=SC2046 | |
| docker buildx imagetools create \ | |
| -t "${IMAGE}:${TAG_NAME}" \ | |
| $(printf "${IMAGE}@sha256:%s " *) | |
| sign: | |
| name: Sign and Release | |
| needs: [validate-release-ref, release-please, merge] | |
| if: >- | |
| ${{ | |
| always() && | |
| needs.validate-release-ref.result == 'success' && | |
| ( | |
| needs.release-please.outputs.release_created == 'true' || | |
| inputs.finalize_tag != '' | |
| ) | |
| }} | |
| runs-on: ubuntu-26.04 | |
| permissions: | |
| contents: write | |
| id-token: write | |
| env: | |
| REGISTRY_ADDRESS: ${{ vars.REGISTRY_ADDRESS || '8gears.container-registry.com' }} | |
| REGISTRY_PROJECT: ${{ vars.REGISTRY_PROJECT || '8gcr' }} | |
| TAG_NAME: ${{ needs.release-please.outputs.tag_name || inputs.finalize_tag }} | |
| RELEASE_BRANCH: ${{ github.ref_name }} | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install envsubst | |
| run: command -v envsubst || (sudo apt-get update && sudo apt-get install -y gettext-base) | |
| - name: Install cosign | |
| uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 | |
| - name: Log in to registry | |
| uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 | |
| with: | |
| registry: ${{ env.REGISTRY_ADDRESS }} | |
| username: ${{ vars.REGISTRY_USERNAME }} | |
| password: ${{ secrets.REGISTRY_PASSWORD }} | |
| - name: Sign images | |
| run: | | |
| for image in core jobservice registryctl exporter portal registry trivy-adapter; do | |
| image_name="harbor-${image}" | |
| if [ "${image}" = "trivy-adapter" ]; then | |
| image_name="trivy-adapter" | |
| fi | |
| cosign sign --yes \ | |
| "${REGISTRY_ADDRESS}/${REGISTRY_PROJECT}/${image_name}:${TAG_NAME}" | |
| done | |
| update-release-notes: | |
| name: Update Release Notes | |
| needs: [release-please, sign] | |
| if: ${{ always() && needs.sign.result == 'success' }} | |
| permissions: | |
| contents: write | |
| uses: ./.github/workflows/release-notes-engine.yml | |
| with: | |
| tag_name: ${{ needs.release-please.outputs.tag_name || inputs.finalize_tag }} | |
| secrets: | |
| SYNC_APP_PRIVATE_KEY: ${{ secrets.SYNC_APP_PRIVATE_KEY }} | |
| mark-commercial-release: | |
| # Stamp the release marker into each 8gcr patch branch's changelog file. | |
| # Runs strictly AFTER the notes job: notes render the entries above the | |
| # newest marker, then this marks them as shipped in this tag. Manual | |
| # re-renders of old tags never dispatch (this job only runs on a fresh | |
| # release), so old markers are never disturbed. | |
| name: Mark Commercial Release | |
| needs: [release-please, update-release-notes] | |
| if: ${{ needs.release-please.outputs.release_created == 'true' }} | |
| runs-on: ubuntu-26.04 | |
| timeout-minutes: 10 | |
| permissions: | |
| # checkout of this repo (the app token below is scoped to 8gcr only) | |
| contents: read | |
| steps: | |
| - name: Generate GitHub App token | |
| id: app-token | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| app-id: ${{ vars.SYNC_APP_ID }} | |
| private-key: ${{ secrets.SYNC_APP_PRIVATE_KEY }} | |
| owner: container-registry | |
| repositories: 8gcr | |
| # repository_dispatch needs contents write; request nothing else | |
| permission-contents: write | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup-task | |
| - name: Dispatch release-cut | |
| env: | |
| DISPATCH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| TAG_NAME: ${{ needs.release-please.outputs.tag_name }} | |
| TARGET_SHA: ${{ github.sha }} | |
| LINE: ${{ github.ref_name }} | |
| run: task release-notes:dispatch-release-cut |