From 4fb60bdd5a805ba0adca5e7013e27d6bbd8110c3 Mon Sep 17 00:00:00 2001 From: Aria Minaei Date: Sun, 5 Feb 2023 15:05:54 +0100 Subject: [PATCH] Implement chat-ops for insiders release --- .github/workflows/publish-prerelease.yml | 24 ---- .github/workflows/release-insiders.yml | 157 +++++++++++++++++++++++ package.json | 3 + scripts/prerelease.mjs | 15 ++- yarn.lock | 27 ++++ 5 files changed, 198 insertions(+), 28 deletions(-) delete mode 100644 .github/workflows/publish-prerelease.yml create mode 100644 .github/workflows/release-insiders.yml diff --git a/.github/workflows/publish-prerelease.yml b/.github/workflows/publish-prerelease.yml deleted file mode 100644 index 2635865..0000000 --- a/.github/workflows/publish-prerelease.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: 'Publish Prerelease' -on: - workflow_dispatch: - -jobs: - publish: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - uses: ./.github/actions/yarn-nm-install - - name: Build the Theatre.js packages - run: yarn build - - name: Update .yarnrc.yml with the auth config for the npmPublishRegistry - run: cat .github/.yarnrc.publish.yml >> .yarnrc.yml - - name: Publish the Theatre.js packages - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - # LATEST_COMMIT_HASH: ${{ github.event.pull_request.head.sha }} - run: yarn zx scripts/prerelease.mjs diff --git a/.github/workflows/release-insiders.yml b/.github/workflows/release-insiders.yml new file mode 100644 index 0000000..1ea6c41 --- /dev/null +++ b/.github/workflows/release-insiders.yml @@ -0,0 +1,157 @@ +name: Release insiders + +# This workflow is triggered when a comment is created on a PR that contains the string "/release insiders". +# The comment must be created by a user with write access to the repo. +on: + # only run when a comment is created under a pr + issue_comment: + types: [created] + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + insiders: + # run if the comment contains "/release insiders" and if the comment is created under a PR + if: + ${{ github.event.issue.pull_request && contains(github.event.comment.body, + '/release insiders') }} + runs-on: ubuntu-latest + + permissions: + issues: write + # allow writing comments on the PR + contents: write + pull-requests: write + + steps: + # check if the user is an owner of the repo + - name: Has write access + id: has-write-access + uses: actions/github-script@v6 + with: + script: | + const res = await github.rest.repos.getCollaboratorPermissionLevel({ + ...context.repo, + username: context.payload.comment.user.login, + }); + + const hasPermission = ['admin', 'write', 'maintain'].includes(res.data.permission) + + if (!hasPermission) { + // if the user doesn't have write access, comment on the PR + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `🚫 Cannot publish because user @${context.payload.comment.user.login} doesn't have write access.` + }) + } + + return hasPermission + + # stop the workflow if the user doesn't have write access + - name: Stop if user doesn't have write access + if: ${{ !steps.has-write-access.outputs.result }} + run: | + echo "User doesn't have write access. Stopping the workflow." + exit 1 + + - name: Start the comment + id: start-comment + uses: actions/github-script@v6 + with: + result-encoding: string + script: | + const result = await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: ` + ⏳ Okay @${context.payload.comment.user.login}, I'm releasing an insiders build to npm. I will update this comment when done. +
More detail + + In case this fails, follow the workflow run [here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) to debug. + +
+ ` + }) + + const commentId = result.data.id + + return commentId + + - name: Get the pull request's ref + id: pr-ref + uses: actions/github-script@v6 + with: + result-encoding: string + script: | + const {data: pullRequest} = await github.rest.pulls.get({ + ...context.repo, + pull_number: context.issue.number + }) + + return pullRequest.head.sha + + # checkout the repo at the latest commit of the PR + - uses: actions/checkout@v2 + with: + ref: ${{ steps.pr-ref.outputs.result }} + + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 16.x + + - uses: ./.github/actions/yarn-nm-install + - name: Build the Theatre.js packages + run: yarn build + - name: Update .yarnrc.yml with the auth config for the npmPublishRegistry + run: cat .github/.yarnrc.publish.yml >> .yarnrc.yml + - name: Publish the Theatre.js packages + id: publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: yarn zx scripts/prerelease.mjs + + - name: Update the comment + id: update-comment + uses: actions/github-script@v6 + with: + script: | + const published = JSON.parse(${{ toJSON( steps.publish.outputs.data ) }}) + + const result = await github.rest.issues.updateComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: "${{ steps.start-comment.outputs.result }}", + body: ` + + +
+ 🎉 Released an insiders' build to npm. Here is how to upgrade: + + * 🚧 This is an insiders' build. It possibly **is not stable and _may_ corrupt your data**. Always **backup your work** before upgrading. + * If you do try this build, welcome aboard, insider 😉. If you're feeling generous, share some feedback here or on [\`#contributing\`](https://discord.com/channels/870988717190426644/940301611023073400) at Discord. + * 🔼 To upgrade, edit \`package.json\` and replace the versions of all \`@theatre\` or \`theatric\` packages with their new versions: + + \`\`\`diff + ${published.map((pkg) => { + return `--- ${pkg.packageName}: "old-version",\n+++ ${pkg.packageName}: "${pkg.version}",` + }).join('\n')} + \`\`\` + + All published packages are on npm: + + ${published.map((pkg) => { + return `* [\`${pkg.packageName}@${pkg.version}\`](https://www.npmjs.com/package/${pkg.packageName}/v/${pkg.version})` + }).join('\n')} + + + Published at the request of @${context.payload.comment.user.login}, on commit ${{ steps.pr-ref.outputs.result }}. Workflow log [here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) to debug. + +
+ ` + }) diff --git a/package.json b/package.json index 91bee94..15daf4f 100644 --- a/package.json +++ b/package.json @@ -64,5 +64,8 @@ "resolutions": { "@types/react": "^17.0.9", "@types/react-dom": "^17.0.9" + }, + "dependencies": { + "@actions/core": "^1.10.0" } } diff --git a/scripts/prerelease.mjs b/scripts/prerelease.mjs index 7c3e08c..df7e10e 100644 --- a/scripts/prerelease.mjs +++ b/scripts/prerelease.mjs @@ -4,6 +4,7 @@ import os from 'os' import path from 'path' +import * as core from '@actions/core' const packagesToPublish = [ '@theatre/core', @@ -166,10 +167,16 @@ async function writeVersionsToPackageJSONs( }), ) - for (const packageName of packagesToPublish) { - if (process.env.GITHUB_ACTIONS) { - await $`echo ${`Published ${packageName}@${assignedVersionByPackageName[packageName]}`} >> $GITHUB_STEP_SUMMARY` - } else { + if (process.env.GITHUB_ACTIONS) { + const data = packagesToPublish.map((packageName) => ({ + packageName, + version: assignedVersionByPackageName[packageName], + })) + + // set the output for github actions. + core.setOutput('data', JSON.stringify(data)) + } else { + for (const packageName of packagesToPublish) { await $`echo ${`Published ${packageName}@${assignedVersionByPackageName[packageName]}`}` } } diff --git a/yarn.lock b/yarn.lock index aa20d00..87c9551 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,25 @@ __metadata: version: 6 cacheKey: 8 +"@actions/core@npm:^1.10.0": + version: 1.10.0 + resolution: "@actions/core@npm:1.10.0" + dependencies: + "@actions/http-client": ^2.0.1 + uuid: ^8.3.2 + checksum: 0a75621e007ab20d887434cdd165f0b9036f14c22252a2faed33543d8b9d04ec95d823e69ca636a25245574e4585d73e1e9e47a845339553c664f9f2c9614669 + languageName: node + linkType: hard + +"@actions/http-client@npm:^2.0.1": + version: 2.0.1 + resolution: "@actions/http-client@npm:2.0.1" + dependencies: + tunnel: ^0.0.6 + checksum: 799ec3df91e28a9da91ce6592e94f8b8923ccf6cc21a2f72c7429be5af5273f1625335411adc2a1bb222d56c852d5767214dfa6fa32a6da7e81dba8290e08f17 + languageName: node + linkType: hard + "@ampproject/remapping@npm:^2.1.0": version: 2.1.2 resolution: "@ampproject/remapping@npm:2.1.2" @@ -31271,6 +31290,7 @@ fsevents@^1.2.7: version: 0.0.0-use.local resolution: "theatre-monorepo@workspace:." dependencies: + "@actions/core": ^1.10.0 "@babel/core": ^7.18.9 "@babel/plugin-proposal-class-properties": ^7.18.6 "@babel/plugin-proposal-nullish-coalescing-operator": ^7.18.6 @@ -31941,6 +31961,13 @@ fsevents@^1.2.7: languageName: node linkType: hard +"tunnel@npm:^0.0.6": + version: 0.0.6 + resolution: "tunnel@npm:0.0.6" + checksum: c362948df9ad34b649b5585e54ce2838fa583aa3037091aaed66793c65b423a264e5229f0d7e9a95513a795ac2bd4cb72cda7e89a74313f182c1e9ae0b0994fa + languageName: node + linkType: hard + "tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0": version: 0.14.5 resolution: "tweetnacl@npm:0.14.5"