Skip to content

Commit

Permalink
Add command to publish preleases via CI (#20728)
Browse files Browse the repository at this point in the history
```
yarn publish-prereleases
```

Script to trigger a CircleCI workflow that publishes preleases.

**The CI workflow doesn't actually publish yet; it just runs and logs
its inputs.**
  • Loading branch information
acdlite committed Feb 3, 2021
1 parent 00e38c8 commit c1cfa73
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 1 deletion.
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -139,6 +139,7 @@
"prettier-all": "node ./scripts/prettier/index.js write",
"version-check": "node ./scripts/tasks/version-check.js",
"merge-fork": "node ./scripts/merge-fork/merge-fork.js",
"replace-fork": "node ./scripts/merge-fork/replace-fork.js"
"replace-fork": "node ./scripts/merge-fork/replace-fork.js",
"publish-prereleases": "node ./scripts/release/publish-using-ci-workflow.js"
}
}
117 changes: 117 additions & 0 deletions scripts/release/publish-using-ci-workflow.js
@@ -0,0 +1,117 @@
'use strict';

const fetch = require('node-fetch');

const {logPromise} = require('./utils');
const theme = require('./theme');

const CIRCLE_TOKEN = process.env.CIRCLE_CI_API_TOKEN;

if (!CIRCLE_TOKEN) {
console.error(
theme.error('Missing required environment variable: CIRCLE_CI_API_TOKEN')
);
process.exit(1);
}

function sleep(ms) {
return new Promise(resolve => {
setTimeout(() => resolve(), ms);
});
}

async function getPublishWorkflowID(pipelineID) {
// Since we just created the pipeline in a POST request, the server may 404.
// Try up to three times before giving up.
for (let i = 0; i < 3; i++) {
const pipelineWorkflowsResponse = await fetch(
`https://circleci.com/api/v2/pipeline/${pipelineID}/workflow`
);
if (pipelineWorkflowsResponse.ok) {
const pipelineWorkflowsJSON = await pipelineWorkflowsResponse.json();
const workflows = pipelineWorkflowsJSON.items;
if (workflows.length !== 0) {
return workflows[0].id;
}
}
// CircleCI server may be stale. Wait a sec and try again.
await sleep(1000);
}
throw new Error('Failed to create CircleCI workflow.');
}

async function pollUntilWorkflowFinishes(workflowID) {
while (true) {
const workflowResponse = await fetch(
`https://circleci.com/api/v2/workflow/${workflowID}`
);
const workflow = await workflowResponse.json();
switch (workflow.status) {
case 'running':
// Workflow still running. Wait a bit then check again.
await sleep(2000);
continue;
case 'success':
// Publish succeeded! Continue.
return;
case 'not_run':
case 'failed':
case 'error':
case 'failing':
case 'on_hold':
case 'canceled':
case 'unauthorized':
default:
console.error(
theme.error(
`Failed to publish. Workflow exited with status: ${workflow.status}`
)
);
console.error(
`Visit https://app.circleci.com/pipelines/workflows/${workflowID} for details.`
);
process.exit(1);
break;
}
}
}

async function main() {
const pipelineResponse = await fetch(
'https://circleci.com/api/v2/project/github/facebook/react/pipeline',
{
method: 'post',
body: JSON.stringify({
parameters: {
// TODO: Make commit SHA configurable
prerelease_commit_sha: 'master',
},
}),
headers: {
'Circle-Token': CIRCLE_TOKEN,
'Content-Type': 'application/json',
},
}
);

const pipelineJSON = await pipelineResponse.json();
const pipelineID = pipelineJSON.id;

const workflowID = await logPromise(
getPublishWorkflowID(pipelineID),
theme`{header Creating CI workflow}`,
2 * 1000 // Estimated time: 2 seconds,
);

await logPromise(
pollUntilWorkflowFinishes(workflowID),
theme`{header Publishing in CI workflow}: https://app.circleci.com/pipelines/workflows/${workflowID}`,
2 * 60 * 1000 // Estimated time: 2 minutes,
);
}

main().catch(error => {
console.error(theme.error('Failed to trigger publish workflow.'));
console.error(error.message);
process.exit(1);
});

0 comments on commit c1cfa73

Please sign in to comment.