@samitouri / QOS-React-2 / commits / c1cfa734fd

Add command to publish preleases via CI (#20728)

``` 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.**

Andrew Clark committed Feb 3, 2021 at 17:42 UTC c1cfa734fd4e72850a9d583d03d4244dabcee585
2 files changed +119 -1
package.json
+2 -1
@@ -139,6 +139,7 @@
139 "prettier-all": "node ./scripts/prettier/index.js write",
140 "version-check": "node ./scripts/tasks/version-check.js",
141 "merge-fork": "node ./scripts/merge-fork/merge-fork.js",
142 - "replace-fork": "node ./scripts/merge-fork/replace-fork.js"
142 + "replace-fork": "node ./scripts/merge-fork/replace-fork.js",
143 + "publish-prereleases": "node ./scripts/release/publish-using-ci-workflow.js"
144 }
145 }
scripts/release/publish-using-ci-workflow.js new
+117
@@ -0,0 +1,117 @@
1 +'use strict';
2 +
3 +const fetch = require('node-fetch');
4 +
5 +const {logPromise} = require('./utils');
6 +const theme = require('./theme');
7 +
8 +const CIRCLE_TOKEN = process.env.CIRCLE_CI_API_TOKEN;
9 +
10 +if (!CIRCLE_TOKEN) {
11 + console.error(
12 + theme.error('Missing required environment variable: CIRCLE_CI_API_TOKEN')
13 + );
14 + process.exit(1);
15 +}
16 +
17 +function sleep(ms) {
18 + return new Promise(resolve => {
19 + setTimeout(() => resolve(), ms);
20 + });
21 +}
22 +
23 +async function getPublishWorkflowID(pipelineID) {
24 + // Since we just created the pipeline in a POST request, the server may 404.
25 + // Try up to three times before giving up.
26 + for (let i = 0; i < 3; i++) {
27 + const pipelineWorkflowsResponse = await fetch(
28 + `https://circleci.com/api/v2/pipeline/${pipelineID}/workflow`
29 + );
30 + if (pipelineWorkflowsResponse.ok) {
31 + const pipelineWorkflowsJSON = await pipelineWorkflowsResponse.json();
32 + const workflows = pipelineWorkflowsJSON.items;
33 + if (workflows.length !== 0) {
34 + return workflows[0].id;
35 + }
36 + }
37 + // CircleCI server may be stale. Wait a sec and try again.
38 + await sleep(1000);
39 + }
40 + throw new Error('Failed to create CircleCI workflow.');
41 +}
42 +
43 +async function pollUntilWorkflowFinishes(workflowID) {
44 + while (true) {
45 + const workflowResponse = await fetch(
46 + `https://circleci.com/api/v2/workflow/${workflowID}`
47 + );
48 + const workflow = await workflowResponse.json();
49 + switch (workflow.status) {
50 + case 'running':
51 + // Workflow still running. Wait a bit then check again.
52 + await sleep(2000);
53 + continue;
54 + case 'success':
55 + // Publish succeeded! Continue.
56 + return;
57 + case 'not_run':
58 + case 'failed':
59 + case 'error':
60 + case 'failing':
61 + case 'on_hold':
62 + case 'canceled':
63 + case 'unauthorized':
64 + default:
65 + console.error(
66 + theme.error(
67 + `Failed to publish. Workflow exited with status: ${workflow.status}`
68 + )
69 + );
70 + console.error(
71 + `Visit https://app.circleci.com/pipelines/workflows/${workflowID} for details.`
72 + );
73 + process.exit(1);
74 + break;
75 + }
76 + }
77 +}
78 +
79 +async function main() {
80 + const pipelineResponse = await fetch(
81 + 'https://circleci.com/api/v2/project/github/facebook/react/pipeline',
82 + {
83 + method: 'post',
84 + body: JSON.stringify({
85 + parameters: {
86 + // TODO: Make commit SHA configurable
87 + prerelease_commit_sha: 'master',
88 + },
89 + }),
90 + headers: {
91 + 'Circle-Token': CIRCLE_TOKEN,
92 + 'Content-Type': 'application/json',
93 + },
94 + }
95 + );
96 +
97 + const pipelineJSON = await pipelineResponse.json();
98 + const pipelineID = pipelineJSON.id;
99 +
100 + const workflowID = await logPromise(
101 + getPublishWorkflowID(pipelineID),
102 + theme`{header Creating CI workflow}`,
103 + 2 * 1000 // Estimated time: 2 seconds,
104 + );
105 +
106 + await logPromise(
107 + pollUntilWorkflowFinishes(workflowID),
108 + theme`{header Publishing in CI workflow}: https://app.circleci.com/pipelines/workflows/${workflowID}`,
109 + 2 * 60 * 1000 // Estimated time: 2 minutes,
110 + );
111 +}
112 +
113 +main().catch(error => {
114 + console.error(theme.error('Failed to trigger publish workflow.'));
115 + console.error(error.message);
116 + process.exit(1);
117 +});