mirror of
https://github.com/zebrajr/react.git
synced 2025-12-07 00:20:28 +01:00
The download-build script works by scraping the CircleCI job number from the GitHub status API. Yes, I know this is super hacky but last I checked this was the least bad of not a lot of options. Because the response is paginated, sometimes the status for the build job exceeds the page size. This increases the page size to 100 so this is less likely to happen. It'd be great to find a better way to download the artifacts. I don't love how brittle this solution is. I think switching to the GitHub Checks API might be worth trying, but last I looked into it, it has other flaws.
76 lines
2.5 KiB
JavaScript
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?per_page=100`
|
|
);
|
|
|
|
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;
|