Skip to content

additional tweaks to release process #51

additional tweaks to release process

additional tweaks to release process #51

Workflow file for this run

name: Release
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-*"
concurrency:
group: release
cancel-in-progress: false
env:
DIST: dist-${{ github.ref_name }}
jobs:
verify-tag:
name: Verify tag
runs-on: ubuntu-latest
permissions:
contents: read
environment:
name: release
# inspired by Caddy's release process: https://github.com/caddyserver/caddy/blob/987375297862d9cd0a3fa33cfb199c25e504ad1b/.github/workflows/release.yml#L29C1-L143C54
outputs:
verification_passed: ${{ steps.verify.outputs.passed }}
tag_version: ${{ steps.info.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Force fetch upstream tags
run: git fetch --tags --force
- name: Get tag info
id: info
run: |
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
echo "version_tag=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
- name: Validate commits and tag signatures
id: verify
env:
RELEASE_MANAGERS: ${{ vars.RELEASE_MANAGERS }}
run: |
if [ -z "${RELEASE_MANAGERS}" ]; then
echo "RELEASE_MANAGERS variable is not set"
echo "passed=false" >> $GITHUB_OUTPUT
exit 1
fi
IFS=',' read -ra rms <<< "${RELEASE_MANAGERS}"
for u in "${rms[@]}"; do
curl -fsSL "https://github.com/${u}.gpg" | gpg --batch --import >/dev/null
done
echo "Verifying the tag: ${{ steps.info.outputs.version_tag }}"
if ! git verify-tag -v "${{ steps.info.outputs.version_tag }}" 2>&1; then
echo "❌ Tag verification failed!"
echo "passed=false" >> $GITHUB_OUTPUT
exit 1
fi
# Run it again to capture the output
git verify-tag -v "${{ steps.info.outputs.version_tag }}" 2>&1 | tee /tmp/verify-output.txt;
# SSH verification output typically includes the key fingerprint
# Use GNU grep with Perl regex for cleaner extraction (Linux environment)
KEY_SHA256=$(grep -oP "SHA256:[\"']?\K[A-Za-z0-9+/=]+(?=[\"']?)" /tmp/verify-output.txt | head -1 || echo "")
if [ -z "$KEY_SHA256" ]; then
# Try alternative pattern with "key" prefix
KEY_SHA256=$(grep -oP "key SHA256:[\"']?\K[A-Za-z0-9+/=]+(?=[\"']?)" /tmp/verify-output.txt | head -1 || echo "")
fi
if [ -z "$KEY_SHA256" ]; then
# Fallback: extract any base64-like string (40+ chars)
KEY_SHA256=$(grep -oP '[A-Za-z0-9+/]{40,}=?' /tmp/verify-output.txt | head -1 || echo "")
fi
if [ -z "$KEY_SHA256" ]; then
echo "Somehow could not extract SSH key fingerprint from git verify-tag output"
echo "passed=false" >> $GITHUB_OUTPUT
exit 1
fi
echo "✅ Tag verification succeeded!"
echo "passed=true" >> $GITHUB_OUTPUT
echo "key_id=$KEY_SHA256" >> $GITHUB_OUTPUT
- name: Summary
run: |
echo "## Tag Verification Summary 🔐" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Tag:** ${{ steps.info.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Commit:** ${{ steps.info.outputs.sha }}" >> $GITHUB_STEP_SUMMARY
echo "- **Signature:** ✅ Verified" >> $GITHUB_STEP_SUMMARY
echo "- **Signed by:** ${{ steps.verify.outputs.key_id }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Proceeding with release build..." >> $GITHUB_STEP_SUMMARY
publish-crates:
name: Publish crates
needs: verify-tag
if: ${{ needs.verify-tag.outputs.verification_passed == 'true' }}
uses: ./.github/workflows/publish-crates.yaml
with:
dry_run: false
secrets: inherit
publish-npmjs:
name: Publish npmjs packages
needs: verify-tag
if: ${{ needs.verify-tag.outputs.verification_passed == 'true' }}
uses: ./.github/workflows/publish-npmjs.yaml
with:
dry_run: false
secrets: inherit
publish-dockerhub:
name: Publish Docker image to Dockerhub
runs-on: ubuntu-latest
needs: verify-tag
if: ${{ needs.verify-tag.outputs.verification_passed == 'true' }}
permissions:
contents: read
id-token: write
attestations: write
artifact-metadata: write
environment:
name: release
env:
IMAGE_NAME: solanafoundation/anchor
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Docker metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=ref,event=tag
type=sha
- name: Build and push
id: build
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: docker/build
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
SOLANA_CLI=v2.3.0
ANCHOR_CLI=${{ github.ref_name }}
provenance: mode=max
sbom: true
- name: Attest build provenance
uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0
id: attest
with:
subject-name: ${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: false # provenance: mode=max above already pushes it to Dockerhub
build-cli:
name: Build binaries
needs: verify-tag
if: ${{ needs.verify-tag.outputs.verification_passed == 'true' }}
uses: ./.github/workflows/build-cli.yaml
with:
dry_run: false
dist: dist-${{ github.ref_name }}
upload-cli:
name: Upload binaries to release
runs-on: ubuntu-latest
needs: [verify-tag, build-cli]
if: ${{ needs.verify-tag.outputs.verification_passed == 'true' }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
pattern: anchor-*
path: ${{ env.DIST }}
- name: Upload
shell: bash
run: |
publish_args=()
# If version looks like vX.Y.Z-<something> (e.g. v1.0.0-rc.2), publish as a pre-release
if [[ "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-.+ ]]; then
publish_args+=(--prerelease)
# avm (and its older versions) do not filter out pre-releases right now,
# meaning that if we were to create a pre-release, this would change the
# default version installed for new users
echo "Skipping creating GitHub release for a pre-release."
exit 0
fi
GH_TOKEN=${{ secrets.GITHUB_TOKEN }} gh release create $GITHUB_REF_NAME $DIST/*/* --title "$GITHUB_REF_NAME" "${publish_args[@]}"
publish-cli:
name: Publish CLI onto npmjs
runs-on: ubuntu-latest
needs: [verify-tag, build-cli]
if: ${{ needs.verify-tag.outputs.verification_passed == 'true' }}
permissions:
id-token: write
contents: read
environment:
name: release
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
package-manager-cache: false
- name: Enable corepack (yarn)
run: corepack enable
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
pattern: anchor-*
path: ${{ env.DIST }}
- run: |
set -xeuo pipefail
cp $DIST/anchor-*-x86_64-unknown-linux-gnu/anchor-*-x86_64-unknown-linux-gnu cli/npm-package/anchor
cd cli/npm-package/
chmod +x anchor
version="$(node -p "require('./package.json').version")"
publish_args=()
# If version looks like X.Y.Z-<something> (e.g. 1.0.0-rc.2), publish under dist-tag "next"
if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+-.+ ]]; then
publish_args+=(--tag next)
fi
echo "Publishing CLI"
npm publish "${publish_args[@]}" --provenance --access public