Files
react/scripts/release/shared-commands/get-build-id-for-commit.js
Andrew Clark 7a5b8227c7 Allow aritfacts download even if CI is broken (#24666)
* Allow aritfacts download even if CI is broken

Adds an option to the download script to disable the CI check and
continue downloading the artifacts even if CI is broken.

I often rely on this to debug broken build artifacts. I was thinking
the sizebot should also use this when downloading the base artifacts
from main, since for the purposes of size tracking, it really doesn't
matter whether the base commit is broken.

* Sizebot should work even if base rev is broken

Sizebot works by downloading the build artifacts for the base revision
and comparing the fize sizes, but the download script will fail if
the base revision has a failing CI job. This happens more often than it
should because of flaky cron jobs, but even when it does, we shouldn't
let it affect the sizebot — for the purposes of tracking sizes, it
doesn't really matter whether the base revision is broken.
2022-06-02 21:55:35 -04:00

76 lines
2.5 KiB
JavaScript

'use strict';
const fetch = require('node-fetch');
const POLLING_INTERVAL = 10 * 1000; // 10 seconds
const RETRY_TIMEOUT = 4 * 60 * 1000; // 4 minutes
function wait(ms) {
return new Promise(resolve => {
setTimeout(() => resolve(), ms);
});
}
function scrapeBuildIDFromStatus(status) {
return /\/facebook\/react\/([0-9]+)/.exec(status.target_url)[1];
}
async function getBuildIdForCommit(sha, allowBrokenCI = false) {
const retryLimit = Date.now() + RETRY_TIMEOUT;
retry: while (true) {
const statusesResponse = await fetch(
`https://api.github.com/repos/facebook/react/commits/${sha}/status`
);
if (!statusesResponse.ok) {
if (statusesResponse.status === 404) {
throw Error('Could not find commit for: ' + sha);
}
const {message, documentation_url} = await statusesResponse.json();
const msg = documentation_url
? `${message}\n\t${documentation_url}`
: message;
throw Error(msg);
}
const {statuses, state} = await statusesResponse.json();
if (!allowBrokenCI && state === 'failure') {
throw new Error(`Base commit is broken: ${sha}`);
}
for (let i = 0; i < statuses.length; i++) {
const status = statuses[i];
if (status.context === `ci/circleci: process_artifacts_combined`) {
if (status.state === 'success') {
return scrapeBuildIDFromStatus(status);
}
if (status.state === 'failure') {
throw new Error(`Build job for commit failed: ${sha}`);
}
if (status.state === 'pending') {
if (Date.now() < retryLimit) {
await wait(POLLING_INTERVAL);
continue retry;
}
// GitHub's status API is super flaky. Sometimes it reports a job
// as "pending" even after it completes in CircleCI. If it's still
// pending when we time out, return the build ID anyway.
// TODO: The location of the retry loop is a bit weird. We should
// probably combine this function with the one that downloads the
// artifacts, and wrap the retry loop around the whole thing.
return scrapeBuildIDFromStatus(status);
}
}
}
if (state === 'pending') {
if (Date.now() < retryLimit) {
await wait(POLLING_INTERVAL);
continue retry;
}
throw new Error('Exceeded retry limit. Build job is still pending.');
}
throw new Error('Could not find build for commit: ' + sha);
}
}
module.exports = getBuildIdForCommit;