Skip to content

Release

Release #9

Workflow file for this run

name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to release (e.g., v0.2.6)'
required: true
type: string
permissions:
contents: write
packages: write
jobs:
test:
name: Test before release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.tag || github.ref }}
- uses: actions/setup-go@v5
with:
go-version: '1.25'
- run: make test
release:
name: Release
needs: test
runs-on: ubuntu-latest
steps:
- name: Resolve tag
id: tag
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "version=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
else
echo "version=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT
fi
- uses: actions/checkout@v4
with:
ref: ${{ steps.tag.outputs.version }}
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: Get project name
id: project
run: echo "name=$(basename $GITHUB_REPOSITORY)" >> $GITHUB_OUTPUT
- name: Build and package binaries
run: |
VERSION=${{ steps.tag.outputs.version }}
VERSION_NUM=${VERSION#v}
PROJECT=${{ steps.project.outputs.name }}
LDFLAGS="-s -w -X main.version=${VERSION_NUM}"
platforms=(
"linux/amd64"
"linux/arm64"
"darwin/amd64"
"darwin/arm64"
"windows/amd64"
)
mkdir -p dist staging
for platform in "${platforms[@]}"; do
GOOS="${platform%/*}"
GOARCH="${platform#*/}"
binary="${PROJECT}"
archive="${PROJECT}_${VERSION_NUM}_${GOOS}_${GOARCH}"
if [ "$GOOS" = "windows" ]; then
binary="${binary}.exe"
GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="$LDFLAGS" -o "staging/${binary}" ./cmd/${PROJECT}/
cd staging && zip "../dist/${archive}.zip" "${binary}" && cd ..
else
GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="$LDFLAGS" -o "staging/${binary}" ./cmd/${PROJECT}/
tar -czf "dist/${archive}.tar.gz" -C staging "${binary}"
fi
rm -f "staging/${binary}"
done
- name: Generate checksums
run: |
cd dist
sha256sum * > checksums.txt
- name: Extract release notes from CHANGELOG
id: notes
run: |
TAG=${{ steps.tag.outputs.version }}
VERSION=${TAG#v}
PROJECT=${{ steps.project.outputs.name }}
REPO=${{ github.repository }}
CHANGELOG=$(awk "/^## \[${VERSION}\]/{found=1; next} /^## \[/{found=0} found" CHANGELOG.md 2>/dev/null || true)
if [ -z "$CHANGELOG" ]; then
CHANGELOG="Release ${TAG}"
fi
{
echo "${CHANGELOG}"
echo ""
echo "## Install"
echo ""
echo '```bash'
echo "# macOS (Apple Silicon)"
echo "curl -LO https://github.com/${REPO}/releases/download/${TAG}/${PROJECT}_${VERSION}_darwin_arm64.tar.gz"
echo "tar -xzf ${PROJECT}_${VERSION}_darwin_arm64.tar.gz"
echo "sudo mv ${PROJECT} /usr/local/bin/"
echo ""
echo "# macOS (Intel)"
echo "curl -LO https://github.com/${REPO}/releases/download/${TAG}/${PROJECT}_${VERSION}_darwin_amd64.tar.gz"
echo "tar -xzf ${PROJECT}_${VERSION}_darwin_amd64.tar.gz"
echo "sudo mv ${PROJECT} /usr/local/bin/"
echo ""
echo "# Linux (amd64)"
echo "curl -LO https://github.com/${REPO}/releases/download/${TAG}/${PROJECT}_${VERSION}_linux_amd64.tar.gz"
echo "tar -xzf ${PROJECT}_${VERSION}_linux_amd64.tar.gz"
echo "sudo mv ${PROJECT} /usr/local/bin/"
echo '```'
echo ""
echo "**Verify checksums:** \`sha256sum -c checksums.txt\`"
} > /tmp/release-body.md
echo "notes<<EOF" >> $GITHUB_OUTPUT
cat /tmp/release-body.md >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.tag.outputs.version }}
body: ${{ steps.notes.outputs.notes }}
files: dist/*
generate_release_notes: false
docker-image:
name: Docker image
needs: test
runs-on: ubuntu-latest
steps:
- name: Resolve tag
id: tag
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "version=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
else
echo "version=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT
fi
- uses: actions/checkout@v4
with:
ref: ${{ steps.tag.outputs.version }}
- uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=${{ steps.tag.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max