CLI

Diff и CI

Сравнение отчёта с базовым и подключение ranklint к пайплайнам GitLab и GitHub.

ranklint diff

ФлагОписание
--baseпуть к report.json или git-ref — тогда отчёт достаётся из артефактов CI
--currentтекущий report.json
--reportermarkdown | json
--outputв файл

CI-адаптер по окружению: GITHUB_ACTIONS=true → GitHub (артефакт по имени, zip распаковывается встроенным ридером), иначе GitLab (job-артефакт ветки). Политика ошибок: нет CI-контекста → warn + полный отчёт «first run» (base не найден — не ошибка); ошибка загрузки (401/403/сеть) → падение, чтобы протухший токен не маскировался вечным first run. Exit 1 только при новых error-issues.

Diff и CI

Ключ проблемы: checkId + url без origin + selector — стабилен между окружениями (UAT сравнивается с prod). diffReports → newIssues / fixedIssues / pagesDelta.

Хранилища базовых отчётов (ReportStorage): fs (директория JSON, latest по mtime), GitLab artifacts (read-only, по job-артефакту ветки), GitHub artifacts (read-only: список по имени, фильтр по ветке, скачивание zip — свой минимальный zip-ридер: EOCD → central directory → inflateRawSync; битый вход → null, не исключение), S3 (для монитора; SDK — опциональный peer, любой S3-совместимый endpoint).

Готовые CI-пресеты: presets/gitlab-ci/seo.yml (джобы .ranklint-audit, .ranklint-diff с автокомментом в MR, .ranklint-lighthouse, .ranklint-monitor с кешем Playwright и отчётов) и presets/github-actions/seo.yml, presets/github-actions/monitor.yml (монитор по расписанию с кешем отчётов). Репортер github — аннотации в PR.

SARIF для GitHub Code Scanning

SARIF — формат, который GitHub читает на вкладке Security → Code scanning. ranklint audit --reporter sarif пишет документ SARIF 2.1.0: один run, tool.driver.name: ranklint, по правилу на каждый checkId с helpUri на доку правила, по результату на каждый issue с level (error / warning / note), URL страницы как location и стабильный partialFingerprints.primaryLocationLineHash из diff-ключа checkId + путь + selector, чтобы GitHub сохранял алерт между прогонами, а не заводил новый.

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

В переиспользуемом пресете presets/github-actions/seo.yml шаг включается инпутом sarif: true. Находки появляются в Security → Code scanning с фильтром по инструменту ranklint. Локации — абсолютные URL страниц, а не файлы репозитория: SARIF это допускает, алерты группируются по id правила.

Sticky-комментарий в PR и MR

markdownDiff начинает вывод скрытым маркером <!-- ranklint-diff -->. Пресеты используют его, чтобы обновлять прежний комментарий, а не добавлять новый на каждый прогон пайплайна.

GitLab: джоба .ranklint-diff проходит постранично GET /merge_requests/:iid/notes (per_page=100), находит note, тело которой начинается с маркера, и шлёт PUT .../notes/:note_id; если такой нет, остаётся POST. Для поиска нужен jq в образе и RANKLINT_GITLAB_TOKEN со scope api.

GitHub: шаг Comment on PR получает комментарии PR через actions/github-script, ищет тот же маркер и зовёт updateComment или createComment. Шагу нужен 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 достаёт базовый отчёт из артефактов CI: в GitLab — из job-артефакта ветки, в GitHub Actions — из артефакта ranklint-report (распаковка zip встроена). Отсутствующий base — не ошибка: diff деградирует до полного отчёта.