name: CI # Go CI for sherlock. Runs gofmt, go vet, errcheck, staticcheck, # go test -race, and go build on every push and PR. No deploy pipeline # — sherlock is operator-installed via `go install`, not host-deployed. # # 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. # # Runner notes: # - Charlie runner image: gitea/act_runner + git/sops/docker-cli/bash/sudo # (alpine-based). No Go preinstalled — installed lazily below. # - runs-on: self-hosted picks any Charlie runner. No SSH-into-host # because there's no docker build / no host state to mutate. on: push: branches: [main] pull_request: workflow_dispatch: env: # Bumped from 1.23.4 → 1.26.3 in Phase 1: go-oidc/v3, x/oauth2 and # x/sync now declare `go 1.25.0`, which transitively forces our module # to `go 1.25+`. 1.26.3 is the current upstream stable. GO_VERSION: "1.26.3" # Pinned linter versions. Bump deliberately; the runner caches the # built binaries under ~/go/bin so re-runs are no-ops. ERRCHECK_VERSION: "v1.20.0" STATICCHECK_VERSION: "v0.7.0" jobs: build: runs-on: self-hosted defaults: run: shell: sh env: # Gitea auto-generates a per-job `secrets.GITHUB_TOKEN` (read-scoped # to this repo) for compat with GitHub Actions, but act_runner does # NOT auto-export it as an env var — referencing it explicitly here # makes it available to the Checkout step's `git fetch`. Same role # as `secrets.RUNNER_REPO_PAT` / `CALLER_REPO_PAT` in the Charlie # deploy/build workflows, except we don't need a long-lived PAT — # the per-job token is enough for a one-shot fetch. GITHUB_TOKEN: ${{ github.token }} steps: - name: Install Go and toolchain run: | set -eu # curl: fetch the Go tarball. # build-base (gcc + musl-dev + make): `go test -race` requires cgo. missing="" command -v curl >/dev/null 2>&1 || missing="$missing curl" command -v gcc >/dev/null 2>&1 || missing="$missing build-base" 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" # cgo on for the rest of the job (race detector needs it). echo "CGO_ENABLED=1" >> "$GITHUB_ENV" - name: Checkout run: | set -eu cd "$GITHUB_WORKSPACE" # Wipe any leftovers from a previous job using the same workspace. rm -rf ./* ./.[!.]* 2>/dev/null || true git init -q git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" # Gitea injects GITHUB_TOKEN per job; use it as a one-shot # Authorization header (not persisted to .git/config). 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 # Both tools are cached under $HOME/go/bin across jobs since # the host-executor runner persists the home directory. 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: $(errcheck -h 2>&1 | head -1 || true)" 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 ./...