From eb9d96b23b56cb75b5d248290deff47047e08f08 Mon Sep 17 00:00:00 2001 From: dcadolph Date: Sun, 27 Sep 2026 20:07:25 -0500 Subject: [PATCH] Run the tests on every push preen had a release workflow and nothing that ran the twenty-five test files it already carries, so a tool whose pitch is that it provably does not lose your work shipped no visible evidence that anything was checked. Build, vet, test and a gofmt check, with git given an identity because the tests drive a real one. The run package now clears GIT_CONFIG_GLOBAL and GIT_CONFIG_SYSTEM for itself. Its harness already did that for the commands it runs, but the engine spawns git of its own and those children read the process environment, so anyone with core.hooksPath set globally watched three hook tests fail against hooks they never wrote. The suite was red on my machine and green everywhere else, which is the wrong way round. --- .github/workflows/ci.yml | 31 +++++++++++++++++++++++++++++++ README.md | 1 + run/engine_test.go | 20 ++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..afc28ac --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: ci +on: + push: + branches: [main] + pull_request: +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - run: go build ./... + - run: go vet ./... + # preen drives a real git, so the tests need an identity to commit with + # and a runner whose git is not carrying a stale default branch name. + - name: Configure git for the tests + run: | + git config --global user.name "preen ci" + git config --global user.email "ci@example.com" + git config --global init.defaultBranch main + - run: go test ./... + - name: Check formatting + run: | + unformatted="$(gofmt -l .)" + if [ -n "$unformatted" ]; then + echo "::error::gofmt would change these files:" + echo "$unformatted" + exit 1 + fi diff --git a/README.md b/README.md index fb93c76..0cb5fa8 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ # preen +[![ci](https://github.com/dcadolph/preen/actions/workflows/ci.yml/badge.svg)](https://github.com/dcadolph/preen/actions/workflows/ci.yml) [![Latest release](https://img.shields.io/github/v/release/dcadolph/preen)](https://github.com/dcadolph/preen/releases/latest) [![License](https://img.shields.io/github/license/dcadolph/preen)](LICENSE) diff --git a/run/engine_test.go b/run/engine_test.go index 4544d02..34ff4ed 100644 --- a/run/engine_test.go +++ b/run/engine_test.go @@ -14,6 +14,26 @@ import ( "github.com/dcadolph/preen/repo" ) +// TestMain isolates the package from the developer's git configuration. +// +// The harness already passes GIT_CONFIG_GLOBAL and GIT_CONFIG_SYSTEM to the +// commands it runs itself, but the engine under test spawns git on its own, and +// those children inherit the process environment rather than the harness's. A +// developer who installs shared hooks the usual way, by pointing core.hooksPath +// at a directory in their global config, would watch the hook tests fail against +// hooks they never wrote: the repository-local hook the test installs is ignored +// while core.hooksPath is set, so a hook that is supposed to reject a rewrite +// never runs at all. +func TestMain(m *testing.M) { + if err := os.Setenv("GIT_CONFIG_GLOBAL", os.DevNull); err != nil { + panic(err) + } + if err := os.Setenv("GIT_CONFIG_SYSTEM", os.DevNull); err != nil { + panic(err) + } + os.Exit(m.Run()) +} + // harness is a real repository plus an engine wired to it. type harness struct { // Engine is the engine under test.