refactor(dev-infra): use shared github repo interface (#38656)

Instead of maintaining multiple interface for grouping
owner name and repo name, we expose a shared interface
describing a Github repository.

One unfortunate downside is that the GraphQL Github
and Rest API diverge slightly with the key for the
repository name. i.e. rest uses `repo` for the name
of a repository, while GraphQL uses `name` for the name.

If that would be consistent, we could use the rest operator
to pass a repository to the Octokit REST or GraphQL API. This
does not work, so we have a small manual overhead as seen
in the `branches.ts` file.

PR Close #38656
This commit is contained in:
Paul Gschwendtner 2020-09-01 12:32:09 +02:00 committed by Alex Rickabaugh
parent 3a598cf5ed
commit d7ff8d765c
4 changed files with 22 additions and 17 deletions

View File

@ -7,16 +7,12 @@
*/ */
import * as semver from 'semver'; import * as semver from 'semver';
import {GithubClient} from '../../../utils/git/github'; import {GithubClient, GithubRepo} from '../../../utils/git/github';
/** Type describing a Github repository with corresponding API client. */ /** Type describing a Github repository with corresponding API client. */
export interface GithubRepo { export interface GithubRepoWithApi extends GithubRepo {
/** API client that can access the repository. */ /** API client that can access the repository. */
api: GithubClient; api: GithubClient;
/** Owner login of the repository. */
owner: string;
/** Name of the repository. */
repo: string;
} }
/** Type describing a version-branch. */ /** Type describing a version-branch. */
@ -51,7 +47,7 @@ const releaseTrainBranchNameRegex = /(\d+)\.(\d+)\.x/;
* a currently active feature-freeze/release-candidate release-train. * a currently active feature-freeze/release-candidate release-train.
*/ */
export async function fetchActiveReleaseTrainBranches( export async function fetchActiveReleaseTrainBranches(
repo: GithubRepo, nextVersion: semver.SemVer): Promise<{ repo: GithubRepoWithApi, nextVersion: semver.SemVer): Promise<{
/** Release-train currently in active release-candidate/feature-freeze phase. */ /** Release-train currently in active release-candidate/feature-freeze phase. */
releaseCandidate: ReleaseTrain | null, releaseCandidate: ReleaseTrain | null,
/** Latest non-prerelease release train (i.e. for the patch branch). */ /** Latest non-prerelease release train (i.e. for the patch branch). */
@ -102,9 +98,9 @@ export async function fetchActiveReleaseTrainBranches(
/** Gets the version of a given branch by reading the `package.json` upstream. */ /** Gets the version of a given branch by reading the `package.json` upstream. */
export async function getVersionOfBranch( export async function getVersionOfBranch(
repo: GithubRepo, branchName: string): Promise<semver.SemVer> { repo: GithubRepoWithApi, branchName: string): Promise<semver.SemVer> {
const {data} = const {data} = await repo.api.repos.getContents(
await repo.api.repos.getContents({...repo, path: '/package.json', ref: branchName}); {owner: repo.owner, repo: repo.name, path: '/package.json', ref: branchName});
const {version} = JSON.parse(Buffer.from(data.content, 'base64').toString()); const {version} = JSON.parse(Buffer.from(data.content, 'base64').toString());
const parsedVersion = semver.parse(version); const parsedVersion = semver.parse(version);
if (parsedVersion === null) { if (parsedVersion === null) {
@ -136,8 +132,9 @@ export function getVersionForReleaseTrainBranch(branchName: string): semver.SemV
* order. i.e. latest version branches first. * order. i.e. latest version branches first.
*/ */
export async function getBranchesForMajorVersions( export async function getBranchesForMajorVersions(
repo: GithubRepo, majorVersions: number[]): Promise<VersionBranch[]> { repo: GithubRepoWithApi, majorVersions: number[]): Promise<VersionBranch[]> {
const {data: branchData} = await repo.api.repos.listBranches({...repo, protected: true}); const {data: branchData} =
await repo.api.repos.listBranches({owner: repo.owner, repo: repo.name, protected: true});
const branches: VersionBranch[] = []; const branches: VersionBranch[] = [];
for (const {name} of branchData) { for (const {name} of branchData) {
@ -159,7 +156,7 @@ export async function getBranchesForMajorVersions(
/** Finds the currently active release trains from the specified version branches. */ /** Finds the currently active release trains from the specified version branches. */
export async function findActiveReleaseTrainsFromVersionBranches( export async function findActiveReleaseTrainsFromVersionBranches(
repo: GithubRepo, nextVersion: semver.SemVer, branches: VersionBranch[], repo: GithubRepoWithApi, nextVersion: semver.SemVer, branches: VersionBranch[],
expectedReleaseCandidateMajor: number): Promise<{ expectedReleaseCandidateMajor: number): Promise<{
latest: ReleaseTrain | null, latest: ReleaseTrain | null,
releaseCandidate: ReleaseTrain | null, releaseCandidate: ReleaseTrain | null,

View File

@ -11,7 +11,7 @@ import {GithubClient} from '../../../utils/git/github';
import {TargetLabel} from '../config'; import {TargetLabel} from '../config';
import {InvalidTargetBranchError, InvalidTargetLabelError} from '../target-label'; import {InvalidTargetBranchError, InvalidTargetLabelError} from '../target-label';
import {fetchActiveReleaseTrainBranches, getVersionOfBranch, GithubRepo, isReleaseTrainBranch, nextBranchName} from './branches'; import {fetchActiveReleaseTrainBranches, getVersionOfBranch, GithubRepoWithApi, isReleaseTrainBranch, nextBranchName} from './branches';
import {assertActiveLtsBranch} from './lts-branch'; import {assertActiveLtsBranch} from './lts-branch';
/** /**
@ -22,7 +22,7 @@ import {assertActiveLtsBranch} from './lts-branch';
*/ */
export async function getDefaultTargetLabelConfiguration( export async function getDefaultTargetLabelConfiguration(
api: GithubClient, github: GithubConfig, npmPackageName: string): Promise<TargetLabel[]> { api: GithubClient, github: GithubConfig, npmPackageName: string): Promise<TargetLabel[]> {
const repo: GithubRepo = {owner: github.owner, repo: github.name, api}; const repo: GithubRepoWithApi = {owner: github.owner, name: github.name, api};
const nextVersion = await getVersionOfBranch(repo, nextBranchName); const nextVersion = await getVersionOfBranch(repo, nextBranchName);
const hasNextMajorTrain = nextVersion.minor === 0; const hasNextMajorTrain = nextVersion.minor === 0;
const {latest, releaseCandidate} = await fetchActiveReleaseTrainBranches(repo, nextVersion); const {latest, releaseCandidate} = await fetchActiveReleaseTrainBranches(repo, nextVersion);

View File

@ -12,7 +12,7 @@ import * as semver from 'semver';
import {promptConfirm, red, warn, yellow} from '../../../utils/console'; import {promptConfirm, red, warn, yellow} from '../../../utils/console';
import {InvalidTargetBranchError} from '../target-label'; import {InvalidTargetBranchError} from '../target-label';
import {getVersionOfBranch, GithubRepo} from './branches'; import {getVersionOfBranch, GithubRepoWithApi} from './branches';
/** /**
* Number of months a major version in Angular is actively supported. See: * Number of months a major version in Angular is actively supported. See:
@ -39,7 +39,7 @@ const majorActiveTermSupportDuration = 12;
* @param branchName Branch that is checked to be an active LTS version-branch. * @param branchName Branch that is checked to be an active LTS version-branch.
* */ * */
export async function assertActiveLtsBranch( export async function assertActiveLtsBranch(
repo: GithubRepo, representativeNpmPackage: string, branchName: string) { repo: GithubRepoWithApi, representativeNpmPackage: string, branchName: string) {
const version = await getVersionOfBranch(repo, branchName); const version = await getVersionOfBranch(repo, branchName);
const {'dist-tags': distTags, time} = const {'dist-tags': distTags, time} =
await (await fetch(`https://registry.npmjs.org/${representativeNpmPackage}`)).json(); await (await fetch(`https://registry.npmjs.org/${representativeNpmPackage}`)).json();

View File

@ -11,6 +11,14 @@ import * as Octokit from '@octokit/rest';
import {RequestParameters} from '@octokit/types'; import {RequestParameters} from '@octokit/types';
import {query, types} from 'typed-graphqlify'; import {query, types} from 'typed-graphqlify';
/** Interface describing a Github repository. */
export interface GithubRepo {
/** Owner login of the repository. */
owner: string;
/** Name of the repository. */
name: string;
}
/** Error for failed Github API requests. */ /** Error for failed Github API requests. */
export class GithubApiRequestError extends Error { export class GithubApiRequestError extends Error {
constructor(public status: number, message: string) { constructor(public status: number, message: string) {