Diff & CI
ranklint diff
| Flag | Description |
|---|---|
--base | path to report.json or a git ref — then the report is pulled from CI artifacts |
--current | current report.json |
--reporter | markdown | json |
--output | to a file |
The CI adapter picks by environment: GITHUB_ACTIONS=true → GitHub (artifact by name, zip unpacked by a built-in reader), otherwise GitLab (branch job artifact). Error policy: no CI context → warn + full "first run" report (a missing base is not an error); a download error (401/403/network) → hard fail, so an expired token can't hide behind an eternal first run. Exit 1 only on new error issues.
Diff & CI
Issue key: checkId + url without origin + selector — stable across environments (UAT compares against prod). diffReports → newIssues / fixedIssues / pagesDelta.
Base report storages (ReportStorage): fs (a JSON directory, latest by mtime), GitLab artifacts (read-only, branch job artifact), GitHub artifacts (read-only: list by name, branch filter, zip download — a built-in minimal zip reader: EOCD → central directory → inflateRawSync; corrupt input → null, not an exception), S3 (for the monitor; the SDK is an optional peer, any S3-compatible endpoint).
Ready-made CI presets: presets/gitlab-ci/seo.yml (jobs .ranklint-audit, .ranklint-diff with an automatic MR comment, .ranklint-lighthouse, .ranklint-monitor with Playwright and report caches) and presets/github-actions/seo.yml, presets/github-actions/monitor.yml (scheduled monitor with report cache). The github reporter emits PR annotations.
SARIF for GitHub Code Scanning
SARIF is the format GitHub reads on the Security → Code scanning tab. ranklint audit --reporter sarif writes a SARIF 2.1.0 document: one run, tool.driver.name: ranklint, one rule per checkId with helpUri pointing at the rule docs, one result per issue with level (error / warning / note), the page URL as the location and a stable partialFingerprints.primaryLocationLineHash built from the diff key checkId + path + selector, so GitHub keeps an alert across runs instead of opening a new one.
ranklint audit --url "$URL" --reporter sarif --output ranklint.sarif
permissions:
security-events: write
steps:
- run: ranklint audit --url "$URL" --reporter sarif --output ranklint.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ranklint.sarif
category: ranklint
In the reusable preset presets/github-actions/seo.yml this is behind the sarif: true input. Findings land in Security → Code scanning, filtered by tool ranklint. Locations are absolute page URLs, not repository files, which SARIF allows; alerts are grouped by rule id.
Sticky comment in a PR or MR
markdownDiff starts its output with the hidden marker <!-- ranklint-diff -->. Presets use it to update the previous comment instead of appending a new one on every pipeline run.
GitLab: the .ranklint-diff job pages through GET /merge_requests/:iid/notes (per_page=100), picks the note whose body starts with the marker and sends PUT .../notes/:note_id; when nothing matches it falls back to POST. The lookup needs jq in the image and RANKLINT_GITLAB_TOKEN with api scope.
GitHub: the Comment on PR step lists the PR comments via actions/github-script, looks for the same marker and calls updateComment or createComment. The step needs pull-requests: write.
GitLab CI
include:
- remote: 'https://raw.githubusercontent.com/aakazancev/ranklint/main/presets/gitlab-ci/seo.yml'
seo:audit:
extends: .ranklint-audit
needs: [deploy:uat]
variables:
RANKLINT_URL: $CI_ENVIRONMENT_URL
ranklint diff --base main resolves the base report from CI artifacts: in GitLab — from the branch's job artifact, in GitHub Actions — from the ranklint-report artifact (zip extraction is built in). A missing base is not an error: diff degrades to a full report.