Skip to content

fix(strategy): stabilize fetch/rebase git CLI tests under race #179

fix(strategy): stabilize fetch/rebase git CLI tests under race

fix(strategy): stabilize fetch/rebase git CLI tests under race #179

Workflow file for this run

# Canonical CI workflow for hawk-eco Go repos.
# Source of truth: .shared-templates/workflows/go-ci.yml.tmpl
#
# Two deployment models:
#
# 1. NOW — render this template inline into each repo's
# .github/workflows/ci.yml. Every repo has identical content.
#
# 2. LATER — once GrayCodeAI/.github exists as a central repo, move this
# file to GrayCodeAI/.github/.github/workflows/go-ci.yml with
# `on: workflow_call:`. Each repo's ci.yml becomes a 5-line caller:
#
# name: CI
# on: { push: { branches: [main] }, pull_request: }
# jobs:
# ci:
# uses: GrayCodeAI/.github/.github/workflows/go-ci.yml@main
name: CI
on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
GO_VERSION: "1.26.4"
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
# -------------------------------------------------------------------------
# Format + vet — fastest, fail fast.
# -------------------------------------------------------------------------
fmt-vet:
name: fmt + vet
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: actions/setup-go@v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: gofumpt diff
run: |
go install mvdan.cc/gofumpt@v0.10.0
out=$(gofumpt -l .)
if [ -n "$out" ]; then
echo "::error::gofumpt would reformat the following files:"
echo "$out"
exit 1
fi
- name: go vet
run: go vet ./...
# -------------------------------------------------------------------------
# Lint — golangci-lint covers most static checks.
# -------------------------------------------------------------------------
lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: actions/setup-go@v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- uses: golangci/golangci-lint-action@v9.2.1
with:
version: v2.11.3
install-mode: goinstall
verify: false
args: --timeout=5m
# -------------------------------------------------------------------------
# Tests with race detector + coverage upload.
# -------------------------------------------------------------------------
test:
name: test (race + cover)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: actions/setup-go@v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Tidy check
run: |
go mod tidy
if ! git diff --quiet; then
echo "::error::go.mod / go.sum out of date — run 'go mod tidy' and commit"
git diff
exit 1
fi
- name: Test
run: go test ./... -race -count=1 -coverprofile=coverage.out -covermode=atomic -timeout=180s
- name: Coverage summary
run: go tool cover -func=coverage.out | tail -1
- name: Coverage threshold
run: |
COVERAGE=$(go tool cover -func=coverage.out | tail -1 | grep -oE '[0-9]+\.[0-9]+' || echo "0")
THRESHOLD=58
if [ "$(echo "$COVERAGE < $THRESHOLD" | bc -l)" -eq 1 ]; then
echo "::error::Coverage ${COVERAGE}% is below threshold ${THRESHOLD}%"
exit 1
fi
echo "Coverage ${COVERAGE}% meets threshold ${THRESHOLD}%"
- name: Upload coverage
uses: actions/upload-artifact@v7.0.1
with:
name: coverage
path: coverage.out
# -------------------------------------------------------------------------
# Security scan — vulnerability database + (optional) gosec.
# -------------------------------------------------------------------------
security:
name: security
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: actions/setup-go@v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
govulncheck ./...
- name: gosec (advisory)
run: |
go install github.com/securego/gosec/v2/cmd/gosec@v2.22.4
if ! gosec -exclude=G104,G301,G302,G304,G306 ./...; then
echo "gosec reported advisory findings"
fi
# -------------------------------------------------------------------------
# Dead code detection.
# -------------------------------------------------------------------------
deadcode:
name: deadcode
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: actions/setup-go@v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: deadcode
# Advisory, not blocking: trace is a library with no main() entrypoint,
# so plain `deadcode ./...` flags the entire public API as unreachable.
# We run with -test (tests count as roots) for a meaningful signal, but a
# hard gate would false-positive on legitimate exported API — review the
# output in the logs instead.
run: |
go install golang.org/x/tools/cmd/deadcode@latest
deadcode -test -f '{{range .Funcs}}{{printf "%s\t%s\n" $.Path .Name}}{{end}}' ./... | tee deadcode.txt
echo "deadcode reported $(wc -l < deadcode.txt | tr -d ' ') unreachable funcs (advisory)"
- name: upload deadcode report
uses: actions/upload-artifact@v7.0.1
if: always()
with:
name: deadcode-report
path: deadcode.txt
if-no-files-found: ignore
# -------------------------------------------------------------------------
# Duplication detection — jscpd.
# -------------------------------------------------------------------------
jscpd:
name: duplication
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: actions/setup-node@v6.4.0
with:
node-version: '20'
- name: jscpd
run: |
npx jscpd --min-lines 5 --min-tokens 50 --reporters console --blame . 2>&1 | head -50
# -------------------------------------------------------------------------
# Cross-platform build matrix — only for repos that produce a binary.
# Repos that are pure libraries can keep this job (it'll just `go build ./...`)
# or remove it locally.
# -------------------------------------------------------------------------
build:
name: build (${{ matrix.goos }}/${{ matrix.goarch }})
runs-on: ubuntu-latest
needs: [fmt-vet, lint, test]
strategy:
fail-fast: false
matrix:
goos: [linux, darwin, windows]
goarch: [amd64, arm64]
exclude:
- goos: windows
goarch: arm64
steps:
- uses: actions/checkout@v6.0.3
- uses: actions/setup-go@v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Build
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: "0"
run: go build ./...