WitNote / .github /workflows /release.yml
AUXteam's picture
Upload folder using huggingface_hub
6a7089a verified
name: Release
# Automatic release pipeline triggered on tag push (v0.7.0, etc.)
#
# Pipeline:
# 1. Checkout tag
# 2. Build Go binary + create GitHub release (goreleaser)
# 3. Publish npm package (with postinstall binary download support)
# 4. Build & push Docker images
# See .github/RELEASING.md for the operational checklist.
#
# Secrets required:
# - NPM_TOKEN: npm authentication (https://docs.npmjs.com/creating-and-viewing-access-tokens)
# - DOCKERHUB_USER / DOCKERHUB_TOKEN: Docker Hub credentials
# - GITHUB_TOKEN: Automatic (GitHub Actions)
# - HOMEBREW_TAP_GITHUB_TOKEN: PAT with write access to pinchtab/homebrew-tap
#
# To create a release:
# git tag v0.7.0
# git push origin v0.7.0
on:
push:
tags: ['v*']
workflow_dispatch:
inputs:
tag:
description: 'Tag to release (e.g. v0.2.0). Leave empty for dry-run from ref.'
required: false
ref:
description: 'Git ref for dry-run testing (branch, tag, or SHA). Defaults to main.'
required: false
default: 'main'
dry_run:
description: 'Build release artifacts without publishing them.'
required: false
type: boolean
default: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GORELEASER_VERSION: v2.14.3
permissions:
contents: write
jobs:
release:
name: Release Binaries
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Validate workflow inputs
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
if [ "${{ inputs.dry_run }}" != "true" ] && [ -z "${{ github.event.inputs.tag }}" ]; then
echo "tag is required unless dry_run=true" >&2
exit 1
fi
- uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.event.inputs.tag || github.event.inputs.ref || github.ref }}
- uses: actions/setup-go@v6
with:
go-version: '1.26'
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dashboard dependencies
working-directory: dashboard
run: bun install --frozen-lockfile
- name: Run GoReleaser
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.dry_run }}" = "true" ]; then
ARGS="release --clean --snapshot"
else
ARGS="release --clean"
fi
curl -sfL https://goreleaser.com/static/run | VERSION="$GORELEASER_VERSION" bash -s -- $ARGS
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
npm:
name: Publish to npm
runs-on: ubuntu-latest
needs: release
permissions:
contents: read
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.event.inputs.tag || github.event.inputs.ref || github.ref }}
- uses: actions/setup-node@v5
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: Extract version
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.dry_run }}" = "true" ] && [ -z "${{ github.event.inputs.tag }}" ]; then
VERSION=$(jq -r .version npm/package.json)
else
TAG="${{ github.event.inputs.tag || github.ref_name }}"
VERSION=${TAG#v} # Remove 'v' prefix
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
- name: Update npm package version
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.dry_run }}
working-directory: npm
run: |
CURRENT=$(jq -r .version package.json)
DESIRED=${{ steps.version.outputs.version }}
if [ "$CURRENT" != "$DESIRED" ]; then
npm version "$DESIRED" --no-git-tag-version
else
echo "Version already correct: $CURRENT"
fi
- name: Install dependencies
working-directory: npm
run: npm ci --ignore-scripts
- name: Build TypeScript
working-directory: npm
run: npm run build
- name: Dry-run npm publish
if: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}
working-directory: npm
run: npm publish --dry-run
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish to npm
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.dry_run }}
working-directory: npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
docker:
name: Docker Image
runs-on: ubuntu-latest
needs: release
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.event.inputs.tag || github.event.inputs.ref || github.ref }}
- name: Extract Docker metadata
id: meta
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.dry_run }}" = "true" ]; then
if [ -n "${{ github.event.inputs.tag }}" ]; then
TAG="${{ github.event.inputs.tag }}"
VERSION="${TAG#v}-dryrun-${GITHUB_SHA::7}"
else
TAG="dry-run-${GITHUB_SHA::7}"
VERSION="$(jq -r .version npm/package.json)-dryrun-${GITHUB_SHA::7}"
fi
PUSH="false"
else
TAG="${{ github.event.inputs.tag || github.ref_name }}"
VERSION="${TAG#v}"
PUSH="true"
fi
{
echo "tag=$TAG"
echo "version=$VERSION"
echo "push=$PUSH"
} >> "$GITHUB_OUTPUT"
- name: Docker dry-run note
if: ${{ steps.meta.outputs.push != 'true' }}
run: |
echo "Running a multi-arch Docker build without pushing to GHCR or Docker Hub." >> "$GITHUB_STEP_SUMMARY"
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
if: ${{ steps.meta.outputs.push == 'true' }}
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: docker/login-action@v3
if: ${{ steps.meta.outputs.push == 'true' }}
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: ${{ steps.meta.outputs.push == 'true' }}
provenance: false
labels: |
org.opencontainers.image.source=https://github.com/pinchtab/pinchtab
org.opencontainers.image.version=${{ steps.meta.outputs.version }}
tags: |
ghcr.io/pinchtab/pinchtab:latest
ghcr.io/pinchtab/pinchtab:${{ steps.meta.outputs.tag }}
ghcr.io/pinchtab/pinchtab:${{ steps.meta.outputs.version }}
pinchtab/pinchtab:latest
pinchtab/pinchtab:${{ steps.meta.outputs.tag }}
pinchtab/pinchtab:${{ steps.meta.outputs.version }}
skill:
name: Publish Skill
needs:
- npm
- docker
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.dry_run }}
uses: ./.github/workflows/publish-skill.yml
with:
version: ${{ github.event.inputs.tag || github.ref_name }}
secrets:
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}