Skip to content

Merge pull request #18 from golift/feat/windows-release #11

Merge pull request #18 from golift/feat/windows-release

Merge pull request #18 from golift/feat/windows-release #11

Workflow file for this run

# Release pipeline. Push a full semver tag (v1.2.3) and this workflow:
# 1. Builds and publishes binaries with GoReleaser Pro (Authenticode on
# Windows PE when CODESIGN_URL is set; Apple sign+notarize on darwin
# when MACOS_SIGN_P12 is set).
# 2. Publishes the signerd Docker image to GHCR with the same tag.
# 3. Force-moves the floating tags (v1, v1.2) that GitHub Actions
# consumers track with `uses: golift/codesign@v1`, but only when this
# tag is the highest matching vN.* / vN.N.*.
#
# The trigger matches ONLY vN.N.N. GitHub's filter-pattern syntax (not a
# regex, but it does support `[0-9]` classes and `+` repetition — see the
# "filter pattern cheat sheet" in the GitHub Actions docs) must match the
# whole tag, so the floating vN / vN.N tags this workflow itself pushes can
# never re-trigger it, and neither can prerelease tags like v1.2.3-beta.
# A job-level guard also rejects anything that is not strict vN.N.N.
# Never retag a published vN.N.N. Breaking Action input/output changes mean
# v2.0.0 and a new v2 floater. Floating tags are for `uses:`; Go module
# consumers resolve real semver tags.
name: release
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
permissions:
contents: read
concurrency:
group: codesign-release
cancel-in-progress: false
jobs:
goreleaser:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: require-strict-semver
run: |
if ! [[ "${GITHUB_REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "ref ${GITHUB_REF_NAME} is not a strict vN.N.N tag" >&2
exit 1
fi
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
- name: install-codesign
env:
GOBIN: ${{ runner.temp }}/codesign-bin
run: |
set -euo pipefail
mkdir -p "${GOBIN}"
go install ./cmd/codesign
echo "${GOBIN}" >> "${GITHUB_PATH}"
echo "CODESIGN_BIN=${GOBIN}/codesign" >> "${GITHUB_ENV}"
# GoReleaser Pro enables notarize when MACOS_SIGN_P12 is set, then
# skips the notary submit if issuer/key/id are empty and still exits 0.
# Fail here so a half-configured org cannot publish signed-only darwin.
- name: require-apple-sign-secrets
env:
MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }}
MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }}
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
run: |
set -euo pipefail
if [ -z "${MACOS_SIGN_P12}" ]; then
echo "MACOS_SIGN_P12 unset; Darwin archives will not be signed or notarized"
exit 0
fi
missing=
[ -n "${MACOS_SIGN_PASSWORD}" ] || missing="${missing} MACOS_SIGN_PASSWORD"
[ -n "${MACOS_NOTARY_KEY}" ] || missing="${missing} MACOS_NOTARY_KEY"
[ -n "${MACOS_NOTARY_KEY_ID}" ] || missing="${missing} MACOS_NOTARY_KEY_ID"
[ -n "${MACOS_NOTARY_ISSUER_ID}" ] || missing="${missing} MACOS_NOTARY_ISSUER_ID"
if [ -n "${missing}" ]; then
echo "MACOS_SIGN_P12 is set but Apple sign+notarize secrets are incomplete:${missing}" >&2
exit 1
fi
- uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
distribution: goreleaser-pro
version: '~> v2'
args: release --clean --timeout 60m
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_KEY: ${{ secrets.GORELEASER_PRO_KEY }}
CODESIGN_URL: ${{ secrets.CODESIGN_URL }}
CODESIGN_CLIENT_CERT: ${{ secrets.CODESIGN_CLIENT_CERT }}
CODESIGN_CLIENT_KEY: ${{ secrets.CODESIGN_CLIENT_KEY }}
CODESIGN_NAME: Go Lift Code Sign
CODESIGN_WEBSITE: https://github.com/golift/codesign
MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }}
MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }}
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: require-strict-semver
run: |
if ! [[ "${GITHUB_REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "ref ${GITHUB_REF_NAME} is not a strict vN.N.N tag" >&2
exit 1
fi
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
- name: decide-tags
id: tags
run: |
set -euo pipefail
git fetch --tags --force
image="ghcr.io/${{ github.repository }}"
tags="${image}:${GITHUB_REF_NAME}"
highest="$(git tag -l 'v*.*.*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1)"
if [ "${highest}" = "${GITHUB_REF_NAME}" ]; then
tags="${tags}"$'\n'"${image}:latest"
fi
{
echo "tags<<EOF"
echo "${tags}"
echo "EOF"
echo "date=$(git show -s --format=%cI "${GITHUB_SHA}")"
# GoReleaser stamps {{.Version}} (no leading v); match it so the
# image binary's -version agrees with the archive binary's.
echo "version=${GITHUB_REF_NAME#v}"
} >> "${GITHUB_OUTPUT}"
- uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
push: true
provenance: true
sbom: true
tags: ${{ steps.tags.outputs.tags }}
build-args: |
VERSION=${{ steps.tags.outputs.version }}
REVISION=${{ github.sha }}
BUILDDATE=${{ steps.tags.outputs.date }}
BRANCH=${{ github.ref_name }}
# Plant/move the floating tags AFTER the release succeeds, and only when
# this tag is the highest of its major/minor series so a backport cannot
# regress uses: golift/codesign@v1.
floating-tags:
needs: [goreleaser, docker]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: move-floating-tags
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
if ! [[ "${tag}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "ref ${tag} is not a strict vN.N.N tag" >&2
exit 1
fi
git fetch --tags --force
highest() {
git tag -l "$1" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1
}
major="${tag%%.*}"
minor="${tag%.*}"
advance() {
local floater="$1"
local pattern="$2"
if [ "$(highest "${pattern}")" = "${tag}" ]; then
git tag --force "${floater}" "${tag}"
git push --force origin "${floater}"
else
echo "skip ${floater}: ${tag} is not the highest ${pattern}"
fi
}
advance "${major}" "${major}.*"
advance "${minor}" "${minor}.*"