1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-22 03:12:42 +02:00

Label PRs based on the labels of the associated issue (#17603)

* Implement CI to copy issue labels over to PRs

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* clean up

* clean up
This commit is contained in:
Pedro Figueiredo 2023-05-08 12:51:02 +04:00 committed by GitHub
parent 0306422bbf
commit 8df3bc9c1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 448 additions and 1 deletions

173
.github/scripts/label-prs.ts vendored Normal file
View File

@ -0,0 +1,173 @@
import * as core from '@actions/core';
import { context, getOctokit } from '@actions/github';
import { GitHub } from '@actions/github/lib/utils';
main().catch((error: Error): void => {
console.error(error);
process.exit(1);
});
async function main(): Promise<void> {
const token = process.env.GITHUB_TOKEN;
if (!token) {
core.setFailed('GITHUB_TOKEN not found');
process.exit(1);
}
const octokit = getOctokit(token);
const headRef = context.payload.pull_request?.head.ref || '';
let issueNumber = await getIssueNumberFromPullRequestBody();
if (issueNumber === "") {
bailIfIsBranchNameInvalid(headRef);
bailIfIsNotFeatureBranch(headRef);
issueNumber = getIssueNumberFromBranchName(headRef);
}
await updateLabels(octokit, issueNumber);
}
async function getIssueNumberFromPullRequestBody(): Promise<string> {
console.log("Checking if the PR's body references an issue...");
let ISSUE_LINK_IN_PR_DESCRIPTION_REGEX =
/(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\s#\d+/gi;
const prBody = await getPullRequestBody();
let matches = prBody.match(ISSUE_LINK_IN_PR_DESCRIPTION_REGEX);
if (!matches || matches?.length === 0) {
console.log(
'No direct link can be drawn between the PR and an issue from the PR body because no issue number was referenced.',
);
return "";
}
if (matches?.length > 1) {
console.log(
'No direct link can be drawn between the PR and an issue from the PR body because more than one issue number was referenced.',
);
return "";
}
const ISSUE_NUMBER_REGEX = /\d+/;
const issueNumber = matches[0].match(ISSUE_NUMBER_REGEX)?.[0] || '';
console.log(`Found issue number ${issueNumber} in PR body.`);
return issueNumber;
}
async function getPullRequestBody(): Promise<string> {
if (context.eventName !== 'pull_request') {
console.log('This action should only run on pull_request events.');
process.exit(1);
}
const prBody = context.payload.pull_request?.body || '';
return prBody;
}
function bailIfIsBranchNameInvalid(branchName: string): void {
const BRANCH_REGEX =
/^(main|develop|(ci|chore|docs|feat|feature|fix|perf|refactor|revert|style)\/\d*(?:[-](?![-])\w*)*|Version-v\d+\.\d+\.\d+)$/;
const isValidBranchName = new RegExp(BRANCH_REGEX).test(branchName);
if (!isValidBranchName) {
console.log('This branch name does not follow the convention.');
console.log(
'Here are some example branch names that are accepted: "fix/123-description", "feat/123-longer-description", "feature/123", "main", "develop", "Version-v10.24.2".',
);
console.log(
'No issue could be linked to this PR, so no labels were copied',
);
process.exit(0);
}
}
function bailIfIsNotFeatureBranch(branchName: string): void {
if (
branchName === 'main' ||
branchName === 'develop' ||
branchName.startsWith('Version-v')
) {
console.log(`${branchName} is not a feature branch.`);
console.log(
'No issue could be linked to this PR, so no labels were copied',
);
process.exit(0);
}
}
async function updateLabels(octokit: InstanceType<typeof GitHub>, issueNumber: string): Promise<void> {
interface ILabel {
name: string;
};
const owner = context.repo.owner;
const repo = context.repo.repo;
const issue = await octokit.rest.issues.get({
owner: owner,
repo: repo,
issue_number: Number(issueNumber),
});
const getNameFromLabel = (label: ILabel): string => label.name
const issueLabels = issue.data.labels.map(label => getNameFromLabel(label as ILabel));
const prNumber = context.payload.number;
const pr = await octokit.rest.issues.get({
owner: owner,
repo: repo,
issue_number: prNumber,
});
const startingPRLabels = pr.data.labels.map(label => getNameFromLabel(label as ILabel));
const dedupedFinalPRLabels = [
...new Set([...startingPRLabels, ...issueLabels]),
];
const hasIssueAdditionalLabels = !sortedArrayEqual(
startingPRLabels,
dedupedFinalPRLabels,
);
if (hasIssueAdditionalLabels) {
await octokit.rest.issues.update({
owner,
repo,
issue_number: prNumber,
labels: dedupedFinalPRLabels,
});
}
}
function getIssueNumberFromBranchName(branchName: string): string {
console.log('Checking if the branch name references an issue...');
let issueNumber: string;
if (branchName.split('/').length > 1) {
issueNumber = branchName.split('/')[1].split('-')[0];
} else {
issueNumber = branchName.split('-')[0];
}
console.log(`Found issue number ${issueNumber} in branch name.`);
return issueNumber;
}
function sortedArrayEqual(array1: string[], array2: string[]): boolean {
const lengthsAreEqual = array1.length === array2.length;
const everyElementMatchesByIndex = array1.every(
(value: string, index: number): boolean => value === array2[index],
);
return lengthsAreEqual && everyElementMatchesByIndex;
}

32
.github/workflows/label-prs.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: Label PR
on:
pull_request:
types: [assigned, opened, edited, synchronize, reopened]
jobs:
label-pr:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install Yarn
run: npm install -g yarn
- name: Install dependencies
run: yarn
- name: Run PR labelling script
run: npm run label-prs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

4
.husky/pre-push Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn validate-branch-name

View File

@ -0,0 +1,11 @@
const BRANCH_REGEX =
/^(main|develop|(ci|chore|docs|feat|feature|fix|perf|refactor|revert|style)\/\d*(?:[-](?![-])\w*)*|Version-v\d+\.\d+\.\d+)$/;
const ERROR_MSG =
'This branch name does not follow our conventions.' +
'\n' +
'Rename it with "git branch -m <current-name> <new-name>"' +
'\n' +
'Here are some example branch names that are accepted: "fix/123-description", "feat/123-longer-description", "feature/123", "main", "develop", "Version-v10.24.2".';
module.exports = { pattern: BRANCH_REGEX, errorMsg: ERROR_MSG };

View File

@ -93,7 +93,9 @@
"test-storybook:ci": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"yarn storybook:build && npx http-server storybook-build --port 6006 \" \"wait-on tcp:6006 && yarn test-storybook --maxWorkers=2\"",
"githooks:install": "husky install",
"fitness-functions": "ts-node development/fitness-functions/index.ts",
"generate-beta-commit": "node ./development/generate-beta-commit.js"
"generate-beta-commit": "node ./development/generate-beta-commit.js",
"validate-branch-name": "validate-branch-name",
"label-prs": "ts-node ./.github/scripts/label-prs.ts"
},
"resolutions": {
"analytics-node/axios": "^0.21.2",
@ -211,6 +213,8 @@
"request@^2.85.0": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch"
},
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1",
"@babel/runtime": "^7.5.5",
"@download/blockies": "^1.0.3",
"@ensdomains/content-hash": "^2.5.6",
@ -317,6 +321,7 @@
"fuse.js": "^3.2.0",
"globalthis": "^1.0.1",
"human-standard-token-abi": "^2.0.0",
"husky": "^8.0.3",
"immer": "^9.0.6",
"is-retry-allowed": "^2.2.0",
"jest-junit": "^14.0.1",
@ -360,6 +365,7 @@
"unicode-confusables": "^0.1.1",
"uuid": "^8.3.2",
"valid-url": "^1.0.9",
"validate-branch-name": "^1.3.0",
"web3-stream-provider": "^4.0.0",
"zxcvbn": "^4.4.2"
},

