Skip to content

feat(cli): add hook status command - #162

Merged
errfld merged 3 commits into
mainfrom
gh-144/status-hook-drift
Jun 20, 2026
Merged

feat(cli): add hook status command#162
errfld merged 3 commits into
mainfrom
gh-144/status-hook-drift

Conversation

@errfld

@errfld errfld commented Jun 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • add read-only git smee status [--json] hook coverage and drift reporting
  • report configured command counts, missing/unmanaged/stale wrappers, obsolete managed wrappers, and next actions
  • document status output and add behavior coverage for text, JSON, and read-only obsolete-hook handling

Fixes #144

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo test --workspace --all-targets --all-features

Summary by CodeRabbit

  • New Features

    • Added git smee status subcommand to report hook coverage, detect drift, and identify obsolete hooks
    • Includes --json flag for stable JSON output compatible with tooling and automation
  • Documentation

    • Updated CLI documentation with usage guidance for status and doctor subcommands, including example output

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@errfld, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 51 minutes. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8f1362fd-dc95-4b15-bc35-8063d813f247

📥 Commits

Reviewing files that changed from the base of the PR and between 1d7e6d0 and cce5c53.

📒 Files selected for processing (3)
  • crates/git-smee-cli/src/main.rs
  • crates/git-smee-cli/tests/cli_integration.rs
  • crates/git-smee-core/src/installer.rs
📝 Walkthrough

Walkthrough

Adds a new read-only git smee status [--json] subcommand to the git-smee CLI. The implementation classifies each configured hook phase as installed, missing, unmanaged, stale, or obsolete by inspecting the effective hooks directory against the TOML config. Output is human-readable by default and stable JSON with --json. Four integration tests and README documentation are included.

Changes

git smee status subcommand

Layer / File(s) Summary
CLI wiring and status data model
crates/git-smee-cli/src/main.rs
Adds Command::Status { json: bool } to the Command enum, routes it in run(), and defines StatusReport, StatusState, HookState, HookStatus, and ObsoleteManagedHook structs/enums used throughout the feature.
build_status_report: hook classification and drift detection
crates/git-smee-cli/src/main.rs
Implements build_status_report: resolves repo root and hooks directory, reads the TOML config, classifies each configured phase hook by inspecting file existence and managed wrapper marker content, detects obsolete managed wrappers for unconfigured phases, and derives StatusState from generated next actions.
Human-readable output rendering and path helpers
crates/git-smee-cli/src/main.rs
Adds print_status_report for formatted per-hook state and stale-reason output, HookState::as_text() for state-to-string mapping, and display_repo_path for repo-relative path display.
Integration tests and README documentation
crates/git-smee-cli/tests/cli_integration.rs, README.md
Adds four integration tests covering installed/ok, unmanaged drift, stale/obsolete managed drift (non-destructive assertion), and --json output. Documents git smee status [--json] in the README CLI Commands section with example output and stable JSON fields.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • errfld/git-smee#25: Modifies main.rs around config-path resolution and the installed hook wrapper/template content (embedded executable + config path), which the new status command inspects to determine managed/stale/obsolete hook classification.
  • errfld/git-smee#158: Changes Unix/Windows wrapper templates and marker content, directly affecting the wrapper inspection logic in build_status_report that reads marker strings to classify drift.

Poem

🐇 Hopping through the hooks with care,
git smee status—drift laid bare!
Stale wrappers spotted, obsolete found,
No files removed, just safe and sound.
--json for CI, plain text for me,
A read-only check for all to see! 🪄

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(cli): add hook status command' clearly summarizes the main change: adding a new status subcommand to the CLI. It is concise, specific, and directly reflects the primary modification across all changed files.
Linked Issues check ✅ Passed The implementation fully addresses issue #144 requirements: read-only status command comparing config with effective hooks directory, reporting phases/counts/wrappers/drift, supporting both text and JSON output, comprehensive test coverage for various hook states, and README documentation with sample output.
Out of Scope Changes check ✅ Passed All changes are tightly scoped to implementing the git smee status command as specified in issue #144. Changes include command implementation, integration tests, and documentation with no unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gh-144/status-hook-drift

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1d7e6d0fb9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/git-smee-cli/src/main.rs Outdated
let Ok(content) = fs::read_to_string(&hook_path) else {
continue;
};
if content.contains(MANAGED_FILE_MARKER) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use header-aware managed detection for obsolete hooks

