diff --git a/.github/workflows/label-prs.yml b/.github/workflows/label-prs.yml new file mode 100644 index 000000000..edb94b1d9 --- /dev/null +++ b/.github/workflows/label-prs.yml @@ -0,0 +1,24 @@ +name: Label PR based on changed package + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + label: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - uses: ./.github/actions/setup-and-build + with: + install-dependencies: false + build: false + + - run: pnpm install + + - name: Label PR + run: node scripts/labelPrs.js + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index ff5e41c8a..1a62b1890 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "devDependencies": { "@actions/core": "^1.10.0", "@actions/exec": "^1.1.1", + "@actions/github": "^6.0.0", "@changesets/changelog-github": "^0.4.8", "@changesets/cli": "^2.26.2", "cross-env": "^7.0.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 490debe1a..9867e8d87 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@actions/exec': specifier: ^1.1.1 version: 1.1.1 + '@actions/github': + specifier: ^6.0.0 + version: 6.0.0 '@changesets/changelog-github': specifier: ^0.4.8 version: 0.4.8 @@ -242,12 +245,28 @@ packages: '@actions/io': 1.1.2 dev: true + /@actions/github@6.0.0: + resolution: {integrity: sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==} + dependencies: + '@actions/http-client': 2.2.0 + '@octokit/core': 5.0.1 + '@octokit/plugin-paginate-rest': 9.1.4(@octokit/core@5.0.1) + '@octokit/plugin-rest-endpoint-methods': 10.1.5(@octokit/core@5.0.1) + dev: true + /@actions/http-client@2.0.1: resolution: {integrity: sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==} dependencies: tunnel: 0.0.6 dev: true + /@actions/http-client@2.2.0: + resolution: {integrity: sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==} + dependencies: + tunnel: 0.0.6 + undici: 5.26.5 + dev: true + /@actions/io@1.1.2: resolution: {integrity: sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==} dev: true @@ -1816,6 +1835,92 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 + /@octokit/auth-token@4.0.0: + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} + dev: true + + /@octokit/core@5.0.1: + resolution: {integrity: sha512-lyeeeZyESFo+ffI801SaBKmCfsvarO+dgV8/0gD8u1d87clbEdWsP5yC+dSj3zLhb2eIf5SJrn6vDz9AheETHw==} + engines: {node: '>= 18'} + dependencies: + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.0.2 + '@octokit/request': 8.1.5 + '@octokit/request-error': 5.0.1 + '@octokit/types': 12.3.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + dev: true + + /@octokit/endpoint@9.0.2: + resolution: {integrity: sha512-qhKW8YLIi+Kmc92FQUFGr++DYtkx/1fBv+Thua6baqnjnOsgBYJDCvWZR1YcINuHGOEQt416WOfE+A/oG60NBQ==} + engines: {node: '>= 18'} + dependencies: + '@octokit/types': 12.3.0 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.1 + dev: true + + /@octokit/graphql@7.0.2: + resolution: {integrity: sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==} + engines: {node: '>= 18'} + dependencies: + '@octokit/request': 8.1.5 + '@octokit/types': 12.3.0 + universal-user-agent: 6.0.1 + dev: true + + /@octokit/openapi-types@19.0.2: + resolution: {integrity: sha512-8li32fUDUeml/ACRp/njCWTsk5t17cfTM1jp9n08pBrqs5cDFJubtjsSnuz56r5Tad6jdEPJld7LxNp9dNcyjQ==} + dev: true + + /@octokit/plugin-paginate-rest@9.1.4(@octokit/core@5.0.1): + resolution: {integrity: sha512-MvZx4WvfhBnt7PtH5XE7HORsO7bBk4er1FgRIUr1qJ89NR2I6bWjGyKsxk8z42FPQ34hFQm0Baanh4gzdZR4gQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=5' + dependencies: + '@octokit/core': 5.0.1 + '@octokit/types': 12.3.0 + dev: true + + /@octokit/plugin-rest-endpoint-methods@10.1.5(@octokit/core@5.0.1): + resolution: {integrity: sha512-LMEdsMV8TTMjMTqVoqMzV95XTbv0ZsWxCxQtjAunQOCdwoDH4BVF/Ke5JMSZEVCWGI2kzxnUNbFnK/MxwV7NjA==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=5' + dependencies: + '@octokit/core': 5.0.1 + '@octokit/types': 12.3.0 + dev: true + + /@octokit/request-error@5.0.1: + resolution: {integrity: sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==} + engines: {node: '>= 18'} + dependencies: + '@octokit/types': 12.3.0 + deprecation: 2.3.1 + once: 1.4.0 + dev: true + + /@octokit/request@8.1.5: + resolution: {integrity: sha512-zVKbNbX1xUluD9ZR4/tPs1yuYrK9xeh5fGZUXA6u04XGsTvomg0YO8/ZUC0FqAd49hAOEMFPAVUTh+2lBhOhLA==} + engines: {node: '>= 18'} + dependencies: + '@octokit/endpoint': 9.0.2 + '@octokit/request-error': 5.0.1 + '@octokit/types': 12.3.0 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.1 + dev: true + + /@octokit/types@12.3.0: + resolution: {integrity: sha512-nJ8X2HRr234q3w/FcovDlA+ttUU4m1eJAourvfUUtwAWeqL8AsyRqfnLvVnYn3NFbUnsmzQCzLNdFerPwdmcDQ==} + dependencies: + '@octokit/openapi-types': 19.0.2 + dev: true + /@polka/url@1.0.0-next.23: resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==} dev: true @@ -2812,6 +2917,10 @@ packages: /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + /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'} @@ -3386,6 +3495,10 @@ packages: engines: {node: '>= 0.8'} dev: true + /deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dev: true + /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -4892,6 +5005,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@3.0.2: resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} dependencies: @@ -7536,6 +7654,10 @@ packages: pathe: 1.1.1 dev: false + /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'} diff --git a/scripts/labelPrs.js b/scripts/labelPrs.js new file mode 100644 index 000000000..ae19166be --- /dev/null +++ b/scripts/labelPrs.js @@ -0,0 +1,77 @@ +const github = require("@actions/github"); +const fs = require("fs").promises; +const path = require("path"); + +const token = process.env.GITHUB_TOKEN; +const octokit = github.getOctokit(token); + +const rootDir = path.resolve(__dirname, ".."); + +async function getChangedPackages() { + const prNumber = github.context.payload.pull_request.number; + const owner = github.context.repo.owner; + const repo = github.context.repo.repo; + + const { data: files } = await octokit.rest.pulls.listFiles({ + owner, + repo, + pull_number: prNumber, + }); + + const changedPackages = new Set(); + + for (const file of files) { + if (file.filename.startsWith("packages/")) { + const packageName = file.filename.split("/")[1]; + changedPackages.add(packageName); + } + } + + return changedPackages; +} + +async function getLabelsForPackages(packageNames) { + const labels = []; + + for (const packageName of packageNames) { + const packageJsonPath = path.resolve( + rootDir, + "packages", + packageName, + "package.json" + ); + const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8")); + const label = `📦 ${packageJson.name}`; + labels.push(label); + } + + return labels; +} + +async function labelPR(labels) { + if (labels.length === 0) return; + + const prNumber = github.context.payload.pull_request.number; + const owner = github.context.repo.owner; + const repo = github.context.repo.repo; + + await octokit.rest.issues.addLabels({ + owner, + repo, + issue_number: prNumber, + labels: labels, + }); +} + +async function run() { + const changedPackages = await getChangedPackages(); + if (changedPackages.size > 0) { + const labels = await getLabelsForPackages(changedPackages); + await labelPR(labels); + } +} + +run().catch((error) => { + console.error(error); + process.exit(1); +});