Skip to content

Release

Release #111

Workflow file for this run

name: Release
on:
workflow_dispatch:
inputs:
release_candidate:
type: boolean
description: "Release Candidate"
required: true
default: true
release_candidate_name:
type: string
description: "Release Candidate Name, adjust after every succinct release candidate (e.g. to rc.2, rc.3...)"
required: true
default: "rc.1"
jobs:
release-version:
name: Release Version
uses: ./.github/workflows/release-version.yaml
with:
release_candidate: ${{ inputs.release_candidate }}
release_candidate_name: ${{ inputs.release_candidate_name }}
permissions:
contents: read
repository-projects: read
check:
name: Check Release Preconditions
runs-on: ubuntu-latest
permissions:
contents: read
repository-projects: read
needs: release-version
env:
RELEASE_VERSION: ${{ needs.release-version.outputs.version }}
RELEASE_VERSION_NO_SUFFIX: ${{ needs.release-version.outputs.version_no_suffix }}
REF: ${{ github.ref }}
outputs:
draft-release-notes: ${{ steps.release-notes.outputs.json }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check Tag
run: |
set -e
if git ls-remote --exit-code origin refs/tags/${{ env.RELEASE_VERSION }} ; then
>&2 echo "tag ${{ env.RELEASE_VERSION }} already exists"
exit 1
fi
- name: Check if release is running on release branch
run: |
if [[ ${{ env.REF }} != *"releases/"* ]]; then
echo "The branch ${{ env.REF }} is not a valid release branch and cannot be used for a release"
exit 1
fi
echo "Branch ${{ env.REF }} is a valid release branch"
- name: Generate token
id: generate_token
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.OCMBOT_APP_ID }}
private_key: ${{ secrets.OCMBOT_PRIV_KEY }}
- name: Ensure existing Draft Release Notes exist
id: release-notes
shell: bash
env:
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
run: |
RELEASE_JSON=$( \
gh api /repos/${{ github.repository }}/releases \
-q '.[] | select(.name == "${{ env.RELEASE_VERSION_NO_SUFFIX }}" and .draft == true)' \
)
echo "json=${RELEASE_JSON}" >> $GITHUB_OUTPUT
# if no draft release notes are found, we cannot continue
if [ -z "${RELEASE_JSON}" ]; then
echo "No draft release notes found for ${{ env.RELEASE_VERSION_NO_SUFFIX }}"
exit 1
fi
components:
name: Component CTF Builds
uses: ./.github/workflows/components.yaml
needs: [ check,release-version ]
with:
version: ${{ needs.release-version.outputs.version_no_prefix }}
upload-ctf: true
ref: ${{ github.ref }}
permissions:
contents: read
pull-requests: read
release:
needs:
# run check before actual release to make sure we succeed
# they will be skipped from the needs check
- check
- release-version
- components
name: Release Build
runs-on: large_runner
permissions:
contents: write
id-token: write
packages: write
env:
RELEASE_VERSION: ${{ needs.release-version.outputs.version }}
steps:
- name: Self Hosted Runner Post Job Cleanup Action
uses: TooMuch4U/[email protected]
- name: Generate token
id: generate_token
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.OCMBOT_APP_ID }}
private_key: ${{ secrets.OCMBOT_PRIV_KEY }}
- name: Checkout
uses: actions/checkout@v4
with:
# fetch all history so we can calculate the version and tagging
fetch-depth: 0
token: ${{ steps.generate_token.outputs.token }}
- name: Setup Syft
uses: anchore/sbom-action/download-syft@55dc4ee22412511ee8c3142cbea40418e6cec693 # v0.17.8
- name: Setup Cosign
uses: sigstore/[email protected]
- name: Download CTF
uses: actions/download-artifact@v4
with:
pattern: 'ctf-aggregated'
path: gen/downloaded-ctfs
- name: Move CTF into correct directory to be recognized by the release process
run: |
mv \
${{ github.workspace }}/gen/downloaded-ctfs/ctf-aggregated \
${{ github.workspace }}/gen/ctf
# TODO: Remove Go setup once binaries no longer need to be built by goreleaser.
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: '${{ github.workspace }}/go.mod'
check-latest: false
cache: false
- name: Get go environment for use with cache
run: |
echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV
echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV
# This step will only reuse the go mod and build cache from main made during the Build,
# see push_ocm.yaml => "ocm-cli-latest" Job
# This means it never caches by itself and PRs cannot cause cache pollution / thrashing
# This is because we have huge storage requirements for our cache because of the mass of dependencies
- name: Restore / Reuse Cache from central build
id: cache-golang-restore
uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big)
with:
path: |
${{ env.go_cache }}
${{ env.go_modcache }}
key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }}
restore-keys: |
${{ env.cache_name }}-${{ runner.os }}-go-
env:
cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step
- name: Setup git config
run: |
git config user.name "GitHub Actions Bot"
git config user.email "<41898282+github-actions[bot]@users.noreply.github.com>"
- name: Create and Push Release
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
run: |
# git checkout --detach HEAD
echo -n "${RELEASE_VERSION#v}" > VERSION
git add VERSION
git commit -m "Release $RELEASE_VERSION"
msg="Release ${{ env.RELEASE_VERSION }}"
git tag --annotate --message "${msg}" ${{ env.RELEASE_VERSION }}
# push the tag.
git push origin ${{ env.RELEASE_VERSION }}
# If we encounter a release (i.e. NOT a candidate), we want to keep the tag in the release branch git history
# by merging it (without taking over its contents).
# This allows tools that rely on the latest tag (such as Release Note generators or git describe)
# to recognize the release as the latest version.
# We can then use this to generate release notes based on the previous tag.
# If we previously built a release candidate, the tag is not merged back.
# That results in the tag being "omitted" / not recognized while generating release notes.
# This is intended, because a candidate should never influence further release notes.
# Example:
# Branch releases/v0.19
# - Candidate Build v0.19.0-rc.1 => no merge, release notes based on original cutoff
# - Actual Build v0.19.0 => merge, release notes based on original cutoff
# - Candidate Build v0.19.1-rc.1 => no merge, release notes based on v0.19.0 due to previous merge
- name: Merge Release Tag back into release branch if not a release candidate
if: inputs.release_candidate == false
run: |
git checkout ${{ github.ref }}
git merge --strategy ours ${{ env.RELEASE_VERSION }}
git push origin ${{ github.ref }}
- name: Create GPG Token file from Secret
run: |
echo "${{ secrets.GPG_PRIVATE_KEY_FOR_SIGNING }}" > ocm-releases-key.gpg
echo "GPG_KEY_PATH=ocm-releases-key.gpg" >> $GITHUB_ENV
- name: Setup Release Notes as File to make it readable by GoReleaser
run: |
echo "${{ fromJSON(needs.check.outputs.draft-release-notes).body }}" > $RUNNER_TEMP/RELEASE_NOTES.md
echo "RELEASE_NOTES=$RUNNER_TEMP/RELEASE_NOTES.md" >> $GITHUB_ENV
cat $RUNNER_TEMP/RELEASE_NOTES.md
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: 2.1.0
args: release --clean --timeout 60m --skip=validate --config=.github/config/goreleaser.yaml --release-notes=${{ env.RELEASE_NOTES }}
env:
GITHUBORG: ${{ github.repository_owner }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_CURRENT_TAG: ${{ env.RELEASE_VERSION }}
NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
- name: Remove GPG Token file
run: |
rm ocm-releases-key.gpg
- name: Push OCM Components
env:
GITHUBORG: ${{ github.repository_owner }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: make plain-push
# now distribute the release event so that other jobs can listen for this
# and use the event to publish our release to other package registries
- name: Publish Release Event
if: inputs.release_candidate == false
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ steps.generate_token.outputs.token }}
repository: ${{ github.repository_owner }}/ocm
event-type: publish-ocm-cli
client-payload: '{"version":"${{ env.RELEASE_VERSION }}","push-to-website":true,"push-to-aur":true,"push-to-chocolatey":true,"push-to-winget":true,"push-to-brew-tap":true}'
# make sure that the branch contains the next valid patch
bump-release-branch-pr:
if: inputs.release_candidate == false
uses: ./.github/workflows/release-bump-version.yaml
needs: release
permissions:
contents: write
id-token: write
packages: write
secrets: inherit
with:
bump-type: patch
ref: ${{ github.ref }}