name: Post Playground link to PR on: pull_request_target: types: [labeled] workflow_run: workflows: ["WebAssembly"] types: [completed] jobs: post-summary: name: Post Playground link runs-on: ubuntu-latest permissions: pull-requests: write # Post a comment only if the PR status check is passed and the PR is labeled with `Playground`. # Triggered twice: when the PR is labeled and when PR build is passed. if: >- ${{ false || (true && github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'Playground')) || (true && github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request') }} steps: - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs/promises'); const buildWorkflowPath = '.github/workflows/wasm.yml'; const findSuccessfuBuildRun = async (pr) => { const opts = github.rest.actions.listWorkflowRunsForRepo.endpoint.merge({ owner: context.repo.owner, repo: context.repo.repo, status: 'success', branch: pr.head.ref, }); const runs = await github.paginate(opts); const buildRun = runs.find(run => run.path == buildWorkflowPath); return buildRun; } const postComment = async (body, pr) => { const { data: comments } = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pr.number, }); const commentOpts = { owner: context.repo.owner, repo: context.repo.repo, body: comment }; const existingComment = comments.find(comment => comment.body.startsWith(magicComment)); if (existingComment) { core.info(`Updating existing comment: ${existingComment.html_url}`); await github.rest.issues.updateComment({ ...commentOpts, comment_id: existingComment.id }); } else { await github.rest.issues.createComment({ ...commentOpts, issue_number: pr.number }); } } const derivePRNumber = async () => { if (context.payload.pull_request) { return context.payload.pull_request.number; } // Workaround for https://github.com/orgs/community/discussions/25220 const { data: { artifacts } } = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, run_id: context.payload.workflow_run.id, }); const artifact = artifacts.find(artifact => artifact.name == 'github-pr-info'); if (!artifact) { throw new Error('Cannot find github-pr-info.txt artifact'); } const { data } = await github.rest.actions.downloadArtifact({ owner: context.repo.owner, repo: context.repo.repo, artifact_id: artifact.id, archive_format: 'zip', }); await fs.writeFile('pr-info.zip', Buffer.from(data)); await exec.exec('unzip', ['pr-info.zip']); return await fs.readFile('github-pr-info.txt', 'utf8'); } const prNumber = await derivePRNumber(); const { data: pr } = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: prNumber, }); core.info(`Checking if the PR ${prNumber} is labeled with Playground...`); if (!pr.labels.some(label => label.name == 'Playground')) { core.info(`The PR is not labeled with Playground.`); return; } core.info(`Checking if the build is successful for ${pr.head.ref} in ${pr.head.repo.owner.login}/${pr.head.repo.name}...`); const buildRun = await findSuccessfuBuildRun(pr); if (!buildRun) { core.info(`No successful build run found for ${buildWorkflowPath} on ${pr.head.ref} yet.`); return; } core.info(`Found a successful build run: ${buildRun.html_url}`); const runLink = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`; const magicComment = ``; const comment = `${magicComment} **Try on Playground**: https://ruby.github.io/play-ruby?run=${buildRun.id} This is an automated comment by [\`pr-playground.yml\`](${runLink}) workflow. `; core.info(`Comment: ${comment}`); await postComment(comment, pr);