Skip to content

feat: block force pushes via pre-push hook - #410

Closed
shenxianpeng wants to merge 7 commits into
commit-check:mainfrom
shenxianpeng:feat/block-force-pushes
Closed

feat: block force pushes via pre-push hook#410
shenxianpeng wants to merge 7 commits into
commit-check:mainfrom
shenxianpeng:feat/block-force-pushes

Conversation

@shenxianpeng

@shenxianpeng shenxianpeng commented May 12, 2026

Copy link
Copy Markdown
Member

Summary

Adds a check-no-force-push pre-push hook that detects and blocks git push --force / git push -f by inspecting pushed ref ancestry via git merge-base --is-ancestor.

Closes #203

Detection logic

Reads git's pre-push stdin (<local ref> <local sha> <remote ref> <remote sha>) and evaluates:

  • Remote SHA is zero → new branch push → ✅ pass
  • merge-base returns 0 → fast-forward → ✅ pass
  • Returns 1 → remote not in local ancestry → force push → ❌ fail
  • Returns 128 → git error (SHA unknown) → ✅ pass (safe default)

Standalone mode

When run outside a pre-push hook (no stdin), --no-force-push checks whether pushing HEAD to its configured upstream would require force, using git ls-remote and optional git fetch to resolve the remote commit.

Usage

Config (cchk.toml)

[push]
allow_force_push = false  # default: true (force pushes allowed)

CLI

commit-check --no-force-push

pre-commit hook

repos:
  - repo: https://github.com/commit-check/commit-check
    hooks:
      - id: check-no-force-push
        stages: [pre-push]

Environment variable

export CCHK_ALLOW_FORCE_PUSH=false

Changes

File Change
commit_check/__init__.py Added DEFAULT_PUSH_RULES
commit_check/rules_catalog.py Added PUSH_RULES
commit_check/rule_builder.py Added _build_push_rules()
commit_check/engine.py Added ForcePushValidator
commit_check/config_merger.py Added [push] section support
commit_check/main.py Added --no-force-push CLI flag
commit_check/api.py Added validate_push() API
commit_check/util.py Added upstream helper functions
.pre-commit-hooks.yaml Added check-no-force-push hook
tests/ 34 new tests across 4 test files

Summary by CodeRabbit

Release Notes

  • New Features

    • Added force push detection and blocking via a new --no-force-push CLI flag
    • Introduced a check-no-force-push pre-push hook for integration with pre-commit
    • Added validate_push() Python API for programmatic push safety validation
    • Added push.allow_force_push configuration option to control force push behavior
  • Documentation

    • Added configuration, examples, and changelog documentation for push validation features

Review Change Stack

@netlify

netlify Bot commented May 12, 2026

Copy link
Copy Markdown

Deploy Preview for commit-check ready!

Name Link
🔨 Latest commit c615e63
🔍 Latest deploy log https://app.netlify.com/projects/commit-check/deploys/6a07a4aff58ac00008840aaa
😎 Deploy Preview https://deploy-preview-410--commit-check.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@shenxianpeng has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 55 minutes and 35 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bf2f8600-00ec-4be9-bb2f-099adcd4036d

📥 Commits

Reviewing files that changed from the base of the PR and between f35edd2 and c615e63.

📒 Files selected for processing (1)
  • .github/workflows/labeler.yml
📝 Walkthrough

Walkthrough

This PR implements force-push detection and blocking via a new --no-force-push CLI flag and corresponding pre-commit hook. It adds a validate_push() public API, extends configuration to support push.allow_force_push, implements a ForcePushValidator that detects non-fast-forward updates using git ancestry checks, and includes comprehensive tests and documentation.

Changes

Force-Push Detection and Blocking

