Skip to content

chore: bump kmp-toolkit to 00b8e0f #506

chore: bump kmp-toolkit to 00b8e0f

chore: bump kmp-toolkit to 00b8e0f #506

Workflow file for this run

name: Screenshots
# Self-maintaining Roborazzi baselines.
#
# Why this exists: pixel-exact baselines only match the environment they were recorded in. Recording them
# by hand on a laptop guarantees they drift from CI's Linux renderer (font antialiasing), which is what kept
# reding the old "verify" job. Instead, CI records the baselines *itself* and proposes them back
# (as a PR, since main requires the Quality Gate check), so:
# - a NEW screen automatically gets a baseline the first time it runs here,
# - a CHANGED screen self-heals (the new rendering is captured),
# - CI never fails for rendering reasons unrelated to code.
#
# CI's runner image renders deterministically run-to-run, so re-recording an unchanged screen produces a
# byte-identical PNG -> git sees no change -> no commit. Only genuinely new/changed screens get committed.
#
# On a PR the baselines are uploaded as an artifact for review instead of committed.
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch: # manual "refresh all baselines now" button in the Actions tab
concurrency:
group: screenshots-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write # allows the bot to push a refresh branch
pull-requests: write # allows the bot to open the baseline-refresh PR
jobs:
record:
name: Record & commit baselines
runs-on: ubuntu-latest
env:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
steps:
- name: Checkout
uses: actions/checkout@v7
with:
# versionCode derives from `git rev-list --count HEAD`. A shallow clone
# reports 1, which silently produced versionCode 2 on every published APK.
fetch-depth: 0
submodules: recursive
- name: Set up JDK 21
uses: actions/setup-java@v6
with:
java-version: '25'
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6
with:
cache-read-only: ${{ github.event_name == 'pull_request' }}
cache-cleanup: on-success
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
# noGms variant: gms Play Services maps crash the Robolectric fork.
- name: Record screenshots (regenerate baselines in the CI environment)
run: ./scripts/run-jvm-tests.sh recordRoborazziNoGmsDebug
# recordRoborazziNoGmsDebug excludes com.mileway.Screenshot*Test (app/build.gradle.kts's
# screenshotTestFilter — isolated into its own forked JVM, Z.5b) — that gallery was never
# gated by CI at all, which is how ScreenshotGalleryTest's Konnection/TripDraftOutbox crashes
# went unnoticed. This step is the actual gate: a real crash/error here fails the job before
# the baseline-refresh PR step below runs. ScreenshotGalleryTest force-records its own PNGs
# into docs/screenshots (see its class doc), so any change it makes is picked up by the
# existing "git add docs/screenshots" step next.
- name: Run screenshot gallery + catalog tests (crash/regression gate)
# This job RECORDS — the next step git-adds docs/screenshots and opens a refresh PR when
# they drift. Without this env var the tests take the compare path instead, write nothing,
# and fail against baselines the job was supposed to be producing. It has to be an env var,
# not a -P property: a Gradle property does not reach a forked test JVM, which is the same
# trap that left the whole capture pipeline silently no-op'ing for weeks.
env:
ROBORAZZI_RECORD: 'true'
run: ./scripts/run-jvm-tests.sh :app:screenshotTestNoGmsDebug
# main: baselines drifted. main is protected by the "Quality Gate required" ruleset, so the bot
# can't push straight to it — open a refresh PR instead (idempotent branch name per source SHA;
# re-runs force-push the same branch and reuse the open PR).
#
# KNOWN FRICTION — these PRs need a human click before they can merge.
# A PR opened with ${{ github.token }} does get `pull_request` workflow runs, but GitHub parks
# every one of them at `action_required` (the workflow-approval gate that exists to stop
# Actions from recursively triggering Actions). Until someone approves, the PR's
# statusCheckRollup is empty, so it can't satisfy the "Quality Gate required on main" ruleset
# and it sits BLOCKED. That is how 7 of these branches accumulated.
# Approve from the PR's Checks tab, or:
# gh api -X POST repos/$GITHUB_REPOSITORY/actions/runs/<run-id>/approve
# Verified 2026-07-26: branch -b21f02a has 5 pull_request runs, all `action_required`;
# branch -7032123 has the same 5 runs `success` (they were approved) and its PR merged.
#
# To remove the friction entirely, the PR must be created by a non-Actions identity — a
# fine-grained PAT or a GitHub App token in place of ${{ github.token }} below. A push
# trigger on the bot branch does NOT work: that push is itself GITHUB_TOKEN-generated and
# fires nothing (no bot branch has ever had a push-event run).
- name: Open baseline-refresh PR
if: github.event_name == 'push'
env:
GH_TOKEN: ${{ github.token }}
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add docs/screenshots
if git diff --cached --quiet; then
echo "Baselines already up to date — nothing to commit."
exit 0
fi
# Stable branch name, NOT per-SHA: the push below is a force-push, so one branch
# and one open PR get reused for every refresh. A ${GITHUB_SHA}-suffixed branch
# opened a fresh PR per commit to main, and they stacked up conflicting on the
# same PNGs (7 open at once in Kursi, 2 in Mileway on 2026-08-27).
branch="bot/refresh-screenshot-baselines"
git checkout -b "$branch"
git commit -m "chore(screenshots): refresh baselines for ${GITHUB_SHA::7}"
git push --force origin "$branch"
if ! gh pr list --head "$branch" --state open --json number --jq '.[0].number' | grep -q .; then
# PR creation needs Settings→Actions→"Allow GitHub Actions to create and approve pull
# requests". If that's off, don't fail the pipeline — the refresh branch is already
# pushed above; warn with the branch so a human can open the PR (or enable the setting).
gh pr create --base main --head "$branch" \
--title "chore(screenshots): refresh render-harness baselines" \
--body "Automated Roborazzi baseline refresh — screens changed on main and CI re-recorded them. Review the PNG diffs and merge." \
|| echo "::warning::Could not auto-open the baseline-refresh PR (branch pushed: $branch). Enable Settings→Actions→'Allow GitHub Actions to create and approve pull requests', or open the PR by hand."
fi
# PR: don't mutate the branch; surface the freshly rendered screenshots for human review.
- name: Upload screenshots (PR review)
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v7
# An artifact is a convenience; the account's 500 MB artifact quota must not fail the gate.
continue-on-error: true
with:
name: screenshots
path: docs/screenshots/
retention-days: 2