Skip to content

ci(release): align image tags and manifests with git tags #9

ci(release): align image tags and manifests with git tags

ci(release): align image tags and manifests with git tags #9

Workflow file for this run

# Create a GitHub release whenever a SemVer tag is pushed and build/push the image.
name: Create Release from Tag
permissions:
contents: write
packages: write
on:
push:
tags:
- "*"
jobs:
ci-checks:
uses: ./.github/workflows/ci.yaml
secrets: inherit
create-release:
needs: ci-checks
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.semver.outputs.tag }}
version: ${{ steps.semver.outputs.version }}
steps:
- name: Validate SemVer tag
id: semver
env:
TAG_NAME: ${{ github.ref_name }}
run: |
TAG="${TAG_NAME}"
REGEX='^v?[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'
if echo "${TAG}" | grep -Eq "${REGEX}"; then
echo "valid=true" >> "${GITHUB_OUTPUT}"
echo "tag=${TAG}" >> "${GITHUB_OUTPUT}"
echo "version=${TAG#v}" >> "${GITHUB_OUTPUT}"
exit 0
fi
echo "Tag '${TAG}' is not a valid SemVer (with optional leading 'v')." >&2
exit 1
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Ensure manifests image tag matches release tag
run: |
EXPECTED_TAG='${{ steps.semver.outputs.tag }}'
IMAGE_TAG=$(grep -A2 'name: ghcr.io/klustrefs/klustre-csi-plugin' manifests/kustomization.yaml | grep 'newTag:' | awk '{print $2}')
if [ -z "${IMAGE_TAG}" ]; then
echo "Could not determine image tag from manifests/kustomization.yaml" >&2
exit 1
fi
if [ "${IMAGE_TAG}" != "${EXPECTED_TAG}" ]; then
echo "Image tag in manifests/kustomization.yaml (${IMAGE_TAG}) does not match release tag (${EXPECTED_TAG})." >&2
echo "Update manifests/kustomization.yaml images.newTag before tagging a release." >&2
exit 1
fi
- name: Generate release notes
id: cliff
uses: orhun/git-cliff-action@v4
with:
config: cliff.toml
args: --tag ${{ steps.semver.outputs.tag }}
env:
OUTPUT: RELEASE_NOTES.md
GITHUB_REPO: ${{ github.repository }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Load release notes
id: notes
run: |
echo "RELEASE_NOTES<<EOF" >> "${GITHUB_OUTPUT}"
cat RELEASE_NOTES.md >> "${GITHUB_OUTPUT}"
echo "EOF" >> "${GITHUB_OUTPUT}"
- name: Create GitHub release
uses: actions/github-script@v7
env:
RELEASE_NOTES: ${{ steps.notes.outputs.RELEASE_NOTES }}
with:
script: |
const tag = '${{ steps.semver.outputs.tag }}';
const owner = context.repo.owner;
const repo = context.repo.repo;
const body = process.env.RELEASE_NOTES ?? '';
try {
const release = await github.rest.repos.createRelease({
owner,
repo,
tag_name: tag,
name: tag,
body
});
core.info(`Created release ${release.data.html_url}`);
} catch (error) {
const errors = error.response?.data?.errors ?? [];
const alreadyExists = errors.some((item) => item.code === 'already_exists');
if (error.status === 422 && alreadyExists) {
core.info(`Release for ${tag} already exists, skipping creation.`);
} else {
throw error;
}
}
build-and-push-image:
needs: create-release
uses: ./.github/workflows/build-and-push.yaml
secrets: inherit
with:
image_tag: ${{ needs.create-release.outputs.tag }}