Layer / File(s) Summary
Rule catalog and default configuration
commit_check/rules_catalog.py, commit_check/__init__.py
PUSH_RULES catalog defines the no_force_push rule, and DEFAULT_PUSH_RULES provides allow_force_push=True as the default permissive setting.
Configuration infrastructure
commit_check/config_merger.py, commit_check/rule_builder.py, tests/rule_builder_test.py
Configuration merging supports push.allow_force_push via CCHK_ALLOW_FORCE_PUSH environment variable and CLI arguments; rule builder conditionally constructs the no_force_push rule based on config state and includes comprehensive builder tests.
Git utilities and validation engine
commit_check/util.py, commit_check/engine.py, tests/util_test.py, tests/engine_test.py
ForcePushValidator implements core detection by parsing pre-push stdin ref lines and checking ancestry via git merge-base, with fallback to upstream-branch comparison; new git utilities provide upstream branch resolution, remote SHA lookups, and ref fetching with full test coverage including subprocess mocking.
CLI flag and public API
commit_check/main.py, commit_check/api.py
New --no-force-push CLI flag enables validation with config override; new validate_push() public API provides programmatic push safety checks; both wire context flags for stdin handling and upstream fallback behavior.
Tests for CLI and API
tests/main_test.py, tests/api_test.py
CLI tests verify --no-force-push flag behavior (pass/fail by push type, stdin/upstream fallback, help text); API tests verify validate_push() handles new branches, fast-forward detection, config override, and result schema.
Hook configuration and documentation
.pre-commit-hooks.yaml, README.rst, docs/configuration.rst, docs/example.rst, docs/changelog.rst, docs/what-is-new.rst
Pre-commit hook check-no-force-push registered for pre-push stage; README adds force-push blocking comparison; configuration docs explain TOML, environment variable, and CLI flag setup; example and release notes document usage patterns and v2.7.0 features.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • commit-check/commit-check#357: Introduces the configuration-merging framework that this PR extends with push.allow_force_push setting and corresponding CCHK_ALLOW_FORCE_PUSH environment variable wiring.
  • commit-check/commit-check#280: Introduces the ValidationEngine and ValidationContext architecture that this PR extends by adding the push_upstream_fallback flag and ForcePushValidator rule/validator.

Suggested labels

tests, documentation

Poem

🐰 A rabbit hops to stop the force,
No --force-with-lease will run its course!
Upstream checks and ancestry knows,
Fast-forward wins, force-push goes.
Pre-push hooks now guard the way,
Hoppy merges every day! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.19% 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 clearly identifies the main feature added: a pre-push hook for blocking force pushes, which matches the primary objectives and code changes.
Linked Issues check ✅ Passed The PR fully addresses issue #203 by implementing force-push detection and blocking via multiple mechanisms: pre-push hook, CLI flag, config option, and environment variable.
Out of Scope Changes check ✅ Passed All code changes are directly related to force-push blocking functionality. Changes span configuration, validation logic, CLI integration, API, utilities, documentation, and comprehensive tests—all in scope.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@shenxianpeng shenxianpeng added the enhancement New feature or request label May 12, 2026
@codecov

codecov Bot commented May 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.37398% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.81%. Comparing base (505c9eb) to head (c615e63).

Files with missing lines Patch % Lines
commit_check/api.py 85.71% 1 Missing ⚠️
commit_check/engine.py 98.24% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #410      +/-   ##
==========================================
+ Coverage   95.51%   95.81%   +0.29%     
==========================================
  Files          10       10              
  Lines        1004     1123     +119     
==========================================
+ Hits          959     1076     +117     
- Misses         45       47       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codspeed-hq

codspeed-hq Bot commented May 12, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 245 untouched benchmarks
🆕 50 new benchmarks
⏩ 108 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
🆕 test_custom_config_is_merged N/A 315.6 µs N/A
🆕 test_fast_forward_push_passes N/A 707.8 µs N/A
🆕 test_force_push_fails N/A 717 µs N/A
🆕 test_new_branch_push_passes N/A 297.7 µs N/A
🆕 test_none_push_refs_passes N/A 281.3 µs N/A
🆕 test_result_has_expected_structure N/A 291 µs N/A
🆕 test_fast_forward_push_is_allowed N/A 560.1 µs N/A
🆕 test_git_error_allows_push N/A 1.6 ms N/A
🆕 test_empty_lines_in_stdin_are_skipped N/A 561.5 µs N/A
🆕 test_force_push_is_blocked N/A 1.1 ms N/A
🆕 test_malformed_push_line_is_skipped N/A 131.8 µs N/A
🆕 test_missing_remote_sha_fetch_prefers_matching_upstream_remote N/A 1.6 ms N/A
🆕 test_missing_remote_sha_is_fetched_then_force_push_is_blocked N/A 2.2 ms N/A
🆕 test_missing_remote_sha_tries_next_remote_until_resolved N/A 2.2 ms N/A
🆕 test_multiple_refs_one_force_push_blocks N/A 1.2 ms N/A
🆕 test_new_branch_push_is_allowed N/A 135.3 µs N/A
🆕 test_no_stdin_skips_validation N/A 123.9 µs N/A
🆕 test_no_stdin_with_upstream_fallback_blocks_force_push N/A 2.1 ms N/A
🆕 test_no_stdin_with_upstream_fallback_fetches_remote_commit_when_needed N/A 2.5 ms N/A
🆕 test_no_stdin_with_upstream_fallback_passes_fast_forward N/A 1.2 ms N/A
... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.


