feat: lint commit message from hash range#22
Conversation
667c89c to
2060aba
Compare
sugat009
left a comment
There was a problem hiding this comment.
Comprehensive review
Reviewed across code quality, architecture, performance, tests, docs, Rust idioms, and CI/CD. Findings below use Conventional Comments. Inline comments below cover the diff-anchored items; this top-level body covers findings that span multiple files or touch code outside the PR's diff.
General findings (not anchored to specific diff lines)
issue (blocking) — cargo fmt --check exits 1 with 22 unformatted hunks (mostly trailing whitespace in tests/cli.rs). cargo clippy --all-targets -- -D warnings exits 101 with 4 needless_return errors at src/linter.rs:13, src/utils.rs:14, src/utils.rs:18, src/main.rs:15. CI doesn't gate either tool today, so the regression slipped in unnoticed. One cleanup commit + adding both gates to .github/workflows/ci.yml closes both.
suggestion — src/linter.rs:12 and src/utils.rs:8 (not modified by this PR but exercised heavily by it): Regex::new(&pattern).unwrap() runs per call. Measured locally: ~80 µs/call for the linter regex, ~280 µs/call for the 9 ignore patterns — combined ~360 µs/commit. For a range of 10k commits that's ~3.6 s of pure regex compilation. Cache via std::sync::LazyLock<Regex> (stable since 1.80) — ~3000× speedup for ~10 lines. Highest-ROI fix on the perf axis.
suggestion — README.md has no mention of --hash, --from-hash, or --to-hash. The only documentation for the new feature is this PR body, which becomes invisible after merge. Three lines under a "Usage" section would meaningfully improve discoverability.
suggestion — many test assertions in tests/cli.rs use predicate::str::contains("Commit validation: successful!") where exact match would be more protective. The success message is a static constant; substring match weakens regression coverage. Future per-commit logging (per the TODO inline below) could silently start passing through these.
question — is the --no-merges filter intentional and meant to deviate from Python upstream? (See inline issue at src/git_helpers.rs:28.)
nitpick — PR body uses closes: #10, #12. The colon may not be recognized by GitHub's auto-close keyword parser. Standard form: Closes #10 on its own line (or paragraph), one per line. Worth checking the auto-link rendering before relying on it.
nitpick — uninlined_format_args clippy lint applies throughout src/command.rs and src/git_helpers.rs. Rust 2021+ supports format!("hash {commit_hash}") instead of format!("hash {}", commit_hash).
nitpick — commit subject typos that will land in CHANGELOG.md if not squash-merged with the (clean) PR title:
addd(commit2060aba) →addconstrain(same commit) →constraintprojecet(commit0f980d7body) →project
👏 Praise
praise — TestRepo is a real contribution. It correctly identifies the cwd-mutation problem and applies a working serialization solution; using it as a fixture-commit factory is exactly what was needed to close #10. Once the run_git exit-code check and the mutex-poison handling are in, it'll be genuinely strong test infrastructure.
praise — the mutual-exclusion test matrix is thorough: 7 new pairs in tests/cli.rs plus the --to-hash-without---from-hash case. Closes #12 cleanly and goes beyond what the issue asked for.
Inline comments follow on specific lines. Happy to file any of the blocking items as standalone tickets if helpful.
sugat009
left a comment
There was a problem hiding this comment.
Escalating my prior comment-level review to formally request changes. The blocking items from that review still stand:
tests/common/git_repo.rs:57-63—run_gitswallows non-zero git exits, which silently breaks therange_errors_on_unknown_to_hashtestsrc/command.rs:51— range mode prints no per-commit failure attribution (the// TODO)cargo fmt --checkandcargo clippy -- -D warningsboth fail today
The non-blocking issues, suggestions, questions, and nitpicks from the prior review are all in scope but won't gate merge. Inline comments from the prior review remain attached.
c7b4e5f to
c72f1ce
Compare
b40ea8e to
63ceeb7
Compare
All blockingissues and most of the suggestions have been implemented. The ones which are't implemented are either reserved for future Pr, or for further discussions.We will have configurations for detailed logs for cocox, for the time being , i have placed home println!() and eprintln!(). Output ExamplesSingle Valid Commit: Ignored Commit: Hash Range (Batch): |
06f23e4 to
45fbd70
Compare
|
The changes in this PR have definitely grown way beyond what's described in the PR description. All the changes are properly committed, following the convention. Please use those for the description when squashing them. |
799ec15 to
1a59c66
Compare
| /// and returns its linting outcome. | ||
| pub fn lint_commit_message(message: &str) -> LintOutcome { | ||
| println!( | ||
| "========= Linting Message:: {} ===========", |
There was a problem hiding this comment.
it's a place holder for detialed logs. Is it ok to just a println!() for this pr? future PR with configuration for detialed logs will be made.
There was a problem hiding this comment.
Why are we going to show the funny logs to the user? Please refer to commitlint for the output format.
There was a problem hiding this comment.
I'll just remove all the logs for now.
| ); | ||
| std::process::exit(1); | ||
| } | ||
| LintOutcome::Ignored => println!("commit message ignored, skipping lint\n"), |
There was a problem hiding this comment.
These are the debug logs, do not redirect them to stdout directly. Lets remove them for now, and plan the debug logging for the future.
There was a problem hiding this comment.
Great, I'll remove them.
- remove projecet's git dependent tests from src/git_helpers.rs
* dev-dependency added: `serial_test = "3"` for blocking threads
- `tests/common/git_repo.rs` to create temporary git repo
- `src/git_helpers.rs`: replaced project's git dependent unittests
with integrationtests in tests/git_helpers.rs
- improved integration tests for --hash flag
- added integration tests for hash-range feature
- extend Cli argument constrains test
- mutual exclusion of message + --hash (opensource-nepal#12)
- from-hash and to-hash are exclusive to : message, hash, file - to-hash requires from-hash and from-hash only
Replace the hardcoded string delimiter with a null byte (%x00) when fetching commit ranges. This prevents potential parsing collisions if a commit body contains the delimiter string and ensures more reliable splitting of git log output.
- enforced rust formatting style - passes cargo clippy -D warning
removed manual mutex, use #[serial] attribute to avoid race condition check the return status for the success of respective git command refactored: use std::process::Command for instatiation. most importantly, fixed typos
to-hash doesn't need to be wrapped around Option, since it'll always have a value
- Update `lint_commit_message` to return a structured `LintOutcome` enum. - Add descriptive console output and banners in `command.rs` for valid, invalid, and ignored messages. - Refactor unit tests in `linter.rs` to test the internal validator directly while adding coverage for the public API. - Update CLI integration tests to assert against the new stdout/stderr output strings. - Ensure consistent exit codes and error messaging across all input types (file, hash, message).
Moves core logic from `src/main.rs` into a new `src/lib.rs` and updates the binary to act as a thin wrapper.
- check if <from> has parent, if yes run git log <from>^..<to> - if not, run git log <to>.
|
I really appreciate the effort here. The code looks awesome. I have added few suggestions for the debug logs and the tests. The PR contains the big feature, so the delay in the review is expected 😀. |
30eff61 to
bb1a5c2
Compare
…ial commit' message
though standard merge commits are to be ignored for linting, they must be extracted when using hash in order to validate custom commit message as invalid.
Adds
--from-hashand--to-hashflags to lint all commit messages between two commits, inclusive.Usage
Feature
--from-hashand--to-hashflags added to the CLI--to-hashdefaults toHEADwhen not provided--to-hashrequires--from-hashand is mutually exclusive withmessage,--file, and--hashsrc/git_helpers.rs: addedget_commit_messages_from_hash_range()which fetches all commit messages in the range and prepends thefromcommit separately, sinceA..Bin git excludesATest infrastructure
tests/common/git_repo.rs: introducesTestRepo, a temporary git repo with minimal config for use in integration testsTestRepo::new()switches the process working directory into the temp repoDroprestores the original working directory whenTestRepogoes out of scopestatic Mutexis acquired on construction and released on drop, serializing all tests that useTestRepoto prevent race conditions on the process-global cwdserial_test = "3"added as a dev-dependencysrc/git_helpers.rsthat depended on the project repo's own git history replaced with integration tests intests/git_helpers.rsusingTestRepo, so tests are self-contained and repo-state independentIntegration tests added
tests/git_helpers.rs: full coverage ofget_commit_message_from_hashandget_commit_messages_from_hash_rangewith known commit messagestests/cli.rs: success and failure cases for--hash(exact hash, invalid message, ignored message) and--from-hash/--to-hash(invalid commit at from, middle, and to positions; ignored commits in range; single-commit range)tests/cli.rs: extended mutual exclusion tests covering all missing argument combinations (message + --hash,message + --from-hash,--hash + --from-hash,--to-hashwith non---from-hashinputs)TestCoverage: 97%
closes #10
closes #12
closes #16