Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/MetaMask/metamask-mobile in…
Browse files Browse the repository at this point in the history
…to morph/convert-cells
  • Loading branch information
brianacnguyen committed Oct 26, 2023
2 parents 9e3aa2e + 4fb2b2b commit 45f112b
Show file tree
Hide file tree
Showing 24 changed files with 1,842 additions and 1,732 deletions.
2 changes: 1 addition & 1 deletion .github/guidelines/LABELING_GUIDELINES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ To maintain a consistent and efficient development workflow, we have set specifi
### Mandatory team labels:
- **Internal Developers**: Every PR raised by an internal developer must include a label prefixed with `team-` (e.g., `team-mobile-ux`, `team-mobile-platform`, etc.). This indicates the respective internal team responsible for the PR.

- **External Contributors**: PRs from contributors outside the organization must have the `external-contributor` label.
- **External Contributors**: PRs submitted by contributors who are not part of the organization will be automatically labeled with `external-contributor`.

It's essential to ensure that PRs have the appropriate labels before they are considered for merging.

Expand Down
2 changes: 1 addition & 1 deletion .github/pull-request-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Fixes: #
- [ ] I've included screenshots/recordings if applicable
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
- [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors.
- [ ] I’ve properly set the pull request status:
- [ ] In case it's not yet "ready for review", I've set it to "draft".
- [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft".
Expand Down
296 changes: 33 additions & 263 deletions .github/scripts/add-release-label-to-pr-and-linked-issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ import * as core from '@actions/core';
import { context, getOctokit } from '@actions/github';
import { GitHub } from '@actions/github/lib/utils';

// A labelable object can be a pull request or an issue
interface Labelable {
id: string;
number: number;
repoOwner: string;
repoName: string;
createdAt: string;
}
import { retrieveLinkedIssues } from './shared/issue';
import { Label } from './shared/label';
import { Labelable, addLabelToLabelable } from './shared/labelable';
import { retrievePullRequest } from './shared/pull-request';

main().catch((error: Error): void => {
console.error(error);
Expand Down Expand Up @@ -42,45 +38,56 @@ async function main(): Promise<void> {
}

if (!isValidVersionFormat(nextReleaseVersionNumber)) {
core.setFailed(`NEXT_SEMVER_VERSION (${nextReleaseVersionNumber}) is not a valid version format. The expected format is "x.y.z", where "x", "y" and "z" are numbers.`);
core.setFailed(
`NEXT_SEMVER_VERSION (${nextReleaseVersionNumber}) is not a valid version format. The expected format is "x.y.z", where "x", "y" and "z" are numbers.`,
);
process.exit(1);
}

// Release label indicates the next release version number
// Example release label: "release-6.5.0"
const releaseLabelName = `release-${nextReleaseVersionNumber}`;
const releaseLabelColor = "ededed";
const releaseLabelDescription = `Issue or pull request that will be included in release ${nextReleaseVersionNumber}`;
const releaseLabel: Label = {
name: `release-${nextReleaseVersionNumber}`,
color: 'EDEDED',
description: `Issue or pull request that will be included in release ${nextReleaseVersionNumber}`,
};

// Initialise octokit, required to call Github GraphQL API
const octokit: InstanceType<typeof GitHub> = getOctokit(
personalAccessToken,
{
previews: ["bane"], // The "bane" preview is required for adding, updating, creating and deleting labels.
},
);
const octokit: InstanceType<typeof GitHub> = getOctokit(personalAccessToken, {
previews: ['bane'], // The "bane" preview is required for adding, updating, creating and deleting labels.
});

// Retrieve pull request info from context
const prRepoOwner = context.repo.owner;
const prRepoName = context.repo.repo;
const prNumber = context.payload.pull_request?.number;
if (!prNumber) {
const pullRequestRepoOwner = context.repo.owner;
const pullRequestRepoName = context.repo.repo;
const pullRequestNumber = context.payload.pull_request?.number;
if (!pullRequestNumber) {
core.setFailed('Pull request number not found');
process.exit(1);
}

// Retrieve pull request
const pullRequest: Labelable = await retrievePullRequest(octokit, prRepoOwner, prRepoName, prNumber);
const pullRequest: Labelable = await retrievePullRequest(
octokit,
pullRequestRepoOwner,
pullRequestRepoName,
pullRequestNumber,
);

// Add the release label to the pull request
await addLabelToLabelable(octokit, pullRequest, releaseLabelName, releaseLabelColor, releaseLabelDescription);
await addLabelToLabelable(octokit, pullRequest, releaseLabel);

// Retrieve linked issues for the pull request
const linkedIssues: Labelable[] = await retrieveLinkedIssues(octokit, prRepoOwner, prRepoName, prNumber);
const linkedIssues: Labelable[] = await retrieveLinkedIssues(
octokit,
pullRequestRepoOwner,
pullRequestRepoName,
pullRequestNumber,
);

// Add the release label to the linked issues
for (const linkedIssue of linkedIssues) {
await addLabelToLabelable(octokit, linkedIssue, releaseLabelName, releaseLabelColor, releaseLabelDescription);
await addLabelToLabelable(octokit, linkedIssue, releaseLabel);
}
}

Expand All @@ -89,240 +96,3 @@ function isValidVersionFormat(str: string): boolean {
const regex = /^\d+\.\d+\.\d+$/;
return regex.test(str);
}

// This function retrieves the repo
async function retrieveRepo(octokit: InstanceType<typeof GitHub>, repoOwner: string, repoName: string): Promise<string> {

const retrieveRepoQuery = `
query RetrieveRepo($repoOwner: String!, $repoName: String!) {
repository(owner: $repoOwner, name: $repoName) {
id
}
}
`;

const retrieveRepoResult: {
repository: {
id: string;
};
} = await octokit.graphql(retrieveRepoQuery, {
repoOwner,
repoName,
});

const repoId = retrieveRepoResult?.repository?.id;

return repoId;
}

// This function retrieves the label on a specific repo
async function retrieveLabel(octokit: InstanceType<typeof GitHub>, repoOwner: string, repoName: string, labelName: string): Promise<string> {

const retrieveLabelQuery = `
query RetrieveLabel($repoOwner: String!, $repoName: String!, $labelName: String!) {
repository(owner: $repoOwner, name: $repoName) {
label(name: $labelName) {
id
}
}
}
`;

const retrieveLabelResult: {
repository: {
label: {
id: string;
};
};
} = await octokit.graphql(retrieveLabelQuery, {
repoOwner,
repoName,
labelName,
});

const labelId = retrieveLabelResult?.repository?.label?.id;

return labelId;
}

// This function creates the label on a specific repo
async function createLabel(octokit: InstanceType<typeof GitHub>, repoId: string, labelName: string, labelColor: string, labelDescription: string): Promise<string> {

const createLabelMutation = `
mutation CreateLabel($repoId: ID!, $labelName: String!, $labelColor: String!, $labelDescription: String) {
createLabel(input: {repositoryId: $repoId, name: $labelName, color: $labelColor, description: $labelDescription}) {
label {
id
}
}
}
`;

const createLabelResult: {
createLabel: {
label: {
id: string;
};
};
} = await octokit.graphql(createLabelMutation, {
repoId,
labelName,
labelColor,
labelDescription,
});

const labelId = createLabelResult?.createLabel?.label?.id;

return labelId;
}

// This function creates or retrieves the label on a specific repo
async function createOrRetrieveLabel(octokit: InstanceType<typeof GitHub>, repoOwner: string, repoName: string, labelName: string, labelColor: string, labelDescription: string): Promise<string> {

// Check if label already exists on the repo
let labelId = await retrieveLabel(octokit, repoOwner, repoName, labelName);

// If label doesn't exist on the repo, create it
if (!labelId) {
// Retrieve PR's repo
const repoId = await retrieveRepo(octokit, repoOwner, repoName);

// Create label on repo
labelId = await createLabel(octokit, repoId, labelName, labelColor, labelDescription);
}

return labelId;
}

// This function retrieves the pull request on a specific repo
async function retrievePullRequest(octokit: InstanceType<typeof GitHub>, repoOwner: string, repoName: string, prNumber: number): Promise<Labelable> {

const retrievePullRequestQuery = `
query GetPullRequest($repoOwner: String!, $repoName: String!, $prNumber: Int!) {
repository(owner: $repoOwner, name: $repoName) {
pullRequest(number: $prNumber) {
id
createdAt
}
}
}
`;

const retrievePullRequestResult: {
repository: {
pullRequest: {
id: string;
createdAt: string;
};
};
} = await octokit.graphql(retrievePullRequestQuery, {
repoOwner,
repoName,
prNumber,
});

const pullRequest: Labelable = {
id: retrievePullRequestResult?.repository?.pullRequest?.id,
number: prNumber,
repoOwner: repoOwner,
repoName: repoName,
createdAt: retrievePullRequestResult?.repository?.pullRequest?.createdAt,
}

return pullRequest;
}


// This function retrieves the list of linked issues for a pull request
async function retrieveLinkedIssues(octokit: InstanceType<typeof GitHub>, repoOwner: string, repoName: string, prNumber: number): Promise<Labelable[]> {

// We assume there won't be more than 100 linked issues
const retrieveLinkedIssuesQuery = `
query ($repoOwner: String!, $repoName: String!, $prNumber: Int!) {
repository(owner: $repoOwner, name: $repoName) {
pullRequest(number: $prNumber) {
closingIssuesReferences(first: 100) {
nodes {
id
number
createdAt
repository {
name
owner {
login
}
}
}
}
}
}
}
`;

const retrieveLinkedIssuesResult: {
repository: {
pullRequest: {
closingIssuesReferences: {
nodes: Array<{
id: string;
number: number;
createdAt: string;
repository: {
name: string;
owner: {
login: string;
};
};
}>;
};
};
};
} = await octokit.graphql(retrieveLinkedIssuesQuery, {
repoOwner,
repoName,
prNumber
});

const linkedIssues = retrieveLinkedIssuesResult?.repository?.pullRequest?.closingIssuesReferences?.nodes?.map((issue: {
id: string;
number: number;
createdAt: string;
repository: {
name: string;
owner: {
login: string;
};
};
}) => {
return {
id: issue?.id,
number: issue?.number,
repoOwner: issue?.repository?.owner?.login,
repoName: issue?.repository?.name,
createdAt: issue?.createdAt
};
}) || [];

return linkedIssues;
}

// This function adds label to a labelable object (i.e. a pull request or an issue)
async function addLabelToLabelable(octokit: InstanceType<typeof GitHub>, labelable: Labelable, labelName: string, labelColor: string, labelDescription: string): Promise<void> {

// Retrieve label from the labelable's repo, or create label if required
const labelId = await createOrRetrieveLabel(octokit, labelable?.repoOwner, labelable?.repoName, labelName, labelColor, labelDescription);

const addLabelsToLabelableMutation = `
mutation AddLabelsToLabelable($labelableId: ID!, $labelIds: [ID!]!) {
addLabelsToLabelable(input: {labelableId: $labelableId, labelIds: $labelIds}) {
clientMutationId
}
}
`;

await octokit.graphql(addLabelsToLabelableMutation, {
labelableId: labelable?.id,
labelIds: [labelId],
});

}
Loading

0 comments on commit 45f112b

Please sign in to comment.