Comparing shenxianpeng:feat/block-force-pushes (c615e63) with main (505c9eb)

Open in CodSpeed

Footnotes

  1. 108 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@shenxianpeng shenxianpeng added the minor A minor version bump label May 12, 2026
@shenxianpeng
shenxianpeng marked this pull request as ready for review May 15, 2026 16:23
@shenxianpeng
shenxianpeng requested a review from a team as a code owner May 15, 2026 16:23
Adds a `check-no-force-push` pre-push hook that detects and blocks
`git push --force` / `git push -f` by inspecting pushed ref ancestry
via `git merge-base --is-ancestor`.

## Detection logic

Reads git's pre-push stdin (<local ref> <local sha> <remote ref> <remote sha>)
and evaluates:

- Remote SHA is zero -> new branch push -> pass
- merge-base returns 0 -> fast-forward -> pass
- Returns 1 -> force push detected -> fail
- Returns 128 -> git error, pass (safe default)

## Standalone mode

When run without stdin, --no-force-push checks whether pushing HEAD to its
configured upstream would require force, using git ls-remote and optional
git fetch to resolve the remote commit.

Closes #203

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 5

🤖 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 `@commit_check/engine.py`:
- Around line 565-583: The retry fetch logic in
_check_current_branch_against_upstream fails when get_upstream_remote_sha()
returns empty because target_ref == upstream_ref prevents fetch_on_128; change
the control so that when git_merge_base(target_ref, "HEAD") returns 128 you
always call fetch_upstream_ref(upstream_ref) and then re-run git_merge_base,
regardless of whether target_ref came from get_upstream_remote_sha; update the
block that checks returncode == 128 to remove the target_ref != upstream_ref
guard and ensure the retry path uses fetch_upstream_ref and reassigns returncode
before evaluating failure (use get_branch_name() and upstream_ref as before for
the failure message).

In `@docs/configuration.rst`:
- Around line 276-278: The table row for allow_force_push is inconsistent: it
currently maps `allow_force_push = true` to `CCHK_ALLOW_FORCE_PUSH=false` and
`--no-force-push`; update the env-var column to `CCHK_ALLOW_FORCE_PUSH=true` so
the value matches the TOML `allow_force_push = true` and the parity pattern, and
keep the `--no-force-push` flag as-is; move the guidance about "set false to
block" out of the value mapping into the descriptive text for `allow_force_push`
so the table only shows matching values.

In `@docs/example.rst`:
- Around line 156-176: The docs mention the check-no-force-push hook but omit
how to enable pre-push hooks; add a short instruction telling users to install
the pre-push hook type (for example by running pre-commit install --hook-type
pre-push) before configuring or relying on the check-no-force-push hook, and
update the Push Validation Examples section to include this installation step so
readers know to enable the pre-push hook type prior to using
check-no-force-push.

In `@README.rst`:
- Around line 207-210: The pre-commit config pins rev: v2.6.0 but declares the
hook id: check-no-force-push which was added after v2.6.0; update the rev value
in the same block (the lines containing rev: and id: check-no-force-push) to a
release that includes that hook (e.g., change rev: v2.6.0 to rev: v2.7.0 or a
newer compatible tag) so pre-commit can resolve the hook without errors.

In `@tests/api_test.py`:
- Line 273: The docstring for the validate_push() tests contains an ambiguous EN
DASH character – which triggers RUF002; open the docstring in tests/api_test.py
where the triple-quoted string reads "Tests for validate_push() – the
programmatic push safety API." and replace the EN DASH with a normal ASCII
hyphen so it reads "Tests for validate_push() - the programmatic push safety
API." to silence the lint warning.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: e044e696-1acf-4479-ac62-104e6bfcec9e

📥 Commits

Reviewing files that changed from the base of the PR and between 505c9eb and f35edd2.

