2023-05-24 21:42:54 +00:00
/ * *
* Copyright ( c ) Meta Platforms , Inc . and affiliates .
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree .
*
2024-01-22 18:29:54 +00:00
* @ flow strict - local
2023-05-24 21:42:54 +00:00
* @ format
* /
'use strict' ;
2024-02-01 14:02:17 +00:00
const { parseVersion } = require ( './releases/utils/version-utils' ) ;
2023-08-10 12:34:13 +00:00
const {
exitIfNotOnGit ,
getCurrentCommit ,
isTaggedLatest ,
} = require ( './scm-utils' ) ;
2023-11-06 20:59:38 +00:00
const { exec } = require ( 'shelljs' ) ;
2023-08-10 12:34:13 +00:00
2024-01-22 18:29:54 +00:00
/ * : :
import type { ExecOptsSync , ShellString } from 'shelljs' ;
type BuildType = 'dry-run' | 'release' | 'nightly' | 'prealpha' ;
type NpmInfo = {
version : string ,
tag : ? string ,
}
type PackageJSON = {
name : string ,
version : string ,
dependencies : { [ string ] : string } ,
devDependencies : { [ string ] : string } ,
...
}
type NpmPackageOptions = {
2024-02-27 17:09:50 +00:00
tags : ? Array < string > | ? Array < ? string > ,
2024-01-22 18:29:54 +00:00
otp : ? string ,
2024-02-27 17:09:50 +00:00
access ? : ? ( 'public' | 'restricted' )
2024-01-22 18:29:54 +00:00
}
* /
2023-08-10 12:34:13 +00:00
// Get `next` version from npm and +1 on the minor for `main` version
function getMainVersion ( ) {
const versionStr = getPackageVersionStrByTag ( 'react-native' , 'next' ) ;
const { major , minor } = parseVersion ( versionStr , 'release' ) ;
return ` ${ major } . ${ parseInt ( minor , 10 ) + 1 } .0 ` ;
}
2024-01-22 18:29:54 +00:00
function getNpmInfo ( buildType /*: BuildType */ ) /*: NpmInfo */ {
2023-08-10 12:34:13 +00:00
const currentCommit = getCurrentCommit ( ) ;
const shortCommit = currentCommit . slice ( 0 , 9 ) ;
if ( buildType === 'dry-run' ) {
return {
version : ` 1000.0.0- ${ shortCommit } ` ,
tag : null , // We never end up publishing this
} ;
}
if ( buildType === 'nightly' ) {
const mainVersion = getMainVersion ( ) ;
const dateIdentifier = new Date ( )
. toISOString ( )
. slice ( 0 , - 14 )
. replace ( /[-]/g , '' ) ;
return {
version : ` ${ mainVersion } -nightly- ${ dateIdentifier } - ${ shortCommit } ` ,
tag : 'nightly' ,
} ;
}
2023-10-11 17:09:57 +00:00
if ( buildType === 'prealpha' ) {
const mainVersion = '0.0.0' ;
// Date in the format of YYYYMMDDHH.
// This is a progressive int that can track subsequent
// releases and it is smaller of 2^32-1.
// It is unlikely that we can trigger two prealpha in less
// than an hour given that nightlies take ~ 1 hr to complete.
const dateIdentifier = new Date ( )
. toISOString ( )
. slice ( 0 , - 10 )
. replace ( /[-T:]/g , '' ) ;
return {
version : ` ${ mainVersion } -prealpha- ${ dateIdentifier } ` ,
tag : 'prealpha' ,
} ;
}
2024-01-22 18:29:54 +00:00
if ( buildType === 'release' ) {
2024-06-20 10:24:29 +00:00
let versionTag /*: string*/ = '' ;
if ( process . env . CIRCLE _TAG != null && process . env . CIRCLE _TAG !== '' ) {
versionTag = process . env . CIRCLE _TAG ;
} else if (
process . env . GITHUB _REF != null &&
process . env . GITHUB _REF . includes ( '/tags/' ) &&
process . env . GITHUB _REF _NAME != null &&
process . env . GITHUB _REF _NAME !== ''
) {
// GITHUB_REF contains the fully qualified ref, for example refs/tags/v0.75.0-rc.0
// GITHUB_REF_NAME contains the short name, for example v0.75.0-rc.0
versionTag = process . env . GITHUB _REF _NAME ;
}
if ( versionTag === '' ) {
2024-01-22 18:29:54 +00:00
throw new Error (
2024-06-20 10:24:29 +00:00
'No version tag found in CI. It looks like this script is running in release mode, but the CIRCLE_TAG or the GITHUB_REF_NAME are missing.' ,
2024-01-22 18:29:54 +00:00
) ;
}
2023-08-10 12:34:13 +00:00
2024-04-25 22:17:34 +00:00
const { version , major , minor , patch , prerelease } = parseVersion (
2024-06-20 10:24:29 +00:00
versionTag ,
2024-01-22 18:29:54 +00:00
buildType ,
) ;
2023-08-10 12:34:13 +00:00
2024-01-22 18:29:54 +00:00
// See if releaser indicated that this version should be tagged "latest"
// Set in `trigger-react-native-release`
const isLatest = exitIfNotOnGit (
( ) => isTaggedLatest ( currentCommit ) ,
'Not in git. We do not want to publish anything' ,
) ;
const releaseBranchTag = ` ${ major } . ${ minor } -stable ` ;
2024-04-25 22:17:34 +00:00
let tag = releaseBranchTag ;
2024-01-22 18:29:54 +00:00
// npm will automatically tag the version as `latest` if no tag is set when we publish
// To prevent this, use `releaseBranchTag` when we don't want that (ex. releasing a patch on older release)
2024-04-25 22:17:34 +00:00
if ( prerelease != null ) {
if ( patch === '0' ) {
// Set `next` tag only on prereleases of 0.m.0-RC.k.
tag = 'next' ;
} else {
tag = '--no-tag' ;
}
} else if ( isLatest === true ) {
tag = 'latest' ;
}
2024-01-22 18:29:54 +00:00
return {
version ,
tag ,
} ;
}
2023-08-10 12:34:13 +00:00
2024-01-22 18:29:54 +00:00
throw new Error ( ` Unsupported build type: ${ buildType } ` ) ;
2023-08-10 12:34:13 +00:00
}
2023-05-24 21:42:54 +00:00
2024-01-22 18:29:54 +00:00
function publishPackage (
packagePath /*: string */ ,
packageOptions /*: NpmPackageOptions */ ,
execOptions /*: ?ExecOptsSync */ ,
) /*: ShellString */ {
2024-02-27 17:09:50 +00:00
const { otp , tags , access } = packageOptions ;
2024-04-25 22:17:34 +00:00
let tagsFlag = '' ;
if ( tags != null ) {
tagsFlag = tags . includes ( '--no-tag' )
? ' --no-tag'
: tags
2024-02-27 17:09:50 +00:00
. filter ( Boolean )
. map ( t => ` --tag ${ t } ` )
2024-04-25 22:17:34 +00:00
. join ( '' ) ;
}
2024-01-22 18:29:54 +00:00
const otpFlag = otp != null ? ` --otp ${ otp } ` : '' ;
2024-02-27 17:09:50 +00:00
const accessFlag = access != null ? ` --access ${ access } ` : '' ;
2023-05-24 21:42:54 +00:00
const options = execOptions
? { ... execOptions , cwd : packagePath }
: { cwd : packagePath } ;
2024-02-27 17:09:50 +00:00
return exec ( ` npm publish ${ tagsFlag } ${ otpFlag } ${ accessFlag } ` , options ) ;
2023-05-24 21:42:54 +00:00
}
2024-01-02 19:46:03 +00:00
/ * *
* ` packageName ` : name of npm package
* ` tag ` : npm tag like ` latest ` or ` next `
*
* This will fetch version of ` packageName ` with npm tag specified
* /
2024-01-22 18:29:54 +00:00
function getPackageVersionStrByTag (
packageName /*: string */ ,
tag /*: ?string */ ,
) /*: string */ {
const npmString =
tag != null
? ` npm view ${ packageName } @ ${ tag } version `
: ` npm view ${ packageName } version ` ;
2024-01-02 19:46:03 +00:00
const result = exec ( npmString , { silent : true } ) ;
if ( result . code ) {
2024-01-22 18:29:54 +00:00
throw new Error ( ` Failed to run ' ${ npmString } ' \n ${ result . stderr } ` ) ;
2024-01-02 19:46:03 +00:00
}
return result . stdout . trim ( ) ;
}
/ * *
* ` packageName ` : name of npm package
* ` spec ` : spec range ex . '^0.72.0'
*
* Return an array of versions of the specified spec range or throw an error
* /
2024-01-22 18:29:54 +00:00
function getVersionsBySpec (
packageName /*: string */ ,
spec /*: string */ ,
) /*: Array<string> */ {
2024-01-02 19:46:03 +00:00
const npmString = ` npm view ${ packageName } @' ${ spec } ' version --json ` ;
const result = exec ( npmString , { silent : true } ) ;
if ( result . code ) {
// Special handling if no such package spec exists
if ( result . stderr . includes ( 'npm ERR! code E404' ) ) {
/ * *
* npm ERR ! code E404
* npm ERR ! 404 No match found for version ^ 0.72 . 0
* npm ERR ! 404
* npm ERR ! 404 '@react-native/community-cli-plugin@^0.72.0' is not in this registry .
* npm ERR ! 404
* npm ERR ! 404 Note that you can also install from a
* npm ERR ! 404 tarball , folder , http url , or git url .
* {
* "error" : {
* "code" : "E404" ,
* "summary" : "No match found for version ^0.72.0" ,
* "detail" : "\n '@react-native/community-cli-plugin@^0.72.0' is not in this registry.\n\nNote that you can also install from a\ntarball, folder, http url, or git url."
* }
* }
* /
const error = JSON . parse (
result . stderr
. split ( '\n' )
. filter ( line => ! line . includes ( 'npm ERR' ) )
. join ( '' ) ,
) . error ;
throw new Error ( error . summary ) ;
} else {
throw new Error ( ` Failed: ${ npmString } ` ) ;
}
}
const versions = JSON . parse ( result . stdout . trim ( ) ) ;
return ! Array . isArray ( versions ) ? [ versions ] : versions ;
}
2023-05-24 21:42:54 +00:00
module . exports = {
2023-08-10 12:34:13 +00:00
getNpmInfo ,
2024-01-02 19:46:03 +00:00
getVersionsBySpec ,
2023-05-24 21:42:54 +00:00
publishPackage ,
} ;