Files
vaultik/Makefile
sneak be786fe25e
All checks were successful
check / check (pull_request) Successful in 2m29s
Gate prune's local-cleanup prose on --json and give make build a rule (closes #108)
CleanupLocalSnapshots wrote three prose lines to stdout with no --json
awareness, and they covered every branch of the function, so no input
avoided them: `vaultik prune --json | jq` failed even after the banner
fix. -q never helped either, because printlnStdout and stdoutf write
straight to Vaultik.Stdout and never consult Vaultik.UI, which is what
SetQuiet affects.

The issue offered three fixes and asked for a decision. Taken: thread
*PruneOptions into the function and gate each write on !opts.JSON,
matching PruneBlobs -- its sibling phase, which already takes the same
struct -- along with RemoveSnapshot and remote info, so the package has
one pattern rather than two. Rejected: moving the lines to log.Info,
because the logger's default level is slog.LevelWarn, so that would not
relocate them to stderr, it would delete them from a plain `vaultik
prune`, and the removal of rows from the local index is not something to
narrate only under --verbose. Also rejected: putting the stale-record
count into PruneBlobsResult, whose every field is blob-scoped and which
is produced by the later phase; a prune document covering both phases is
a reasonable thing to want, but that is a schema design question, not a
stream-hygiene fix. The two events are duplicated as log.Info records,
which PruneBlobs already does alongside its own prints, so they survive
on stderr under --verbose.

Also closes #110. `make build` printed "Nothing to be done for 'build'"
and exited 0 without producing a binary: build was listed in .PHONY with
no build: rule anywhere, and declaring a name phony is exactly what
converts make's "No rule to make target" error into a silent success.
Fixed with `build: vaultik`, keeping vaultik: as the file rule. Audited
all 19 .PHONY names: build was the only one without a rule, and vaultik
is correctly absent from .PHONY, being a real file target.

Tests, each verified to fail with the fix reverted rather than assumed
to. CleanupLocalSnapshots leaves stdout untouched under --json in all
three branches (stale records, none, empty index) and still emits every
line without it, so the guard cannot be satisfied by deleting the
output. prune --json runs end to end through Entry, cobra and fx over
the process's real stdout descriptor against a file:// store, asserting
exactly one JSON document, in both the stale and non-stale branches. And
a parse of the Makefile asserts every .PHONY name has a rule and that
build reaches the rule producing the binary, which keeps the audit true
for names added later; it is a parse rather than an invocation of make
because `make test` is what runs it, so shelling back into `make build`
would nest a build inside the test run. The property a parse cannot
establish -- that the recipe still fails when the build fails -- was
verified by hand against a deliberately broken tree: make build exits 2
and produces nothing.

cmd/vaultik gains its first test file, so `make test` now reports 16
packages ok where it reported 15. flagConfig and programName constants
are extracted in the CLI tests because the new argument vector pushed
"--config" and "vaultik" over goconst's threshold.

README's stdout/stderr section described the banner as "the other thing
that writes to stdout", which this defect contradicted; it now states
the contract that holds, which is that stdout under --json is the
document and nothing else, for prune as well as for the other four.
2026-08-09 17:33:06 +00:00

127 lines
4.3 KiB
Makefile
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
.PHONY: all bootstrap setup check test lint lint-fix fmt fmt-check build clean deps test-coverage local install release release-snapshot docker hooks
# Version number, derived from git by script/version -- the tag when
# HEAD is on one, otherwise dev-<sha>. This used to be a hardcoded
# constant, which meant every local build claimed to be a release that
# had never been tagged.
VERSION := $(shell script/version)
# $(shell) discards exit status, so a script/version that is missing,
# non-executable or broken would otherwise leave VERSION empty and every
# binary built here would print "vaultik " with no version at all. A
# build that cannot determine what it is must not produce an artifact.
ifeq ($(strip $(VERSION)),)
$(error script/version produced no version string; a build that cannot \
determine its version will not be made. Check that script/version exists \
and is executable)
endif
# Build variables
GIT_REVISION := $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
GIT_COMMIT_DATE := $(shell git show -s --format=%cs HEAD 2>/dev/null || echo "unknown")
# Linker flags
LDFLAGS := -X 'sneak.berlin/go/vaultik/internal/globals.Version=$(VERSION)' \
-X 'sneak.berlin/go/vaultik/internal/globals.Commit=$(GIT_REVISION)' \
-X 'sneak.berlin/go/vaultik/internal/globals.CommitDate=$(GIT_COMMIT_DATE)'
# Default target
all: vaultik
# Install all development dependencies.
bootstrap:
@script/bootstrap
# Prepare a fresh clone: bootstrap plus pre-commit hook.
setup:
@script/setup
# Combined pre-commit/CI gate: tests, lint, format check.
check:
@script/check
# Run tests only. This runs the ENTIRE suite -- there is no separate
# integration target and no build-tagged subset held back. In
# particular internal/vaultik/integration_test.go, which does full
# chunk -> pack -> encrypt -> upload -> restore round-trips, runs here.
# A `test-integration` target used to exist and was removed: no file in
# the repo carried a build tag, so `-tags=integration` selected nothing
# extra and the target was an exact duplicate of this one.
test:
@script/test
# Check if code is formatted (read-only).
fmt-check:
@script/fmt-check
# Format code.
fmt:
@script/fmt
# Run linter only.
lint:
@script/lint
# Apply the linter's autofixes (rewrites files).
lint-fix:
@script/lint-fix
# Build binary. `build` is the name the org convention reaches for and
# the one a caller checks the exit code of; `vaultik` is the file rule
# that does the work, so an unchanged tree still short-circuits.
#
# This alias is not decorative. `build` was listed in .PHONY with no
# rule, and a phony target with no prerequisites and no recipe is
# already satisfied: `make build` printed "Nothing to be done" and
# exited 0 without producing a binary (issue #110). Every name in
# .PHONY needs a rule for that reason; TestPhonyTargetsAllHaveRules in
# cmd/vaultik keeps it that way.
build: vaultik
vaultik: internal/*/*.go cmd/vaultik/*.go
go build -ldflags "$(LDFLAGS)" -o $@ ./cmd/vaultik
# Clean build artifacts.
clean:
rm -f vaultik
go clean
# Install dependencies. The linter is deliberately not installed here:
# script/lint runs the digest-pinned golangci-lint image declared by the
# Dockerfile's lint stage, which is the single source of truth for the
# linter version. A second, separately pinned copy on PATH could drift
# from it and make a local `make lint` disagree with CI.
deps:
go mod download
# Run tests with coverage. -count=1 for the same reason script/test
# uses it: without it an unchanged package is served from Go's test
# result cache, and a coverage profile assembled from cached results
# describes a run that did not happen.
test-coverage:
go test -v -count=1 -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
local:
VAULTIK_CONFIG=$(HOME)/etc/vaultik/config.yml ./vaultik snapshot --debug list 2>&1
VAULTIK_CONFIG=$(HOME)/etc/vaultik/config.yml ./vaultik snapshot --debug create 2>&1
install: vaultik
cp ./vaultik $(HOME)/bin/
# Build and publish release artifacts (linux/darwin × amd64/arm64) via goreleaser.
release:
@script/release
# Dry-run a release build without publishing or tagging.
release-snapshot:
@script/release-snapshot
# Build Docker image.
docker:
@script/docker
# Install pre-commit hook.
hooks:
@script/install-precommit