Companion to docs/architecture.md. This document covers
prerequisites, the build pipeline, testing, mock generation, and the checks
the CI runs.
- Go 1.22+
templCLI — compiles.templfiles to Go (templ generate). The Makefile requires it onPATH.- Portal SDK —
go.lumeweb.com/portal-sdk, resolved via a localreplaceingo.mod. - CGO is required (
CGO_ENABLED=1) — there are cgo dependencies, so builds must not disable it. - mockery — pre-installed in the dev environment; generate mocks via
mockerywith no arguments (uses.mockery.yaml).
Use
maketargets. The Makefile chainstempl generate→ Go build. The MCP App asset source (bundles, theme, manifest) is embedded from the pinnedgo.lumeweb.com/pinner/canvasassetsmodule, so rawgo build/go testare safe — templ files are the only locally-generated embeddable assets.
make build # full pipeline, produces ./pinner with version info
make test # build assets, then go test ./...
make install # full pipeline, install to $GOPATH/bin
./pinner --helpRunning from source: go run ./cmd/pinner <command>.
| Target | Depends on | Action |
|---|---|---|
make build (default) |
assets |
CGO_ENABLED=1 go build -ldflags="$(LDFLAGS)" -o pinner ./cmd/pinner |
make install |
assets |
CGO_ENABLED=1 go install -ldflags="$(LDFLAGS)" ./cmd/pinner |
make test |
assets |
go test ./... |
make assets |
templinstall generate |
Regenerates the locally-generated *.templ.go files |
make generate |
— | templ generate (recurses the repo from the root; not go generate ./...) |
make templinstall |
— | go install github.com/a-h/templ/cmd/templ@v0.3.1020 |
make clean |
— | rm -f pinner |
assets is declared .PHONY so make never treats the asset target as
up-to-date and always regenerates the *.templ.go files.
The default goal is pinned to build so a bare make always produces a
binary.
templinstall → generate → go build / go install
templinstall—go install github.com/a-h/templ/cmd/templ@v0.3.1020pins the templ CLI to the version declared in go.mod, so regeneration works on a fresh checkout without templ pre-installed.generate— runstempl generatefrom the repo root. This is invoked deliberately astempl generate, not viago generate ./..., because templ files live in multiple packages and a single root-anchored pass covers every*.templexactly once.- MCP App assets (from the module, not built here) — the embedded
ui://bundles, theme and mcpcanvas manifest are owned bygo.lumeweb.com/pinner/canvasassetsand served from the pinned pinner module, so the CLI's Go build needs no local JS/CSS regeneration or bundle production. Pinner owns the full JS asset pipeline; this repo no longer builds or embeds any JS/CSS itself. - Go build —
CGO_ENABLED=1with-ldflagsinjecting version info.
LDFLAGS injects Version, GitCommit, GitBranch, BuildTime,
GoVersion, Platform, and Architecture into the build package
(go.lumeweb.com/pinner-cli/build). These surface through version display
and pinner doctor.
The Makefile builds for the host. To target other platforms, build directly
with GOOS/GOARCH:
GOOS=linux GOARCH=amd64 go build -o pinner-linux-amd64 ./cmd/pinner
GOOS=darwin GOARCH=arm64 go build -o pinner-darwin-arm64 ./cmd/pinner
GOOS=windows GOARCH=amd64 go build -o pinner-windows-amd64.exe ./cmd/pinnermake test # rebuild assets, then run the whole suite
go test ./... # quick run (assumes assets already built)
go test ./internal/cli # one package
go test -v ./... # verbose
go test ./internal/cli -run TestUpload # a specific testSome tests depend on the MCP App assets embedded from the pinned
go.lumeweb.com/pinner/canvasassets module, so make test regenerates the
templ files first. For quick Go-only checks, go vet ./... / go build ./...
are fine — the app bundles/theme/manifest are always present via the module
dependency.
- Go-level tests — unit tests throughout
internal/..., using service mocks and the*WithServicehelper pattern that lets tests exercise command logic without a live urfave context.
Mocks are configured in .mockery.yaml and generated with mockery (run with
no arguments; the config defines interfaces, output dirs, and testify
templates). Do not reinstall mockery — the environment already has it.
Generated mocks are committed; after changing .mockery.yaml or adding an
interface, regenerate and commit the output.
CI runs templ fmt . followed by git diff --exit-code -- '*.templ'. A
non-canonically formatted .templ file fails the lint job. Always run
templ fmt . after editing .templ files and commit the reformat in the same
change.
Local mirror of the CI checks:
templ fmt . && go vet ./... && go build ./...templ fmt . should report changed=0 before pushing.
go.lumeweb.com/portal-sdk is consumed through a local replace in go.mod.
When bumping the SDK version:
- Bump the version / update
go.mod(go getthe new tag). - Run
make build— the compiler reports every upstream change to absorb. - Fix each compile error (including struct field renames: grep all call sites, rename every occurrence).
- Run
make test— fixture failures like "unknown field X in struct literal" signal swagger schema drift; refresh the fixtures. - Repeat until clean. Absorb all upstream changes, even if the bump only targeted one feature.
When generating or updating OpenAPI client code, the repo uses
oapi-codegen invoked via go run ...@latest (consistent versioning), and
generated types must be verified against client.gen.go — oapi-codegen follows
the swagger spec (e.g. [32]byte swagger fields become []int).