📒 Files selected for processing (19)
  • .pre-commit-hooks.yaml
  • README.rst
  • commit_check/__init__.py
  • commit_check/api.py
  • commit_check/config_merger.py
  • commit_check/engine.py
  • commit_check/main.py
  • commit_check/rule_builder.py
  • commit_check/rules_catalog.py
  • commit_check/util.py
  • docs/changelog.rst
  • docs/configuration.rst
  • docs/example.rst
  • docs/what-is-new.rst
  • tests/api_test.py
  • tests/engine_test.py
  • tests/main_test.py
  • tests/rule_builder_test.py
  • tests/util_test.py

Comment thread commit_check/engine.py
Comment on lines +565 to +583
def _check_current_branch_against_upstream(self) -> ValidationResult:
"""Check whether pushing HEAD to its upstream would require force."""
upstream_ref = get_upstream_branch()
if not upstream_ref:
return ValidationResult.PASS

target_ref = get_upstream_remote_sha(upstream_ref) or upstream_ref
returncode = git_merge_base(target_ref, "HEAD")
if (
returncode == 128
and target_ref != upstream_ref
and fetch_upstream_ref(upstream_ref)
):
returncode = git_merge_base(target_ref, "HEAD")
if returncode == 1:
self._print_failure(f"{get_branch_name()} -> {upstream_ref}")
return ValidationResult.FAIL

return ValidationResult.PASS

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fetch retry skipped when remote SHA lookup fails.

When get_upstream_remote_sha() returns empty (e.g., no network, private repo), target_ref falls back to upstream_ref. If git_merge_base then returns 128 (ref unknown locally), the condition target_ref != upstream_ref is False, so fetch_upstream_ref is never called. This defeats the retry logic for shallow clones or CI environments where the upstream ref isn't available locally.

🐛 Proposed fix: fetch when returncode is 128 regardless of target_ref source
     def _check_current_branch_against_upstream(self) -> ValidationResult:
         """Check whether pushing HEAD to its upstream would require force."""
         upstream_ref = get_upstream_branch()
         if not upstream_ref:
             return ValidationResult.PASS

         target_ref = get_upstream_remote_sha(upstream_ref) or upstream_ref
         returncode = git_merge_base(target_ref, "HEAD")
-        if (
-            returncode == 128
-            and target_ref != upstream_ref
-            and fetch_upstream_ref(upstream_ref)
-        ):
-            returncode = git_merge_base(target_ref, "HEAD")
+        if returncode == 128 and fetch_upstream_ref(upstream_ref):
+            # Re-resolve target_ref after fetch if we didn't have a SHA
+            if target_ref == upstream_ref:
+                target_ref = get_upstream_remote_sha(upstream_ref) or upstream_ref
+            returncode = git_merge_base(target_ref, "HEAD")
         if returncode == 1:
             self._print_failure(f"{get_branch_name()} -> {upstream_ref}")
             return ValidationResult.FAIL

         return ValidationResult.PASS
🤖 Prompt for 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.

In `@commit_check/engine.py` around lines 565 - 583, The retry fetch logic in
_check_current_branch_against_upstream fails when get_upstream_remote_sha()
returns empty because target_ref == upstream_ref prevents fetch_on_128; change
the control so that when git_merge_base(target_ref, "HEAD") returns 128 you
always call fetch_upstream_ref(upstream_ref) and then re-run git_merge_base,
regardless of whether target_ref came from get_upstream_remote_sha; update the
block that checks returncode == 128 to remove the target_ref != upstream_ref
guard and ensure the retry path uses fetch_upstream_ref and reassigns returncode
before evaluating failure (use get_branch_name() and upstream_ref as before for
the failure message).

Comment thread docs/configuration.rst
Comment on lines +276 to +278
* - ``allow_force_push = true``
- ``CCHK_ALLOW_FORCE_PUSH=false``
- ``--no-force-push`` (enable via ``--no-force-push`` flag)

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix inconsistent value mapping for allow_force_push across TOML and env var.

This row maps allow_force_push = true to CCHK_ALLOW_FORCE_PUSH=false, which conflicts with the rest of the table’s parity pattern and is likely to confuse users. Use matching values in the mapping row and move the “set false to block” guidance to description text.

🤖 Prompt for 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.

