@@ -27,9 +27,8 @@ const RNMACOS_NEXT = "react-native-macos@next";
2727 * verbose?: boolean;
2828 * }} Options;
2929 * @typedef {{
30- * npmTag : string;
30+ * npmTags : string[] ;
3131 * prerelease?: string;
32- * isNewTag?: boolean;
3332 * }} TagInfo;
3433 */
3534
@@ -264,7 +263,12 @@ function getPublishedVersion(tag) {
264263}
265264
266265/**
267- * Returns the npm tag and prerelease identifier for the specified branch.
266+ * Returns the npm tags and prerelease identifier for the specified branch.
267+ *
268+ * The first tag in the array is used for the initial publish. When promoting
269+ * to `latest`, also includes additional tags to apply:
270+ * - The version-specific stable tag (e.g., `v0.81-stable`)
271+ * - The `next` tag if the current `next` version is lower
268272 *
269273 * @privateRemarks
270274 * Note that the current implementation treats minor versions as major. If
@@ -276,50 +280,57 @@ function getPublishedVersion(tag) {
276280 * @param {typeof info } log
277281 * @returns {TagInfo }
278282 */
279- function getTagForStableBranch ( branch , { tag } , log ) {
283+ function getTagsForStableBranch ( branch , { tag } , log ) {
280284 if ( ! isStableBranch ( branch ) ) {
281285 throw new Error ( "Expected a stable branch" ) ;
282286 }
283287
284288 const latestVersion = getPublishedVersion ( "latest" ) ;
289+ const nextVersion = getPublishedVersion ( "next" ) ;
285290 const currentVersion = versionToNumber ( branch ) ;
286291
287292 log ( `${ RNMACOS_LATEST } : ${ latestVersion } ` ) ;
293+ log ( `${ RNMACOS_NEXT } : ${ nextVersion } ` ) ;
288294 log ( `Current version: ${ currentVersion } ` ) ;
289295
290296 // Patching latest version
291297 if ( currentVersion === latestVersion ) {
292- const npmTag = "latest" ;
293- log ( `Expected npm tag: ${ npmTag } ` ) ;
294- return { npmTag } ;
298+ const versionTag = branch ;
299+ log ( `Expected npm tags: latest, ${ versionTag } ` ) ;
300+ return { npmTags : [ "latest" , versionTag ] } ;
295301 }
296302
297303 // Demoting or patching an older stable version
298304 if ( currentVersion < latestVersion ) {
299- const npmTag = "v" + branch ;
300- log ( `Expected npm tag: ${ npmTag } ` ) ;
301- // If we're demoting a branch, we will need to create a new tag. This will
302- // make Nx trip if we don't specify a fallback. In all other scenarios, the
303- // tags should exist and therefore prefer it to fail.
304- return { npmTag, isNewTag : true } ;
305+ const npmTag = branch ;
306+ log ( `Expected npm tags: ${ npmTag } ` ) ;
307+ return { npmTags : [ npmTag ] } ;
305308 }
306309
307310 // Publishing a new latest version
308311 if ( tag === "latest" ) {
309- log ( `Expected npm tag: ${ tag } ` ) ;
310- return { npmTag : tag } ;
312+ // When promoting to latest, also add the version-specific stable tag
313+ const versionTag = branch ;
314+ const npmTags = [ "latest" , versionTag ] ;
315+
316+ // Also add "next" tag if the current next version is lower
317+ if ( currentVersion > nextVersion ) {
318+ npmTags . push ( NPM_TAG_NEXT ) ;
319+ }
320+
321+ log ( `Expected npm tags: ${ npmTags . join ( ", " ) } ` ) ;
322+ return { npmTags } ;
311323 }
312324
313325 // Publishing a release candidate
314- const nextVersion = getPublishedVersion ( "next" ) ;
315- log ( `${ RNMACOS_NEXT } : ${ nextVersion } ` ) ;
316- log ( `Expected npm tag: ${ NPM_TAG_NEXT } ` ) ;
326+ // currentVersion > latestVersion
327+ log ( `Expected npm tags: ${ NPM_TAG_NEXT } ` ) ;
317328
318329 if ( currentVersion < nextVersion ) {
319330 throw new Error ( `Current version cannot be a release candidate because it is too old: ${ currentVersion } < ${ nextVersion } ` ) ;
320331 }
321332
322- return { npmTag : NPM_TAG_NEXT , prerelease : "rc" } ;
333+ return { npmTags : [ NPM_TAG_NEXT ] , prerelease : "rc" } ;
323334}
324335
325336/**
@@ -330,11 +341,12 @@ function getTagForStableBranch(branch, { tag }, log) {
330341 * @param {Options } options
331342 * @returns {asserts config is NxConfig["release"] }
332343 */
333- function enablePublishing ( config , currentBranch , { npmTag : tag , prerelease, isNewTag } , options ) {
344+ function enablePublishing ( config , currentBranch , { npmTags , prerelease } , options ) {
334345 /** @type {string[] } */
335346 const errors = [ ] ;
336347
337348 const { defaultBase, release } = config ;
349+ const [ primaryTag , ...additionalTags ] = npmTags ;
338350
339351 // `defaultBase` determines what we diff against when looking for tags or
340352 // released version and must therefore be set to either the main branch or one
@@ -358,23 +370,10 @@ function enablePublishing(config, currentBranch, { npmTag: tag, prerelease, isNe
358370
359371 // What the published version should be tagged as e.g., "latest" or "nightly".
360372 const currentVersionResolverMetadata = /** @type {{ tag?: string } } */ ( versionActionsOptions . currentVersionResolverMetadata || { } ) ;
361- if ( currentVersionResolverMetadata . tag !== tag ) {
362- errors . push ( `'release.version.versionActionsOptions.currentVersionResolverMetadata.tag' must be set to '${ tag } '` ) ;
373+ if ( currentVersionResolverMetadata . tag !== primaryTag ) {
374+ errors . push ( `'release.version.versionActionsOptions.currentVersionResolverMetadata.tag' must be set to '${ primaryTag } '` ) ;
363375 versionActionsOptions . currentVersionResolverMetadata ??= { } ;
364- /** @type {any } */ ( versionActionsOptions . currentVersionResolverMetadata ) . tag = tag ;
365- }
366-
367- // If we're demoting a branch, we will need to create a new tag. This will
368- // make Nx trip if we don't specify a fallback. In all other scenarios, the
369- // tags should exist and therefore prefer it to fail.
370- if ( isNewTag ) {
371- if ( versionActionsOptions . fallbackCurrentVersionResolver !== "disk" ) {
372- errors . push ( "'release.version.versionActionsOptions.fallbackCurrentVersionResolver' must be set to 'disk'" ) ;
373- versionActionsOptions . fallbackCurrentVersionResolver = "disk" ;
374- }
375- } else if ( typeof versionActionsOptions . fallbackCurrentVersionResolver === "string" ) {
376- errors . push ( "'release.version.versionActionsOptions.fallbackCurrentVersionResolver' must be removed" ) ;
377- versionActionsOptions . fallbackCurrentVersionResolver = undefined ;
376+ /** @type {any } */ ( versionActionsOptions . currentVersionResolverMetadata ) . tag = primaryTag ;
378377 }
379378
380379 if ( errors . length > 0 ) {
@@ -388,6 +387,17 @@ function enablePublishing(config, currentBranch, { npmTag: tag, prerelease, isNe
388387 verifyNpmAuth ( ) ;
389388 }
390389
390+ // Output additional tags as pipeline/workflow variable
391+ if ( additionalTags . length > 0 ) {
392+ const tagsValue = additionalTags . join ( "," ) ;
393+ // Azure Pipelines
394+ console . log ( `##vso[task.setvariable variable=additionalTags]${ tagsValue } ` ) ;
395+ // GitHub Actions
396+ if ( process . env [ "GITHUB_OUTPUT" ] ) {
397+ fs . appendFileSync ( process . env [ "GITHUB_OUTPUT" ] , `additionalTags=${ tagsValue } \n` ) ;
398+ }
399+ }
400+
391401 // Don't enable publishing in PRs
392402 if ( ! getTargetBranch ( ) ) {
393403 enablePublishingOnAzurePipelines ( ) ;
@@ -410,10 +420,10 @@ function main(options) {
410420 const config = loadNxConfig ( NX_CONFIG_FILE ) ;
411421 try {
412422 if ( isMainBranch ( branch ) ) {
413- const info = { npmTag : NPM_TAG_NIGHTLY , prerelease : NPM_TAG_NIGHTLY } ;
423+ const info = { npmTags : [ NPM_TAG_NIGHTLY ] , prerelease : NPM_TAG_NIGHTLY } ;
414424 enablePublishing ( config , branch , info , options ) ;
415425 } else if ( isStableBranch ( branch ) ) {
416- const tag = getTagForStableBranch ( branch , options , logger ) ;
426+ const tag = getTagsForStableBranch ( branch , options , logger ) ;
417427 enablePublishing ( config , branch , tag , options ) ;
418428 }
419429 } catch ( e ) {
0 commit comments