179 lines
8.2 KiB
YAML
179 lines
8.2 KiB
YAML
name: publish Playwright report
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: [ci]
|
|
types: [completed]
|
|
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
issues: write
|
|
pull-requests: write
|
|
|
|
concurrency:
|
|
group: playwright-publication
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
publish:
|
|
if: >-
|
|
(github.event.workflow_run.conclusion == 'success' ||
|
|
github.event.workflow_run.conclusion == 'failure' ||
|
|
github.event.workflow_run.conclusion == 'timed_out') &&
|
|
(github.event.workflow_run.event == 'pull_request' ||
|
|
(github.event.workflow_run.event == 'push' &&
|
|
github.event.workflow_run.head_branch == 'main'))
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
# workflow_run has repository secrets. Always use trusted default-branch code here;
|
|
# never check out or execute the contributor's pull-request revision.
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
ref: ${{ github.event.repository.default_branch }}
|
|
persist-credentials: false
|
|
- uses: pnpm/action-setup@v4
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
- run: pnpm install --frozen-lockfile
|
|
- name: Read Playwright job result
|
|
id: playwright
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
RUN_ID: ${{ github.event.workflow_run.id }}
|
|
shell: bash
|
|
run: |
|
|
result="$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/jobs?per_page=100" \
|
|
--jq '[.jobs[] | select(.name == "Web E2E / Web E2E") | .conclusion] | unique | if length == 1 then .[0] else error("expected exactly one Playwright job") end')"
|
|
case "$result" in
|
|
success|failure) ;;
|
|
timed_out) ;;
|
|
*) echo "Unexpected Playwright job conclusion: $result" >&2; exit 1 ;;
|
|
esac
|
|
echo "job_result=$result" >> "$GITHUB_OUTPUT"
|
|
if [[ "$result" == "timed_out" ]]; then result="failure"; fi
|
|
echo "result=$result" >> "$GITHUB_OUTPUT"
|
|
- name: Resolve pull request
|
|
if: github.event.workflow_run.event == 'pull_request'
|
|
id: pull_request
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
|
HEAD_OWNER: ${{ github.event.workflow_run.head_repository.owner.login }}
|
|
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
shell: bash
|
|
run: |
|
|
pulls="$(gh api --method GET \
|
|
"repos/${GITHUB_REPOSITORY}/pulls?state=all&head=${HEAD_OWNER}:${HEAD_BRANCH}&per_page=100")"
|
|
number="$(jq -r --arg sha "$HEAD_SHA" \
|
|
'[.[] | select(.head.sha == $sha)] | if length == 1 then .[0].number else empty end' \
|
|
<<<"$pulls")"
|
|
if [[ -z "$number" ]]; then
|
|
echo "::warning::Could not resolve a pull request for ${HEAD_OWNER}:${HEAD_BRANCH} at ${HEAD_SHA}."
|
|
fi
|
|
echo "number=$number" >> "$GITHUB_OUTPUT"
|
|
- name: Check for Playwright artifact
|
|
id: artifact
|
|
env:
|
|
ARTIFACT_NAME: playwright-artifacts-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
PLAYWRIGHT_JOB_RESULT: ${{ steps.playwright.outputs.job_result }}
|
|
RUN_ID: ${{ github.event.workflow_run.id }}
|
|
shell: bash
|
|
run: |
|
|
artifacts="$(gh api --method GET \
|
|
"repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/artifacts?name=${ARTIFACT_NAME}")"
|
|
count="$(jq --arg name "$ARTIFACT_NAME" \
|
|
'[.artifacts[] | select(.name == $name and .expired == false)] | length' \
|
|
<<<"$artifacts")"
|
|
if [[ "$count" == "1" ]]; then
|
|
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
elif [[ "$count" == "0" && "$PLAYWRIGHT_JOB_RESULT" == "timed_out" ]]; then
|
|
echo "::warning::The timed-out Playwright job ended before it uploaded an artifact. Publishing an empty gallery."
|
|
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "Expected exactly one unexpired Playwright artifact; found $count." >&2
|
|
exit 1
|
|
fi
|
|
- name: Download Playwright artifacts
|
|
if: steps.artifact.outputs.exists == 'true'
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: playwright-artifacts-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}
|
|
path: .
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
run-id: ${{ github.event.workflow_run.id }}
|
|
- name: Publish trusted Playwright screenshot gallery
|
|
id: publish
|
|
env:
|
|
AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
|
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
|
|
AWS_DEFAULT_REGION: ${{ vars.S3_REGION }}
|
|
AWS_EC2_METADATA_DISABLED: "true"
|
|
S3_BUCKET: ${{ vars.S3_BUCKET }}
|
|
S3_ENDPOINT: ${{ vars.S3_ENDPOINT }}
|
|
PLAYWRIGHT_PUBLIC_BASE_URL: ${{ vars.PLAYWRIGHT_PUBLIC_BASE_URL }}
|
|
PLAYWRIGHT_RESULT: ${{ steps.playwright.outputs.result }}
|
|
PLAYWRIGHT_RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }}
|
|
PLAYWRIGHT_RUN_ID: ${{ github.event.workflow_run.id }}
|
|
PLAYWRIGHT_RUN_NUMBER: ${{ github.event.workflow_run.run_number }}
|
|
PLAYWRIGHT_RUN_URL: ${{ github.event.workflow_run.html_url }}
|
|
PLAYWRIGHT_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
PLAYWRIGHT_EVENT: ${{ github.event.workflow_run.event }}
|
|
PLAYWRIGHT_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
|
PLAYWRIGHT_PR_NUMBER: ${{ steps.pull_request.outputs.number }}
|
|
PLAYWRIGHT_REPOSITORY_URL: ${{ github.server_url }}/${{ github.repository }}
|
|
PLAYWRIGHT_PUBLISH_REPORT: ${{ github.event.workflow_run.event == 'push' }}
|
|
run: bash scripts/publish-playwright-report.sh
|
|
- name: Link screenshot gallery from pull request
|
|
if: >-
|
|
github.event.workflow_run.event == 'pull_request' &&
|
|
steps.pull_request.outputs.number != '' &&
|
|
steps.publish.outputs.latest_pr_run == 'true'
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
PLAYWRIGHT_PUBLIC_BASE_URL: ${{ vars.PLAYWRIGHT_PUBLIC_BASE_URL }}
|
|
PR_NUMBER: ${{ steps.pull_request.outputs.number }}
|
|
RUN_URL: ${{ github.event.workflow_run.html_url }}
|
|
SHA: ${{ github.event.workflow_run.head_sha }}
|
|
shell: bash
|
|
run: |
|
|
if [[ ! "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]]; then
|
|
echo "PR_NUMBER must be a positive integer." >&2
|
|
exit 1
|
|
fi
|
|
public_base_url="${PLAYWRIGHT_PUBLIC_BASE_URL%/}"
|
|
gallery_url="$public_base_url/prs/$PR_NUMBER/index.html"
|
|
review_path="$GITHUB_WORKSPACE/.tmp/playwright-dashboard/screenshots/review.json"
|
|
if [[ ! -f "$review_path" ]]; then
|
|
echo "Missing Playwright review manifest at $review_path." >&2
|
|
exit 1
|
|
fi
|
|
changed_paths_file="$(mktemp)"
|
|
gh api --paginate \
|
|
"repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/files?per_page=100" \
|
|
--jq '.[].filename' > "$changed_paths_file"
|
|
body="$(
|
|
PLAYWRIGHT_GALLERY_URL="$gallery_url" \
|
|
PLAYWRIGHT_DASHBOARD_URL="$public_base_url/index.html" \
|
|
PLAYWRIGHT_RUN_URL="$RUN_URL" \
|
|
PLAYWRIGHT_SHA="$SHA" \
|
|
pnpm exec tsx packages/testkit/src/cli/build-playwright-pr-screenshot-comment.ts \
|
|
"$review_path" \
|
|
"$changed_paths_file"
|
|
)"
|
|
marker="<!-- rakazo-playwright-screenshots -->"
|
|
comment_id="$(gh api --paginate --slurp \
|
|
"repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments?per_page=100" | \
|
|
jq -r --arg marker "$marker" \
|
|
'[.[][] | select(.user.login == "github-actions[bot]" and (.body | contains($marker)))] | last | .id // empty')"
|
|
payload="$(jq -n --arg body "$body" '{body: $body}')"
|
|
if [[ -n "$comment_id" ]]; then
|
|
gh api --method PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${comment_id}" --input - <<<"$payload"
|
|
else
|
|
gh api --method POST "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --input - <<<"$payload"
|
|
fi
|