In `@docs/configuration.rst` around lines 276 - 278, The table row for
allow_force_push is inconsistent: it currently maps `allow_force_push = true` to
`CCHK_ALLOW_FORCE_PUSH=false` and `--no-force-push`; update the env-var column
to `CCHK_ALLOW_FORCE_PUSH=true` so the value matches the TOML `allow_force_push
= true` and the parity pattern, and keep the `--no-force-push` flag as-is; move
the guidance about "set false to block" out of the value mapping into the
descriptive text for `allow_force_push` so the table only shows matching values.

Comment thread docs/example.rst
Comment on lines +156 to +176
Push Validation Examples
~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: bash

# Check whether pushing HEAD to its configured upstream would require force
commit-check --no-force-push

.. code-block:: yaml

# Configure the dedicated pre-push hook
- repo: https://github.com/commit-check/commit-check
rev: the tag or revision
hooks:
- id: check-no-force-push
stages: [pre-push]

``git push | commit-check --no-force-push`` is not a prevention mechanism. The
push has already started, and normal ``git push`` output does not include the
pre-push ref lines that Git provides to hooks.

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add explicit pre-push hook installation step in this section.

This section introduces check-no-force-push, but it doesn’t mention that users must install the pre-push hook type (pre-commit install --hook-type pre-push). Without that, the hook won’t run.

🤖 Prompt for 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.

In `@docs/example.rst` around lines 156 - 176, The docs mention the
check-no-force-push hook but omit how to enable pre-push hooks; add a short
instruction telling users to install the pre-push hook type (for example by
running pre-commit install --hook-type pre-push) before configuring or relying
on the check-no-force-push hook, and update the Push Validation Examples section
to include this installation step so readers know to enable the pre-push hook
type prior to using check-no-force-push.

Comment thread README.rst
Comment on lines +207 to +210
rev: v2.6.0
hooks:
- id: check-no-force-push
stages: [pre-push]

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use a release tag that actually contains check-no-force-push.

The snippet defines id: check-no-force-push but pins rev: v2.6.0. That version predates this hook, so copy/paste users can get pre-commit hook resolution errors. Update to the release that includes this feature (e.g., v2.7.0).

Suggested fix
-      - repo: https://github.com/commit-check/commit-check
-        rev: v2.6.0
+      - repo: https://github.com/commit-check/commit-check
+        rev: v2.7.0
         hooks:
           - id: check-no-force-push
             stages: [pre-push]
🤖 Prompt for 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.

In `@README.rst` around lines 207 - 210, The pre-commit config pins rev: v2.6.0
but declares the hook id: check-no-force-push which was added after v2.6.0;
update the rev value in the same block (the lines containing rev: and id:
check-no-force-push) to a release that includes that hook (e.g., change rev:
v2.6.0 to rev: v2.7.0 or a newer compatible tag) so pre-commit can resolve the
hook without errors.

Comment thread tests/api_test.py


class TestValidatePush:
"""Tests for validate_push() – the programmatic push safety API."""

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace ambiguous unicode dash in docstring.

Line 273 uses an EN DASH () that Ruff flags as ambiguous text (RUF002). Use a normal hyphen (-) to avoid lint noise/failures.

Suggested fix
-class TestValidatePush:
-    """Tests for validate_push() – the programmatic push safety API."""
+class TestValidatePush:
+    """Tests for validate_push() - the programmatic push safety API."""
🧰 Tools
🪛 Ruff (0.15.12)

[warning] 273-273: Docstring contains ambiguous (EN DASH). Did you mean - (HYPHEN-MINUS)?

(RUF002)

🤖 Prompt for 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.

In `@tests/api_test.py` at line 273, The docstring for the validate_push() tests
contains an ambiguous EN DASH character – which triggers RUF002; open the
docstring in tests/api_test.py where the triple-quoted string reads "Tests for
validate_push() – the programmatic push safety API." and replace the EN DASH
with a normal ASCII hyphen so it reads "Tests for validate_push() - the
programmatic push safety API." to silence the lint warning.

@sonarqubecloud

Copy link
Copy Markdown

@shenxianpeng

Copy link
Copy Markdown
Member Author

Superseded by #412, which uses commit-check/commit-check:feat/block-force-pushes as the head branch instead of the fork branch.

@shenxianpeng shenxianpeng closed this by deleting the head repository May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request minor A minor version bump

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FR] Block force pushes

1 participant