diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 66e027abcc..55f500cde2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,33 +1,87 @@ # Here lie dragons! # -# Note that there is no artifact step in this script. We do not want Paperclip -# jars to be built for every push & PR; our CI handles pushes to branches, while -# PRs can themselves link to Paperclip jars if it is necessary. Official such -# PRs will take use of testing builds. +# This action either builds the server or +# builds a paperclip jar to be updated in the body +# of the PR relating to this action. name: Build Paper -on: [push, pull_request] +on: + push: + pull_request: + types: + - opened + - reopened + - synchronize + - labeled jobs: - build: - # Only run on PRs if the source branch is on someone else's repo - if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} - runs-on: ubuntu-latest - strategy: - matrix: - java: [17] - fail-fast: true - steps: - - uses: actions/checkout@v3 - - name: JDK ${{ matrix.java }} - uses: actions/setup-java@v3.6.0 - with: - java-version: ${{ matrix.java }} - cache: 'gradle' - distribution: 'temurin' - - name: Patch and build - run: | - git config --global user.email "no-reply@github.com" - git config --global user.name "Github Actions" - ./gradlew applyPatches --stacktrace - ./gradlew build --stacktrace + build: + # Only run on PRs if the source branch is on someone else's repo and the pr is not labeled with `build-pr-jar` + if: github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name + runs-on: ubuntu-latest + strategy: + matrix: + java: [17] + fail-fast: true + steps: + - uses: actions/checkout@v3 + - name: JDK ${{ matrix.java }} + uses: actions/setup-java@v3.6.0 + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - name: Configure Build + uses: actions/github-script@v6 + id: determine + with: + script: | + const {owner, repo} = context.repo; + const event_name = "${{ github.event_name }}"; + const event = ${{ toJSON(github.event) }}; + const ref_type = "${{ github.ref_type }}"; + const ref_name = "${{ github.ref_name }}"; + const result = { + action: "build" + }; + + if (event_name === "push" && ref_type === "branch") { + const {data: pulls} = await github.rest.pulls.list({ owner, repo, head: `${owner}:${ref_name}`, state: "open" }); + const pull = pulls.find((pr) => !!pr.labels.find((l) => l.name === "build-pr-jar")); + if (pull) { + result["pr"] = pull.number; + result["action"] = "paperclip"; + core.info(`This is a push action but to a branch with an open PR with the build paperclip label (${JSON.stringify(result)})`); + return result; + } + } else if (event_name === "pull_request" && event.pull_request.labels.find((l) => l.name === "build-pr-jar")) { + result["pr"] = event.pull_request.number; + result["action"] = "paperclip"; + core.info(`This is a pull request action with a build paperclip label (${JSON.stringify(result)})`); + return result; + } + core.info("This will not build a paperclip jar"); + return result; + + - name: Apply Patches + run: | + git config --global user.email "no-reply@github.com" + git config --global user.name "Github Actions" + ./gradlew applyPatches --stacktrace + + - name: Build + if: fromJSON(steps.determine.outputs.result).action == 'build' + run: ./gradlew build --stacktrace + + - name: Create Paperclip Jar + if: fromJSON(steps.determine.outputs.result).action == 'paperclip' + run: ./gradlew createReobfPaperclipJar --stacktrace + + - name: Upload Paperclip Jar + if: fromJSON(steps.determine.outputs.result).action == 'paperclip' + uses: actions/upload-artifact@v3 + with: + name: paper-${{ fromJSON(steps.determine.outputs.result).pr }} + path: build/libs/paper-paperclip-*-reobf.jar diff --git a/.github/workflows/pr_comment.yml b/.github/workflows/pr_comment.yml new file mode 100644 index 0000000000..f0ca9b57a3 --- /dev/null +++ b/.github/workflows/pr_comment.yml @@ -0,0 +1,68 @@ +# This workflow run on the completion of the +# build workflow but only does anything if the +# triggering workflow uploaded an artifact. +# +# Do note that it is then the trigger workflow that +# determines if this will update the PR text body. All +# this workflow does is check if an uploaded artifact +# exists and there is a PR tied to the previous workflow. + +name: Comment on pull request +on: + workflow_run: + workflows: ['Build Paper'] + types: [completed] +jobs: + pr_comment: + if: github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v6 + with: + # This snippet is public-domain, taken from + # https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml + # Modified extensively by Machine_Maker + script: | + async function updatePR(owner, repo, issue_number, purpose, body) { + const { data } = await github.rest.issues.get({owner, repo, issue_number}); + core.info(JSON.stringify(data, null, 2)); + + const marker = ``; + + let new_body = data.body ? data.body.trim().split(marker)[0] : ""; + if (!new_body.trim()) { + new_body += `${marker}\n${body}` + } else { + new_body += `${marker}\n---\n${body}` + } + + core.info(`Updating the text body of PR #${issue_number} in ${owner}/${repo}`); + await github.rest.issues.update({owner, repo, issue_number, body: new_body}); + } + + const {owner, repo} = context.repo; + const run_id = ${{github.event.workflow_run.id}}; + const repo_id = ${{ github.event.repository.id }}; + + const pull_requests = ${{ toJSON(github.event.workflow_run.pull_requests) }}; + if (!pull_requests.length) { + return core.notice("This workflow doesn't have any pull requests!"); + } + const pull_request = pull_requests.find((pr) => pr.base.repo.id === repo_id); + if (!pull_request) { + return core.notice("This workflow doesn't match any pull request!"); + } + + const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, {owner, repo, run_id}); + if (!artifacts.length) { + return core.info("Skipping comment due to no artifact found"); + } + const artifact = artifacts.find((art) => art.name === `paper-${pull_request.number}`); + if (!artifact) { + return core.info("Skipping comment to no matching artifact found"); + } + + const link = `https://nightly.link/${owner}/${repo}/actions/artifacts/${artifact.id}.zip`; + const body = `Download the paperclip jar for this pull request: [${artifact.name}.zip](${link})`; + core.info(`Adding a link to ${link}`); + await updatePR(owner, repo, pull_request.number, "paperclip-pr-build", body);