From 219509e3ce119741574a266971dc751b89d1ff41 Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Tue, 13 Oct 2026 13:18:02 +0000 Subject: [PATCH] Log failed files at error level so check -q shows them (closes #195) check logged each failed file at info level, and -q shows errors only, so `check -q` reported a failure through its exit status alone. Each failed file, and each file the manifest does not list under --no-extra-files, is now logged at error level. A file the manifest does not list stays a warning without --no-extra-files, and the closing summary stays at info level. Model: opus-5-5 --- internal/cli/check.go | 12 ++++++------ internal/cli/entry_test.go | 30 +++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/internal/cli/check.go b/internal/cli/check.go index 9b63b36..8e6b34c 100644 --- a/internal/cli/check.go +++ b/internal/cli/check.go @@ -189,8 +189,8 @@ func reportCheckProgress(progress <-chan mfer.CheckStatus, wg *sync.WaitGroup) { log.ProgressDone() } -// countCheckFailures consumes check results, counting and logging -// failures, then closes done. +// countCheckFailures consumes check results, counting failures and logging +// each at error level so that --quiet still shows them, then closes done. func countCheckFailures( results <-chan mfer.Result, failures *int64, done chan<- struct{}, ) { @@ -198,7 +198,7 @@ func countCheckFailures( if result.Status != mfer.StatusOK { *failures++ - log.Infof("%s: %s (%s)", result.Status, result.Path, result.Message) + log.Errorf("%s: %s (%s)", result.Status, result.Path, result.Message) } else { log.Verbosef("%s: %s", result.Status, result.Path) } @@ -208,8 +208,8 @@ func countCheckFailures( } // findExtraFiles reports files present on disk but absent from the -// manifest, and anything the search cannot read: each is a failure under -// --no-extra-files, otherwise a warning. +// manifest, and anything the search cannot read: each is a failure, logged +// at error level, under --no-extra-files, otherwise a warning. func findExtraFiles( ctx context.Context, cmd *cli.Command, chk *mfer.Checker, failures *int64, ) error { @@ -221,7 +221,7 @@ func findExtraFiles( if cmd.Bool("no-extra-files") { *failures++ - log.Infof("%s: %s (%s)", result.Status, result.Path, result.Message) + log.Errorf("%s: %s (%s)", result.Status, result.Path, result.Message) } else { log.Warnf("%s: %s (%s)", result.Status, result.Path, result.Message) } diff --git a/internal/cli/entry_test.go b/internal/cli/entry_test.go index 692c9f5..600e571 100644 --- a/internal/cli/entry_test.go +++ b/internal/cli/entry_test.go @@ -694,6 +694,33 @@ func TestCheckCommandWithSizeMismatch(t *testing.T) { "check should have failed for size mismatch") } +// TestCheckQuietShowsFailedFiles asserts that check -q prints nothing for a +// tree that passes and still names each file that fails: --quiet hides +// everything except errors, and a failed file is an error. +func TestCheckQuietShowsFailedFiles(t *testing.T) { + t.Parallel() + + fs := afero.NewMemMapFs() + require.NoError(t, fs.MkdirAll(testDir, 0o755)) + writeTestFile(t, fs, testFile1, "hello world") + + opts := testOpts([]string{testApp, cmdGenerate, "-q", "-o", testManifest, testDir}, fs) + require.Equal(t, 0, runCLI(opts), "generate failed: %s", testStderr(t, opts)) + + args := []string{testApp, cmdCheck, "-q", testFlagBase, testDir, testManifest} + + opts = testOpts(args, fs) + require.Equal(t, 0, runCLI(opts), "stderr: %s", testStderr(t, opts)) + assert.Empty(t, testStdout(t, opts)) + assert.Empty(t, testStderr(t, opts)) + + writeTestFile(t, fs, testFile1, "HELLO WORLD") + + opts = testOpts(args, fs) + assert.Equal(t, 1, runCLI(opts)) + assert.Contains(t, testStderr(t, opts), "HASH_MISMATCH: file1.txt") +} + func TestBannerOutput(t *testing.T) { t.Parallel() @@ -926,8 +953,9 @@ func TestCheckWarnsAboutUnlistedFiles(t *testing.T) { assert.Equal(t, 1, exitCode, "stderr: %s", stderr) assert.Contains(t, stderr, unlisted) - exitCode, _ = check("-q", testFlagNoExtra) + exitCode, stderr = check("-q", testFlagNoExtra) assert.Equal(t, 1, exitCode) + assert.Contains(t, stderr, unlisted) }) } } -- 2.54.0