Release #19
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 | |
| on: | |
| workflow_call: | |
| inputs: | |
| runs-on: | |
| description: | | |
| JSON array of runner(s) to use. | |
| See https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job. | |
| type: string | |
| default: '["ubuntu-latest"]' | |
| required: false | |
| oci-registry: | |
| description: "OCI registry where to pull and push images." | |
| type: string | |
| default: "ghcr.io" | |
| required: false | |
| platforms: | |
| description: | | |
| JSON array of platforms to build images for. | |
| See https://docs.docker.com/buildx/working-with-buildx/#build-multi-platform-images. | |
| type: string | |
| required: false | |
| prerelease: | |
| description: "Whether the release is a prerelease" | |
| type: boolean | |
| default: false | |
| secrets: | |
| github-token: | |
| description: | | |
| GitHub token with permissions `contents: read`. | |
| oci-registry-password: | |
| description: | | |
| Password or GitHub token (packages:read and packages:write scopes) used to log against the OCI registry. | |
| Defaults to GITHUB_TOKEN if not provided. | |
| required: false | |
| workflow_dispatch: | |
| permissions: {} | |
| jobs: | |
| prepare-images: | |
| runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| outputs: | |
| images-matrix: ${{ steps.get-images-matrix.outputs.images-matrix }} | |
| steps: | |
| # jscpd:ignore-start | |
| # FIXME: This is a workaround for having workflow actions. See https://github.com/orgs/community/discussions/38659 | |
| - id: oidc | |
| uses: ChristopherHX/oidc@73eee1ff03fdfce10eda179f617131532209edbd # v3 | |
| - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| with: | |
| persist-credentials: false | |
| path: ./self-workflow | |
| repository: ${{ steps.oidc.outputs.job_workflow_repo_name_and_owner }} | |
| ref: ${{ steps.oidc.outputs.job_workflow_repo_ref }} | |
| sparse-checkout: | | |
| actions | |
| - id: get-available-images | |
| uses: ./self-workflow/actions/get-available-images | |
| - id: get-images-matrix | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| env: | |
| IMAGES: ${{ steps.get-available-images.outputs.images }} | |
| with: | |
| github-token: ${{ secrets.github-token || secrets.GITHUB_TOKEN || github.token }} | |
| script: | | |
| const images = JSON.parse(process.env.IMAGES); | |
| const tags = await github.paginate(github.rest.repos.listTags, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }); | |
| function getImageLatestTagSha(image) { | |
| const tagFilter = `${image}-`; | |
| const imageTags = tags.filter(tag => tag.name.startsWith(tagFilter)); | |
| // Sort tags regarding semver | |
| imageTags.sort((a, b) => { | |
| const aVersion = a.name.replace(tagFilter, ''); | |
| const bVersion = b.name.replace(tagFilter, ''); | |
| return bVersion.localeCompare(aVersion, undefined, { numeric: true }); | |
| }); | |
| return imageTags.length ? imageTags[0].commit.sha : null; | |
| } | |
| // Group images by their latest tag sha | |
| const noTagIdentifier = 'no-tag'; | |
| const imagesGroupedByLatestTagSha = {}; | |
| for (const image of images) { | |
| const latestTagSha = getImageLatestTagSha(image); | |
| if (latestTagSha) { | |
| if (!imagesGroupedByLatestTagSha[latestTagSha]) { | |
| imagesGroupedByLatestTagSha[latestTagSha] = []; | |
| } | |
| imagesGroupedByLatestTagSha[latestTagSha].push(image); | |
| } else { | |
| // If no tag found, consider the image needs to be built | |
| if (!imagesGroupedByLatestTagSha[noTagIdentifier]) { | |
| imagesGroupedByLatestTagSha[noTagIdentifier] = []; | |
| } | |
| imagesGroupedByLatestTagSha[noTagIdentifier].push(image); | |
| } | |
| } | |
| // Prepare a matrix-like output - images, base-sha | |
| const imagesMatrix = []; | |
| for (const [baseSha, images] of Object.entries(imagesGroupedByLatestTagSha)) { | |
| imagesMatrix.push({ | |
| images, | |
| "base-sha": baseSha === noTagIdentifier ? null : baseSha, | |
| }); | |
| } | |
| core.setOutput('images-matrix', JSON.stringify(imagesMatrix)); | |
| - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| if: always() | |
| with: | |
| persist-credentials: false | |
| path: ./self-workflow | |
| repository: ${{ steps.oidc.outputs.job_workflow_repo_name_and_owner }} | |
| ref: ${{ steps.oidc.outputs.job_workflow_repo_ref }} | |
| sparse-checkout: | | |
| actions | |
| prepare-images-to-release: | |
| runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| needs: prepare-images | |
| strategy: | |
| matrix: | |
| images: ${{ fromJson(needs.prepare-images.outputs.images-matrix) }} | |
| fail-fast: false | |
| steps: | |
| # jscpd:ignore-start | |
| # FIXME: This is a workaround for having workflow actions. See https://github.com/orgs/community/discussions/38659 | |
| - id: oidc | |
| uses: ChristopherHX/oidc@73eee1ff03fdfce10eda179f617131532209edbd # v3 | |
| - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| with: | |
| persist-credentials: false | |
| path: ./self-workflow | |
| repository: ${{ steps.oidc.outputs.job_workflow_repo_name_and_owner }} | |
| ref: ${{ steps.oidc.outputs.job_workflow_repo_ref }} | |
| sparse-checkout: | | |
| actions | |
| - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| with: | |
| persist-credentials: false | |
| path: ./self-workflow | |
| repository: ${{ steps.oidc.outputs.job_workflow_repo_name_and_owner }} | |
| ref: ${{ steps.oidc.outputs.job_workflow_repo_ref }} | |
| sparse-checkout: | | |
| actions | |
| - id: should-build-images | |
| uses: ./self-workflow/actions/should-build-images | |
| with: | |
| base-sha: ${{ matrix.images.base-sha }} | |
| images: ${{ toJSON(matrix.images.images) }} | |
| - id: set-images-to-release | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| env: | |
| SHOULD_BUILD_IMAGES: ${{ steps.should-build-images.outputs.should-build-images }} | |
| with: | |
| script: | | |
| const shouldBuildImages = JSON.parse(process.env.SHOULD_BUILD_IMAGES); | |
| const imagesToRelease = Object.entries(shouldBuildImages) | |
| .filter(([image, shouldBuild]) => shouldBuild === true) | |
| .map(([image, shouldBuild]) => image); | |
| if (imagesToRelease.length > 0) { | |
| core.setOutput('images-to-release', JSON.stringify(imagesToRelease)); | |
| } | |
| - if: steps.set-images-to-release.outputs.images-to-release | |
| uses: hoverkraft-tech/ci-github-common/actions/set-matrix-output@5e8d0e6d1e76d8577a070db6d0128a91b1c9d5ad # 0.30.2 | |
| with: | |
| value: ${{ steps.set-images-to-release.outputs.images-to-release }} | |
| artifact-name: images-to-release | |
| - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| if: always() | |
| with: | |
| persist-credentials: false | |
| path: ./self-workflow | |
| repository: ${{ steps.oidc.outputs.job_workflow_repo_name_and_owner }} | |
| ref: ${{ steps.oidc.outputs.job_workflow_repo_ref }} | |
| sparse-checkout: | | |
| actions | |
| get-images-to-release: | |
| needs: prepare-images-to-release | |
| runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }} | |
| outputs: | |
| images: ${{ steps.get-images-to-release.outputs.images }} | |
| steps: | |
| - id: get-matrix-outputs | |
| uses: hoverkraft-tech/ci-github-common/actions/get-matrix-outputs@5e8d0e6d1e76d8577a070db6d0128a91b1c9d5ad # 0.30.2 | |
| with: | |
| artifact-name: "images-to-release" | |
| - id: get-images-to-release | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| env: | |
| IMAGES: ${{ steps.get-matrix-outputs.outputs.result }} | |
| with: | |
| script: | | |
| const images = JSON.parse(process.env.IMAGES); | |
| core.setOutput('images', JSON.stringify(images.flat())); | |
| release-images: | |
| name: Release Image ${{ matrix.image }} | |
| runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }} | |
| if: needs.get-images-to-release.outputs.images != '[]' | |
| permissions: | |
| contents: write | |
| needs: get-images-to-release | |
| strategy: | |
| matrix: | |
| image: ${{ fromJson(needs.get-images-to-release.outputs.images) }} | |
| fail-fast: false | |
| steps: | |
| - id: create-release | |
| uses: hoverkraft-tech/ci-github-publish/actions/release/create@main | |
| with: | |
| prerelease: ${{ inputs.prerelease }} | |
| working-directory: images/${{ matrix.image }} | |
| - id: set-images-to-build | |
| if: steps.create-release.outputs.tag != '' | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| env: | |
| TAG: ${{ steps.create-release.outputs.tag }} | |
| IMAGE: ${{ matrix.image }} | |
| with: | |
| script: | | |
| const buildTag = process.env.TAG.replace(new RegExp(`^${process.env.IMAGE}-`), ''); | |
| core.setOutput('image', JSON.stringify({ | |
| name: process.env.IMAGE, | |
| tag: buildTag, | |
| })); | |
| - if: steps.set-images-to-build.outputs.image | |
| uses: hoverkraft-tech/ci-github-common/actions/set-matrix-output@5e8d0e6d1e76d8577a070db6d0128a91b1c9d5ad # 0.30.2 | |
| with: | |
| value: ${{ steps.set-images-to-build.outputs.image }} | |
| artifact-name: images-to-build | |
| # jscpd:ignore-start | |
| get-images-to-build: | |
| needs: release-images | |
| runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }} | |
| outputs: | |
| images: ${{ steps.get-matrix-outputs.outputs.result }} | |
| steps: | |
| - id: get-matrix-outputs | |
| uses: hoverkraft-tech/ci-github-common/actions/get-matrix-outputs@5e8d0e6d1e76d8577a070db6d0128a91b1c9d5ad # 0.30.2 | |
| with: | |
| artifact-name: "images-to-build" | |
| # jscpd:ignore-end | |
| build-images: | |
| needs: get-images-to-build | |
| if: needs.get-images-to-build.outputs.images != '[]' | |
| uses: ./.github/workflows/docker-build-images.yml | |
| permissions: | |
| contents: read | |
| issues: read | |
| packages: write | |
| pull-requests: write | |
| id-token: write | |
| with: | |
| runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }} | |
| oci-registry: ${{ inputs.oci-registry }} | |
| images: ${{ needs.get-images-to-build.outputs.images }} | |
| platforms: ${{ inputs.platforms || null }} | |
| secrets: | |
| oci-registry-password: ${{ secrets.oci-registry-password || null }} |