Repository navigation
Screenshot failure comment #98
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-FileCopyrightText: 2026 LibreCode coop and contributors | |
| # SPDX-License-Identifier: AGPL-3.0-or-later | |
| name: Screenshot failure comment | |
| on: | |
| workflow_run: | |
| workflows: | |
| - Playwright | |
| types: | |
| - completed | |
| permissions: | |
| actions: read | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| comment: | |
| if: >- | |
| github.event.workflow_run.event == 'pull_request' && | |
| github.event.workflow_run.conclusion == 'failure' && | |
| github.event.workflow_run.pull_requests[0].number != null | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download screenshot artifacts | |
| id: artifacts | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RUN_ID: ${{ github.event.workflow_run.id }} | |
| GH_REPO: ${{ github.repository }} | |
| run: | | |
| if gh run download "$RUN_ID" --repo "$GH_REPO" --name screenshot-diff --dir screenshot-artifacts; then | |
| echo "found=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "found=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Publish screenshot report | |
| if: steps.artifacts.outputs.found == 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }} | |
| RUN_ID: ${{ github.event.workflow_run.id }} | |
| REPORT_BRANCH: screenshot-reports | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if ! gh api "repos/$GH_REPO/git/ref/heads/$REPORT_BRANCH" >/dev/null 2>&1; then | |
| default_branch="$(gh api "repos/$GH_REPO" --jq '.default_branch')" | |
| default_sha="$(gh api "repos/$GH_REPO/git/ref/heads/$default_branch" --jq '.object.sha')" | |
| gh api --method POST "repos/$GH_REPO/git/refs" \ | |
| -f ref="refs/heads/$REPORT_BRANCH" \ | |
| -f sha="$default_sha" >/dev/null | |
| fi | |
| upload_png() { | |
| local file="$1" | |
| local repo_path="$2" | |
| if [[ "$(file --brief --mime-type "$file")" != "image/png" ]]; then | |
| echo "Refusing to publish non-PNG file: $file" >&2 | |
| exit 1 | |
| fi | |
| if (( $(stat -c '%s' "$file") > 5242880 )); then | |
| echo "Refusing to publish PNG larger than 5 MiB: $file" >&2 | |
| exit 1 | |
| fi | |
| local encoded | |
| encoded="$(base64 -w 0 "$file")" | |
| local existing_sha | |
| existing_sha="$(gh api "repos/$GH_REPO/contents/$repo_path?ref=$REPORT_BRANCH" --jq '.sha' 2>/dev/null || true)" | |
| if [[ -n "$existing_sha" ]]; then | |
| jq -n \ | |
| --arg message "ci: update screenshot report for PR #$PR_NUMBER" \ | |
| --arg content "$encoded" \ | |
| --arg branch "$REPORT_BRANCH" \ | |
| --arg sha "$existing_sha" \ | |
| '{message: $message, content: $content, branch: $branch, sha: $sha}' | | |
| gh api --method PUT "repos/$GH_REPO/contents/$repo_path" --input - >/dev/null | |
| else | |
| jq -n \ | |
| --arg message "ci: add screenshot report for PR #$PR_NUMBER" \ | |
| --arg content "$encoded" \ | |
| --arg branch "$REPORT_BRANCH" \ | |
| '{message: $message, content: $content, branch: $branch}' | | |
| gh api --method PUT "repos/$GH_REPO/contents/$repo_path" --input - >/dev/null | |
| fi | |
| } | |
| report_path="pr-$PR_NUMBER" | |
| upload_png screenshot-artifacts/demo-screenshot-expected.png "$report_path/expected.png" | |
| upload_png screenshot-artifacts/demo-screenshot-current.png "$report_path/generated.png" | |
| has_diff=false | |
| if [[ -f screenshot-artifacts/demo-screenshot-diff.png ]]; then | |
| upload_png screenshot-artifacts/demo-screenshot-diff.png "$report_path/diff.png" | |
| has_diff=true | |
| fi | |
| raw_base="https://raw.githubusercontent.com/$GH_REPO/$REPORT_BRANCH/$report_path" | |
| run_url="https://github.com/$GH_REPO/actions/runs/$RUN_ID" | |
| marker='<!-- readme-screenshot-report -->' | |
| summary_line="Screenshot output differs from the committed README image." | |
| if [[ -f screenshot-artifacts/demo-screenshot-report.json ]]; then | |
| report_type="$(jq -r '.type' screenshot-artifacts/demo-screenshot-report.json)" | |
| if [[ "$report_type" == "pixels" ]]; then | |
| changed_pixels="$(jq -r '.changedPixels' screenshot-artifacts/demo-screenshot-report.json)" | |
| total_pixels="$(jq -r '.totalPixels' screenshot-artifacts/demo-screenshot-report.json)" | |
| ratio="$(jq -r '.ratio * 100' screenshot-artifacts/demo-screenshot-report.json)" | |
| max_ratio="$(jq -r '.maxDiffRatio * 100' screenshot-artifacts/demo-screenshot-report.json)" | |
| summary_line="$(printf '**Difference:** %.4f%% · **Allowed:** %.4f%% \\n%s of %s pixels differ.' "$ratio" "$max_ratio" "$changed_pixels" "$total_pixels")" | |
| elif [[ "$report_type" == "size" ]]; then | |
| committed_size="$(jq -r '"\(.committed.width)x\(.committed.height)"' screenshot-artifacts/demo-screenshot-report.json)" | |
| generated_size="$(jq -r '"\(.generated.width)x\(.generated.height)"' screenshot-artifacts/demo-screenshot-report.json)" | |
| summary_line="**Size changed:** $committed_size → $generated_size" | |
| fi | |
| fi | |
| cat > screenshot-comment.md <<EOF | |
| $marker | |
| ## README screenshot check failed | |
| $summary_line | |
| [View workflow run]($run_url) | |
| ### Visual diff | |
| EOF | |
| if [[ "$has_diff" == "true" ]]; then | |
| cat >> screenshot-comment.md <<EOF | |
|  | |
| EOF | |
| else | |
| cat >> screenshot-comment.md <<'EOF' | |
| A pixel diff is not available because the image dimensions changed. | |
| EOF | |
| fi | |
| cat >> screenshot-comment.md <<EOF | |
| <details> | |
| <summary>Expected screenshot</summary> | |
|  | |
| </details> | |
| <details> | |
| <summary>Generated screenshot</summary> | |
|  | |
| </details> | |
| If the visual change is expected, run: | |
| \`npm run screenshots:update\` | |
| EOF | |
| existing_comment_id="$( | |
| gh api "repos/$GH_REPO/issues/$PR_NUMBER/comments" --paginate \ | |
| --jq '.[] | select(.body | contains("<!-- readme-screenshot-report -->")) | .id' | | |
| head -n 1 | |
| )" | |
| if [[ -n "$existing_comment_id" ]]; then | |
| jq -n --rawfile body screenshot-comment.md '{body: $body}' | | |
| gh api --method PATCH "repos/$GH_REPO/issues/comments/$existing_comment_id" --input - >/dev/null | |
| else | |
| gh pr comment "$PR_NUMBER" --repo "$GH_REPO" --body-file screenshot-comment.md | |
| fi | |
| cat >> "$GITHUB_STEP_SUMMARY" <<EOF | |
| ## README screenshot check failed | |
| $summary_line | |
| [Open pull request](https://github.com/$GH_REPO/pull/$PR_NUMBER) · [View workflow run]($run_url) | |
| ### Visual diff | |
| EOF | |
| if [[ "$has_diff" == "true" ]]; then | |
| cat >> "$GITHUB_STEP_SUMMARY" <<EOF | |
|  | |
| EOF | |
| else | |
| cat >> "$GITHUB_STEP_SUMMARY" <<'EOF' | |
| A pixel diff is not available because the image dimensions changed. | |
| EOF | |
| fi | |
| cat >> "$GITHUB_STEP_SUMMARY" <<EOF | |
| <details> | |
| <summary>Expected screenshot</summary> | |
|  | |
| </details> | |
| <details> | |
| <summary>Generated screenshot</summary> | |
|  | |
| </details> | |
| EOF |