Skip to content

git-cleaner parity: add config/init, JSON output, and cleanup UX improvements#72

Open
markcallen wants to merge 1 commit intomainfrom
feat/3-git-cleaner-parity
Open

git-cleaner parity: add config/init, JSON output, and cleanup UX improvements#72
markcallen wants to merge 1 commit intomainfrom
feat/3-git-cleaner-parity

Conversation

@markcallen
Copy link
Owner

Summary

  • Add optional config support to git-cleaner:
    • --config path
    • --init starter config generation
    • --force overwrite with backup
    • options.defaultScanPath fallback when --scan is omitted
  • Add --json mode with structured report output for scans and cleanup runs
  • Add --yes cleanup confirmation bypass and interactive confirmation prompt when --clean is used without --yes
  • Add --show-pct to include .git size percentage of full repository size
  • Update git-cleaner README and tests

Issues

Validation

  • go test ./... in git-cleaner
  • go test ./... in dev-cache
  • go test ./... in mac-cache-cleaner

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR brings git-cleaner closer to feature parity with the other repo CLIs by adding optional YAML config support, a machine-readable JSON reporting mode, and cleanup UX improvements to better support automation and interactive use.

Changes:

  • Add YAML config support (--config, --init, --force) and defaultScanPath fallback when --scan is omitted.
  • Add --json report output (including post-clean disk savings) and redirect cleanup subprocess output to stderr in JSON mode.
  • Add cleanup confirmation UX (--yes + interactive prompt) and optional .git-size percentage reporting (--show-pct).

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
git-cleaner/main.go Implements config IO, JSON reporting, confirmation prompt, and .git percent enrichment.
git-cleaner/main_test.go Updates tests for signature changes and adds config/scan-path resolution tests.
git-cleaner/README.md Documents new flags and adds examples for config init and JSON usage.
git-cleaner/go.mod Adds YAML dependency.
git-cleaner/go.sum Updates sums for added dependencies.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if *flagJSON {
if *flagClean {
if !*flagYes {
report.Warnings = append(report.Warnings, "cleanup skipped: confirmation required (use --yes with --clean in non-interactive mode)")
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

In --json + --clean mode when --yes is not provided, cleanup is skipped but the report still has DryRun: false (since --clean was set) and the program exits successfully. This makes the JSON output ambiguous/misleading for CI and automation. Consider either (a) treating --json --clean without --yes as an error (non-zero exit) or (b) reflecting the skip in the report (e.g., set DryRun back to true or add an explicit cleanup_performed field).

Suggested change
report.Warnings = append(report.Warnings, "cleanup skipped: confirmation required (use --yes with --clean in non-interactive mode)")
report.Warnings = append(report.Warnings, "cleanup skipped: confirmation required (use --yes with --clean in non-interactive mode)")
// Reflect that no cleanup was actually performed, even though --clean was requested.
report.DryRun = true

Copilot uses AI. Check for mistakes.
// Initial scan
findings := scanDirectory(scanPath)
if *flagShowPct {
_ = enrichWithRepoPercent(findings)
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

enrichWithRepoPercent returns warnings, but they’re currently discarded. This can silently produce missing/zero git_percent values without surfacing why. Consider appending these warnings to the JSON report (and/or printing them to stderr in table mode).

Suggested change
_ = enrichWithRepoPercent(findings)
if warnings := enrichWithRepoPercent(findings); len(warnings) > 0 {
for _, w := range warnings {
fmt.Fprintln(os.Stderr, "Warning:", w)
}
}

Copilot uses AI. Check for mistakes.
time.Sleep(100 * time.Millisecond)
afterFindings := scanDirectory(scanPath)
if *flagShowPct {
_ = enrichWithRepoPercent(afterFindings)
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

enrichWithRepoPercent warnings are also discarded in the non-JSON post-clean rescan. Even in table mode, users may want to know why the Git % column is missing/0 for some repos; consider printing these warnings to stderr.

Suggested change
_ = enrichWithRepoPercent(afterFindings)
warnings := enrichWithRepoPercent(afterFindings)
for _, w := range warnings {
fmt.Fprintln(os.Stderr, "Warning:", w)
}

Copilot uses AI. Check for mistakes.
Comment on lines +404 to +406
if *flagJSON {
if *flagClean {
if !*flagYes {
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

New --json behavior (including --json --clean disk savings reporting and the --yes gating) doesn’t appear to have automated tests. Adding a test that validates stdout is parseable JSON (and includes expected fields for both scan-only and clean runs) would help prevent regressions.

Copilot uses AI. Check for mistakes.
}
os.Exit(1)
}

Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

In non-JSON mode, the "Scanning ..." message is printed after scanDirectory(scanPath) has already completed, which makes the output misleading (and delays feedback for large scans). Consider printing the scanning header before starting the walk (and before any optional --show-pct enrichment).

Suggested change
if !*flagJSON {
fmt.Printf("Scanning %s ...\n", scanPath)
}

Copilot uses AI. Check for mistakes.
Comment on lines +423 to +425
if *flagShowPct {
_ = enrichWithRepoPercent(afterFindings)
}
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

enrichWithRepoPercent warnings are ignored again for the post-clean rescan. If repo size inspection fails for any repo, it would be helpful to carry those warnings into the JSON report / stderr so users understand missing git_percent values.

Copilot uses AI. Check for mistakes.
Comment on lines +408 to +410
b, _ := json.MarshalIndent(report, "", " ")
fmt.Println(string(b))
return
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

Errors from json.MarshalIndent are ignored here as well. Please check the error and fail fast (non-zero exit) if JSON encoding fails, rather than printing an empty/invalid payload.

Copilot uses AI. Check for mistakes.
Comment on lines +439 to +440
b, _ := json.MarshalIndent(report, "", " ")
fmt.Println(string(b))
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

Errors from json.MarshalIndent are ignored here too. This is the last output path in --json mode, so it’s especially important to handle the error and set a failing exit code if marshalling fails.

Copilot uses AI. Check for mistakes.
Comment on lines +89 to +92
```bash
./build/git-cleaner --init
./build/git-cleaner
```
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

This example implies ./build/git-cleaner will work immediately after --init, but the starter config defaults to ~/src and the tool errors if the path doesn’t exist. Consider adjusting the docs to mention editing defaultScanPath (or choosing a more universally-existing default) so users don’t hit a confusing failure after init.

Copilot uses AI. Check for mistakes.
Comment on lines +325 to +332
fmt.Print("Proceed with git gc for all discovered repositories? [y/N]: ")
reader := bufio.NewReader(os.Stdin)
line, err := reader.ReadString('\n')
if err != nil {
return false
}
line = strings.TrimSpace(strings.ToLower(line))
return line == "y" || line == "yes"
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

confirmCleanup returns false on any read error. With piped/non-interactive input that ends without a trailing newline, ReadString('\n') can return the user’s response plus io.EOF; in that case this would incorrectly cancel even if the input was "y"/"yes". Consider treating io.EOF as non-fatal and still evaluating the collected bytes.

Copilot uses AI. Check for mistakes.
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.

[git-cleaner] Config file support for default scan path [git-cleaner] JSON output for scriptable/CI usage

2 participants