The merge script currently accepts a configuration function that will be invoked _only_ when the `ng-dev merge` command is executed. This has been done that way because the merge tooling usually relies on external requests to Git or NPM for constructing the branch configurations. We do not want to perform these slow external queries on any `ng-dev` command though, so this became a lazily invoked function. This commit adds support for these configuration functions to run asynchronously (by returning a Promise that will be awaited), so that requests could also be made to the Github API. This is benefical as it could avoid dependence on the local Git state and the HTTP requests are more powerful/faster. Additionally, in order to be able to perform Github API requests with an authenticated instance, the merge tool will pass through a `GithubClient` instance that uses the specified `--github-token` (or from the environment). This ensures that all API requests use the same `GithubClient` instance and can be authenticated (mitigating potential rate limits). PR Close #38223
94 lines
2.8 KiB
TypeScript
94 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 {graphql} from '@octokit/graphql';
|
|
import * as Octokit from '@octokit/rest';
|
|
import {RequestParameters} from '@octokit/types';
|
|
import {query, types} from 'typed-graphqlify';
|
|
|
|
/** Error for failed Github API requests. */
|
|
export class GithubApiRequestError extends Error {
|
|
constructor(public status: number, message: string) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A Github client for interacting with the Github APIs.
|
|
*
|
|
* Additionally, provides convenience methods for actions which require multiple requests, or
|
|
* would provide value from memoized style responses.
|
|
**/
|
|
export class GithubClient extends Octokit {
|
|
/** The Github GraphQL (v4) API. */
|
|
graqhql: GithubGraphqlClient;
|
|
|
|
/** The current user based on checking against the Github API. */
|
|
private _currentUser: string|null = null;
|
|
|
|
constructor(token?: string) {
|
|
// Pass in authentication token to base Octokit class.
|
|
super({auth: token});
|
|
|
|
this.hook.error('request', error => {
|
|
// Wrap API errors in a known error class. This allows us to
|
|
// expect Github API errors better and in a non-ambiguous way.
|
|
throw new GithubApiRequestError(error.status, error.message);
|
|
});
|
|
|
|
// Create authenticated graphql client.
|
|
this.graqhql = new GithubGraphqlClient(token);
|
|
}
|
|
|
|
/** Retrieve the login of the current user from Github. */
|
|
async getCurrentUser() {
|
|
// If the current user has already been retrieved return the current user value again.
|
|
if (this._currentUser !== null) {
|
|
return this._currentUser;
|
|
}
|
|
const result = await this.graqhql.query({
|
|
viewer: {
|
|
login: types.string,
|
|
}
|
|
});
|
|
return this._currentUser = result.viewer.login;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An object representation of a GraphQL Query to be used as a response type and to generate
|
|
* a GraphQL query string.
|
|
*/
|
|
type GraphQLQueryObject = Parameters<typeof query>[1];
|
|
|
|
/**
|
|
* A client for interacting with Github's GraphQL API.
|
|
*
|
|
* This class is intentionally not exported as it should always be access/used via a
|
|
* _GithubClient instance.
|
|
*/
|
|
class GithubGraphqlClient {
|
|
/** The Github GraphQL (v4) API. */
|
|
private graqhql = graphql;
|
|
|
|
constructor(token?: string) {
|
|
// Set the default headers to include authorization with the provided token for all
|
|
// graphQL calls.
|
|
if (token) {
|
|
this.graqhql.defaults({headers: {authorization: `token ${token}`}});
|
|
}
|
|
}
|
|
|
|
|
|
/** Perform a query using Github's GraphQL API. */
|
|
async query<T extends GraphQLQueryObject>(queryObject: T, params: RequestParameters = {}) {
|
|
const queryString = query(queryObject);
|
|
return (await this.graqhql(queryString, params)) as T;
|
|
}
|
|
}
|