diff --git a/.github/workflows/pr-playground.yml b/.github/workflows/pr-playground.yml new file mode 100644 index 0000000000..28ea7f55ad --- /dev/null +++ b/.github/workflows/pr-playground.yml @@ -0,0 +1,125 @@ +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 + + console.log(JSON.stringify(context.payload, null, 2)); + const { data: { artifacts } } = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + console.log(JSON.stringify(artifacts, null, 2)); + 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(); + + console.log(`PR number: ${prNumber}`); + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + }); + + 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); + diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index f69df0f58d..8c946eb0cb 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -140,6 +140,9 @@ jobs: with: name: ruby-wasm-install path: ${{ github.workspace }}/install.tar.gz + - name: Show Playground URL to try the build + run: | + echo "Try on Playground: https://ruby.github.io/play-ruby?run=$GITHUB_RUN_ID" >> $GITHUB_STEP_SUMMARY - name: Run basictest run: wasmtime run ./../build/miniruby --mapdir /::./ -- basictest/test.rb @@ -157,6 +160,16 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot if: ${{ failure() }} + # Workaround for https://github.com/orgs/community/discussions/25220 + - name: Save Pull Request number + if: ${{ github.event_name == 'pull_request' }} + run: echo "${{ github.event.pull_request.number }}" >> ./github-pr-info.txt + - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + if: ${{ github.event_name == 'pull_request' }} + with: + name: github-pr-info + path: github-pr-info.txt + defaults: run: working-directory: build