From 2d3539f4dfa4911c2be1aac14e6a6fa294db56c7 Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Tue, 6 Apr 2021 07:43:21 -0700 Subject: [PATCH] refactor(dev-infra): use graphql to query PRs in merge tooling (#41459) Migrate to use graqhql to query for PR information during the validation and preperation portions of the pr merge tooling. PR Close #41459 --- dev-infra/ng-dev.js | 64 +++++++++++++++++++----------- dev-infra/pr/merge/BUILD.bazel | 1 + dev-infra/pr/merge/pull-request.ts | 48 ++++++++++++++++------ 3 files changed, 78 insertions(+), 35 deletions(-) diff --git a/dev-infra/ng-dev.js b/dev-infra/ng-dev.js index 2949c3f0a29..b25d5092242 100755 --- a/dev-infra/ng-dev.js +++ b/dev-infra/ng-dev.js @@ -3396,7 +3396,7 @@ function loadAndValidatePullRequest(_a, prNumber, ignoreNonFatalFailures) { if (prData === null) { return [2 /*return*/, PullRequestFailure.notFound()]; } - labels = prData.labels.map(function (l) { return l.name; }); + labels = prData.labels.nodes.map(function (l) { return l.name; }); if (!labels.some(function (name) { return matchesPattern(name, config.mergeReadyLabel); })) { return [2 /*return*/, PullRequestFailure.notMergeReady()]; } @@ -3412,36 +3412,34 @@ function loadAndValidatePullRequest(_a, prNumber, ignoreNonFatalFailures) { } throw error; } - return [4 /*yield*/, git.github.repos.getCombinedStatusForRef(tslib.__assign(tslib.__assign({}, git.remoteParams), { ref: prData.head.sha }))]; - case 2: - state = (_b.sent()).data.state; - if (state === 'failure' && !ignoreNonFatalFailures) { + state = prData.commits.nodes.slice(-1)[0].commit.status.state; + if (state === 'FAILURE' && !ignoreNonFatalFailures) { return [2 /*return*/, PullRequestFailure.failingCiJobs()]; } - if (state === 'pending' && !ignoreNonFatalFailures) { + if (state === 'PENDING' && !ignoreNonFatalFailures) { return [2 /*return*/, PullRequestFailure.pendingCiJobs()]; } - githubTargetBranch = prData.base.ref; + githubTargetBranch = prData.baseRefOid; requiredBaseSha = config.requiredBaseCommits && config.requiredBaseCommits[githubTargetBranch]; needsCommitMessageFixup = !!config.commitMessageFixupLabel && labels.some(function (name) { return matchesPattern(name, config.commitMessageFixupLabel); }); hasCaretakerNote = !!config.caretakerNoteLabel && labels.some(function (name) { return matchesPattern(name, config.caretakerNoteLabel); }); - _b.label = 3; - case 3: - _b.trys.push([3, 5, , 6]); + _b.label = 2; + case 2: + _b.trys.push([2, 4, , 5]); return [4 /*yield*/, getBranchesFromTargetLabel(targetLabel, githubTargetBranch)]; - case 4: + case 3: targetBranches = _b.sent(); - return [3 /*break*/, 6]; - case 5: + return [3 /*break*/, 5]; + case 4: error_1 = _b.sent(); if (error_1 instanceof InvalidTargetBranchError || error_1 instanceof InvalidTargetLabelError) { return [2 /*return*/, new PullRequestFailure(error_1.failureMessage)]; } throw error_1; - case 6: return [2 /*return*/, { - url: prData.html_url, + case 5: return [2 /*return*/, { + url: prData.url, prNumber: prNumber, labels: labels, requiredBaseSha: requiredBaseSha, @@ -3450,24 +3448,44 @@ function loadAndValidatePullRequest(_a, prNumber, ignoreNonFatalFailures) { hasCaretakerNote: hasCaretakerNote, targetBranches: targetBranches, title: prData.title, - commitCount: prData.commits, + commitCount: prData.commits.nodes.length, }]; } }); }); } +/* GraphQL schema for the response body the requested PR. */ +var PR_SCHEMA$2 = { + url: typedGraphqlify.types.string, + number: typedGraphqlify.types.number, + commits: typedGraphqlify.params({ first: 100 }, { + nodes: [{ + commit: { + status: { + state: typedGraphqlify.types.oneOf(['FAILURE', 'PENDING', 'SUCCESS']), + }, + message: typedGraphqlify.types.string, + }, + }], + }), + baseRefOid: typedGraphqlify.types.string, + title: typedGraphqlify.types.string, + labels: typedGraphqlify.params({ first: 100 }, { + nodes: [{ + name: typedGraphqlify.types.string, + }] + }), +}; /** Fetches a pull request from Github. Returns null if an error occurred. */ function fetchPullRequestFromGithub(git, prNumber) { return tslib.__awaiter(this, void 0, void 0, function () { - var result, e_1; + var e_1; return tslib.__generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); - return [4 /*yield*/, git.github.pulls.get(tslib.__assign(tslib.__assign({}, git.remoteParams), { pull_number: prNumber }))]; - case 1: - result = _a.sent(); - return [2 /*return*/, result.data]; + return [4 /*yield*/, getPr(PR_SCHEMA$2, prNumber, git)]; + case 1: return [2 /*return*/, _a.sent()]; case 2: e_1 = _a.sent(); // If the pull request could not be found, we want to return `null` so @@ -4315,7 +4333,7 @@ var MergeCommandModule = { * found in the LICENSE file at https://angular.io/license */ /* GraphQL schema for the response body for each pending PR. */ -const PR_SCHEMA$2 = { +const PR_SCHEMA$3 = { state: typedGraphqlify.types.string, maintainerCanModify: typedGraphqlify.types.boolean, viewerDidAuthor: typedGraphqlify.types.boolean, @@ -4353,7 +4371,7 @@ function rebasePr(prNumber, githubToken, config = getConfig()) { */ const previousBranchOrRevision = git.getCurrentBranchOrRevision(); /* Get the PR information from Github. */ - const pr = yield getPr(PR_SCHEMA$2, prNumber, git); + const pr = yield getPr(PR_SCHEMA$3, prNumber, git); const headRefName = pr.headRef.name; const baseRefName = pr.baseRef.name; const fullHeadRef = `${pr.headRef.repository.nameWithOwner}:${headRefName}`; diff --git a/dev-infra/pr/merge/BUILD.bazel b/dev-infra/pr/merge/BUILD.bazel index b252fddc1fc..db52d4b1954 100644 --- a/dev-infra/pr/merge/BUILD.bazel +++ b/dev-infra/pr/merge/BUILD.bazel @@ -24,6 +24,7 @@ ts_library( "@npm//@types/semver", "@npm//@types/yargs", "@npm//chalk", + "@npm//typed-graphqlify", ], ) diff --git a/dev-infra/pr/merge/pull-request.ts b/dev-infra/pr/merge/pull-request.ts index 222df0007a1..b1f7ef877a2 100644 --- a/dev-infra/pr/merge/pull-request.ts +++ b/dev-infra/pr/merge/pull-request.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import * as Octokit from '@octokit/rest'; +import {params, types as graphQLTypes} from 'typed-graphqlify'; import {GitClient} from '../../utils/git/index'; +import {getPr} from '../../utils/github'; import {TargetLabel} from './config'; import {PullRequestFailure} from './failures'; @@ -53,7 +54,7 @@ export async function loadAndValidatePullRequest( return PullRequestFailure.notFound(); } - const labels = prData.labels.map(l => l.name); + const labels = prData.labels.nodes.map(l => l.name); if (!labels.some(name => matchesPattern(name, config.mergeReadyLabel))) { return PullRequestFailure.notMergeReady(); @@ -72,17 +73,16 @@ export async function loadAndValidatePullRequest( throw error; } - const {data: {state}} = - await git.github.repos.getCombinedStatusForRef({...git.remoteParams, ref: prData.head.sha}); - if (state === 'failure' && !ignoreNonFatalFailures) { + const state = prData.commits.nodes.slice(-1)[0].commit.status.state; + if (state === 'FAILURE' && !ignoreNonFatalFailures) { return PullRequestFailure.failingCiJobs(); } - if (state === 'pending' && !ignoreNonFatalFailures) { + if (state === 'PENDING' && !ignoreNonFatalFailures) { return PullRequestFailure.pendingCiJobs(); } - const githubTargetBranch = prData.base.ref; + const githubTargetBranch = prData.baseRefOid; const requiredBaseSha = config.requiredBaseCommits && config.requiredBaseCommits[githubTargetBranch]; const needsCommitMessageFixup = !!config.commitMessageFixupLabel && @@ -105,7 +105,7 @@ export async function loadAndValidatePullRequest( } return { - url: prData.html_url, + url: prData.url, prNumber, labels, requiredBaseSha, @@ -114,16 +114,40 @@ export async function loadAndValidatePullRequest( hasCaretakerNote, targetBranches, title: prData.title, - commitCount: prData.commits, + commitCount: prData.commits.nodes.length, }; } +/* GraphQL schema for the response body the requested PR. */ +const PR_SCHEMA = { + url: graphQLTypes.string, + number: graphQLTypes.number, + commits: params({first: 100}, { + nodes: [{ + commit: { + status: { + state: graphQLTypes.oneOf(['FAILURE' as const, 'PENDING' as const, 'SUCCESS' as const]), + }, + message: graphQLTypes.string, + }, + }], + }), + baseRefOid: graphQLTypes.string, + title: graphQLTypes.string, + labels: params({first: 100}, { + nodes: [{ + name: graphQLTypes.string, + }] + }), +}; + + + /** Fetches a pull request from Github. Returns null if an error occurred. */ async function fetchPullRequestFromGithub( - git: GitClient, prNumber: number): Promise { + git: GitClient, prNumber: number): Promise { try { - const result = await git.github.pulls.get({...git.remoteParams, pull_number: prNumber}); - return result.data; + return await getPr(PR_SCHEMA, prNumber, git); } catch (e) { // If the pull request could not be found, we want to return `null` so // that the error can be handled gracefully.