166 lines
5.9 KiB
YAML
166 lines
5.9 KiB
YAML
name: Release
|
|
|
|
# Single pipeline: lint + test + build, then (only on push to main and
|
|
# only if every gate passed) tag the release from the VERSION file.
|
|
# A tag is therefore never created unless the build and tests are green.
|
|
#
|
|
# Why no actions/checkout + actions/setup-go:
|
|
# act_runner re-clones every third-party JS action from github.com per
|
|
# job. setup-go is large and that clone routinely hangs / times out on
|
|
# the homelab runner. We avoid the failure mode entirely by doing the
|
|
# checkout with plain git and downloading Go directly from go.dev.
|
|
# /usr/local/go persists across jobs in the host-executor runner
|
|
# container, so subsequent runs are no-ops.
|
|
#
|
|
# Tagging token:
|
|
# Pushing a tag needs write access. Gitea injects a per-job
|
|
# `github.token`; this workflow uses it, so the repository's
|
|
# Settings → Actions → General → "Workflow permissions" must allow
|
|
# read/write. If your instance restricts the auto token, set a PAT
|
|
# secret named RELEASE_TAG_PAT (repo write) and it is used instead.
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
GO_VERSION: "1.26.3"
|
|
ERRCHECK_VERSION: "v1.20.0"
|
|
STATICCHECK_VERSION: "v0.7.0"
|
|
|
|
jobs:
|
|
release:
|
|
runs-on: self-hosted
|
|
defaults:
|
|
run:
|
|
shell: sh
|
|
env:
|
|
# Gitea auto-generates a per-job read-scoped token for git fetch;
|
|
# RELEASE_TAG_PAT (if set) is preferred for the tag push.
|
|
GITHUB_TOKEN: ${{ github.token }}
|
|
RELEASE_TAG_PAT: ${{ secrets.RELEASE_TAG_PAT }}
|
|
steps:
|
|
- name: Install Go and toolchain
|
|
run: |
|
|
set -eu
|
|
missing=""
|
|
command -v curl >/dev/null 2>&1 || missing="$missing curl"
|
|
command -v gcc >/dev/null 2>&1 || missing="$missing build-base"
|
|
command -v git >/dev/null 2>&1 || missing="$missing git"
|
|
if [ -n "$missing" ]; then
|
|
apk add --no-cache $missing
|
|
fi
|
|
want="go${GO_VERSION}"
|
|
have="$(/usr/local/go/bin/go env GOVERSION 2>/dev/null || echo none)"
|
|
if [ "$have" != "$want" ]; then
|
|
echo "installing Go ${GO_VERSION} (had: ${have})"
|
|
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" -o /tmp/go.tgz
|
|
rm -rf /usr/local/go
|
|
tar -C /usr/local -xzf /tmp/go.tgz
|
|
rm -f /tmp/go.tgz
|
|
else
|
|
echo "Go ${GO_VERSION} already installed"
|
|
fi
|
|
echo "/usr/local/go/bin" >> "$GITHUB_PATH"
|
|
echo "$HOME/go/bin" >> "$GITHUB_PATH"
|
|
echo "CGO_ENABLED=1" >> "$GITHUB_ENV"
|
|
|
|
- name: Checkout
|
|
run: |
|
|
set -eu
|
|
cd "$GITHUB_WORKSPACE"
|
|
rm -rf ./* ./.[!.]* 2>/dev/null || true
|
|
git init -q
|
|
git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
|
auth=$(printf '%s' "x-access-token:${GITHUB_TOKEN}" | base64 -w0)
|
|
git -c "http.extraheader=Authorization: Basic ${auth}" \
|
|
fetch --depth=1 origin "${GITHUB_SHA}"
|
|
git checkout -q FETCH_HEAD
|
|
|
|
- name: Install linters (errcheck, staticcheck)
|
|
run: |
|
|
set -eu
|
|
if ! command -v errcheck >/dev/null 2>&1; then
|
|
echo "installing errcheck ${ERRCHECK_VERSION}"
|
|
go install "github.com/kisielk/errcheck@${ERRCHECK_VERSION}"
|
|
else
|
|
echo "errcheck already installed"
|
|
fi
|
|
if ! command -v staticcheck >/dev/null 2>&1; then
|
|
echo "installing staticcheck ${STATICCHECK_VERSION}"
|
|
go install "honnef.co/go/tools/cmd/staticcheck@${STATICCHECK_VERSION}"
|
|
else
|
|
echo "staticcheck already installed: $(staticcheck -version)"
|
|
fi
|
|
|
|
- name: gofmt
|
|
run: |
|
|
set -eu
|
|
diff=$(gofmt -l $(find . -name '*.go' -not -path './vendor/*'))
|
|
if [ -n "$diff" ]; then
|
|
echo "gofmt would reformat:"
|
|
echo "$diff"
|
|
exit 1
|
|
fi
|
|
|
|
- name: go vet
|
|
run: go vet ./...
|
|
|
|
- name: errcheck
|
|
run: errcheck ./...
|
|
|
|
- name: staticcheck
|
|
run: staticcheck ./...
|
|
|
|
- name: go test -race
|
|
run: go test ./... -race
|
|
|
|
- name: go build
|
|
run: go build ./...
|
|
|
|
# ── Release: only on push to main, and only after every gate above
|
|
# passed (steps run sequentially and fail-fast). ──────────────
|
|
- name: Tag release from VERSION
|
|
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
|
run: |
|
|
set -eu
|
|
cd "$GITHUB_WORKSPACE"
|
|
|
|
token="${RELEASE_TAG_PAT:-$GITHUB_TOKEN}"
|
|
if [ -z "$token" ]; then
|
|
echo "no token available to push tags" >&2
|
|
exit 1
|
|
fi
|
|
auth=$(printf '%s' "x-access-token:${token}" | base64 -w0)
|
|
|
|
# Fetch existing tags so we can check the target tag.
|
|
git -c "http.extraheader=Authorization: Basic ${auth}" \
|
|
fetch --quiet --tags origin || true
|
|
|
|
version="$(tr -d ' \t\r\n' < VERSION)"
|
|
if [ -z "$version" ]; then
|
|
echo "VERSION file is empty" >&2
|
|
exit 1
|
|
fi
|
|
tag="v${version}"
|
|
|
|
if git rev-parse -q --verify "refs/tags/${tag}" >/dev/null; then
|
|
echo "Tag ${tag} already exists — nothing to release."
|
|
exit 0
|
|
fi
|
|
if git -c "http.extraheader=Authorization: Basic ${auth}" \
|
|
ls-remote --tags origin "refs/tags/${tag}" | grep -q "${tag}"; then
|
|
echo "Tag ${tag} already exists on the remote — nothing to release."
|
|
exit 0
|
|
fi
|
|
|
|
echo "Creating tag ${tag} at ${GITHUB_SHA}"
|
|
git config user.name "sherlock-release"
|
|
git config user.email "release@sherlock.local"
|
|
git tag -a "${tag}" -m "Release ${tag}"
|
|
git -c "http.extraheader=Authorization: Basic ${auth}" \
|
|
push origin "refs/tags/${tag}"
|
|
echo "Pushed ${tag}."
|