fix: integrate git hooks with pre-commit - #17
Conversation
8d6cf24 to
4f9098f
Compare
|
Thanks for the feedback @agherzan. I’ve updated the branch on top of #13, which includes #12, and limited my commit to the pre-commit integration. I also expanded the commit message to include the implementation rationale and validation details. All checks are passing locally. Ready for another review when you have time. |
agherzan
left a comment
There was a problem hiding this comment.
Any reason not use the pre-commit install directly? I'm not sure I understand why you need the changes in gitlance.
Some small extra comments:
- keep git log lines at resonable lengths.
- SOB should have your name and email
|
Thanks, that makes sense. I added the Gitlance changes only to translate pre-commit's pre-push environment variables, but after rechecking #12 and #13, I agree this can be simpler. I'll use I'll also wrap the commit message at reasonable line lengths and update the author and sign-off to: |
4f9098f to
ee632a6
Compare
|
Updated as discussed. The contribution commit now uses I also wrapped the commit message at 72 columns and updated both the author and sign-off to |
There was a problem hiding this comment.
Pull request overview
This PR introduces pre-commit–based installation and configuration for local Git hooks, and extends the gitlance CLI to support commit-msg style validation (message-file mode) and pre-push style validation of only unpublished commits (not-on-remotes mode).
Changes:
- Add
--message-fileand--not-on-remotesCLI modes and supporting git utilities (remote_tracking_refs,get_commits_excluding). - Add integration/units tests covering message-file mode and not-on-remotes commit selection.
- Add pre-commit configuration + Taskfile/docs updates to install hooks via
pre-commit installand document install/uninstall behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/integration_tests.rs | Refactors test harness and adds integration coverage for --message-file and --not-on-remotes. |
| Taskfile.yml | Switches install-githooks to pre-commit install with preconditions. |
| src/main.rs | Adds CLI flags and implements message-file + not-on-remotes commit selection flow. |
| src/lib.rs | Re-exports new git APIs used by the CLI and other crates. |
| src/git.rs | Adds commit creation from message files, comment stripping, remote-tracking ref listing, and exclude-based revwalk selection. |
| README.md | Documents direct CLI usage for message-file and not-on-remotes modes. |
| githooks/pre-push | Updates hook behavior for new-branch pushes to use not-on-remotes logic. |
| githooks/commit-msg | Adds a standalone commit-msg hook script invoking --message-file. |
| CONTRIBUTING.md | Documents local hook installation via pre-commit and uninstall behavior. |
| .pre-commit-config.yaml | Adds pre-commit hooks for commit-msg and pre-push stages using gitlance. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
ee632a6 to
266711e
Compare
| hooks: | ||
| - id: gitlance-commit-msg | ||
| name: Validate commit message with gitlance | ||
| entry: gitlance --message-file |
There was a problem hiding this comment.
I would use the existing hook. Any disadvantages to that?
There was a problem hiding this comment.
No functional disadvantage here. Pre-commit passes the commit-message filename as the first argument, which matches what the existing githooks/commit-msg script expects. I used the binary directly to avoid an extra shell layer, but reusing the existing hook is clearer and avoids duplicating its behavior. I'll switch this entry to the existing hook.
| entry: gitlance --head HEAD --not-on-remotes | ||
| language: system | ||
| stages: [pre-push] | ||
| always_run: true |
There was a problem hiding this comment.
Could you explain why you added this?
There was a problem hiding this comment.
Gitlance validates commits rather than files, so this keeps the hook running for pushes with no changed files, such as an empty commit.
There was a problem hiding this comment.
Gitlance supports now validating files as well. If you mean a git log entry in a file. Did you find a limitation?
| language: system | ||
| stages: [pre-push] | ||
| always_run: true | ||
| pass_filenames: false |
There was a problem hiding this comment.
Could you explain why you added this?
There was a problem hiding this comment.
The adapter gets the pushed ref from pre-commit's environment. Changed filenames are not inputs to Gitlance, so they should not be passed.
There was a problem hiding this comment.
I'm not sure I understand. Why is that different in the other hook?
| preconditions: | ||
| - sh: pre-commit --version | ||
| msg: "pre-commit is required: https://pre-commit.com/#install" | ||
| - sh: gitlance --not-on-remotes --head HEAD --help |
There was a problem hiding this comment.
Agreed, gitlance --help is enough. I'll simplify it.
266711e to
1e94c46
Compare
agherzan
left a comment
There was a problem hiding this comment.
I have merged the PRs that you use here. Could you please rebase it?
Copying commit-msg and pre-push directly into .git/hooks can replace hooks that contributors already use. Configure both stages through pre-commit and install its dispatcher from the existing task. Pre-commit preserves prior hooks as legacy hooks, runs them alongside Gitlance, and keeps repeated installation idempotent. Reuse the commit-msg hook and the --not-on-remotes mode added by canonical#12 and canonical#13. Pre-commit passes the prepared message file to the existing hook. For pre-push, use a small adapter to select the pushed ref from PRE_COMMIT_TO_REF or PRE_COMMIT_LOCAL_BRANCH. This validates a branch that is not checked out and skips non-branch refs without changing the Gitlance CLI. Document the local setup and uninstall workflow. Closes: canonical#9 Signed-off-by: Dhruv Vaishnav <dhruvvaishav687@gmail.com>
1e94c46 to
288c1df
Compare
| task install-githooks | ||
| ``` | ||
|
|
||
| The installation is idempotent. If a `commit-msg` or `pre-push` hook already |
There was a problem hiding this comment.
How does it behave when installing the gitlance hooks after they were updated locally? Does it update the hooks? Does it ignore the updates as it already has them?
| @@ -0,0 +1,24 @@ | |||
| #!/usr/bin/env python3 | |||
There was a problem hiding this comment.
Gitlance supports taking advantage of Git's commit file, which is exposed to hooks before creating the commit. Does this script fill any gap in that implementation?
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
Suppressed comments (5)
.pre-commit-config.yaml:17
- The pre-commit pre-push implementation consumes the Git stdin stream and exposes only one non-deleted ref through
PRE_COMMIT_TO_REF/PRE_COMMIT_LOCAL_BRANCH. This adapter therefore validates at most one ref from a multi-ref push; if the first ref is a tag it returns success here and any later branch ref is never checked. The pre-commit integration needs a way to process every pushed ref, or this hook must be installed outside the single-ref pre-commit adapter.
entry: python githooks/pre_commit_pre_push.py
Taskfile.yml:30
pre-commit installdoes not replace an existing non-pre-commit hook unless overwrite is requested, so this task will fail on exactly the repositories with an existingcommit-msgorpre-pushhook instead of moving it to the legacy hook and chaining it. Invoke the legacy-hook installation path withpre-commit install --overwriteso the documented preservation behavior actually occurs.
- pre-commit install
Taskfile.yml:30
pre-commit installrefuses to run when Git hascore.hooksPathconfigured. The previous task resolved the effective hooks directory withgit rev-parse --git-path hooks, so this change makestask install-githooksfail for contributors who use a custom hooks path instead of installing the requested hooks. Handle or document this case explicitly, rather than silently regressing the existing path support.
- pre-commit install
githooks/pre_commit_pre_push.py:20
- Unlike the existing
githooks/commit-msgandgithooks/pre-pushscripts, this adapter does not handle a missinggitlanceexecutable. If the binary is removed or the hook is run from an environment without Cargo's bin directory,subprocess.callraisesFileNotFoundErrorand pre-commit prints a traceback instead of the actionable failure/bypass message. Catch this case and return a normal nonzero hook result.
return subprocess.call(
["gitlance", "--head", head, "--not-on-remotes"],
)
githooks/pre_commit_pre_push.py:15
- Allowing the literal
HEADbypasses the non-branch filter for an explicit tag push such asgit push origin HEAD:refs/tags/v1: pre-commit reports the local ref asHEAD, so this adapter invokes Gitlance instead of skipping the tag. CheckPRE_COMMIT_REMOTE_BRANCHas well (or otherwise distinguishHEADpushed to a tag) before accepting the ref.
if local_branch != "HEAD" and not local_branch.startswith("refs/heads/"):
return 0
| head = os.environ.get("PRE_COMMIT_TO_REF") or local_branch | ||
| return subprocess.call( | ||
| ["gitlance", "--head", head, "--not-on-remotes"], |
Closes #9
Summary
Copying
commit-msgandpre-pushdirectly into.git/hookscan replace hooks that contributors already use.This branch is based on #13, which includes the commit-message support from #12. The change on top is limited to pre-commit integration:
commit-msghook through pre-commit--not-on-remotesmodePRE_COMMIT_TO_REForPRE_COMMIT_LOCAL_BRANCHpre-commit installfromtask install-githooksThe Rust source changes displayed in the combined PR diff are inherited from #12 and #13. This contribution commit does not modify Gitlance's Rust code.
Testing
cargo fmt --all -- --checkcargo clippy --locked --all-targets --all-features -- -D warningscargo test --locked— 47 unit and 19 integration tests passedreuse lintcargo llvm-cov --locked report --fail-under-lines 70— 85.12% line coveragepre-commit validate-config .pre-commit-config.yamlpre-commit installcommit-msgand configuredpre-pushhook runs