Skip to content

Instantly share code, notes, and snippets.

@nsmirosh
Last active May 31, 2026 18:54
Show Gist options
  • Select an option

  • Save nsmirosh/bccecc79b5a5391f76e8cf3adb1eade4 to your computer and use it in GitHub Desktop.

Select an option

Save nsmirosh/bccecc79b5a5391f76e8cf3adb1eade4 to your computer and use it in GitHub Desktop.
Skill for Paparazzi Github Actions CI integration with Git LFS
name paparazzi-github-actions
description Set up Paparazzi screenshot testing in GitHub Actions CI, with snapshot images stored in Git LFS so they don't bloat the repo. Use this whenever a user wants to run Paparazzi screenshot tests on CI, get a failure report as an artifact, move existing snapshot PNGs into Git LFS, or wire up a GitHub Actions workflow for verifying screenshots — even if they only mention "screenshot tests on CI", "Paparazzi on GitHub", or "stop my snapshots bloating the repo".
metadata
author keywords
Mykola Miroshnychenko
Screenshot testing
CI
Continuous integration
Paparazzi
Github
Github Actions
Git LFS

Paparazzi screenshot testing in GitHub Actions

This skill wires up an existing Paparazzi setup to run on GitHub Actions, stores snapshot images in Git LFS to keep the repository small, and uploads a Paparazzi report as a CI artifact when a screenshot test fails.

Git LFS matters here because a real app accumulates hundreds or thousands of snapshot PNGs. Committing them as normal git blobs bloats clone size and hits per-push and per-repo size limits. LFS stores the binaries on a separate server and keeps only small text pointers in history.

Prerequisites

Verify all three before doing anything. If any fail, stop and tell the user what's missing.

  1. Paparazzi Gradle plugin is applied. Confirm the plugin is declared in the relevant module's build.gradle(.kts). Check the latest version at https://cashapp.github.io/paparazzi/changelog/ and suggest updating if it's old.

  2. Git LFS is installed on the machine. Run git lfs version to check. If it's missing, ask the user for permission before installing. Then:

    • macOS: brew install git-lfs
    • Debian/Ubuntu: sudo apt-get install git-lfs
    • Other: see https://git-lfs.com/
  3. Paparazzi tests and their generated images already exist. Search the test sources for paparazzi.snapshot { to find the tests. For each test, confirm the matching image exists under app/src/test/snapshots/images. Snapshot filenames end with the test method name. For example:

    @Test
    fun testListItemWithLongNameFollowing() {
        paparazzi.snapshot {
            ListItemWithLongNameFollowing()
        }
    }

    …must have a corresponding file ending in ..._testListItemWithLongNameFollowing.png in app/src/test/snapshots/images.

    If tests or images are missing, abort and ask the user whether they want screenshot tests created first.

Steps

Step 1 — Ensure a workflow file exists

Workflows live in .github/workflows/ (note the leading dot). If that directory or a workflow file doesn't exist, create .github/workflows/screenshot-tests.yml using the reference workflow below, then go to Step 3.

If a workflow file already exists, do not overwrite it — go to Step 2 instead.

Reference workflow:

name: Screenshot Tests

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  paparazzi:
    runs-on: ubuntu-latest
    steps:
      # Checks out the repo. lfs: true pulls the real PNGs, not just LFS pointers.
      - name: Checkout Repo
        uses: actions/checkout@v4
        with:
          lfs: true

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: 17

      - name: Set up Gradle
        uses: gradle/actions/setup-gradle@v4

      - name: Verify Paparazzi screenshots
        run: ./gradlew :app:verifyPaparazziDebug

      # Paparazzi only emits a report on failure; upload it so the diff is inspectable.
      - name: Upload Paparazzi failure report
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: paparazzi-report
          path: app/build/reports/tests/testDebugUnitTest/
          if-no-files-found: ignore

Adjust :app:verifyPaparazziDebug and the report path to match the user's module name and build variant (e.g. :feature-profile:verifyPaparazziRelease → feature-profile/build/reports/tests/testReleaseUnitTest/).

Step 2 — Amend an existing workflow

When a workflow already exists, make two edits to the job that runs the tests:

  1. Add lfs: true to the checkout step so CI pulls the actual images instead of LFS pointers (without this, every verify will fail):

    - name: Checkout Repo
      uses: actions/checkout@v4
      with:
        lfs: true
  2. Ensure the workflow runs ./gradlew :app:verifyPaparazziDebug and uploads the report on failure. If the verify and upload-artifact steps from the reference workflow are absent, add them (adjusting module/variant names).

Step 3 — Initialize LFS and track snapshots

Run from the repository root:

# One-time init of LFS hooks for this user
git lfs install

# Track every PNG under any snapshots directory
git lfs track "**/snapshots/**/*.png"

# Commit the tracking config
git add .gitattributes

# Optional: avoids LFS marking files read-only, which speeds up checkouts
git config lfs.setlockablereadonly false

git lfs track only affects files committed after this point — it does not retroactively move already-committed images into LFS. That's handled in Step 4.

Step 4 — Move existing images into LFS

Determine whether the snapshot PNGs are already committed to git history:

git log --oneline -- "**/snapshots/**/*.png" | head -1

Case A — images already committed (the common case). Rewrite history to move them into LFS:

git lfs migrate import --include="**/snapshots/**/*.png"

This rewrites commits, so it changes commit hashes. On a shared branch, coordinate with the team and expect a force-push (git push --force-with-lease). Add --everything to migrate across all branches and tags rather than just the current branch. Warn the user about the history rewrite before running this.

Case B — images present on disk but never committed. Just stage and commit them normally; git lfs track from Step 3 routes them into LFS automatically:

git add .
git commit -m "Track Paparazzi snapshots with Git LFS"

Step 5 — Verify and push

Confirm the images are now LFS-tracked rather than stored inline:

git lfs ls-files

Each snapshot PNG should appear in the list. To double-check a single file shows a pointer (three lines: version, oid, size) instead of binary content:

git show HEAD:app/src/test/snapshots/images/<some_snapshot>.png

Then push (git push, or git push --force-with-lease if Step 4 Case A rewrote history). On push you should see LFS upload progress, e.g. Uploading LFS objects: 100% (6/6), 162 KB | 0 B/s, done.

Push the branch and open/update a PR so the workflow runs. On the first green run, the setup is complete: CI checks out real images via LFS, runs verifyPaparazziDebug, and uploads a downloadable HTML report only when a screenshot regression is detected.

Notes

  • GitHub-hosted Ubuntu runners ship with Git LFS preinstalled, so no install step is needed in the workflow — only lfs: true on checkout.
  • Paparazzi produces a report only on failure. A passing run uploads nothing, which is expected.
  • The failure report is an index.html plus assets under the test report path; the uploaded artifact is a zip the user downloads and opens locally.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment