{"id":51192305,"url":"https://github.com/agherzan/gitlance","last_synced_at":"2026-06-27T16:30:32.979Z","repository":{"id":366012684,"uuid":"1274710463","full_name":"agherzan/gitlance","owner":"agherzan","description":"Vigilance for your Git commit","archived":false,"fork":false,"pushed_at":"2026-06-19T22:19:20.000Z","size":45,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-19T22:20:11.062Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agherzan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-19T20:06:44.000Z","updated_at":"2026-06-19T22:19:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/agherzan/gitlance","commit_stats":null,"previous_names":["agherzan/gitlance"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/agherzan/gitlance","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agherzan%2Fgitlance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agherzan%2Fgitlance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agherzan%2Fgitlance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agherzan%2Fgitlance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agherzan","download_url":"https://codeload.github.com/agherzan/gitlance/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agherzan%2Fgitlance/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34860892,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-27T16:30:24.546Z","updated_at":"2026-06-27T16:30:32.769Z","avatar_url":"https://github.com/agherzan.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\nSPDX-FileCopyrightText: Canonical Ltd.\n\nSPDX-License-Identifier: Apache-2.0\n--\u003e\n\n# gitlance\n\n[![Validate](https://github.com/agherzan/gitlance/actions/workflows/validate.yml/badge.svg)](https://github.com/agherzan/gitlance/actions/workflows/validate.yml)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)\n[![REUSE](https://api.reuse.software/badge/github.com/agherzan/gitlance)](https://api.reuse.software/info/github.com/agherzan/gitlance)\n\nA GitHub Action for validating Git commit messages and history. Checks for WIP/fixup commits, Signed-off-by trailers, and conventional commit format.\n\n## Features\n\n- **Fast execution** - Written in Rust for minimal overhead\n- **Extensible** - Easy to add new checks in the future\n- **Clear feedback** - GitHub Actions annotations for failed checks\n- **Automatic failure** - Fails the workflow step when checks don't pass\n- **Default all-checks mode** - Runs all validations in a single invocation\n- **Auto-detection** - Automatically detects base/head SHAs from PR context\n\n## Usage\n\n### Basic Usage\n\nAdd to your workflow:\n\n```yaml\nsteps:\n  - uses: actions/checkout@v4\n    with:\n      fetch-depth: 0  # Required to access commit history\n  - uses: agherzan/gitlance@v1\n```\n\nThis will run all checks by default in your PR context.\n\n### Specific Check\n\nRun only a single check:\n\n```yaml\nsteps:\n  - uses: actions/checkout@v4\n    with:\n      fetch-depth: 0\n  - uses: agherzan/gitlance@v1\n    with:\n      check: wip-fixup\n```\n\n### Manual SHA Specification\n\nFor non-PR workflows (e.g., push events), provide SHAs explicitly:\n\n```yaml\nsteps:\n  - uses: actions/checkout@v4\n    with:\n      fetch-depth: 0\n  - uses: agherzan/gitlance@v1\n    with:\n      base-sha: ${{ github.event.before }}\n      head-sha: ${{ github.sha }}\n```\n\nNote: In PR context, SHAs are auto-detected and this is not needed.\n\n### Using the Output\n\nThe action automatically fails the workflow when checks fail. Use the `passed` output for conditional logic:\n\n```yaml\nsteps:\n  - uses: actions/checkout@v4\n    with:\n      fetch-depth: 0\n  - id: checks\n    uses: agherzan/gitlance@v1\n    continue-on-error: true  # Don't fail workflow immediately\n\n  - name: Post comment on validation failure\n    if: steps.checks.outputs.passed == 'false'\n    uses: actions/github-script@v7\n    with:\n      script: |\n        await github.rest.issues.createComment({  // Wait for comment to post before failing\n          issue_number: context.issue.number,\n          owner: context.repo.owner,\n          repo: context.repo.repo,\n          body: '❌ Commit validation failed. Please review the checks.'\n        })\n\n  - name: Fail workflow if checks failed\n    if: steps.checks.outputs.passed == 'false'\n    run: exit 1\n```\n\n## Available Checks\n\n### wip-fixup\nDetects Work-in-Progress, fixup, squash, and amend commits. Fails if any commit message starts with:\n- `fixup!`\n- `squash!`\n- `amend!`\n- `WIP` or `wip` (followed by space or colon)\n\n### signed-off-by\nValidates that all commits have a valid `Signed-off-by` trailer in the format:\n```\nSigned-off-by: Name \u003cemail@domain\u003e\n```\n\n### conventional-commits\nEnforces conventional commit format for all commits. Valid types:\n- `feat` - New feature\n- `fix` - Bug fix\n- `docs` - Documentation\n- `style` - Code style\n- `refactor` - Refactoring\n- `perf` - Performance\n- `test` - Tests\n- `build` - Build system\n- `ci` - CI/CD\n- `chore` - Chores\n- `revert` - Revert\n\nFormat: `type(scope)?: description`\n\nBreaking changes are indicated with `!` before the colon:\n- `feat!: breaking change in API`\n- `fix(auth)!: change authentication flow`\n\nExamples:\n- `feat: add new feature`\n- `fix(api): resolve authentication bug`\n- `docs: update README`\n- `feat(cli): add verbose output flag`\n\n### all\nRuns all available checks. This is the default if no check is specified.\n\n## Example Workflows\n\n### Check all commits on PR\n\n```yaml\nname: Commit Checks\n\non:\n  pull_request:\n    branches: [ main ]\n\njobs:\n  checks:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: agherzan/gitlance@v1\n```\n\n### Check with strict conventional commits\n\n```yaml\nsteps:\n  - uses: actions/checkout@v4\n    with:\n      fetch-depth: 0\n  - uses: agherzan/gitlance@v1\n    with:\n      check: conventional-commits\n```\n\n### Multiple checks with different steps\n\nRun all checks even if some fail, then fail the workflow if any failed:\n\n```yaml\nsteps:\n  - uses: actions/checkout@v4\n    with:\n      fetch-depth: 0\n\n  - uses: agherzan/gitlance@v1\n    id: wip-check\n    continue-on-error: true\n    with:\n      check: wip-fixup\n\n  - uses: agherzan/gitlance@v1\n    id: signoff-check\n    continue-on-error: true\n    with:\n      check: signed-off-by\n\n  - name: Fail if any check failed\n    if: steps.wip-check.outputs.passed == 'false' || steps.signoff-check.outputs.passed == 'false'\n    run: exit 1\n```\n\n## Installation\n\nThe action automatically downloads the pre-built binary for the specified version. No additional setup is required.\n\n**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.\n\n## Building Locally\n\n### Using Task\n\n```bash\n# Run all validation checks\ntask validate\n\n# Build release binary\ntask build-release\n\n# Run tests\ntask test\n\n# Show all available tasks\ntask help\n```\n\n### Using Cargo Directly\n\n```bash\n# Build the project\ncargo build --release\n\n# Run tests\ncargo test --verbose\n\n# Run specific check on your repo\n./target/release/gitlance wip-fixup \\\n  --base-sha \u003cbase_sha\u003e \\\n  --head-sha \u003chead_sha\u003e \\\n  --repo .\n```\n\n## License\n\nLicensed under the Apache License 2.0. See [LICENSE](LICENSE) for details.\n\n## Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagherzan%2Fgitlance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagherzan%2Fgitlance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagherzan%2Fgitlance/lists"}