Skip to content

feat: lint commit message from hash range#22

Open
JustBipin wants to merge 21 commits into
opensource-nepal:mainfrom
JustBipin:feat/hash-range
Open

feat: lint commit message from hash range#22
JustBipin wants to merge 21 commits into
opensource-nepal:mainfrom
JustBipin:feat/hash-range

Conversation

@JustBipin

@JustBipin JustBipin commented May 19, 2026

Copy link
Copy Markdown
Member

Adds --from-hash and --to-hash flags to lint all commit messages between two commits, inclusive.

Usage

cocox --from-hash <hash>              # from <hash> to HEAD
cocox --from-hash <hash> --to-hash <hash>   # explicit range

Feature

  • --from-hash and --to-hash flags added to the CLI
  • --to-hash defaults to HEAD when not provided
  • --to-hash requires --from-hash and is mutually exclusive with message, --file, and --hash
  • src/git_helpers.rs: added get_commit_messages_from_hash_range() which fetches all commit messages in the range and prepends the from commit separately, since A..B in git excludes A

Test infrastructure

  • tests/common/git_repo.rs: introduces TestRepo, a temporary git repo with minimal config for use in integration tests
    • TestRepo::new() switches the process working directory into the temp repo
    • Drop restores the original working directory when TestRepo goes out of scope
    • A static Mutex is acquired on construction and released on drop, serializing all tests that use TestRepo to prevent race conditions on the process-global cwd
  • serial_test = "3" added as a dev-dependency
  • Unit tests in src/git_helpers.rs that depended on the project repo's own git history replaced with integration tests in tests/git_helpers.rs using TestRepo, so tests are self-contained and repo-state independent

Integration tests added

  • tests/git_helpers.rs: full coverage of get_commit_message_from_hash and get_commit_messages_from_hash_range with known commit messages
  • tests/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-hash with non---from-hash inputs)

TestCoverage: 97%

closes #10
closes #12
closes #16

@aj3sh aj3sh requested a review from sugat009 May 19, 2026 13:35

@sugat009 sugat009 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

suggestionsrc/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.

suggestionREADME.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.

nitpickuninlined_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 (commit 2060aba) → add
  • constrain (same commit) → constraint
  • projecet (commit 0f980d7 body) → project

👏 Praise

praiseTestRepo 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.

Comment thread tests/common/git_repo.rs
Comment thread src/command.rs Outdated
Comment thread tests/common/git_repo.rs Outdated
Comment thread src/git_helpers.rs Outdated
Comment thread src/git_helpers.rs
Comment thread Cargo.toml
Comment thread src/git_helpers.rs Outdated
Comment thread tests/common/git_repo.rs Outdated
Comment thread tests/cli.rs Outdated
Comment thread src/command.rs Outdated

@sugat009 sugat009 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Escalating my prior comment-level review to formally request changes. The blocking items from that review still stand:

  1. tests/common/git_repo.rs:57-63run_git swallows non-zero git exits, which silently breaks the range_errors_on_unknown_to_hash test
  2. src/command.rs:51 — range mode prints no per-commit failure attribution (the // TODO)
  3. cargo fmt --check and cargo clippy -- -D warnings both 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.

@JustBipin JustBipin force-pushed the feat/hash-range branch 2 times, most recently from c7b4e5f to c72f1ce Compare June 1, 2026 06:06
@JustBipin

JustBipin commented Jun 1, 2026

Copy link
Copy Markdown
Member Author

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 Examples

Single Valid Commit:

========= Linting Message:: feat: add new feature ===========
Commit validation: successful!

Ignored Commit:

========= Linting Message:: Initial commit ===========
commit message ignored, skipping lint

Hash Range (Batch):

========= Linting Message:: feat: feature A ===========
lint success

========= Linting Message:: Merge pull request #1 ===========
commit message ignored, skipping lint

Commit validation: successful!

@JustBipin JustBipin requested a review from sugat009 June 1, 2026 08:42
@JustBipin JustBipin marked this pull request as draft June 1, 2026 20:38
@JustBipin JustBipin marked this pull request as ready for review June 2, 2026 00:00
@JustBipin

Copy link
Copy Markdown
Member Author

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.

Comment thread src/linter.rs Outdated
/// and returns its linting outcome.
pub fn lint_commit_message(message: &str) -> LintOutcome {
println!(
"========= Linting Message:: {} ===========",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is this for?

@JustBipin JustBipin Jun 6, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why are we going to show the funny logs to the user? Please refer to commitlint for the output format.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'll just remove all the logs for now.

Comment thread README.md Outdated
Comment thread src/command.rs Outdated
);
std::process::exit(1);
}
LintOutcome::Ignored => println!("commit message ignored, skipping lint\n"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Great, I'll remove them.

JustBipin added 13 commits June 7, 2026 14:28
- 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.
Comment thread tests/cli.rs Outdated
Comment thread tests/cli.rs Outdated
@aj3sh

aj3sh commented Jun 7, 2026

Copy link
Copy Markdown
Member

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 😀.

@JustBipin JustBipin marked this pull request as draft June 7, 2026 15:40
JustBipin added 4 commits June 9, 2026 16:48
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.
@JustBipin JustBipin marked this pull request as ready for review June 9, 2026 11:37
@JustBipin JustBipin requested a review from aj3sh June 9, 2026 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants