Skip to content

Release

Release #20

Workflow file for this run

name: Release
on:
workflow_call:
inputs:
release_tag:
description: Tag to build and publish
required: true
type: string
workflow_dispatch:
inputs:
release_tag:
description: Existing tag to build and publish
required: true
type: string
permissions:
contents: read
concurrency:
group: release-${{ inputs.release_tag || github.ref_name }}
cancel-in-progress: false
jobs:
validate:
name: Validate release commit
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.release_tag || github.ref_name }}
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: true
cache-dependency-path: go.sum
- uses: actions/setup-node@v7
with:
node-version: 22
- run: go test ./...
- run: go vet ./...
- run: test -z "$(gofmt -l .)"
- name: Verify release version
shell: bash
env:
VERSION: ${{ inputs.release_tag || github.ref_name }}
run: node scripts/verify-release-version.mjs "${VERSION#v}"
- run: npm run test:npm
build-npm-binaries:
name: Build npm binary ${{ matrix.target }}
needs: [validate, platform_matrix]
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.platform_matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.release_tag || github.ref_name }}
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: true
cache-dependency-path: go.sum
- name: Build native binary
shell: bash
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: "0"
TARGET: ${{ matrix.target }}
BINARY: ${{ matrix.binary }}
VERSION: ${{ inputs.release_tag || github.ref_name }}
run: |
mkdir -p "dist/$TARGET"
go build -trimpath -ldflags "-s -w -X main.version=${VERSION#v}" -o "dist/$TARGET/$BINARY" ./cmd/gitcontribute
- uses: actions/upload-artifact@v7
with:
name: native-${{ matrix.target }}
path: dist/${{ matrix.target }}/${{ matrix.binary }}
if-no-files-found: error
platform_matrix:
name: Derive npm release targets
needs: validate
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
matrix: ${{ steps.platforms.outputs.matrix }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.release_tag || github.ref_name }}
- uses: actions/setup-node@v7
with:
node-version: 22
- id: platforms
shell: bash
run: echo "matrix=$(node scripts/release-platform-matrix.mjs)" >> "$GITHUB_OUTPUT"
goreleaser:
name: Build and release
needs: validate
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ inputs.release_tag || github.ref_name }}
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: true
cache-dependency-path: go.sum
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v7
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-npm:
name: Publish npm package
needs: [validate, build-npm-binaries, goreleaser]
runs-on: ubuntu-latest
timeout-minutes: 20
environment: npm
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.release_tag || github.ref_name }}
- uses: actions/setup-node@v7
with:
node-version: 22
registry-url: https://registry.npmjs.org
- run: npm install --global npm@11.15.0
- uses: actions/download-artifact@v8
with:
pattern: native-*
path: dist
- name: Normalize downloaded artifact layout
shell: bash
run: |
for directory in dist/native-*; do
target=${directory##*/native-}
mkdir -p "dist/$target"
cp "$directory"/* "dist/$target/"
if [[ $target != win32-* ]]; then chmod +x "dist/$target/gitcontribute"; fi
done
- name: Verify release version
shell: bash
env:
VERSION: ${{ inputs.release_tag || github.ref_name }}
run: node scripts/verify-release-version.mjs "${VERSION#v}"
- run: npm run test:npm
- run: npm run build:npm
- name: Build and inspect npm tarball
shell: bash
env:
VERSION: ${{ inputs.release_tag || github.ref_name }}
run: |
npm pack --pack-destination dist
tarball=$(find dist -maxdepth 1 -name 'gitcontribute-*.tgz' -print -quit)
test -n "$tarball"
test "$(stat -c %s "$tarball")" -le 100000000
sha256sum "$tarball" | sed 's# dist/# #' > dist/npm-SHA256SUMS
npm install --prefix "$RUNNER_TEMP/npm-smoke" --ignore-scripts --no-audit --no-fund "$(realpath "$tarball")"
metadata=$("$RUNNER_TEMP/npm-smoke/node_modules/.bin/gitcontribute" metadata --json)
EXPECTED_VERSION="${VERSION#v}" node -e '
const expected = process.env.EXPECTED_VERSION;
let input = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", chunk => { input += chunk; });
process.stdin.on("end", () => {
const actual = JSON.parse(input).version;
if (actual !== expected) {
throw new Error(`packed binary version ${actual} does not match release ${expected}`);
}
});
' <<<"$metadata"
- name: Publish npm package
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
run: npm publish --provenance --access public
- name: Attach npm package to GitHub release
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ inputs.release_tag || github.ref_name }}
shell: bash
run: |
tarball=$(find dist -maxdepth 1 -name 'gitcontribute-*.tgz' -print -quit)
gh release upload "$RELEASE_TAG" "$tarball" dist/npm-SHA256SUMS --clobber
release-notes:
name: Generate release notes
runs-on: ubuntu-latest
timeout-minutes: 5
needs: [goreleaser, publish-npm]
permissions:
contents: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ inputs.release_tag || github.ref_name }}
- name: Generate changelog
uses: orhun/git-cliff-action@v4
with:
config: cliff.toml
args: --latest --strip all
env:
OUTPUT: CHANGELOG.md
- name: Upload release notes
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.release_tag }}
body_path: CHANGELOG.md
generate_release_notes: true