Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,5 @@ if ! command -v golangci-lint >/dev/null 2>&1; then
exit 1
fi

root=$(git rev-parse --show-toplevel)
cfg="$root/proxy/.golangci.yml"
# Lints the working tree, not just the staged content.
(cd "$root/proxy" && golangci-lint run ./... && golangci-lint run --build-tags stress ./...)
(cd "$root/tests/stress/driver" && golangci-lint run --config "$cfg" ./...)
exec "$(git rev-parse --show-toplevel)/scripts/lint.sh"
83 changes: 83 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CI

on:
pull_request:
push:
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: proxy/go.mod
cache-dependency-path: "**/go.sum"
- uses: golangci/golangci-lint-action@v9
with:
version: v2.14
install-only: true
- run: ./scripts/lint.sh

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: proxy/go.mod
cache-dependency-path: proxy/go.sum
- run: go test ./... -race -count=1
working-directory: proxy

image:
needs: [lint, test]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write # OIDC token that signs the provenance attestation
attestations: write
steps:
- uses: actions/checkout@v7
- uses: docker/setup-buildx-action@v4
# GHCR image names must be lowercase; the org name isn't.
- run: echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV"
- id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.IMAGE }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha
- if: github.event_name == 'push'
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# PRs only fill the cache; main reuses it and pushes. PR caches are
# scoped to their ref, so main's own cache is what PRs start from.
- id: build
uses: docker/build-push-action@v7
with:
context: proxy
push: ${{ github.event_name == 'push' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- if: github.event_name == 'push'
uses: actions/attest-build-provenance@v4
with:
subject-name: ${{ env.IMAGE }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ docker compose logs -f hallmaster-proxy
go vet ./... && go vet -tags stress ./...
go test ./... -race -count=1
go test -run '^$' -bench . -benchmem ./... # in-process microbenchmarks
golangci-lint run && golangci-lint run --build-tags stress ./... # v2 config; brew install golangci-lint
../scripts/lint.sh # golangci-lint v2, all tags + stress driver; quiet on success

# once per clone (from repo root): pre-commit = secret guard + golangci-lint
# once per clone (from repo root): pre-commit = secret guard + scripts/lint.sh
git config core.hooksPath .githooks

# end-to-end load harness (from repo root)
Expand Down
18 changes: 12 additions & 6 deletions docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,11 @@ Useful while developing:
- `go test ./... -race -count=1` — run the full test suite, including the
end-to-end handler harness (`handlers/https_test.go`) and the `Serve`
graceful-shutdown tests (`mitm_test.go`).
- `golangci-lint run` — full lint per the config in `.golangci.yml`
- `../scripts/lint.sh` — full lint per the config in `.golangci.yml`
(`errcheck`, `govet`, `ineffassign`, `staticcheck`, `unused`, `gofmt`,
`goimports`). The config uses the v2 format, so it needs golangci-lint 2.x
(`brew install golangci-lint`).
`goimports`) over the proxy (default and `stress` build tags) and the
stress driver. Prints one line on success. The config uses the v2 format,
so it needs golangci-lint 2.x (`brew install golangci-lint`).

Enable the pre-commit hook once per clone:

Expand All @@ -211,9 +212,14 @@ git config core.hooksPath .githooks

[.githooks/pre-commit](../.githooks/pre-commit) refuses to commit
`.env` / `.env.*` (except `*.example`), `*.pem` and `*.key` (removing them from the index still
works). When Go files are staged, it also runs `golangci-lint` on the proxy
(default and `stress` build tags) and on the stress driver. It lints the
working tree, not just the staged changes.
works). When Go files are staged, it also runs `scripts/lint.sh`. It lints
the working tree, not just the staged changes.

CI ([.github/workflows/ci.yml](../.github/workflows/ci.yml)) runs the same
lint script and the race tests on every PR and push to `main`, then builds
the proxy image with a GitHub Actions layer cache. Only pushes to `main`
publish it, to `ghcr.io/hallmasterorg/hallmaster-proxy` (`latest` and
`sha-<short>`), with a signed build-provenance attestation.

When you change the Go code, rebuild the container with:

Expand Down
27 changes: 27 additions & 0 deletions scripts/lint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh
# Lints every Go target with golangci-lint. Used by the pre-commit hook and CI.
# Quiet on success (one summary line); issues print under their target's name.
set -u

root=$(cd "$(dirname "$0")/.." && pwd)
cfg="$root/proxy/.golangci.yml"
failed=""

lint() { # <name> <dir> [golangci-lint args...]
name=$1 dir=$2
shift 2
if ! out=$(cd "$dir" && golangci-lint run --show-stats=false --config "$cfg" "$@" ./... 2>&1); then
printf '\n── %s ──\n%s\n' "$name" "$out" >&2
failed="$failed $name"
fi
}

lint proxy "$root/proxy"
lint proxy/stress "$root/proxy" --build-tags stress
lint stress-driver "$root/tests/stress/driver"

if [ -n "$failed" ]; then
echo "lint: FAILED:$failed" >&2
exit 1
fi
echo "lint: ok (proxy, proxy/stress, stress-driver)"
Loading