When an unconfigured hook merely mentions THIS FILE IS MANAGED BY git-smee in its body, this substring check reports it as an obsolete managed wrapper and adds a remove obsolete managed hook ... action, even though the installer’s managed-file logic treats marker-in-body files as unmanaged and would not prune them. This can make git smee status recommend deleting a user-owned hook; use the same header-scoped managed detection semantics here (and for configured hook classification) instead of raw contains.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Addressed in cce5c53 by exposing/reusing installer header-scoped managed detection (has_managed_header) for status classification and obsolete-hook detection. Added integration tests for marker text that appears only in hook bodies.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/git-smee-cli/src/main.rs`:
- Around line 325-326: The print_status_report function uses the Debug format
specifier {:?} to display report.status, which relies on the Debug trait
implementation and is fragile for user-facing output. Instead, add an explicit
as_text() method to the StatusState type for consistency with how HookState is
handled (which already uses as_text() for output), then replace the {:?} debug
format call in the println! statement with a call to report.status.as_text() to
provide stable, intentional formatting for user output.

In `@crates/git-smee-cli/tests/cli_integration.rs`:
- Around line 187-215: The test
`given_stale_and_obsolete_managed_hooks_when_status_then_reports_drift_without_modifying`
contains a hardcoded path assertion with forward slashes `.git/hooks/commit-msg`
on line 214. Since `display_repo_path()` uses `Path::display()` which renders
platform-native separators (backslashes on Windows), this assertion will fail on
Windows. Replace the assertion that checks for the exact path "remove obsolete
managed hook .git/hooks/commit-msg" with a more platform-agnostic matcher by
using `predicate::str::contains("commit-msg")` instead, or normalize the path to
use only forward slashes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0492fb13-9792-4606-9d51-46c65ee404d0

📥 Commits

Reviewing files that changed from the base of the PR and between 3833e48 and 1d7e6d0.

📒 Files selected for processing (3)
  • README.md
  • crates/git-smee-cli/src/main.rs
  • crates/git-smee-cli/tests/cli_integration.rs

Comment thread crates/git-smee-cli/src/main.rs Outdated
Comment thread crates/git-smee-cli/tests/cli_integration.rs
@errfld
errfld merged commit 56fd7b3 into main Jun 20, 2026
28 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cce5c53421

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +240 to +241
if !content.contains(&expected_config) {
stale_reasons.push(format!("expected config path {expected_config}"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Match the wrapper config argument exactly

When the configured path is a prefix of the stale path, such as reinstalling with .git-smee.toml after a wrapper was generated for .git-smee.toml.bak, this substring check passes and status reports the hook as installed/Ok even though Git will still run with the old config. Match the actual escaped --config argument, or parse the wrapper invocation, instead of accepting any occurrence of the expected path.

Useful? React with 👍 / 👎.

Comment on lines +249 to +250
if stale_reasons.is_empty() {
(HookState::Installed, None)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Verify the wrapper invokes this phase

When a managed wrapper for one phase is left at another hook path, for example copying the generated pre-push wrapper to .git/hooks/pre-commit, the marker/config/executable checks leave stale_reasons empty and this branch reports Installed. Git would then run the pre-push commands during pre-commit, so status should also validate the expected run {phase} invocation before declaring the hook current.

Useful? React with 👍 / 👎.

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.

Add git smee status to show installed hook coverage and drift

2 participants