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
+});