Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: commit-check/commit-check
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 98fb97c
Choose a base ref
...
head repository: commit-check/commit-check
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 90c5abe
Choose a head ref
  • 2 commits
  • 3 files changed
  • 2 contributors

Commits on Aug 7, 2026

  1. fix: distinguish an absent commit message from an empty one (#534)

    * fix: treat an empty commit message as supplied, not absent
    
    main went red on the push run right after #532 merged, on a test that
    had been green on the pull request. Nothing regressed -- the merge was
    the first time the test met a real commit.
    
    _get_commit_body tested stdin_text for truth, so an empty string read
    as "not provided" and the check fell through to get_commit_info("b"),
    the repository's HEAD commit. test_empty_message_passes therefore never
    measured an empty message: on a pull_request run HEAD is GitHub's
    synthetic merge commit, whose body is empty, so it passed for the wrong
    reason; on main HEAD became the squashed commit carrying a
    Co-authored-by trailer, CC013 detected it, and the test failed. Measured
    on this checkout, the "empty" message resolved to 6694 characters.
    
    The same looseness reaches the public API: validate_message("") answers
    about the last commit rather than the empty message it was given.
    
    The skip logic in this file already draws the line at None
    (_should_skip_validation, _resolve_current_author); _get_commit_body now
    follows it. The CLI is unaffected -- _resolve_commit_message_source
    already normalises empty stdin to None.
    
    Adds a hermetic regression test: the existing one only holds while the
    checkout's own HEAD carries no AI trailers, which is what made it fragile
    in the first place. The new one patches get_commit_info and asserts it is
    never consulted.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01U9zFxq8V4qxG4aMzJhGBFn
    
    * fix: distinguish an absent commit message from an empty one
    
    Follows the one-line fix on _get_commit_body by applying the same rule
    to the readers that were still testing stdin_text for truth, so an
    empty string is no longer read as "the caller said nothing".
    
    _get_commit_message, _get_subject, _get_author_value and BranchValidator
    now split on None, matching _should_skip_validation and
    _resolve_current_author, which already did. api.validate_author draws
    the same line with `name is not None`, so the intent was there; only
    these readers had not followed it. ForcePushValidator deliberately keeps
    a truth test: its stdin_text carries a *list* of refs, where empty
    genuinely means nothing to check rather than a value to judge.
    
    That surfaced a rule that could never fire. _is_empty_commit_allowed
    exists to reject an empty message under allow_empty_commits = false, but
    CommitTypeValidator returned PASS on a falsy message before ever
    reaching it, so the rejecting branch was dead code. A supplied message
    now reaches the rule even when empty; one git never gave us still
    returns early. Measured after the change:
    
        validate_message("")                          -> pass  (default)
        validate_message("", allow_empty_commits=off) -> fail  CC008
    
    The other validators keep their early return: BodyValidator documents
    whitespace-only input as "no commit message at all", and
    allow_empty_commits is the rule that owns that judgement.
    
    Adds two tests pinning both directions, each patching get_commit_info to
    prove the verdict comes from the supplied message rather than the
    repository's HEAD. Restoring the early return fails them.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01U9zFxq8V4qxG4aMzJhGBFn
    
    * docs: record why an unreadable commit file still counts as named
    
    Review asked whether _message_was_supplied should drop to False when a
    commit_file cannot be read, since the text then comes from git. Measured
    the only reachable case: a HEAD commit whose message is genuinely empty,
    where allow_empty_commits = false makes CC008 the correct verdict.
    Deriving the flag from successful resolution would restore the miss this
    branch fixes, so the behaviour stands and the docstring now says why.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01U9zFxq8V4qxG4aMzJhGBFn
    
    ---------
    
    Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
    shenxianpeng and claude authored Aug 7, 2026
    Configuration menu
    Copy the full SHA
    08d14c1 View commit details
    Browse the repository at this point in the history
  2. docs: refresh README sample output to match what commit-check prints (#…

    …535)
    
    The README's output blocks predate rule IDs, so they showed neither the
    CCxxx identifiers nor the Docs links that every failure now prints. Same
    staleness #530 fixed in the demo GIF; the docs site was already current,
    only the README had been left behind.
    
    Measured by running each documented command against the checkout:
    
      Type message check failed ==> ...  ->  CC001 message check failed ==> ...
      Type branch check failed  ==> ...  ->  CC201 branch check failed  ==> ...
    
    plus a trailing Docs: https://commit-check.com/rules/#ccNNN line on both,
    and two commit types the list had never picked up (perf, build).
    
    Four more blocks were stale the same way: --no-banner carried an
    "It doesn't match regex:" line that no longer exists in the source,
    --compact now prints the rule id, both --format json examples were missing
    rule_id and docs_url and named a subject_imperative check the default run
    does not emit (it reports subject_max_length and subject_min_length), and
    the Python API return-value schema was missing rule_id and docs_url.
    
    Every block was re-captured and compared byte for byte against the
    committed text, so these are transcripts rather than transcriptions.
    shenxianpeng authored Aug 7, 2026
    Configuration menu
    Copy the full SHA
    90c5abe View commit details
    Browse the repository at this point in the history
Loading