DocsGuidesGithub actions

GitHub Actions

Quell ships a composite GitHub Action that scans every pull request for untested guard clauses and posts results as inline diff annotations and a PR comment. No API key. No LLM. No code leaves your runner.


Quickest setup

Run this once inside your repo:

quell install --pr

That writes .github/workflows/quell.yml and you're done. Every future PR triggers the scanner automatically.


Manual setup

Create .github/workflows/quell.yml:

name: Quell — Guard Clause Scan

on:
  pull_request:
    types: [opened, synchronize, reopened]
    paths:
      - "**.py"

permissions:
  contents: read
  pull-requests: write

jobs:
  quell:
    name: Guard clause scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Scan for untested guard clauses
        uses: shashank7109/quelltest_lib@main
        with:
          target: '.'
          post-comment: 'true'
          fail-on-gaps: 'false'

pull-requests: write is required for the PR comment step. Without it the scan still runs and annotations appear, but no comment is posted.


What you see in the PR

Inline diff annotations — each untested guard clause appears as a warning directly on the line where it is written:

⚠  Untested guard [boundary] in process_payment()
   if amount <= 0:

PR comment — a summary table is posted on open and updated (never re-posted) on each push:

🟡 Quell — Guard Clause Scan

3 untested guard clauses found — 60% covered (3/5)

| File            | Function        | Guard                    | Type     |
|-----------------|-----------------|--------------------------|----------|
| payments.py:32  | process_payment | if amount <= 0:          | boundary |
| sessions.py:18  | create_session  | if not user:             | not_null |
| auth.py:44      | require_auth    | if not is_authenticated: | auth     |

Fix locally: quell scan . --fix

Action inputs

InputDefaultDescription
target.File or directory to scan, relative to repo root. Use src/ if your sources live there.
python-version3.11Python version used on the runner.
post-commenttruePost/update a PR comment. Requires pull-requests: write.
fail-on-gapsfalseExit 1 if any untested guard clauses are found. Set to true to block merges.
github-token${{ github.token }}Token for comments. Default works for same-repo PRs.

Action outputs

- name: Scan
  id: quell
  uses: shashank7109/quelltest_lib@main

- name: Use the result
  run: echo "Found ${{ steps.quell.outputs.gaps-found }} gaps out of ${{ steps.quell.outputs.total-guards }} guards"
OutputDescription
gaps-foundUntested guard clauses found in changed files
total-guardsTotal guard clauses detected
report-pathAlways quell-report.json

Recipes

Block merges when gaps exist:

- uses: shashank7109/quelltest_lib@main
  with:
    fail-on-gaps: 'true'

Scan only src/ and lib/:

- uses: shashank7109/quelltest_lib@main
  with:
    target: 'src/'

Upload the JSON report as a CI artifact:

- uses: shashank7109/quelltest_lib@main
  id: quell

- uses: actions/upload-artifact@v4
  if: always()
  with:
    name: quell-report
    path: quell-report.json

Run Quell only when Python files change:

on:
  pull_request:
    paths:
      - "src/**/*.py"
      - "lib/**/*.py"

How it works

The action runs quell scan <target> --format github on the GitHub Actions runner. That command:

  1. Walks every .py file in the target directory
  2. Parses each file with the Python AST — no LLM, no network call
  3. Detects if/raise, try/except/raise, assert, and standalone raise patterns
  4. Checks which ones already have a corresponding test
  5. Emits ::warning file=...,line=...,title=...::guard text annotations (visible inline in the diff)
  6. Writes quell-report.json

The PR comment step reads that JSON and posts a formatted markdown table.

Want Quell installed on every repo in your org automatically, with no YAML to add? See the GitHub App guide — one install covers everything.