Skip to content

Move the Go module into src/ and build into build/<os>/ - #42

Merged
imanimanyara merged 8 commits into
mainfrom
chore/src-module-layout
Nov 8, 2026
Merged

imanimanyara merged 8 commits into
mainfrom
chore/src-module-layout

Conversation

@imanimanyara

Copy link
Copy Markdown
Member

Summary

Brings probaci onto the simtabi Go layout, in eight commits that keep moves and changes apart:

  • Module in src/. go.mod, the root package, cmd/, internal/, pkg/, scripts/ and the GoReleaser and golangci configs move with git mv alone (first commit). The module path becomes github.com/simtabi/probaci/src; imports, -X ldflags, the Makefile, Taskfile, CI, CodeQL (now build-mode: manual), golangci-lint (working-directory: src), Dependabot (gomod at /src) and GoReleaser (builds[].dir: src, go -C src mod tidy, run with --config src/.goreleaser.yaml) follow it. release.yml mirrors src/vX.Y.Z before GoReleaser and stays dispatch-only behind confirm=release-go.
  • Embedded docs. The root package embeds README.md and docs/ for probaci docs, and //go:embed cannot reach above src/. The docs stay at the root and are copied into src/embedded/ by make sync-docs. TestEmbeddedDocsMatchTheRepository fails when the copy drifts in either direction.
  • build/ layout. One folder per OS (macos, never darwin), probaci_{os}_{arch}[.exe], build/checksums.txt over {os}/{file}, build/archives/ only from make dist. make build writes build/<host-os>/probaci, and make cross/make dist use src/scripts/build-all.sh, never GoReleaser. GoReleaser's dist: moved to .cache/goreleaser (gitignored), and the attestation reads its checksums from there. A new CI snapshot job runs make cross and uploads the binaries.
  • Makefile is the single definition. Every Taskfile task keeps its name and forwards to make.
  • Guards. TestBuildLayout (and its negative test), TestNoContainerImage and TestDocsOfferNoGoInstall, each with floors, in src/internal/release. The existing release guard moved there and now also requires the refusal to be the first step.
  • Docs, CONTRIBUTING and CHANGELOG [Unreleased] follow the new paths. They still say releases are on hold, build from source, and offer no go install.

Removed

The owner approved removing the container image. Removed in bb8ebd1:

  • Dockerfile (distroless wrapper around the binary). No .dockerignore existed.
  • The GoReleaser dockers_v2 block (ghcr.io/simtabi/probaci, linux/amd64 and linux/arm64, tags {{ .Version }} and latest).
  • release.yml: docker/setup-qemu-action, docker/setup-buildx-action, the docker/login-action ghcr.io login, the packages: write permission, and the header line about pushing the image.
  • Dependabot's docker ecosystem.
  • docker from make bundle's --skip list.
  • The docs lines offering the image (docs/installation.md, docs/release.md).

No image was ever published. The release workflow has never run, the repository has no releases, and GET /orgs/simtabi/packages/container/probaci answers 404, so there is nothing on ghcr.io to freeze or delete.

Replaced, not removed: the CI gitleaks job ran docker run zricethezav/gitleaks:latest. It now runs go install github.com/zricethezav/gitleaks/v8@v8.30.1 and the same gitleaks dir . --no-banner --redact --exit-code 1, so the scan stays and the repository runs no container. probaci's own feature of brokering tools through the host container runtime (src/internal/docker) is untouched.

Verification

Run locally on the head commit:

  • go -C src vet ./...: clean
  • go -C src test ./... -count=1: 16 packages ok. -race is also clean.
  • gofmt -l src: empty
  • make build writes build/macos/probaci. probaci docs release renders from the embedded copy.
  • make cross builds 10 targets plus probaci_macos_universal. cd build && shasum -a 256 -c checksums.txt reports 11 OK.
  • make dist writes build/archives/ with 11 archives and their checksums. check-build passes.
  • goreleaser check --config src/.goreleaser.yaml: 1 configuration file validated. This only checks the config. No release, build or snapshot was run.
  • golangci-lint run ./... in src/: 0 issues

Red proofs: each defect was planted, the guard failed, and it passed again after reverting:

Guard Planted defect
TestReleaseRunsOnlyOnAConfirmedDispatch a push: tags trigger; a checkout step before the refusal
TestBuildLayout build/dist/x; build/darwin/probaci
TestNoContainerImage the old Dockerfile; docker run in ci.yml; a dockers_v2 block in GoReleaser; a docker Dependabot ecosystem
TestDocsOfferNoGoInstall a go install github.com/simtabi/probaci/src/cmd/probaci@latest line in installation.md
TestEmbeddedDocsMatchTheRepository an extra line in docs/security.md. It also caught a real drift during this work (fixed in 70789c2).

Notes for review

  • setup-go stays on go-version: "1.25" rather than go-version-file: src/go.mod. go.mod says go 1.25.0, which setup-go would install exactly, and the govulncheck and gosec pins rely on the newest 1.25 patch. Every setup-go now has cache-dependency-path: src/go.sum.
  • The selftest job runs go -C src run ./cmd/probaci …. probaci walks up to the git root, so it still proves the whole repository. However, its detect stage now reports no languages, because there is no go.mod at the root. Detecting a module in a subdirectory would be a change to probaci itself, so it is not made here.
  • bb8ebd1 alone fails the embedded-docs drift test. The next commit, 70789c2, resyncs the copy.

The simtabi Go layout keeps everything the toolchain reads under src/ and
everything the repository presents at the top. This commit only moves
files with git mv: go.mod, go.sum, the root package, cmd/, internal/,
pkg/, scripts/ and the GoReleaser and golangci configs. Nothing inside
them changes here, so the move reviews as renames.

