Skip to content

Publish Test Results #44974

Publish Test Results

Publish Test Results #44974

name: Publish Test Results
on:
workflow_run:
workflows: ["tests 1", "tests 2", "tests others", "MCP"]
types:
- completed
permissions: {}
jobs:
merge-reports:
permissions:
pull-requests: write
checks: write
statuses: write
contents: read # This is required for actions/checkout to succeed
if: ${{ github.event.workflow_run.event == 'pull_request' || github.event.workflow_run.event == 'push' }}
runs-on: ubuntu-latest
outputs:
pr_number: ${{ steps.pr.outputs.number }}
has_failures: ${{ steps.failures.outputs.has_failures }}
triage_allowed: ${{ steps.pr.outputs.triage_allowed }}
env:
MARKDOWN_OUTPUT_FILE: ${{ github.workspace }}/report.md
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: lts/*
- run: npm ci
- run: npm run build
- name: Download blob report artifact
uses: ./.github/actions/download-artifact
with:
namePrefix: 'blob-report'
path: 'all-blob-reports'
- name: Merge reports
run: |
npx playwright merge-reports --config .github/workflows/merge.config.ts ./all-blob-reports
env:
NODE_OPTIONS: --max-old-space-size=8192
WORKFLOW_RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
- name: Detect failures
id: failures
run: |
if [ -f "$MARKDOWN_OUTPUT_FILE" ] && grep -qE '\*\*[0-9]+ failed\*\*' "$MARKDOWN_OUTPUT_FILE"; then
echo "has_failures=true" >> "$GITHUB_OUTPUT"
else
echo "has_failures=false" >> "$GITHUB_OUTPUT"
fi
- name: Upload HTML report
id: upload-report
uses: actions/upload-artifact@v7
with:
path: playwright-report/index.html
archive: false # Upload as a single, browser-openable file (no zip)
retention-days: 30
# The triggering workflow ran on a pull_request event, but workflow_run.pull_requests is
# empty for PRs from forks, so resolve the number from the head ref instead. gh's head
# filter wants "owner:branch" for forks but a bare branch for same-repo PRs.
- name: Resolve PR number and triage allow-list
if: ${{ github.event.workflow_run.event == 'pull_request' }}
id: pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HEAD_REF: ${{ github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch || format('{0}:{1}', github.event.workflow_run.head_repository.owner.login, github.event.workflow_run.head_branch) }}
run: |
NUMBER=$(gh pr view --repo "${{ github.repository }}" "$HEAD_REF" --json number --jq '.number' 2>/dev/null || true)
echo "number=$NUMBER" >> "$GITHUB_OUTPUT"
AUTHOR=$(gh pr view --repo "${{ github.repository }}" "$HEAD_REF" --json author --jq '.author.login' 2>/dev/null || true)
ALLOWED="github-actions[bot] pavelfeldman yury-s dgozman Skn0tt dcrousso"
TRIAGE_ALLOWED=false
for a in $ALLOWED; do
if [ "$a" = "$AUTHOR" ]; then TRIAGE_ALLOWED=true; break; fi
done
echo "triage_allowed=$TRIAGE_ALLOWED" >> "$GITHUB_OUTPUT"
- name: Post report comment to PR
if: ${{ steps.pr.outputs.number }}
uses: actions/github-script@v8
env:
HTML_REPORT_URL: ${{ steps.upload-report.outputs.artifact-url }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { postReportComment } = require('./tests/config/postReportComment');
await postReportComment({
github,
context,
core,
reportFile: process.env.MARKDOWN_OUTPUT_FILE,
prNumber: +process.env.PR_NUMBER,
reportUrl: process.env.HTML_REPORT_URL,
});
- name: Publish Report URL as Commit Status
uses: actions/github-script@v9
with:
script: |
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: '${{ github.event.workflow_run.head_sha }}',
state: 'success',
target_url: '${{ steps.upload-report.outputs.artifact-url }}',
context: 'HTML Report (${{ github.event.workflow_run.name }})',
});
triage:
needs: merge-reports
if: ${{ needs.merge-reports.outputs.has_failures == 'true' && needs.merge-reports.outputs.pr_number && needs.merge-reports.outputs.triage_allowed == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
copilot-requests: write
outputs:
has_draft: ${{ steps.triage.outputs.has_draft }}
pr_number: ${{ needs.merge-reports.outputs.pr_number }}
env:
PR_NUMBER: ${{ needs.merge-reports.outputs.pr_number }}
GH_TOKEN: ${{ github.token }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: "24"
- name: Install Copilot CLI
run: npm install -g @github/copilot
- name: Triage failures with Copilot CLI
id: triage
env:
COPILOT_GITHUB_TOKEN: ${{ github.token }}
run: |
mkdir -p output
PROMPT=$(cat <<EOF
Come up with a verdict on the CI test failures on pull request #$PR_NUMBER of ${{ github.repository }}: are they likely caused by this PR? Follow the pr-ci-triage guide (.github/workflows/pr-ci-triage.md) for the analysis.
Write your verdict to output/triage.md as a PR comment, in the format the guide specifies and the playwright-bot-voice register (.claude/skills/playwright-bot-voice/SKILL.md).
Do not post anything yourself — a later workflow step posts output/triage.md.
EOF
)
copilot \
--allow-all-tools \
--allow-all-paths \
--no-ask-user \
--enable-all-github-mcp-tools \
--share=output/copilot-session.md \
--model claude-opus-4.8 \
--max-ai-credits 500 \
-p "$PROMPT"
if [ -s output/triage.md ]; then
echo "has_draft=true" >> "$GITHUB_OUTPUT"
else
echo "has_draft=false" >> "$GITHUB_OUTPUT"
fi
- name: Add session transcript to job summary
if: ${{ always() }}
run: |
{
echo "## CI triage session transcript (PR #$PR_NUMBER)"
echo ''
cat "output/copilot-session.md" 2>/dev/null || echo "(no transcript)"
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload output
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: ci-triage-${{ needs.merge-reports.outputs.pr_number }}
path: output/triage.md
if-no-files-found: warn
post:
needs: triage
if: needs.triage.outputs.has_draft == 'true'
runs-on: ubuntu-latest
permissions:
pull-requests: write
env:
PR_NUMBER: ${{ needs.triage.outputs.pr_number }}
GH_TOKEN: ${{ github.token }}
WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download triage output
uses: actions/download-artifact@v4
with:
name: ci-triage-${{ needs.triage.outputs.pr_number }}
path: output
- name: Post triage comment
uses: actions/github-script@v9
with:
script: |
const fs = require('fs');
const { collapsePreviousComments } = require('./tests/config/postReportComment');
const sentinel = `<!-- playwright-ci-triage --><!-- ${context.payload.workflow_run.name} -->`;
const prNumber = +process.env.PR_NUMBER;
await collapsePreviousComments(github, context, prNumber, sentinel);
const triage = fs.readFileSync('output/triage.md', 'utf8');
const body = `${triage}\n\n<sub>Triaged by the Playwright bot - [agent run](${process.env.WORKFLOW_URL})</sub>\n${sentinel}\n`;
await github.rest.issues.createComment({
...context.repo,
issue_number: prNumber,
body,
});