Paul Gschwendtner 67f65a9d25 refactor(dev-infra): improve type-safety of git client utility (#42468)
Currently the `GitClient` accepts a generic parameter for determining
whether the `githubToken` should be set or not. This worked fine so far
in terms of distinguishing between an authenticated and
non-authenticated git client instance, but if we intend to conditionally
show methods only for authenticated instances, the generic parameter
is not suitable.

This commit splits up the `GitClient` into two classes. One for
the base logic without any authorization, and a second class that
extends the base logic with authentication logic. i.e. the
`AuthenticatedGitClient`. This allows us to have specific methods only
for the authenticated instance. e.g.

  * `hasOauthScopes` has been moved to only exist for authenticated
    instances.
  * the GraphQL functionality within `gitClient.github` is not
    accessible for non-authenticated instances. GraphQL API requires
    authentication as per Github.

The initial motiviation for this was that we want to throw if
`hasOAuthScopes` is called without the Octokit instance having
a token configured. This should help avoiding issues as within
3b434ed94d
that prevented the caretaker process momentarily.

Additionally, the Git client has moved from `index.ts` to
`git-client.ts` for better discoverability in the codebase.

PR Close #42468
2021-06-03 14:34:33 -07:00

86 lines
2.8 KiB
TypeScript

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {params, types} from 'typed-graphqlify';
import {AuthenticatedGitClient} from './git/authenticated-git-client';
/** Get a PR from github */
export async function getPr<PrSchema>(
prSchema: PrSchema, prNumber: number, git: AuthenticatedGitClient) {
/** The owner and name of the repository */
const {owner, name} = git.remoteConfig;
/** The Graphql query object to get a the PR */
const PR_QUERY = params(
{
$number: 'Int!', // The PR number
$owner: 'String!', // The organization to query for
$name: 'String!', // The organization to query for
},
{
repository: params({owner: '$owner', name: '$name'}, {
pullRequest: params({number: '$number'}, prSchema),
})
});
const result = (await git.github.graphql(PR_QUERY, {number: prNumber, owner, name}));
return result.repository.pullRequest;
}
/** Get all pending PRs from github */
export async function getPendingPrs<PrSchema>(prSchema: PrSchema, git: AuthenticatedGitClient) {
/** The owner and name of the repository */
const {owner, name} = git.remoteConfig;
/** The Graphql query object to get a page of pending PRs */
const PRS_QUERY = params(
{
$first: 'Int', // How many entries to get with each request
$after: 'String', // The cursor to start the page at
$owner: 'String!', // The organization to query for
$name: 'String!', // The repository to query for
},
{
repository: params({owner: '$owner', name: '$name'}, {
pullRequests: params(
{
first: '$first',
after: '$after',
states: `OPEN`,
},
{
nodes: [prSchema],
pageInfo: {
hasNextPage: types.boolean,
endCursor: types.string,
},
}),
})
});
/** The current cursor */
let cursor: string|undefined;
/** If an additional page of members is expected */
let hasNextPage = true;
/** Array of pending PRs */
const prs: Array<PrSchema> = [];
// For each page of the response, get the page and add it to the list of PRs
while (hasNextPage) {
const params = {
after: cursor || null,
first: 100,
owner,
name,
};
const results = await git.github.graphql(PRS_QUERY, params) as typeof PRS_QUERY;
prs.push(...results.repository.pullRequests.nodes);
hasNextPage = results.repository.pullRequests.pageInfo.hasNextPage;
cursor = results.repository.pullRequests.pageInfo.endCursor;
}
return prs;
}