feat(dev-infra): show CI status of all active release trains (#39067)

As part of the ng-dev caretaker check command, show the status of the
lastest CircleCI run for each active release train.

PR Close #39067
This commit is contained in:
Joey Perrott 2020-09-30 13:16:33 -07:00
parent f4f1bcc997
commit f3150223da
2 changed files with 23 additions and 19 deletions

View File

@ -8,6 +8,7 @@ ts_library(
module_name = "@angular/dev-infra-private/caretaker", module_name = "@angular/dev-infra-private/caretaker",
visibility = ["//dev-infra:__subpackages__"], visibility = ["//dev-infra:__subpackages__"],
deps = [ deps = [
"//dev-infra/release/versioning",
"//dev-infra/utils", "//dev-infra/utils",
"@npm//@types/node", "@npm//@types/node",
"@npm//@types/node-fetch", "@npm//@types/node-fetch",

View File

@ -7,52 +7,55 @@
*/ */
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import {fetchActiveReleaseTrains} from '../../release/versioning/index';
import {bold, green, info, red} from '../../utils/console'; import {bold, debug, info} from '../../utils/console';
import {GitClient} from '../../utils/git'; import {GitClient} from '../../utils/git';
/** The results of checking the status of CI. */ /** The results of checking the status of CI. */
interface StatusCheckResult { interface StatusCheckResult {
status: 'success'|'failed'|'canceled'|'infrastructure_fail'|'timedout'|'failed'|'no_tests'; status: 'success'|'failed';
timestamp: Date;
buildUrl: string;
} }
/** Retrieve and log status of CI for the project. */ /** Retrieve and log status of CI for the project. */
export async function printCiStatus(git: GitClient) { export async function printCiStatus(git: GitClient) {
const releaseTrains = await fetchActiveReleaseTrains({api: git.github, ...git.remoteConfig});
info.group(bold(`CI`)); info.group(bold(`CI`));
// TODO(josephperrott): Expand list of branches checked to all active branches. for (const [trainName, train] of Object.entries(releaseTrains)) {
await printStatus(git, 'master'); if (train === null) {
debug(`No active release train for ${trainName}`);
continue;
}
const status = await getStatusOfBranch(git, train.branchName);
await printStatus(`${trainName.padEnd(6)} (${train.branchName})`, status);
}
info.groupEnd(); info.groupEnd();
info(); info();
} }
/** Log the status of CI for a given branch to the console. */ /** Log the status of CI for a given branch to the console. */
async function printStatus(git: GitClient, branch: string) { async function printStatus(label: string, status: StatusCheckResult|null) {
const result = await getStatusOfBranch(git, branch); const branchName = label.padEnd(16);
const branchName = branch.padEnd(10); if (status === null) {
if (result === null) {
info(`${branchName} was not found on CircleCI`); info(`${branchName} was not found on CircleCI`);
} else if (result.status === 'success') { } else if (status.status === 'success') {
info(`${branchName}`); info(`${branchName}`);
} else { } else {
info(`${branchName} (Ran at: ${result.timestamp.toLocaleString()})`); info(`${branchName}`);
} }
} }
/** Get the CI status of a given branch from CircleCI. */ /** Get the CI status of a given branch from CircleCI. */
async function getStatusOfBranch(git: GitClient, branch: string): Promise<StatusCheckResult|null> { async function getStatusOfBranch(git: GitClient, branch: string): Promise<StatusCheckResult|null> {
const {owner, name} = git.remoteConfig; const {owner, name} = git.remoteConfig;
const url = `https://circleci.com/api/v1.1/project/gh/${owner}/${name}/tree/${ const url = `https://circleci.com/gh/${owner}/${name}/tree/${branch}.svg?style=shield`;
branch}?limit=1&filter=completed&shallow=true`; const result = await fetch(url).then(result => result.text());
const result = (await fetch(url).then(result => result.json()))?.[0];
if (result) { if (result && !result.includes('no builds')) {
return { return {
status: result.outcome, status: result.includes('passing') ? 'success' : 'failed',
timestamp: new Date(result.stop_time),
buildUrl: result.build_url
}; };
} }
return null; return null;