Gate prune's local-cleanup prose on --json and give make build a rule (closes #108)
All checks were successful
check / check (pull_request) Successful in 2m29s
All checks were successful
check / check (pull_request) Successful in 2m29s
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.
This commit is contained in:
@@ -28,8 +28,13 @@ const (
|
||||
cmdRemote = "remote"
|
||||
cmdInfo = "info"
|
||||
|
||||
flagJSON = "--json"
|
||||
flagQuiet = "--quiet"
|
||||
flagJSON = "--json"
|
||||
flagQuiet = "--quiet"
|
||||
flagConfig = "--config"
|
||||
|
||||
// programName is argv[0] as the real process receives it. Entry
|
||||
// strips it before scanning, so it has to be present.
|
||||
programName = "vaultik"
|
||||
|
||||
// someSnapshotID is any snapshot identifier: these tests never run
|
||||
// the command, so it only has to occupy the positional argument.
|
||||
@@ -65,7 +70,7 @@ var jsonArgumentVectors = map[string][]string{
|
||||
// A --json invocation that also carries a flag with a value, so the
|
||||
// scan cannot be fooled by an argument that consumes the next one.
|
||||
"json with config": {
|
||||
"--config", "/nonexistent/vaultik.yml", cmdSnapshot, cmdList, flagJSON,
|
||||
flagConfig, "/nonexistent/vaultik.yml", cmdSnapshot, cmdList, flagJSON,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -222,7 +227,7 @@ func TestEntryJSONStdoutIsExactlyOneDocument(t *testing.T) {
|
||||
})
|
||||
|
||||
os.Args = []string{
|
||||
"vaultik", "--config", configPath, cmdSnapshot, cmdList, flagJSON,
|
||||
programName, flagConfig, configPath, cmdSnapshot, cmdList, flagJSON,
|
||||
}
|
||||
|
||||
stdout := captureProcessStdout(t, Entry)
|
||||
|
||||
Reference in New Issue
Block a user