Repository navigation
docs: add contributor and agent guides - #29
Merged
Merged
Conversation
Ports all 31 rows of LINTER_FIXTURE_PARAMS from commitlint 2.0.0. Only the pass or fail column is asserted, because cocox has no per-field validator yet, and the error strings are recorded for when it does. Adds tests pinning that a CRLF commit message is rejected on every input path, and a ratchet that fails when a message gains no end-to-end test. Declares rust-version 1.85, which comes from edition 2024 rather than any language feature, and denies str::len and String::len, because Python len() counts characters while Rust len() counts UTF-8 bytes. Also ignores .claude/settings.local.json, which was covered only by a personal global git config.
CONTRIBUTING.md and the code of conduct follow the structure used by opensource-nepal/commitlint, so both projects in the organization read the same way, with the Rust toolchain in place of the Python one. AGENTS.md is the single source of truth for agent guidance. It records the parity contract, ten Python to Rust porting traps that have each produced a real defect, and the divergences from upstream measured so far. CLAUDE.md only points at it, because not every contributor uses Claude and the guidance should not fork.
aj3sh
approved these changes
Sep 11, 2026
JustBipin
added a commit
to JustBipin/cocox
that referenced
this pull request
Sep 13, 2026
- Add LintOptions struct (skip_detail, hide_input, strip_comments, max_header_length) - lint_commit_message and run_validators take &LintOptions instead of reading global config - Remove ConfigGuard, set_config, config(), update_config - command.rs builds LintOptions from Cli and passes it explicitly - OutputConfig remains global for console output only Additional review fixes: - Remove AGENTS.md from PR (arrives from main via opensource-nepal#29) - Fix CONTRIBUTING.md rust-version to 1.88 - Fix clippy.toml stale item reference - Remove COMMIT_HEADER_MAX_LENGTH assert from messages.rs - Add 14 CLI tests pinning exact error message text - Add ignored-message success line tests - Add -q guards tests for --file, --hash, --from-hash - Add CRLF/CR normalization tests - Add CRLF header-length test - Add ^ anchor regression test - Fix max_header_length_string_fails_clap to assert message text - Rewrite PR description with accurate test counts and behavior changes
sugat009
pushed a commit
that referenced
this pull request
Sep 18, 2026
…l test suite (#28) * feat: detailed error output, help strings, max-header-length, and full test suite Implements feature parity with Python commitlint for #27 and #25. - Display specific validation errors (type missing, scope empty, description issues, etc.) instead of just "Commit validation: failed!" (#27) - Add help = "..." strings to every clap argument (#25) - Add --max-header-length <N> CLI flag with positive integer validation - Add Config (global LazyLock<Mutex>), Console (colored output), and Validators (simple + detailed regex patterns) modules - Add AGENTS.md with architecture docs, parity checklist, and agent conventions - Add 75+ integration tests and 43 unit tests covering all CLI paths, output flags, hash ranges, and max-header-length behavior - Run cargo fmt on all files Refs: #27, #25 * fix: description missing bug and header length character counting - validate_description: use map_or instead of ? early return so missing description correctly returns DESCRIPTION_MISSING_ERROR - validate_header_length: use chars().count() instead of len() to match upstream Python code-point counting (not UTF-8 bytes) - Fix errors.is_empty() nitpick: always false after push, use return (false, errors) - Add comments explaining ? early returns match upstream 'if group and ...' logic Refs: review feedback on PR #28 * fix: type order, ignored messages output, quiet mode error suppression - COMMIT_TYPES: move 'bump' to last position to match upstream Python order - Ignored messages: print success line in single-message mode (parity with upstream which prints 'Commit validation: successful!' for ignored commits) - Quiet mode: suppress file and git errors when -q is set (exit silently instead of printing anyhow error chain) * fix: --max-header-length negative value handling - Add allow_negative_numbers = true so clap passes -5 to the value_parser instead of treating it as a flag - Rewrite positive_usize to parse as i64 first, then convert to usize, matching upstream error messages for both negative and zero values - Remove redundant clap attributes: long = 'from-hash'/'to-hash' (derived from field names), action = ArgAction::SetTrue (default for bools) - Drop unused ArgAction import * docs: update README, AGENTS.md, and Cargo.toml rust-version - README: update about text, help columns with all flags documented - AGENTS.md: fix test counts (81 CLI + 60 unit), remove is_orphan (Rust-only detail), soften parity claims, remove architecture freeze, remove fixed divergence #5 (type order) - Cargo.toml: bump rust-version to 1.88 (let chains require it) * test: add comprehensive unit and CLI tests for all error messages - Add rejects_missing_description to linter.rs (was deleted in original PR) - Add 16 unit tests covering all 13 error messages plus multi-error cases - Add 16 CLI end-to-end tests asserting per-field error output including 'Found N error(s).' for N > 1 - Add help_flag_shows_descriptions_for_all_flags verifying all help strings - Fix max_header_length_negative_fails_clap to assert error message text - Add header_length_counts_chars_not_bytes for non-ASCII parity * fix: normalize CRLF newlines in git and file readers Upstream reads git output with subprocess.check_output(text=True) and files with open(), both of which normalize \r\n and lone \r to \n. cocox read raw bytes, so CRLF messages passed validation unchanged. Add normalize_newlines() in utils.rs and call it from: - get_commit_message_from_hash (git show output) - get_commit_messages_from_hash_range (git log output) - read_file (--file input) CLI arguments are NOT normalized, matching upstream behavior. Fixes known divergence #2 from AGENTS.md. All 158 tests pass. * docs: remove fixed CRLF divergence from AGENTS.md * refactor: LintOptions struct replaces global Config - Add LintOptions struct (skip_detail, hide_input, strip_comments, max_header_length) - lint_commit_message and run_validators take &LintOptions instead of reading global config - Remove ConfigGuard, set_config, config(), update_config - command.rs builds LintOptions from Cli and passes it explicitly - OutputConfig remains global for console output only Additional review fixes: - Remove AGENTS.md from PR (arrives from main via #29) - Fix CONTRIBUTING.md rust-version to 1.88 - Fix clippy.toml stale item reference - Remove COMMIT_HEADER_MAX_LENGTH assert from messages.rs - Add 14 CLI tests pinning exact error message text - Add ignored-message success line tests - Add -q guards tests for --file, --hash, --from-hash - Add CRLF/CR normalization tests - Add CRLF header-length test - Add ^ anchor regression test - Fix max_header_length_string_fails_clap to assert message text - Rewrite PR description with accurate test counts and behavior changes * feat: add verbose output matching upstream and assert error strings in parity test - Add verbose lines to linter, validators, and git helpers matching upstream commitlint output (HeaderLengthValidator, PatternValidator, git commands) - Thread &OutputConfig through lint_commit_message_with_errors and run_validators so verbose lines can be emitted from the lint path - Fix failure text to match upstream format (': validation failed') - upstream_parity.rs now asserts error strings, not just pass/fail - Remove stale divergence #4 from AGENTS.md (bump already listed last) - Fix upstream_parity.rs stale doc comment - Update all unit and integration tests for new function signatures * fix: address round 3 review — lower rust-version, fix empty message output, correct stale docs - Restore AGENTS.md from main (remove from diff) - Lower rust-version from 1.88 to 1.85, remove stale let-chain comment - Update CONTRIBUTING.md minimum Rust version to 1.85 - Fix stale doc comment in upstream_parity.rs - Print VALIDATION_FAILED on empty/whitespace/comment-only commit messages - Add CLI test for comment-only file input
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two commits on one branch:
test: add upstream parity tests and lint guardrailsanddocs: add contributor and agent guides. They are separable, but the docs nameclippy.tomlandtests/upstream_parity.rsdirectly, so they only read correctly together.Merging with rebase rather than squash keeps both messages on
main, which is what release-please reads to build the changelog. A squash collapses them into one entry.Tests and guardrails (
c05ab0b)tests/upstream_parity.rs: ports all 31 rows ofLINTER_FIXTURE_PARAMSfrom commitlint 2.0.0, in upstream order, with the same three columns. Only the pass/fail column is asserted, because cocox has no per-field validator yet; the error strings are listed verbatim so the second assertion is a small diff once it lands.fixture_table_has_all_upstream_rowspins the count at 31, so a dropped row fails instead of quietly shrinking coverage.tests/crlf_parity.rs: pins today's CRLF behavior on all three input paths that read from git or disk (crlf_commit_is_rejected_via_hash,crlf_commit_is_rejected_via_from_hash,crlf_message_file_is_rejected). The module header records why this is a divergence and not a contract: Python text mode rewrites\r\nbefore linting, so upstream accepts these. Normalization belongs in the readers only, since upstream does not normalize a message passed as an argument.tests/message_coverage.rs: a ratchet, not a snapshot.src/messages.rsholds only the two verdict lines today and both are exempt, so the test passes with nothing to check. It fails, and names the message, the first time a per-field error is added without an assertion intests/cli.rs.clippy.toml: deniesstr::lenandString::lenviadisallowed_methods, because Pythonlen()counts code points and Rustlen()counts UTF-8 bytes.[lints.clippy] disallowed_methods = "deny"inCargo.tomlmakes a plaincargo clippyfail on its own, without-D warningson the command line.str::linesis listed as a commented-out entry with the reason, sincesrc/utils.rs:10still calls it and fixing that changes behavior.Cargo.toml: declaresrust-version = "1.85", with a comment recording that it comes from edition 2024 rather than any language feature..gitignore: ignores.claude/settings.local.json, which until now was only covered by a personal global git config.Guides (
f9ba909)CONTRIBUTING.mdand.github/CODE_OF_CONDUCT.mdfollow the structure of the commitlint guides, so both projects in the organization read the same way, with the Rust toolchain in place of the Python one.AGENTS.mdis the single source of truth for agent guidance: the parity contract, ten Python-to-Rust porting traps that have each produced a real defect here, the testing rules, and the divergences from upstream measured so far. The two upstream behaviors that are defects rather than contracts are called out so nobody ports them.CLAUDE.mdonly importsAGENTS.mdand holds the two facts specific to Claude Code, so the guidance does not fork per tool.The divergence list is what has been measured, not a complete audit. Each entry was reproduced against commitlint 2.0.0, and each is a separate follow-up pull request.
Verification
Run on
f9ba909:98 = 38 lib, 43
cli, 11git_helpers, 3crlf_parity, 1message_coverage, 2upstream_parity. The branch also passes its own linter:cocox --from-hash c05ab0b --to-hash f9ba909exits 0.No behavior change to the binary.
tests/cli.rsis touched only to reorder ause.🤖 Generated with Claude Code