From c063ef66ed15114e6fdd13fefed3fe73afc4372b Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Thu, 18 Apr 2024 14:11:13 +0100 Subject: [PATCH] chore(actions): Add Discord message release hook (#29) * Copy over discord-message action * Update Node LTS in actions * Add discord-message hook * Remove node-fetch --- .github/actions/discord-message/action.mjs | 85 +++++++++++ .github/actions/discord-message/action.yml | 9 ++ .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 13 +- package.json | 2 + pnpm-lock.yaml | 158 +++++++++++++++++++++ 6 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 .github/actions/discord-message/action.mjs create mode 100644 .github/actions/discord-message/action.yml diff --git a/.github/actions/discord-message/action.mjs b/.github/actions/discord-message/action.mjs new file mode 100644 index 0000000..e56f072 --- /dev/null +++ b/.github/actions/discord-message/action.mjs @@ -0,0 +1,85 @@ +import * as core from '@actions/core'; +import * as github from '@actions/github'; + +const GITHUB_TOKEN = process.env.GITHUB_TOKEN; +const WEBHOOK_URL = process.env.DISCORD_WEBHOOK_URL; + +const octokit = github.getOctokit(GITHUB_TOKEN); + +const formatBody = (input) => { + const titleRe = /(?:^|\n)#+[^\n]+/g; + const updatedDepsRe = /\n-\s*Updated dependencies[\s\S]+\n(\n\s+-[\s\S]+)*/gi; + const markdownLinkRe = /\[([^\]]+)\]\(([^\)]+)\)/g; + const creditRe = new RegExp(`Submitted by (?:undefined|${markdownLinkRe.source})`, 'ig'); + const repeatedNewlineRe = /(\n[ ]*)+/g; + return input + .replace(titleRe, '') + .replace(updatedDepsRe, '') + .replace(creditRe, (_match, text, url) => { + if (!text || /@kitten|@JoviDeCroock/i.test(text)) return ''; + return `Submitted by [${text}](${url})`; + }) + .replace(markdownLinkRe, (_match, text, url) => { + return `[${text}](<${url}>)`; + }) + .replace(repeatedNewlineRe, '\n') + .trim(); +}; + +async function getReleaseBody(name, version) { + const tag = `${name}@${version}`; + const result = await octokit.rest.repos.getReleaseByTag({ + owner: 'urql-graphql', + repo: 'urql', + tag, + }); + + const release = result.status === 200 ? result.data : undefined; + if (!release || !release.body) return; + + const title = `:package: [${tag}](<${release.html_url}>)`; + const body = formatBody(release.body); + if (!body) return; + + return `${title}\n${body}`; +} + +async function main() { + const inputPackages = core.getInput('publishedPackages'); + let packages; + + try { + packages = JSON.parse(inputPackages); + } catch (e) { + console.error('invalid JSON in publishedPackages input.'); + return; + } + + // Get releases + const releasePromises = packages.map((entry) => { + return getReleaseBody(entry.name, entry.version); + }); + + const content = (await Promise.allSettled(releasePromises)) + .map((x) => x.status === 'fulfilled' && x.value) + .filter(Boolean) + .join('\n\n'); + + // Send message through a discord webhook or bot + const response = fetch(WEBHOOK_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ content }), + }); + + if (!response.ok) { + console.log('Something went wrong while sending the discord webhook.'); + return; + } + + return response; +} + +main().then().catch(console.error); diff --git a/.github/actions/discord-message/action.yml b/.github/actions/discord-message/action.yml new file mode 100644 index 0000000..adca219 --- /dev/null +++ b/.github/actions/discord-message/action.yml @@ -0,0 +1,9 @@ +name: 'Send a discord message' +description: 'Send a discord message as a result of a gql.tada publish.' +inputs: + publishedPackages: + description: > + A JSON array to present the published packages. The format is `[{"name": "@xx/xx", "version": "1.2.0"}, {"name": "@xx/xy", "version": "0.8.9"}]` +runs: + using: 'node20' + main: 'action.mjs' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b855652..6c26bfb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v1 with: - node-version: 18 + node-version: 20 - name: Setup pnpm uses: pnpm/action-setup@v2.2.2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 194c4ad..2502deb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 20 - name: Setup pnpm uses: pnpm/action-setup@v2.2.2 @@ -59,6 +59,17 @@ jobs: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Notify discord + id: discord-msg + if: steps.changesets.outputs.published == 'true' + uses: ./.github/actions/discord-message + with: + publishedPackages: ${{ steps.changesets.outputs.publishedPackages }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + - name: Publish Prerelease if: steps.changesets.outputs.published != 'true' env: diff --git a/package.json b/package.json index d172706..5cbd202 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,8 @@ ] }, "devDependencies": { + "@actions/core": "^1.10.0", + "@actions/github": "^5.1.1", "@babel/plugin-transform-block-scoping": "^7.23.4", "@babel/plugin-transform-typescript": "^7.23.6", "@changesets/cli": "^2.27.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7892889..7e08049 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,6 +12,12 @@ importers: specifier: ^14.0.0 || ^15.0.0 || ^16.0.0 version: 16.8.1 devDependencies: + '@actions/core': + specifier: ^1.10.0 + version: 1.10.1 + '@actions/github': + specifier: ^5.1.1 + version: 5.1.1 '@babel/plugin-transform-block-scoping': specifier: ^7.23.4 version: 7.23.4(@babel/core@7.23.9) @@ -112,6 +118,31 @@ packages: engines: {node: '>=0.10.0'} dev: true + /@actions/core@1.10.1: + resolution: {integrity: sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==} + dependencies: + '@actions/http-client': 2.2.1 + uuid: 8.3.2 + dev: true + + /@actions/github@5.1.1: + resolution: {integrity: sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==} + dependencies: + '@actions/http-client': 2.2.1 + '@octokit/core': 3.6.0 + '@octokit/plugin-paginate-rest': 2.21.3(@octokit/core@3.6.0) + '@octokit/plugin-rest-endpoint-methods': 5.16.2(@octokit/core@3.6.0) + transitivePeerDependencies: + - encoding + dev: true + + /@actions/http-client@2.2.1: + resolution: {integrity: sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==} + dependencies: + tunnel: 0.0.6 + undici: 5.28.4 + dev: true + /@ampproject/remapping@2.2.1: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} engines: {node: '>=6.0.0'} @@ -857,6 +888,11 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@fastify/busboy@2.1.1: + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + dev: true + /@humanwhocodes/config-array@0.11.14: resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -992,6 +1028,94 @@ packages: fastq: 1.17.0 dev: true + /@octokit/auth-token@2.5.0: + resolution: {integrity: sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==} + dependencies: + '@octokit/types': 6.41.0 + dev: true + + /@octokit/core@3.6.0: + resolution: {integrity: sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==} + dependencies: + '@octokit/auth-token': 2.5.0 + '@octokit/graphql': 4.8.0 + '@octokit/request': 5.6.3 + '@octokit/request-error': 2.1.0 + '@octokit/types': 6.41.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/endpoint@6.0.12: + resolution: {integrity: sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==} + dependencies: + '@octokit/types': 6.41.0 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.1 + dev: true + + /@octokit/graphql@4.8.0: + resolution: {integrity: sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==} + dependencies: + '@octokit/request': 5.6.3 + '@octokit/types': 6.41.0 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/openapi-types@12.11.0: + resolution: {integrity: sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==} + dev: true + + /@octokit/plugin-paginate-rest@2.21.3(@octokit/core@3.6.0): + resolution: {integrity: sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==} + peerDependencies: + '@octokit/core': '>=2' + dependencies: + '@octokit/core': 3.6.0 + '@octokit/types': 6.41.0 + dev: true + + /@octokit/plugin-rest-endpoint-methods@5.16.2(@octokit/core@3.6.0): + resolution: {integrity: sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==} + peerDependencies: + '@octokit/core': '>=3' + dependencies: + '@octokit/core': 3.6.0 + '@octokit/types': 6.41.0 + deprecation: 2.3.1 + dev: true + + /@octokit/request-error@2.1.0: + resolution: {integrity: sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==} + dependencies: + '@octokit/types': 6.41.0 + deprecation: 2.3.1 + once: 1.4.0 + dev: true + + /@octokit/request@5.6.3: + resolution: {integrity: sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==} + dependencies: + '@octokit/endpoint': 6.0.12 + '@octokit/request-error': 2.1.0 + '@octokit/types': 6.41.0 + is-plain-object: 5.0.0 + node-fetch: 2.7.0 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + dev: true + + /@octokit/types@6.41.0: + resolution: {integrity: sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==} + dependencies: + '@octokit/openapi-types': 12.11.0 + dev: true + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1568,6 +1692,10 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + dev: true + /better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -1934,6 +2062,10 @@ packages: object-keys: 1.1.1 dev: true + /deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dev: true + /detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -2839,6 +2971,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + /is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} dependencies: @@ -4361,6 +4498,11 @@ packages: yargs: 17.7.2 dev: true + /tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + dev: true + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -4455,6 +4597,17 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /undici@5.28.4: + resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} + engines: {node: '>=14.0'} + dependencies: + '@fastify/busboy': 2.1.1 + dev: true + + /universal-user-agent@6.0.1: + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + dev: true + /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -4477,6 +4630,11 @@ packages: punycode: 2.3.0 dev: true + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: true + /v8-to-istanbul@9.2.0: resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} engines: {node: '>=10.12.0'}