Skip to content

CI Integration

GitHub Action

The GitHub Action installs skillsaw, runs it, and prints violations in the CI log. A separate review action posts violations as inline PR comments with automatic deduplication and thread resolution.

Basic usage (lint only)

name: Lint

on: [pull_request]

permissions:
  contents: read

jobs:
  skillsaw:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          persist-credentials: false
      - uses: stbenjam/skillsaw@v0
        with:
          strict: true

With PR review comments

To post inline comments on PRs (including fork PRs), use the two-workflow pattern. The lint workflow runs with read-only permissions and uploads the report as an artifact. A second workflow triggers on completion and posts comments with write permissions — without ever checking out untrusted code.

# .github/workflows/lint.yml
name: Lint

on:
  pull_request:
  push:
    branches: [main]

# SECURITY: This workflow runs on untrusted PR code, so it has read-only
# permissions. It cannot post comments — that's handled by lint-review.yml.
permissions:
  contents: read

jobs:
  skillsaw:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          persist-credentials: false
      - uses: stbenjam/skillsaw@v0
        with:
          strict: true
# .github/workflows/lint-review.yml
name: Lint Review

# SECURITY: workflow_run triggers run in the context of the BASE branch (main),
# not the PR branch. This workflow never checks out or executes untrusted PR
# code — it only downloads the lint report artifact produced by the Lint
# workflow and posts review comments. This is GitHub's recommended pattern for
# safely granting write permissions to PR feedback workflows.
# See: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run
on:
  workflow_run:
    workflows: ["Lint"]
    types: [completed]

jobs:
  review:
    # Only run for pull requests, not push events.
    if: github.event.workflow_run.event == 'pull_request'
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      # Reads the lint report artifact from the Lint workflow and posts inline
      # PR comments. Does not run skillsaw or execute any PR code.
      - uses: stbenjam/skillsaw/review@v0

The review action assumes its token posts as github-actions[bot]. When using a GitHub App or PAT, set comment-author to that token's login so subsequent runs can update and remove only the comments they own:

- uses: stbenjam/skillsaw/review@v0
  with:
    token: ${{ secrets.REVIEW_APP_TOKEN }}
    comment-author: skillsaw-reviewer[bot]

Inputs

Input Description Default
path Path to lint .
version PyPI version to install; empty installs the action checkout ''
strict Treat warnings as errors false
fail-on Fail on violations at this severity or above (error, warning, info); strict: true is equivalent to fail-on: warning, and combining strict with a contradictory fail-on fails the run ''
verbose Include info-level violations false
no-custom-rules Skip custom rules defined in .skillsaw.yaml true
plugins Trusted newline-separated pip requirements to install as rule plugins; values can select indexes or URLs ''

With version left empty, the linter comes from the same tag or commit SHA as the action. Set version to install a specific PyPI release instead:

- uses: stbenjam/skillsaw@v0
  with:
    version: '0.20.0'

Outputs

Output Description
exit-code skillsaw exit code (0=pass, 1=violations at or above the fail-on threshold)
errors Number of errors found
warnings Number of warnings found
report-file Path to JSON report file

Supply Chain Protection

The examples above use @v0 for brevity. For supply-chain protection, replace @v0 with a pinned commit SHA:

- uses: stbenjam/skillsaw@d252498eb6260e197c9c395a650643d9c49ae37b # v0

While this project follows current best practices — PyPI trusted provenance, 2FA, signed releases — pinning to a SHA prevents a compromised tag from injecting malicious code into your workflow. Find the current SHA for a tag with:

git ls-remote --tags https://github.com/stbenjam/skillsaw.git v0

PR comment behavior

  • Each violation gets its own inline comment on the relevant line or file
  • Comments are deduplicated across re-runs using fingerprints that include the source line. Upgrading from an older action may repost existing comments once as the new fingerprints take effect.
  • When a violation is fixed, its unreplied review comment is deleted
  • Comments with human replies are preserved

The repository's privileged PR follow-up agent does not reply to or resolve inline review threads directly. It posts at most one PR-level summary naming the inline comments it handled, leaving thread resolution to a collaborator.

External URL availability depends on third-party servers and is outside skillsaw's deterministic lint scope. Use a dedicated link checker on a schedule instead of making remote availability a pull-request gate. For GitHub Actions, Lychee provides a maintained checker with Markdown-aware extraction, retries, exclusions, and job summaries.

name: Link Check

on:
  workflow_dispatch:
  schedule:
    - cron: '17 7 * * 1'

permissions:
  contents: read

concurrency:
  group: link-check
  cancel-in-progress: false

jobs:
  links:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v5
        with:
          persist-credentials: false
      - uses: lycheeverse/lychee-action@v2
        with:
          args: >-
            --no-progress
            --exclude-all-private
            --root-dir .
            './**/*.md'
          fail: true
          jobSummary: true

Pin both Actions to commit SHAs in a real workflow. Resolve the current Lychee v2 SHA with:

git ls-remote --tags https://github.com/lycheeverse/lychee-action.git v2

Badge and report card

skillsaw badge writes .skillsaw-badge.json (a shields.io endpoint payload) and prints ready-to-paste README markdown. Add --large to also render .skillsaw-card.svg — a self-contained SVG card with the repository name and letter grade (--theme light|dark, default dark):

skillsaw's own report card, dark theme (the default)

Regenerate both on pushes to your default branch and commit them when they change:

name: Badge

on:
  push:
    branches: [main]

permissions:
  contents: write

jobs:
  badge:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - run: pipx install skillsaw
      - run: skillsaw badge --large .  # grades, never gates (always exits 0)
      - name: Commit badge artifacts
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add .skillsaw-badge.json .skillsaw-card.svg
          git diff --cached --quiet || git commit -m "Update skillsaw badge"
          git push

Both images are served from your repository via raw.githubusercontent.com. GitHub proxies README images through its camo cache, which caches aggressively — a freshly regenerated badge or card can appear stale for a while after pushing.

Other output formats

skillsaw supports several machine-readable output formats — --format (stdout) and --output (file) accept text, json, sarif, html, code-climate, and gitlab — including SARIF 2.1.0 for tools that ingest it. See the CLI reference for details.

Committed generated docs

Deprecated in 0.20.0

skillsaw docs is deprecated and will be removed in an upcoming release. Existing CI jobs can keep using it during the deprecation period.

Some repositories commit the output of skillsaw docs and gate CI on it being current — regenerating in CI and failing if the working tree changed. Upgrading skillsaw can change that output, so plan on regenerating and committing the result as part of a version bump.

GitLab CI

For GitLab merge-request widgets, use the gitlab output format (a Code Quality report, available since skillsaw 0.11.3):

skillsaw:
  script:
    - pip install skillsaw==0.20.0
    - skillsaw lint --output gitlab:gl-code-quality-report.json .
  artifacts:
    reports:
      codequality: gl-code-quality-report.json