mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-21 17:37:01 +01:00
feat: github actions to automatically create and close bug report issue (#20391)
* feat(action): github action to create bug report issue at RC cut * feat(action): github action to close bug report issue once release is ready * fix(action): replace main by master * fix(action): create event does not support branch filter * fix(action): indentation * fix(action): actionlint erors * fix(action): actionlint erors 2 * fix(action): actionlint erors 3 * fix(action): replace npm by yarn for consistency
This commit is contained in:
parent
ca1ddeb59b
commit
23249b68b7
120
.github/scripts/close-release-bug-report-issue.ts
vendored
Normal file
120
.github/scripts/close-release-bug-report-issue.ts
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
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> {
|
||||
// "GITHUB_TOKEN" is an automatically generated, repository-specific access token provided by GitHub Actions.
|
||||
// We can't use "GITHUB_TOKEN" here, as its permissions are scoped to the repository where the action is running.
|
||||
// "GITHUB_TOKEN" does not have access to other repositories, even when they belong to the same organization.
|
||||
// As we want to update bug report issues which are not located in the same repository,
|
||||
// we need to create our own "BUG_REPORT_TOKEN" with "repo" permissions.
|
||||
// Such a token allows to access other repositories of the MetaMask organisation.
|
||||
const personalAccessToken = process.env.BUG_REPORT_TOKEN;
|
||||
if (!personalAccessToken) {
|
||||
core.setFailed('BUG_REPORT_TOKEN not found');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const repoOwner = context.repo.owner; // MetaMask
|
||||
|
||||
const bugReportRepo = process.env.BUG_REPORT_REPO;
|
||||
if (!bugReportRepo) {
|
||||
core.setFailed('BUG_REPORT_REPO not found');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Extract branch name from the context
|
||||
const branchName: string = context.payload.pull_request?.head.ref || "";
|
||||
|
||||
// Extract semver version number from the branch name
|
||||
const releaseVersionNumberMatch = branchName.match(/^Version-v(\d+\.\d+\.\d+)$/);
|
||||
|
||||
if (!releaseVersionNumberMatch) {
|
||||
core.setFailed(`Failed to extract version number from branch name: ${branchName}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const releaseVersionNumber = releaseVersionNumberMatch[1];
|
||||
|
||||
// Initialise octokit, required to call Github GraphQL API
|
||||
const octokit: InstanceType<typeof GitHub> = getOctokit(personalAccessToken);
|
||||
|
||||
const bugReportIssue = await retrieveOpenBugReportIssue(octokit, repoOwner, bugReportRepo, releaseVersionNumber);
|
||||
|
||||
if (!bugReportIssue) {
|
||||
throw new Error(`No open bug report issue was found for release ${releaseVersionNumber} on ${repoOwner}/${bugReportRepo} repo`);
|
||||
}
|
||||
|
||||
if (bugReportIssue.title?.toLocaleLowerCase() !== `v${releaseVersionNumber} Bug Report`.toLocaleLowerCase()) {
|
||||
throw new Error(`Unexpected bug report title: "${bugReportIssue.title}" instead of "v${releaseVersionNumber} Bug Report"`);
|
||||
}
|
||||
|
||||
console.log(`Closing bug report issue with title "${bugReportIssue.title}" and id: ${bugReportIssue.id}`);
|
||||
|
||||
await closeIssue(octokit, bugReportIssue.id);
|
||||
|
||||
console.log(`Issue with id: ${bugReportIssue.id} successfully closed`);
|
||||
}
|
||||
|
||||
// This function retrieves the issue titled "vx.y.z Bug Report" on a specific repo
|
||||
async function retrieveOpenBugReportIssue(octokit: InstanceType<typeof GitHub>, repoOwner: string, repoName: string, releaseVersionNumber: string): Promise<{
|
||||
id: string;
|
||||
title: string;
|
||||
} | undefined> {
|
||||
|
||||
const retrieveOpenBugReportIssueQuery = `
|
||||
query RetrieveOpenBugReportIssue {
|
||||
search(query: "repo:${repoOwner}/${repoName} type:issue is:open in:title v${releaseVersionNumber} Bug Report", type: ISSUE, first: 1) {
|
||||
nodes {
|
||||
... on Issue {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const retrieveOpenBugReportIssueQueryResult: {
|
||||
search: {
|
||||
nodes: {
|
||||
id: string;
|
||||
title: string;
|
||||
}[];
|
||||
};
|
||||
} = await octokit.graphql(retrieveOpenBugReportIssueQuery);
|
||||
|
||||
const bugReportIssues = retrieveOpenBugReportIssueQueryResult?.search?.nodes;
|
||||
|
||||
return bugReportIssues?.length > 0 ? bugReportIssues[0] : undefined;
|
||||
}
|
||||
|
||||
|
||||
// This function closes a Github issue, based on its ID
|
||||
async function closeIssue(octokit: InstanceType<typeof GitHub>, issueId: string): Promise<string> {
|
||||
|
||||
const closeIssueMutation = `
|
||||
mutation CloseIssue($issueId: ID!) {
|
||||
updateIssue(input: {id: $issueId, state: CLOSED}) {
|
||||
clientMutationId
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const closeIssueMutationResult: {
|
||||
updateIssue: {
|
||||
clientMutationId: string;
|
||||
};
|
||||
} = await octokit.graphql(closeIssueMutation, {
|
||||
issueId,
|
||||
});
|
||||
|
||||
const clientMutationId = closeIssueMutationResult?.updateIssue?.clientMutationId;
|
||||
|
||||
return clientMutationId;
|
||||
}
|
2
.github/workflows/add-release-label.yml
vendored
2
.github/workflows/add-release-label.yml
vendored
@ -37,4 +37,4 @@ jobs:
|
||||
env:
|
||||
RELEASE_LABEL_TOKEN: ${{ secrets.RELEASE_LABEL_TOKEN }}
|
||||
NEXT_SEMVER_VERSION: ${{ env.NEXT_SEMVER_VERSION }}
|
||||
run: npm run add-release-label-to-pr-and-linked-issues
|
||||
run: yarn run add-release-label-to-pr-and-linked-issues
|
||||
|
2
.github/workflows/check-pr-labels.yml
vendored
2
.github/workflows/check-pr-labels.yml
vendored
@ -35,4 +35,4 @@ jobs:
|
||||
id: check-pr-has-required-labels
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npm run check-pr-has-required-labels
|
||||
run: yarn run check-pr-has-required-labels
|
||||
|
34
.github/workflows/close-bug-report.yml
vendored
Normal file
34
.github/workflows/close-bug-report.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
name: Close release bug report issue when release branch gets merged
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
types:
|
||||
- closed
|
||||
|
||||
jobs:
|
||||
close-bug-report:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'Version-v')
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1 # This retrieves only the latest commit.
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn --immutable
|
||||
|
||||
- name: Close release bug report issue
|
||||
id: close-release-bug-report-issue
|
||||
env:
|
||||
BUG_REPORT_REPO: MetaMask-planning
|
||||
BUG_REPORT_TOKEN: ${{ secrets.BUG_REPORT_TOKEN }}
|
||||
run: yarn run close-release-bug-report-issue
|
47
.github/workflows/create-bug-report.yml
vendored
Normal file
47
.github/workflows/create-bug-report.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
name: Create release bug report issue when release branch gets created
|
||||
|
||||
on: create
|
||||
|
||||
jobs:
|
||||
create-bug-report:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Extract version from branch name if release branch
|
||||
id: extract_version
|
||||
run: |
|
||||
if [[ "$GITHUB_REF" == "refs/heads/Version-v"* ]]; then
|
||||
version="${GITHUB_REF#refs/heads/Version-v}"
|
||||
echo "New release branch($version), continue next steps"
|
||||
echo "version=$version" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "Not a release branch, skip next steps"
|
||||
fi
|
||||
|
||||
- name: Create bug report issue on planning repo
|
||||
if: env.version
|
||||
uses: octokit/request-action@v2.x
|
||||
with:
|
||||
route: POST /repos/MetaMask/MetaMask-planning/issues
|
||||
owner: MetaMask
|
||||
title: v${{ env.version }} Bug Report
|
||||
body: |
|
||||
This bug report was automatically created by a GitHub action upon the creation of release branch `Version-v${{ env.version }}` (release cut).
|
||||
|
||||
|
||||
**Expected actions for release engineers:**
|
||||
|
||||
1. Convert this issue into a Zenhub epic and link all bugs identified during the release regression testing phase to this epic.
|
||||
|
||||
2. After completing the first regression run, move this epic to "Regression Completed" on the [Extension Release Regression board](https://app.zenhub.com/workspaces/extension-release-regression-6478c62d937eaa15e95c33c5/board?filterLogic=any&labels=release-${{ env.version }},release-task).
|
||||
|
||||
|
||||
Note that once the release is prepared for store submission, meaning the `Version-v${{ env.version }}` branch merges into `master`, another GitHub action will automatically close this epic.
|
||||
|
||||
labels: |
|
||||
[
|
||||
"type-bug",
|
||||
"regression-RC",
|
||||
"release-${{ env.version }}"
|
||||
]
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.BUG_REPORT_TOKEN }}
|
@ -98,6 +98,7 @@
|
||||
"validate-branch-name": "validate-branch-name",
|
||||
"add-release-label-to-pr-and-linked-issues": "ts-node ./.github/scripts/add-release-label-to-pr-and-linked-issues.ts",
|
||||
"check-pr-has-required-labels": "ts-node ./.github/scripts/check-pr-has-required-labels.ts",
|
||||
"close-release-bug-report-issue": "ts-node ./.github/scripts/close-release-bug-report-issue.ts",
|
||||
"audit": "yarn npm audit --recursive --environment production --severity moderate"
|
||||
},
|
||||
"resolutions": {
|
||||
|
Loading…
Reference in New Issue
Block a user