A GitHub Action for validating Git commit messages and history. Checks for WIP/fixup commits, Signed-off-by trailers, and conventional commit format.
- Fast execution - Written in Rust for minimal overhead
- Extensible - Easy to add new checks in the future
- Clear feedback - GitHub Actions annotations for failed checks
- Automatic failure - Fails the workflow step when checks don't pass
- Default all-checks mode - Runs all validations in a single invocation
- Auto-detection - Automatically detects base/head refs from PR context
Add to your workflow:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required to access commit history
- uses: canonical/gitlance@v1This will run all checks by default in your PR context.
Run only a single check:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: canonical/gitlance@v1
with:
check: wip-fixupFor non-PR workflows (e.g., push events), provide git references explicitly:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: canonical/gitlance@v1
with:
base: ${{ github.event.before }}
head: ${{ github.sha }}Git references can be:
- Full SHAs:
abc123def456...(40 characters) - Short SHAs:
abc123(any unambiguous abbreviation accepted by Git) - Symbolic refs:
HEAD,HEAD~4,HEAD^ - Branch names:
main,origin/main - Tags:
v1.0.0
Note: In PR context, refs are auto-detected and this is not needed.
The action automatically fails the workflow when checks fail. Use the passed output for conditional logic:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- id: checks
uses: canonical/gitlance@v1
continue-on-error: true # Don't fail workflow immediately
- name: Post comment on validation failure
if: steps.checks.outputs.passed == 'false'
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({ // Wait for comment to post before failing
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '❌ Commit validation failed. Please review the checks.'
})
- name: Fail workflow if checks failed
if: steps.checks.outputs.passed == 'false'
run: exit 1Detects Work-in-Progress, fixup, squash, and amend commits. Fails if any commit message starts with:
fixup!squash!amend!WIPorwip(followed by space or colon)
Validates that all commits have a valid Signed-off-by trailer in the format:
Signed-off-by: Name <email@domain>
Enforces conventional commit format for all commits. Valid types:
feat- New featurefix- Bug fixdocs- Documentationstyle- Code stylerefactor- Refactoringperf- Performancetest- Testsbuild- Build systemci- CI/CDchore- Choresrevert- Revert
Format: type(scope)?: description
Breaking changes are indicated with ! before the colon:
feat!: breaking change in APIfix(auth)!: change authentication flow
Examples:
feat: add new featurefix(api): resolve authentication bugdocs: update READMEfeat(cli): add verbose output flag
Runs all available checks. This is the default if no check is specified.
By default, gitlance checks all commits including merge commits. To skip merge commits (e.g., auto-generated "Merge branch 'feature'" messages that don't follow conventional format):
- uses: canonical/gitlance@v1
with:
skip-merge-commits: trueOr via CLI:
gitlance all --base abc123 --head def456 --skip-merge-commitsname: Commit Checks
on:
pull_request:
branches: [ main ]
jobs:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: canonical/gitlance@v1steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: canonical/gitlance@v1
with:
check: conventional-commitsRun all checks even if some fail, then fail the workflow if any failed:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: canonical/gitlance@v1
id: wip-check
continue-on-error: true
with:
check: wip-fixup
- uses: canonical/gitlance@v1
id: signoff-check
continue-on-error: true
with:
check: signed-off-by
- name: Fail if any check failed
if: steps.wip-check.outputs.passed == 'false' || steps.signoff-check.outputs.passed == 'false'
run: exit 1The action automatically downloads the pre-built binary for the specified version. No additional setup is required.
Note: Prebuilt binaries are only available for immutable release tags (e.g., @v1.2.3). Major tags like @v1 will build from source on each run.
Install from the Snap Store:
sudo snap install gitlance# Run all validation checks
task validate
# Build release binary
task build-release
# Run tests
task test
# Show all available tasks
task help# Build the project
cargo build --release
# Run tests
cargo test --verbose
# Run specific check on your repo
./target/release/gitlance wip-fixup \
--base <base_ref> \
--head <head_ref> \
--repo .Licensed under the Apache License 2.0. See LICENSE for details.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.