Skip to content

canonical/gitlance

Repository files navigation

gitlance

Validate License REUSE

A GitHub Action for validating Git commit messages and history. Checks for WIP/fixup commits, Signed-off-by trailers, and conventional commit format.

Features

  • 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

Usage

Basic Usage

Add to your workflow:

steps:
  - uses: actions/checkout@v4
    with:
      fetch-depth: 0  # Required to access commit history
  - uses: canonical/gitlance@v1

This will run all checks by default in your PR context.

Specific Check

Run only a single check:

steps:
  - uses: actions/checkout@v4
    with:
      fetch-depth: 0
  - uses: canonical/gitlance@v1
    with:
      check: wip-fixup

Manual Reference Specification

For 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.

Using the Output

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 1

Available Checks

wip-fixup

Detects Work-in-Progress, fixup, squash, and amend commits. Fails if any commit message starts with:

  • fixup!
  • squash!
  • amend!
  • WIP or wip (followed by space or colon)

signed-off-by

Validates that all commits have a valid Signed-off-by trailer in the format:

Signed-off-by: Name <email@domain>

conventional-commits

Enforces conventional commit format for all commits. Valid types:

  • feat - New feature
  • fix - Bug fix
  • docs - Documentation
  • style - Code style
  • refactor - Refactoring
  • perf - Performance
  • test - Tests
  • build - Build system
  • ci - CI/CD
  • chore - Chores
  • revert - Revert

Format: type(scope)?: description

Breaking changes are indicated with ! before the colon:

  • feat!: breaking change in API
  • fix(auth)!: change authentication flow

Examples:

  • feat: add new feature
  • fix(api): resolve authentication bug
  • docs: update README
  • feat(cli): add verbose output flag

all

Runs all available checks. This is the default if no check is specified.

Merge Commit Handling

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: true

Or via CLI:

gitlance all --base abc123 --head def456 --skip-merge-commits

Example Workflows

Check all commits on PR

name: 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@v1

Check with strict conventional commits

steps:
  - uses: actions/checkout@v4
    with:
      fetch-depth: 0
  - uses: canonical/gitlance@v1
    with:
      check: conventional-commits

Multiple checks with different steps

Run 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 1

Installation

GitHub Action

The 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.

Snap Package

Install from the Snap Store:

sudo snap install gitlance

Building Locally

Using Task

# Run all validation checks
task validate

# Build release binary
task build-release

# Run tests
task test

# Show all available tasks
task help

Using Cargo Directly

# 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 .

License

Licensed under the Apache License 2.0. See LICENSE for details.

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

About

Vigilance for your Git commits

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages