Skip to content

Release

Release #13

Workflow file for this run

name: Release
on:
workflow_dispatch:
inputs:
release-type:
description: "Release type"
required: true
type: choice
options:
- patch
- minor
- major
permissions:
contents: write
issues: read
actions: read
defaults:
run:
shell: bash -euxo pipefail {0}
jobs:
prepare-release:
name: Prepare Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.update-version.outputs.version }}
release-tag: ${{ steps.create-release.outputs.release-tag }}
temp-branch: ${{ steps.create-temp-branch.outputs.branch }}
steps:
- name: Check if running on allowed branch
run: |
if [[ "${{ github.ref_name }}" == "main" || "${{ github.ref_name }}" == "release/"* ]]; then
echo "✅ Running on allowed branch: ${{ github.ref_name }}"
else
echo "❌ Release workflow can only be triggered from 'main' or 'release/*' branches"
echo "Current branch: ${{ github.ref_name }}"
exit 1
fi
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
token: ${{ github.token }}
fetch-depth: 0
fetch-tags: true
- name: Create temporary branch
id: create-temp-branch
run: |
TEMP_BRANCH="release-prep-$(date +%s)"
git checkout -b "${TEMP_BRANCH:?}"
echo "branch=${TEMP_BRANCH:?}" >> $GITHUB_OUTPUT
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@1780873c7b576612439a134613cc4cc74ce5538c # v1.15.2
with:
toolchain: stable
rustflags: ""
- name: Install cargo-quickinstall
run: cargo install cargo-quickinstall
- name: Install cargo-edit
run: cargo quickinstall cargo-edit
- name: Update version in Cargo.toml
id: update-version
run: |
cargo set-version --package ${{ github.event.repository.name }} --bump "${{ github.event.inputs.release-type }}"
VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "${{ github.event.repository.name }}") | .version')
echo "version=${VERSION?}" >> $GITHUB_OUTPUT
- name: Install git-cliff
run: |
# Install git-cliff for generating release notes
CLIFF_VERSION="2.10.1"
curl -sSfL "https://github.com/orhun/git-cliff/releases/download/v${CLIFF_VERSION}/git-cliff-${CLIFF_VERSION}-x86_64-unknown-linux-gnu.tar.gz" | tar -xz
sudo mv git-cliff-*/git-cliff /usr/local/bin/
git-cliff --version
- name: Generate release notes
id: release-notes
run: |
VERSION=${{ steps.update-version.outputs.version }}
PREVIOUS_TAG=$(git tag -l "v*.*.*" --merged HEAD --sort=-version:refname | head -1 || echo "")
git-cliff --tag "v${VERSION:?}" --output RELEASE_NOTES.md --verbose "${PREVIOUS_TAG:?}..HEAD"
env:
GITHUB_REPO: ${{ github.repository }}
GITHUB_TOKEN: ${{ github.token }}
- name: Create draft release
id: create-release
run: |
VERSION=${{ steps.update-version.outputs.version }}
# Check if version is a pre-release (contains hyphen)
if [[ "${VERSION}" == *-* ]]; then
PRERELEASE_FLAG="--prerelease"
else
PRERELEASE_FLAG=""
fi
gh release create "v${VERSION:?}" \
--title "v${VERSION:?}" \
--notes-file RELEASE_NOTES.md \
--draft \
${PRERELEASE_FLAG}
echo "release-tag=v${VERSION:?}" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ github.token }}
- name: Commit version update
run: |
git config --local user.name "missionis[bot]"
git config --local user.email "234988995+missionis[bot]@users.noreply.github.com"
git add Cargo.toml Cargo.lock
git commit -m "chore(release): bump version to ${{ steps.update-version.outputs.version }}"
git push origin "refs/heads/${{ steps.create-temp-branch.outputs.branch }}"
build:
name: Build and Upload Binaries
needs: prepare-release
uses: ./.github/workflows/build.yml
with:
release: ${{ needs.prepare-release.outputs.release-tag }}
ref: ${{ needs.prepare-release.outputs.temp-branch }}
permissions:
contents: write
issues: read
actions: read
finalize-release:
name: Finalize Release
runs-on: ubuntu-latest
needs: [prepare-release, build]
steps:
- name: Generate GitHub App Token
id: generate-token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }},action-hub
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
token: ${{ steps.generate-token.outputs.token }}
ref: ${{ needs.prepare-release.outputs.temp-branch }}
fetch-depth: 0
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@c5a866b6ab867e88becbed4467b93592bce69f8a # v21
- name: Generate Nix binary hashes file
run: |
VERSION=${{ needs.prepare-release.outputs.version }}
RELEASE_TAG=${{ needs.prepare-release.outputs.release-tag }}
# Install nixfmt for pretty formatting
nix profile add nixpkgs#nixfmt
# Get filtered assets and convert hex hashes to SRI format
gh release view "${RELEASE_TAG:?}" --json assets --jq '.assets
| map(select(.name | test("^${{ github.event.repository.name }}-(linux-(x86_64|arm64)-musl|macos-(x86_64|arm64))\\.tar\\.gz$")))
| .[] | .name + ":" + (.digest | ltrimstr("sha256:"))' | \
while IFS=':' read -r name hex; do
echo "${name:?}:sha256-$(echo -n "${hex:?}" | xxd -r -p | base64)"
done > /tmp/assets-sri.txt
# Convert SRI hashes to JSON format
jq -R -s --arg version "${VERSION:?}" '
{($version): (
split("\n")
| map(select(length > 0) | split(":") | {key: .[0], value: .[1]})
| from_entries
)}' < /tmp/assets-sri.txt > /tmp/hashes.json
# Convert JSON to Nix and format
nix eval --impure --expr 'builtins.fromJSON (builtins.readFile "/tmp/hashes.json")' | \
nixfmt > nix/binary-hashes.nix
env:
GH_TOKEN: ${{ github.token }}
- name: Commit hash updates and create final tag
run: |
VERSION=${{ needs.prepare-release.outputs.version }}
git config --local user.name "missionis[bot]"
git config --local user.email "234988995+missionis[bot]@users.noreply.github.com"
git add nix/binary-hashes.nix
git commit -m "build(nix): update binary hashes for v${VERSION:?}"
# Push the commit to remote branch
git push origin "refs/heads/${{ needs.prepare-release.outputs.temp-branch }}"
# Create final tag pointing to commit with all changes
git tag "v${VERSION:?}"
- name: Merge into the target branch and publish release
run: |
VERSION=${{ needs.prepare-release.outputs.version }}
RELEASE_TAG=${{ needs.prepare-release.outputs.release-tag }}
TEMP_BRANCH=${{ needs.prepare-release.outputs.temp-branch }}
TARGET_BRANCH=${{ github.ref_name }}
# Merge the temporary branch into the target branch
git checkout -B "${TARGET_BRANCH:?}" "origin/${TARGET_BRANCH:?}"
git merge "refs/heads/${TEMP_BRANCH:?}"
git push origin "refs/heads/${TARGET_BRANCH:?}"
# Push the release tag
git push origin "refs/tags/v${VERSION:?}"
# Check if release is marked as pre-release and publish accordingly
IS_PRERELEASE=$(gh release view "${RELEASE_TAG:?}" --json isPrerelease --jq '.isPrerelease')
# Update latest tag if it exists and release is not a pre-release
if [[ "${IS_PRERELEASE:?}" == "false" ]] && [ "$(git tag -l latest --merged HEAD)" = latest ]; then
gh release edit "${RELEASE_TAG:?}" --tag "v${VERSION:?}" --draft=false --latest
git tag -f latest HEAD
git push -f origin refs/tags/latest
else
gh release edit "${RELEASE_TAG:?}" --tag "v${VERSION:?}" --draft=false
fi
# Delete the temporary branch
git push origin --delete "refs/heads/${TEMP_BRANCH:?}" || true
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
- name: Trigger publish workflow to distribute release
run: |
VERSION=${{ needs.prepare-release.outputs.version }}
RELEASE_TAG=${{ needs.prepare-release.outputs.release-tag }}
IS_PRERELEASE=$(gh release view "${RELEASE_TAG:?}" --json isPrerelease --jq '.isPrerelease')
if [[ "${IS_PRERELEASE:?}" == "false" ]]; then
gh workflow run publish.yml \
--repo "${{ github.repository_owner }}/action-hub" \
--field package="${{ github.event.repository.name }}"
fi
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}