@@ -8,10 +8,21 @@ const NX_CONFIG_FILE = "nx.json";
8
8
9
9
const NPM_TAG_NEXT = "next" ;
10
10
const NPM_TAG_NIGHTLY = "nightly" ;
11
+ const RNMACOS_LATEST = "react-native-macos@latest" ;
12
+ const RNMACOS_NEXT = "react-native-macos@next" ;
11
13
12
14
/**
13
- * @typedef {typeof import("../../nx.json") } NxConfig
14
- * @typedef {{ tag?: string; update?: boolean; } } Options
15
+ * @typedef {import("nx/src/command-line/release/version").ReleaseVersionGeneratorSchema } ReleaseVersionGeneratorSchema;
16
+ * @typedef {{
17
+ * defaultBase: string;
18
+ * release: {
19
+ * version: {
20
+ * generatorOptions: ReleaseVersionGeneratorSchema;
21
+ * };
22
+ * };
23
+ * }} NxConfig;
24
+ * @typedef {{ tag?: string; update?: boolean; verbose?: boolean; } } Options;
25
+ * @typedef {{ npmTag: string; prerelease?: string; isNewTag?: boolean; } } TagInfo;
15
26
*/
16
27
17
28
/**
@@ -33,6 +44,14 @@ function error(message) {
33
44
console . error ( "❌" , message ) ;
34
45
}
35
46
47
+ /**
48
+ * Logs an informational message to the console.
49
+ * @param {string } message
50
+ */
51
+ function info ( message ) {
52
+ console . log ( "ℹ️" , message ) ;
53
+ }
54
+
36
55
/**
37
56
* Returns whether the given branch is considered main branch.
38
57
* @param {string } branch
@@ -91,10 +110,11 @@ function getCurrentBranch() {
91
110
92
111
/**
93
112
* Returns the latest published version of `react-native-macos` from npm.
113
+ * @param {"latest" | "next" } tag
94
114
* @returns {number }
95
115
*/
96
- function getLatestVersion ( ) {
97
- const { stdout } = spawnSync ( "npm" , [ "view" , " react-native-macos@latest" , "version" ] ) ;
116
+ function getPublishedVersion ( tag ) {
117
+ const { stdout } = spawnSync ( "npm" , [ "view" , ` react-native-macos@${ tag } ` , "version" ] ) ;
98
118
return versionToNumber ( stdout . toString ( ) . trim ( ) ) ;
99
119
}
100
120
@@ -108,44 +128,80 @@ function getLatestVersion() {
108
128
*
109
129
* @param {string } branch
110
130
* @param {Options } options
111
- * @returns {{ npmTag: string; prerelease?: string; } }
131
+ * @param {typeof info } log
132
+ * @returns {TagInfo }
112
133
*/
113
- function getTagForStableBranch ( branch , { tag } ) {
134
+ function getTagForStableBranch ( branch , { tag } , log ) {
114
135
if ( ! isStableBranch ( branch ) ) {
115
136
throw new Error ( "Expected a stable branch" ) ;
116
137
}
117
138
118
- const latestVersion = getLatestVersion ( ) ;
139
+ const latestVersion = getPublishedVersion ( "latest" ) ;
119
140
const currentVersion = versionToNumber ( branch ) ;
120
141
142
+ log ( `${ RNMACOS_LATEST } : ${ latestVersion } ` ) ;
143
+ log ( `Current version: ${ currentVersion } ` ) ;
144
+
121
145
// Patching latest version
122
146
if ( currentVersion === latestVersion ) {
123
- return { npmTag : "latest" } ;
147
+ const npmTag = "latest" ;
148
+ log ( `Expected npm tag: ${ npmTag } ` ) ;
149
+ return { npmTag } ;
124
150
}
125
151
126
- // Patching an older stable version
152
+ // Demoting or patching an older stable version
127
153
if ( currentVersion < latestVersion ) {
128
- return { npmTag : "v" + branch } ;
154
+ const npmTag = "v" + branch ;
155
+ log ( `Expected npm tag: ${ npmTag } ` ) ;
156
+ // If we're demoting a branch, we will need to create a new tag. This will
157
+ // make Nx trip if we don't specify a fallback. In all other scenarios, the
158
+ // tags should exist and therefore prefer it to fail.
159
+ return { npmTag, isNewTag : true } ;
129
160
}
130
161
131
162
// Publishing a new latest version
132
163
if ( tag === "latest" ) {
164
+ log ( `Expected npm tag: ${ tag } ` ) ;
133
165
return { npmTag : tag } ;
134
166
}
135
167
136
168
// Publishing a release candidate
169
+ const nextVersion = getPublishedVersion ( "next" ) ;
170
+ log ( `${ RNMACOS_NEXT } : ${ nextVersion } ` ) ;
171
+ log ( `Expected npm tag: ${ NPM_TAG_NEXT } ` ) ;
172
+
173
+ if ( currentVersion < nextVersion ) {
174
+ throw new Error ( `Current version cannot be a release candidate because it is too old: ${ currentVersion } < ${ nextVersion } ` ) ;
175
+ }
176
+
137
177
return { npmTag : NPM_TAG_NEXT , prerelease : "rc" } ;
138
178
}
139
179
180
+ /**
181
+ * @param {string } file
182
+ * @param {string } tag
183
+ * @returns {void }
184
+ */
185
+ function verifyPublishPipeline ( file , tag ) {
186
+ const data = fs . readFileSync ( file , { encoding : "utf-8" } ) ;
187
+ const m = data . match ( / p u b l i s h T a g : ' ( l a t e s t | n e x t | n i g h t l y | v \d + \. \d + - s t a b l e ) ' / ) ;
188
+ if ( ! m ) {
189
+ throw new Error ( `${ file } : Could not find npm publish tag` ) ;
190
+ }
191
+
192
+ if ( m [ 1 ] !== tag ) {
193
+ throw new Error ( `${ file } : 'publishTag' must be set to '${ tag } '` ) ;
194
+ }
195
+ }
196
+
140
197
/**
141
198
* Verifies the configuration and enables publishing on CI.
142
199
* @param {NxConfig } config
143
200
* @param {string } currentBranch
144
- * @param {string } tag
145
- * @param {string } [prerelease]
201
+ * @param {TagInfo } tag
146
202
* @returns {asserts config is NxConfig["release"] }
147
203
*/
148
- function enablePublishing ( config , currentBranch , tag , prerelease ) {
204
+ function enablePublishing ( config , currentBranch , { npmTag : tag , prerelease, isNewTag } ) {
149
205
/** @type {string[] } */
150
206
const errors = [ ] ;
151
207
@@ -160,52 +216,46 @@ function enablePublishing(config, currentBranch, tag, prerelease) {
160
216
}
161
217
162
218
// Determines whether we need to add "nightly" or "rc" to the version string.
163
- const { currentVersionResolverMetadata , preid } = release . version . generatorOptions ;
164
- if ( preid !== prerelease ) {
219
+ const { generatorOptions } = release . version ;
220
+ if ( generatorOptions . preid !== prerelease ) {
165
221
errors . push ( `'release.version.generatorOptions.preid' must be set to '${ prerelease || "" } '` ) ;
166
222
if ( prerelease ) {
167
- release . version . generatorOptions . preid = prerelease ;
223
+ generatorOptions . preid = prerelease ;
168
224
} else {
169
- // @ts -expect-error `preid` is optional
170
- release . version . generatorOptions . preid = undefined ;
225
+ generatorOptions . preid = undefined ;
171
226
}
172
227
}
173
228
174
229
// What the published version should be tagged as e.g., "latest" or "nightly".
175
- if ( currentVersionResolverMetadata . tag !== tag ) {
230
+ const { currentVersionResolverMetadata } = generatorOptions ;
231
+ if ( currentVersionResolverMetadata ?. tag !== tag ) {
176
232
errors . push ( `'release.version.generatorOptions.currentVersionResolverMetadata.tag' must be set to '${ tag } '` ) ;
177
- release . version . generatorOptions . currentVersionResolverMetadata . tag = tag ;
233
+ generatorOptions . currentVersionResolverMetadata ??= { } ;
234
+ generatorOptions . currentVersionResolverMetadata . tag = tag ;
235
+ }
236
+
237
+ // If we're demoting a branch, we will need to create a new tag. This will
238
+ // make Nx trip if we don't specify a fallback. In all other scenarios, the
239
+ // tags should exist and therefore prefer it to fail.
240
+ if ( isNewTag ) {
241
+ if ( generatorOptions . fallbackCurrentVersionResolver !== "disk" ) {
242
+ errors . push ( "'release.version.generatorOptions.fallbackCurrentVersionResolver' must be set to 'disk'" ) ;
243
+ generatorOptions . fallbackCurrentVersionResolver = "disk" ;
244
+ }
245
+ } else if ( typeof generatorOptions . fallbackCurrentVersionResolver === "string" ) {
246
+ errors . push ( "'release.version.generatorOptions.fallbackCurrentVersionResolver' must be unset" ) ;
247
+ generatorOptions . fallbackCurrentVersionResolver = undefined ;
178
248
}
179
249
180
250
if ( errors . length > 0 ) {
181
251
errors . forEach ( error ) ;
182
252
throw new Error ( "Nx Release is not correctly configured for the current branch" ) ;
183
253
}
184
254
255
+ verifyPublishPipeline ( ADO_PUBLISH_PIPELINE , tag ) ;
185
256
enablePublishingOnAzurePipelines ( ) ;
186
257
}
187
258
188
- /**
189
- * @param {string } file
190
- * @param {string } tag
191
- * @returns {boolean }
192
- */
193
- function verifyPublishPipeline ( file , tag ) {
194
- const data = fs . readFileSync ( file , { encoding : "utf-8" } ) ;
195
- const m = data . match ( / p u b l i s h T a g : ' ( \w * ?) ' / ) ;
196
- if ( ! m ) {
197
- error ( `${ file } : Could not find npm publish tag` ) ;
198
- return false ;
199
- }
200
-
201
- if ( m [ 1 ] !== tag ) {
202
- error ( `${ file } : 'publishTag' needs to be set to '${ tag } '` ) ;
203
- return false ;
204
- }
205
-
206
- return true ;
207
- }
208
-
209
259
/**
210
260
* @param {Options } options
211
261
* @returns {number }
@@ -217,17 +267,15 @@ function main(options) {
217
267
return 1 ;
218
268
}
219
269
220
- if ( ! verifyPublishPipeline ( ADO_PUBLISH_PIPELINE , options . tag || NPM_TAG_NEXT ) ) {
221
- return 1 ;
222
- }
270
+ const logger = options . verbose ? info : ( ) => undefined ;
223
271
224
272
const config = loadNxConfig ( NX_CONFIG_FILE ) ;
225
273
try {
226
274
if ( isMainBranch ( branch ) ) {
227
- enablePublishing ( config , branch , NPM_TAG_NIGHTLY , NPM_TAG_NIGHTLY ) ;
275
+ enablePublishing ( config , branch , { npmTag : NPM_TAG_NIGHTLY , prerelease : NPM_TAG_NIGHTLY } ) ;
228
276
} else if ( isStableBranch ( branch ) ) {
229
- const { npmTag , prerelease } = getTagForStableBranch ( branch , options ) ;
230
- enablePublishing ( config , branch , npmTag , prerelease ) ;
277
+ const tag = getTagForStableBranch ( branch , options , logger ) ;
278
+ enablePublishing ( config , branch , tag ) ;
231
279
}
232
280
} catch ( e ) {
233
281
if ( options . update ) {
@@ -236,7 +284,7 @@ function main(options) {
236
284
fs . writeSync ( fd , "\n" ) ;
237
285
fs . closeSync ( fd )
238
286
} else {
239
- console . error ( `${ e } ` ) ;
287
+ error ( `${ e . message } ` ) ;
240
288
}
241
289
return 1 ;
242
290
}
@@ -255,6 +303,10 @@ const { values } = util.parseArgs({
255
303
type : "boolean" ,
256
304
default : false ,
257
305
} ,
306
+ verbose : {
307
+ type : "boolean" ,
308
+ default : false ,
309
+ } ,
258
310
} ,
259
311
strict : true ,
260
312
} ) ;
0 commit comments