The module path, the embedded docs, the tooling and the workflows are
pointed at src/ in the following commits; until then the root package's
//go:embed of README.md and docs/ cannot resolve.
With the module in src/, its path becomes github.com/simtabi/probaci/src:
GitHub's go-import tag has no subdir field, so Go treats the rest of the
path as a directory. Imports, the -X ldflags and GoReleaser follow it.

Everything that runs go now names the module: the Makefile and Taskfile
use go -C src, CI and CodeQL point setup-go's cache at src/go.sum and
golangci-lint at src/, CodeQL builds in manual mode because autobuild
does not look in src/, and Dependabot's gomod entry reads /src. A bare
`go test ./...` at the root would find no packages and pass.

The root package embeds README.md and docs/ for `probaci docs`, and
//go:embed cannot reach above src/, while the docs must stay at the root
for GitHub and the docs site. They are mirrored into src/embedded/ by
`make sync-docs`, and TestEmbeddedDocsMatchTheRepository fails when the
copy drifts in either direction.

release.yml mirrors src/vX.Y.Z onto the release commit, since that is
the only tag Go resolves a subdirectory module through, writes the
CHANGELOG notes to $RUNNER_TEMP so GoReleaser does not see a dirty tree,
and sets GOPRIVATE for the org's modules. It is still dispatch-only.

setup-go stays on go-version "1.25" rather than go-version-file: go.mod
says go 1.25.0, which setup-go installs exactly, and the govulncheck and
gosec pins rely on the newest 1.25 patch.
The simtabi Go layout gives build/ one folder per OS and nothing else:
build/{macos,linux,windows}/probaci_{os}_{arch}[.exe], one
build/checksums.txt over {os}/{file} paths so `cd build && shasum -a 256
-c checksums.txt` verifies as-is, and build/archives/ only from
`make dist`. build/dist/ is gone: GoReleaser now writes its scratch dist
to .cache/goreleaser (gitignored), and the release attestation reads the
checksums from there.

The Makefile is now the one definition of every task, with build,
cross, dist and check-build added; `make build` writes
build/<host-os>/probaci and `make cross`/`make dist` go through
src/scripts/build-all.sh, never GoReleaser. The Taskfile keeps every
task name and forwards to make. The build script no longer deletes
build/targets.txt; it writes the default matrix only when the file is
missing.

TestBuildLayout fails on anything else in build/, and its negative test
plants each wrong shape (dist/, darwin/, a per-target folder, a loose
binary, GoReleaser metadata, a nested macos build) to prove it can fail.
make build, cross and dist run it, and a new CI snapshot job runs
`make cross`, verifies the checksums and uploads the binaries.
The owner decided probaci ships as a binary built from source and no
longer builds a container image. Removed: the Dockerfile, the
GoReleaser dockers_v2 block (ghcr.io/simtabi/probaci, linux/amd64 and
arm64), release.yml's QEMU, buildx and ghcr.io login steps with the
packages: write permission they needed, Dependabot's docker ecosystem,
the --skip=docker flag of `make bundle`, and the docs lines offering the
image.

No image was ever published: the release workflow has never run, the
repository has no releases, and the packages API answers 404 for
simtabi/probaci, so there is nothing on ghcr.io to freeze or delete.

The CI gitleaks job ran gitleaks from a container. The scan stays: it
now installs gitleaks v8.30.1 with go install and runs the same command,
so the repository runs no container anywhere. probaci's own feature of
brokering tools through the host's container runtime is untouched.
The previous commit edited docs/installation.md and docs/release.md without refreshing src/embedded/, and TestEmbeddedDocsMatchTheRepository caught the drift. This is `make sync-docs`, nothing else.
TestReleaseRunsOnlyOnAConfirmedDispatch sat in the root package because
the module used to start at the repository root. The build-layout guard
now lives in src/internal/release, so the release guard joins it there
and finds release.yml through the same repoRoot helper. Only the package
clause and the path lookup change; the assertions are untouched.
TestReleaseRunsOnlyOnAConfirmedDispatch keeps its assertions and gains
two: pull_request_target and workflow_run count as automatic triggers,
and the refusal (confirm=release-go on a v[0-9]* tag, then exit 1) has
to be the first step, before anything is checked out or built.

TestNoContainerImage walks the repository for a Dockerfile, Containerfile,
.dockerignore or compose file, and reads every workflow and
src/.goreleaser.yaml for docker/ actions, docker build/run/push/login,
ghcr.io and dockers/dockers_v2/docker_manifests blocks, and
dependabot.yml for a docker ecosystem. It asserts it visited at least 80
files (116 today) and at least 5 workflows, so a walk rooted in the
wrong place cannot pass.

TestDocsOfferNoGoInstall fails when README, CONTRIBUTING or a docs page
offers `go install github.com/...` while releases are on hold, with a
floor of 5 docs pages.

Each was proven red by planting its defect (a tag push trigger, a step
before the refusal, a Dockerfile, docker run in ci.yml, a dockers_v2
block, a docker Dependabot ecosystem, a go install line) and green
after reverting.
README, the installation and release guides, the architecture page,
CONTRIBUTING and the pull request template now name src/ for the
module, build/<os>/probaci for the host build, make cross and make dist
for the OS folders and archives, .cache/goreleaser for GoReleaser's
scratch output, and src/scripts/ for the install and pin scripts. The
release guide explains the src/vX.Y.Z tag, and CONTRIBUTING explains
`make sync-docs`.

They still say what they said before about releases: binary releases
are on hold, probaci is built from source, and no go install path is
offered. CHANGELOG [Unreleased] records the move, the new guards and
the removed container image. src/embedded/ is resynced.
Copilot AI balanced review requested due to automatic review settings November 8, 2026 05:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@imanimanyara
imanimanyara merged commit b11b7d6 into main Nov 8, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants