Skip to content

Release

Release #19

Workflow file for this run

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 }}