221
yarn.lock
View File

@ -5,6 +5,37 @@ __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/github@npm:^5.1.1":
version: 5.1.1
resolution: "@actions/github@npm:5.1.1"
dependencies:
"@actions/http-client": ^2.0.1
"@octokit/core": ^3.6.0
"@octokit/plugin-paginate-rest": ^2.17.0
"@octokit/plugin-rest-endpoint-methods": ^5.13.0
checksum: 2210bd7f8e1e8b407b7df74a259523dc4c63f4ad3a6bfcc0d7867b6e9c3499bd3e25d7de7a9a1bbd0de3be441a8832d5c0b5c0cff3036cd477378c0ec5502434
languageName: node
linkType: hard
"@actions/http-client@npm:^2.0.1":
version: 2.1.0
resolution: "@actions/http-client@npm:2.1.0"
dependencies:
tunnel: ^0.0.6
checksum: 25a72a952cc95fb4b3ab086da73a5754dd0957c206637cace69be2e16f018cc1b3d3c40d3bcf89ffd8a5929d5e8445594b498b50db306a50ad7536023f8e3800
languageName: node
linkType: hard
"@ampproject/remapping@npm:^2.1.0":
version: 2.2.0
resolution: "@ampproject/remapping@npm:2.2.0"
@ -4692,6 +4723,116 @@ __metadata:
languageName: node
linkType: hard
"@octokit/auth-token@npm:^2.4.4":
version: 2.5.0
resolution: "@octokit/auth-token@npm:2.5.0"
dependencies:
"@octokit/types": ^6.0.3
checksum: 45949296c09abcd6beb4c3f69d45b0c1f265f9581d2a9683cf4d1800c4cf8259c2f58d58e44c16c20bffb85a0282a176c0d51f4af300e428b863f27b910e6297
languageName: node
linkType: hard
"@octokit/core@npm:^3.6.0":
version: 3.6.0
resolution: "@octokit/core@npm:3.6.0"
dependencies:
"@octokit/auth-token": ^2.4.4
"@octokit/graphql": ^4.5.8
"@octokit/request": ^5.6.3
"@octokit/request-error": ^2.0.5
"@octokit/types": ^6.0.3
before-after-hook: ^2.2.0
universal-user-agent: ^6.0.0
checksum: f81160129037bd8555d47db60cd5381637b7e3602ad70735a7bdf8f3d250c7b7114a666bb12ef7a8746a326a5d72ed30a1b8f8a5a170007f7285c8e217bef1f0
languageName: node
linkType: hard
"@octokit/endpoint@npm:^6.0.1":
version: 6.0.12
resolution: "@octokit/endpoint@npm:6.0.12"
dependencies:
"@octokit/types": ^6.0.3
is-plain-object: ^5.0.0
universal-user-agent: ^6.0.0
checksum: b48b29940af11c4b9bca41cf56809754bb8385d4e3a6122671799d27f0238ba575b3fde86d2d30a84f4dbbc14430940de821e56ecc6a9a92d47fc2b29a31479d
languageName: node
linkType: hard
"@octokit/graphql@npm:^4.5.8":
version: 4.8.0
resolution: "@octokit/graphql@npm:4.8.0"
dependencies:
"@octokit/request": ^5.6.0
"@octokit/types": ^6.0.3
universal-user-agent: ^6.0.0
checksum: f68afe53f63900d4a16a0a733f2f500df2695b731f8ed32edb728d50edead7f5011437f71d069c2d2f6d656227703d0c832a3c8af58ecf82bd5dcc051f2d2d74
languageName: node
linkType: hard
"@octokit/openapi-types@npm:^12.11.0":
version: 12.11.0
resolution: "@octokit/openapi-types@npm:12.11.0"
checksum: 8a7d4bd6288cc4085cabe0ca9af2b87c875c303af932cb138aa1b2290eb69d32407759ac23707bb02776466e671244a902e9857896903443a69aff4b6b2b0e3b
languageName: node
linkType: hard
"@octokit/plugin-paginate-rest@npm:^2.17.0":
version: 2.21.3
resolution: "@octokit/plugin-paginate-rest@npm:2.21.3"
dependencies:
"@octokit/types": ^6.40.0
peerDependencies:
"@octokit/core": ">=2"
checksum: acf31de2ba4021bceec7ff49c5b0e25309fc3c009d407f153f928ddf436ab66cd4217344138378d5523f5fb233896e1db58c9c7b3ffd9612a66d760bc5d319ed
languageName: node
linkType: hard
"@octokit/plugin-rest-endpoint-methods@npm:^5.13.0":
version: 5.16.2
resolution: "@octokit/plugin-rest-endpoint-methods@npm:5.16.2"
dependencies:
"@octokit/types": ^6.39.0
deprecation: ^2.3.1
peerDependencies:
"@octokit/core": ">=3"
checksum: 30fcc50c335d1093f03573d9fa3a4b7d027fc98b215c43e07e82ee8dabfa0af0cf1b963feb542312ae32d897a2f68dc671577206f30850215517bebedc5a2c73
languageName: node
linkType: hard
"@octokit/request-error@npm:^2.0.5, @octokit/request-error@npm:^2.1.0":
version: 2.1.0
resolution: "@octokit/request-error@npm:2.1.0"
dependencies:
"@octokit/types": ^6.0.3
deprecation: ^2.0.0
once: ^1.4.0
checksum: baec2b5700498be01b4d958f9472cb776b3f3b0ea52924323a07e7a88572e24cac2cdf7eb04a0614031ba346043558b47bea2d346e98f0e8385b4261f138ef18
languageName: node
linkType: hard
"@octokit/request@npm:^5.6.0, @octokit/request@npm:^5.6.3":
version: 5.6.3
resolution: "@octokit/request@npm:5.6.3"
dependencies:
"@octokit/endpoint": ^6.0.1
"@octokit/request-error": ^2.1.0
"@octokit/types": ^6.16.1
is-plain-object: ^5.0.0
node-fetch: ^2.6.7
universal-user-agent: ^6.0.0
checksum: c0b4542eb4baaf880d673c758d3e0b5c4a625a4ae30abf40df5548b35f1ff540edaac74625192b1aff42a79ac661e774da4ab7d5505f1cb4ef81239b1e8510c5
languageName: node
linkType: hard
"@octokit/types@npm:^6.0.3, @octokit/types@npm:^6.16.1, @octokit/types@npm:^6.39.0, @octokit/types@npm:^6.40.0":
version: 6.41.0
resolution: "@octokit/types@npm:6.41.0"
dependencies:
"@octokit/openapi-types": ^12.11.0
checksum: fd6f75e0b19b90d1a3d244d2b0c323ed8f2f05e474a281f60a321986683548ef2e0ec2b3a946aa9405d6092e055344455f69f58957c60f58368c8bdda5b7d2ab
languageName: node
linkType: hard
"@oozcitak/dom@npm:1.15.10":
version: 1.15.10
resolution: "@oozcitak/dom@npm:1.15.10"
@ -9913,6 +10054,13 @@ __metadata:
languageName: node
linkType: hard
"babel-plugin-add-module-exports@npm:^0.2.1":
version: 0.2.1
resolution: "babel-plugin-add-module-exports@npm:0.2.1"
checksum: 0d40e7b970161a10960fbbd0492565ae2f3f4872b4da089f8f5bb874cfac4e38e088e4d96bc33cef22a8963774abe84622feeebbbe049ad95c4ee33c907b277d
languageName: node
linkType: hard
"babel-plugin-add-react-displayname@npm:^0.0.5":
version: 0.0.5
resolution: "babel-plugin-add-react-displayname@npm:0.0.5"
@ -10351,6 +10499,13 @@ __metadata:
languageName: node
linkType: hard
"before-after-hook@npm:^2.2.0":
version: 2.2.3
resolution: "before-after-hook@npm:2.2.3"
checksum: a1a2430976d9bdab4cd89cb50d27fa86b19e2b41812bf1315923b0cba03371ebca99449809226425dd3bcef20e010db61abdaff549278e111d6480034bebae87
languageName: node
linkType: hard
"better-opn@npm:^2.1.1":
version: 2.1.1
resolution: "better-opn@npm:2.1.1"
@ -13247,6 +13402,17 @@ __metadata:
languageName: node
linkType: hard
"current-git-branch@npm:^1.1.0":
version: 1.1.0
resolution: "current-git-branch@npm:1.1.0"
dependencies:
babel-plugin-add-module-exports: ^0.2.1
execa: ^0.6.1
is-git-repository: ^1.0.0
checksum: 57042d5c9fc608a951e81310da1caa3bdf917d0fede06996bfd7eaab5bdee7d29ced3440c3c73e5d90e503e689e2084e1906b1a17723e35684b1579d1bb5a54f
languageName: node
linkType: hard
"cwd@npm:^0.10.0":
version: 0.10.0
resolution: "cwd@npm:0.10.0"
@ -13774,6 +13940,13 @@ __metadata:
languageName: node
linkType: hard
"deprecation@npm:^2.0.0, deprecation@npm:^2.3.1":
version: 2.3.1
resolution: "deprecation@npm:2.3.1"
checksum: f56a05e182c2c195071385455956b0c4106fe14e36245b00c689ceef8e8ab639235176a96977ba7c74afb173317fac2e0ec6ec7a1c6d1e6eaa401c586c714132
languageName: node
linkType: hard
"deps-regex@npm:^0.1.4":
version: 0.1.4
resolution: "deps-regex@npm:0.1.4"
@ -16173,6 +16346,21 @@ __metadata:
languageName: node
linkType: hard
"execa@npm:^0.6.1":
version: 0.6.3
resolution: "execa@npm:0.6.3"
dependencies:
cross-spawn: ^5.0.1
get-stream: ^3.0.0
is-stream: ^1.1.0
npm-run-path: ^2.0.0
p-finally: ^1.0.0
signal-exit: ^3.0.0
strip-eof: ^1.0.0
checksum: 2c66177731273a7c0a4c031af81b486b67ec1eeeb8f353ebc68e0cfe7f63aca9ebc1e6fe03ba10f130f2bd179c0ac69b35668fe2bfc1ceb68fbf5291d0783457
languageName: node
linkType: hard
"execa@npm:^0.7.0":
version: 0.7.0
resolution: "execa@npm:0.7.0"
@ -20036,6 +20224,16 @@ __metadata:
languageName: node
linkType: hard
"is-git-repository@npm:^1.0.0":
version: 1.1.1
resolution: "is-git-repository@npm:1.1.1"
dependencies:
execa: ^0.6.1
path-is-absolute: ^1.0.1
checksum: 2873d41da9ae5771a9118bdd743f32fa868301c57e8e4d8e255d4e14c04267112294a29f2824531fa554696042d8d87185811cff2de2a06381cff7d61d9ac22d
languageName: node
linkType: hard
"is-glob@npm:^2.0.0, is-glob@npm:^2.0.1":
version: 2.0.1
resolution: "is-glob@npm:2.0.1"
@ -23951,6 +24149,8 @@ __metadata:
version: 0.0.0-use.local
resolution: "metamask-crx@workspace:."
dependencies:
"@actions/core": ^1.10.0
"@actions/github": ^5.1.1
"@babel/code-frame": ^7.12.13
"@babel/core": ^7.12.1
"@babel/eslint-parser": ^7.13.14
@ -24280,6 +24480,7 @@ __metadata:
unicode-confusables: ^0.1.1
uuid: ^8.3.2
valid-url: ^1.0.9
validate-branch-name: ^1.3.0
vinyl: ^2.2.1
vinyl-buffer: ^1.0.1
vinyl-source-stream: ^2.0.0
@ -33597,6 +33798,13 @@ __metadata:
languageName: node
linkType: hard
"universal-user-agent@npm:^6.0.0":
version: 6.0.0
resolution: "universal-user-agent@npm:6.0.0"
checksum: 5092bbc80dd0d583cef0b62c17df0043193b74f425112ea6c1f69bc5eda21eeec7a08d8c4f793a277eb2202ffe9b44bec852fa3faff971234cd209874d1b79ef
languageName: node
linkType: hard
"universalify@npm:^0.1.0, universalify@npm:^0.1.2":
version: 0.1.2
resolution: "universalify@npm:0.1.2"
@ -33956,6 +34164,19 @@ __metadata:
languageName: node
linkType: hard
"validate-branch-name@npm:^1.3.0":
version: 1.3.0
resolution: "validate-branch-name@npm:1.3.0"
dependencies:
commander: ^8.3.0
cosmiconfig: ^7.0.1
current-git-branch: ^1.1.0
bin:
validate-branch-name: cli.js
checksum: be82c1e39bfe0519fa02f01670b5ef928903a19289249559c9148c0fd20df356f373f2490fbfd54d018868a6348cc2ceb82fb67d5f5c48c15ecb48735b9b87fb
languageName: node
linkType: hard
"validate-npm-package-license@npm:^3.0.1":
version: 3.0.4
resolution: "validate-npm-package-license@npm:3.0.4"