diff --git a/.ado/Brewfile b/.ado/Brewfile index c94fbdf002..78fe5e50f1 100644 --- a/.ado/Brewfile +++ b/.ado/Brewfile @@ -1,2 +1,4 @@ brew "watchman" brew "xcbeautify" +# macOS 12 doesn't have `realpath` but macOS 13 does. Remove this line when Azure Pipelines supports macOS 13 images. +brew "coreutils" diff --git a/.ado/apple-pr.yml b/.ado/apple-pr.yml index 85acbd8b71..681c754343 100644 --- a/.ado/apple-pr.yml +++ b/.ado/apple-pr.yml @@ -223,3 +223,52 @@ jobs: - template: templates/react-native-macos-init.yml parameters: configuration: $(configuration) + + - job: NPMPublishDryRun + displayName: NPM Publish Dry Run + pool: + vmImage: $(VmImageApple) + timeoutInMinutes: 60 # how long to run the job before automatically cancelling + cancelTimeoutInMinutes: 5 # how much time to give 'run always even if cancelled tasks' before killing them + steps: + - checkout: self # self represents the repo where the initial Pipelines YAML file was found + clean: true # whether to fetch clean each time + # fetchDepth: 2 # the depth of commits to ask Git to fetch + lfs: false # whether to download Git-LFS files + submodules: recursive # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules + persistCredentials: true # set to 'true' to leave the OAuth token in the Git config after the initial fetch + + - template: templates/apple-tools-setup.yml + + - template: templates/apple-install-dependencies.yml + + - task: CmdLine@2 + displayName: Set next version if release branch + inputs: + script: | + VERSION=$(node .ado/get-next-semver-version.js) + echo "Set Version to: $VERSION" + condition: and(succeeded(), ne(variables['Build.TargetBranchName'], 'main')) + + + - task: CmdLine@2 + displayName: Prepare package for release + inputs: + script: | + if [[ -z "$VERSION" ]]; then + VERSION=$(grep '"version"' package.json | cut -d '"' -f 4 | head -1) + echo "Using the version from the package.json: $VERSION" + fi + node ./scripts/prepare-package-for-release.js -v "$VERSION" -l false --dry-run true + + - task: CmdLine@2 + displayName: NPM Publish Dry Run + inputs: + script: | + node ./scripts/publish-npm.js --dry-run + + - task: CmdLine@2 + displayName: Print tarball output + inputs: + script: | + npm publish --dry-run diff --git a/.ado/bumpFileVersions.js b/.ado/bumpFileVersions.js deleted file mode 100644 index 11a520ff5f..0000000000 --- a/.ado/bumpFileVersions.js +++ /dev/null @@ -1,3 +0,0 @@ -// @ts-check -const {updateVersionsInFiles} = require('./versionUtils'); -updateVersionsInFiles(); \ No newline at end of file diff --git a/.ado/versionUtils.js b/.ado/get-next-semver-version.js similarity index 56% rename from .ado/versionUtils.js rename to .ado/get-next-semver-version.js index 29c7d21279..67b7336599 100644 --- a/.ado/versionUtils.js +++ b/.ado/get-next-semver-version.js @@ -19,7 +19,7 @@ function gatherVersionInfo() { return {pkgJson, releaseVersion, branchVersionSuffix}; } -function updateVersionsInFiles(patchVersionPrefix) { +function getNextVersion(patchVersionPrefix) { let {pkgJson, releaseVersion, branchVersionSuffix} = gatherVersionInfo(); @@ -42,34 +42,9 @@ function updateVersionsInFiles(patchVersionPrefix) { } pkgJson.version = releaseVersion; - console.log(`Bumping files to version ${releaseVersion}`); - execSync(`node ./scripts/set-rn-version.js --rnmpublish --to-version ${releaseVersion}`, {stdio: 'inherit', env: process.env}); return {releaseVersion, branchVersionSuffix}; } -const workspaceJsonPath = path.resolve(require('os').tmpdir(), 'rnpkg.json'); - -function removeWorkspaceConfig() { - let {pkgJson} = gatherVersionInfo(); - fs.writeFileSync(workspaceJsonPath, JSON.stringify(pkgJson, null, 2)); - delete pkgJson.private; - delete pkgJson.workspaces; - fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2)); - console.log(`Removing workspace config from package.json to prepare to publish.`); -} - -function restoreWorkspaceConfig() { - let pkgJson = JSON.parse(fs.readFileSync(workspaceJsonPath, "utf8")); - fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2)); - console.log(`Restoring workspace config from package.json`); -} - -module.exports = { - gatherVersionInfo, - publishBranchName, - pkgJsonPath, - removeWorkspaceConfig, - restoreWorkspaceConfig, - updateVersionsInFiles -} \ No newline at end of file +const nextVersion = getNextVersion().releaseVersion; +console.log(nextVersion); \ No newline at end of file diff --git a/.ado/get-release-type.js b/.ado/get-release-type.js new file mode 100644 index 0000000000..019c9d70b1 --- /dev/null +++ b/.ado/get-release-type.js @@ -0,0 +1,19 @@ +// @ts-check +const fs = require("fs"); +const path = require("path"); +const semver = require('semver'); +const {execSync} = require('child_process'); + +const pkgJsonPath = path.resolve(__dirname, "../package.json"); +let publishBranchName = ''; +try { + publishBranchName = process.env.BUILD_SOURCEBRANCH.match(/refs\/heads\/(.*)/)[1]; +} catch (error) {} + +if (publishBranchName === 'main') { + console.log('nightly'); +} else if (publishBranchName.endsWith('-stable')) { + console.log('release'); +} else { + process.exit(1); +} \ No newline at end of file diff --git a/.ado/gitTagRelease.js b/.ado/gitTagRelease.js deleted file mode 100644 index 75c96ccc08..0000000000 --- a/.ado/gitTagRelease.js +++ /dev/null @@ -1,47 +0,0 @@ -// @ts-check -// Used to apply the package updates: the git tag for the published release. - -const execSync = require("child_process").execSync; -const {pkgJsonPath, publishBranchName, gatherVersionInfo} = require('./versionUtils'); - -function exec(command) { - try { - console.log(`Running command: ${command}`); - return execSync(command, { - stdio: "inherit" - }); - } catch (err) { - process.exitCode = 1; - console.log(`Failure running: ${command}`); - throw err; - } -} - -function doPublish() { - console.log(`Target branch to publish to: ${publishBranchName}`); - - const {releaseVersion} = gatherVersionInfo() - - const tempPublishBranch = `publish-temp-${Date.now()}`; - exec(`git checkout -b ${tempPublishBranch}`); - - exec(`git config --global user.email "53619745+rnbot@users.noreply.github.com"`); - exec(`git config --global user.name "React-Native Bot"`); - - exec(`git add .`); - exec(`git commit -m "Applying package update to ${releaseVersion} ***NO_CI***"`); - exec(`git tag v${releaseVersion}`); - exec(`git push origin HEAD:${tempPublishBranch} --follow-tags --verbose`); - exec(`git push origin tag v${releaseVersion}`); - - exec(`git checkout ${publishBranchName}`); - exec(`git pull origin ${publishBranchName}`); - exec(`git merge ${tempPublishBranch} --no-edit`); - exec( - `git push origin HEAD:${publishBranchName} --follow-tags --verbose` - ); - exec(`git branch -d ${tempPublishBranch}`); - exec(`git push origin --delete -d ${tempPublishBranch}`); -} - -doPublish(); \ No newline at end of file diff --git a/.ado/publish.yml b/.ado/publish.yml index 896f51df9a..67a71a16f7 100644 --- a/.ado/publish.yml +++ b/.ado/publish.yml @@ -10,6 +10,7 @@ trigger: include: - main - 0.68-stable + - 0.71-stable paths: exclude: - package.json @@ -43,79 +44,63 @@ jobs: submodules: recursive # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules persistCredentials: true # set to 'true' to leave the OAuth token in the Git config after the initial fetch - - script: exit 1 - displayName: Validate variables - condition: eq(variables.latestStableBranch, '') - - - bash: echo "##vso[task.setvariable variable=npmDistTag]latest" - displayName: Set dist-tag to latest - condition: eq(variables['Build.SourceBranchName'], variables.latestStableBranch) - - - bash: echo "##vso[task.setvariable variable=npmDistTag]canary" - displayName: Set dist-tag to canary - condition: eq(variables['Build.SourceBranchName'], 'main') - - - bash: echo "##vso[task.setvariable variable=npmDistTag]v${{variables['Build.SourceBranchName']}}" - displayName: Set dist-tag to v0.x-stable - condition: and(ne(variables['Build.SourceBranchName'], 'main'), ne(variables['Build.SourceBranchName'], variables.latestStableBranch)) - - template: templates/apple-tools-setup.yml - - task: CmdLine@2 - displayName: yarn install - inputs: - script: yarn install --frozen-lockfile + - template: templates/apple-install-dependencies.yml + + - template: templates/apple-release-setup.yml - task: CmdLine@2 - displayName: Bump stable package version + displayName: Set next version if release branch inputs: - script: node .ado/bumpFileVersions.js + script: | + VERSION=$(node .ado/get-next-semver-version.js) + echo "Set version to: $VERSION" condition: and(succeeded(), ne(variables['Build.SourceBranchName'], 'main')) - task: CmdLine@2 - displayName: Set canary package version + displayName: Set release type inputs: - script: node scripts/set-rn-version.js --nightly --autogenerateVersionNumber - condition: and(succeeded(), eq(variables['Build.SourceBranchName'], 'main')) - - # Publish will fail if package.json is marked as private + script: | + RELEASE_TYPE=$(node .ado/get-next-release-type.js) + echo "Set release type to: $RELEASE_TYPE" + - task: CmdLine@2 - displayName: Remove workspace config from package.json + displayName: Set latest tag if latest stable branch inputs: - script: node .ado/removeWorkspaceConfig.js + script: | + LATEST=true + echo "Set latest to: $LATEST" + condition: eq(variables['Build.SourceBranchName'], $(latest_stable_branch)) + + - task: CmdLine@2 + displayName: Prepare package for release + inputs: + script: | + if [[ -z "$VERSION" ]]; then + VERSION=$(grep '"version"' package.json | cut -d '"' -f 4 | head -1) + echo "Using the version from the package.json: $VERSION" + fi + node ./scripts/prepare-package-for-release.js -v "$VERSION" -l $LATEST + condition: and(succeeded(), ne(variables['Build.SourceBranchName'], 'main')) - task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 displayName: 📒 Generate Manifest inputs: BuildDropPath: $(System.DefaultWorkingDirectory) + - task: CmdLine@2 + displayName: NPM Publish + inputs: + script: | + node ./scripts/publish-npm.js --$RELEASE_TYPE + - task: PublishPipelineArtifact@1 displayName: 📒 Publish Manifest inputs: artifactName: SBom-RNGithubNpmJSPublish-$(System.JobAttempt) targetPath: $(System.DefaultWorkingDirectory)/_manifest - - script: npm publish --tag $(npmDistTag) --registry https://registry.npmjs.org/ --//registry.npmjs.org/:_authToken=$(npmAuthToken) - displayName: Publish react-native-macos to npmjs.org - - # Put the private flag back so that the removal does not get committed by the tag release step - - task: CmdLine@2 - displayName: Restore package.json workspace config - inputs: - script: node .ado/restoreWorkspaceConfig.js - - - task: CmdLine@2 - displayName: 'Tag published release' - inputs: - script: node .ado/gitTagRelease.js - env: - BUILD_STAGINGDIRECTORY: $(Build.StagingDirectory) - BUILD_SOURCEBRANCH: $(Build.SourceBranch) - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - githubApiToken: $(githubAuthToken) - condition: and(succeeded(), ne(variables['Build.SourceBranchName'], 'main')) - - - job: RNMacOSInitNpmJSPublish displayName: react-native-macos-init Publish to npmjs.org pool: cxeiss-ubuntu-20-04-large @@ -132,17 +117,14 @@ jobs: submodules: recursive # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules persistCredentials: true # set to 'true' to leave the OAuth token in the Git config after the initial fetch - - template: templates/configure-git.yml + - template: templates/apple-tools-setup.yml + + - template: templates/apple-install-dependencies.yml + + - template: templates/apple-release-setup.yml - task: CmdLine@2 - displayName: yarn install - inputs: - script: | - cd packages/react-native-macos-init - yarn install --frozen-lockfile - - - task: CmdLine@2 - displayName: yarn build + displayName: Build react-native-macos-init inputs: script: | cd packages/react-native-macos-init diff --git a/.ado/removeWorkspaceConfig.js b/.ado/removeWorkspaceConfig.js deleted file mode 100644 index b6969e2841..0000000000 --- a/.ado/removeWorkspaceConfig.js +++ /dev/null @@ -1,3 +0,0 @@ -// @ts-check -const {removeWorkspaceConfig} = require('./versionUtils'); -removeWorkspaceConfig(); \ No newline at end of file diff --git a/.ado/restoreWorkspaceConfig.js b/.ado/restoreWorkspaceConfig.js deleted file mode 100644 index cd779e9954..0000000000 --- a/.ado/restoreWorkspaceConfig.js +++ /dev/null @@ -1,3 +0,0 @@ -// @ts-check -const {restoreWorkspaceConfig} = require('./versionUtils'); -restoreWorkspaceConfig(); \ No newline at end of file diff --git a/.ado/templates/apple-install-dependencies.yml b/.ado/templates/apple-install-dependencies.yml new file mode 100644 index 0000000000..77b38323cb --- /dev/null +++ b/.ado/templates/apple-install-dependencies.yml @@ -0,0 +1,12 @@ +steps: + - task: CmdLine@2 + displayName: yarn install + inputs: + script: yarn install --frozen-lockfile + + - task: CmdLine@2 + displayName: bundle install + inputs: + script: | + cd packages/rn-tester + bundle install diff --git a/.ado/templates/configure-git.yml b/.ado/templates/apple-release-setup.yml similarity index 58% rename from .ado/templates/configure-git.yml rename to .ado/templates/apple-release-setup.yml index ed6e71d08c..1472d4b0a7 100644 --- a/.ado/templates/configure-git.yml +++ b/.ado/templates/apple-release-setup.yml @@ -1,9 +1,13 @@ - steps: - - task: CmdLine@2 displayName: Configure git inputs: script: | git config --global user.email "53619745+rnbot@users.noreply.github.com" git config --global user.name "React-Native Bot" + + - task: CmdLine@2 + displayName: Set NPM Auth Token + inputs: + script: | + echo "//registry.npmjs.org/:_authToken=${npmAuthToken}" > ~/.npmrc diff --git a/.ado/templates/apple-tools-setup.yml b/.ado/templates/apple-tools-setup.yml index 7358364138..fec6bd715a 100644 --- a/.ado/templates/apple-tools-setup.yml +++ b/.ado/templates/apple-tools-setup.yml @@ -1,7 +1,7 @@ steps: - task: NodeTool@0 inputs: - versionSource: 'fromFile' # 'spec' | 'fromFile'. Required. Source of version. Default: spec. + versionSource: 'fromFile' versionFilePath: '.node-version' - task: UseRubyVersion@0 diff --git a/.ado/templates/react-native-macos-init.yml b/.ado/templates/react-native-macos-init.yml index b1fecda78f..1f2410961d 100644 --- a/.ado/templates/react-native-macos-init.yml +++ b/.ado/templates/react-native-macos-init.yml @@ -52,24 +52,12 @@ steps: - task: CmdLine@2 displayName: Set package version inputs: - script: node scripts/set-rn-version.js --nightly -v 0.0.1000 - - # Publish will fail if package.json is marked as private - - task: CmdLine@2 - displayName: Remove workspace config from package.json - inputs: - script: node .ado/removeWorkspaceConfig.js + script: node scripts/set-rn-version.js -b dry-run -v 1000.0.0 - script: | npm publish --registry http://localhost:4873 displayName: Publish react-native-macos to verdaccio - # Put the private flag back - - task: CmdLine@2 - displayName: Restore package.json workspace config - inputs: - script: node .ado/restoreWorkspaceConfig.js - - script: | npx beachball publish --branch origin/$(System.PullRequest.TargetBranch) --no-push --registry http://localhost:4873 --yes --access public displayName: Publish react-native-macos-init to verdaccio @@ -77,7 +65,7 @@ steps: - task: CmdLine@2 displayName: Init new project inputs: - script: npx --yes react-native@0.71.4 init testcli --template react-native@0.71.4 --skip-install + script: npx --yes react-native@0.71.5 init testcli --template react-native@0.71.5 --skip-install workingDirectory: $(Agent.BuildDirectory) - task: CmdLine@2 diff --git a/.ado/variables/vars.yml b/.ado/variables/vars.yml index 77104d18c4..1e0cbacd73 100644 --- a/.ado/variables/vars.yml +++ b/.ado/variables/vars.yml @@ -2,3 +2,4 @@ variables: VmImageApple: internal-macos12 slice_name: 'Xcode_14.2' xcode_version: '/Applications/Xcode_14.2.app' + latest_stable_branch: '0.71-stable' diff --git a/scripts/prepare-package-for-release.js b/scripts/prepare-package-for-release.js index 2a61023cae..376bccd91b 100755 --- a/scripts/prepare-package-for-release.js +++ b/scripts/prepare-package-for-release.js @@ -44,7 +44,11 @@ const argv = yargs default: false, }).argv; -const branch = process.env.CIRCLE_BRANCH; +// [macOS Use git to get the branch name, rather than relying on CircleCI env vars. +const branch = exec('git rev-parse --abbrev-ref HEAD', { + silent: true, +}).stdout.trim(); +// // macOS] const remote = argv.remote; const releaseVersion = argv.toVersion; const isLatest = argv.latest; @@ -102,7 +106,8 @@ if (exec(`git commit -a -m "[${version}] Bump version numbers"`).code) { } // Add tag v0.21.0-rc.1 -if (exec(`git tag -a v${version} -m "v${version}"`).code) { +// [macOS] Add "-microsoft" suffix to tag to distinguish from React Native Core. +if (exec(`git tag -a v${version}-microsoft -m "v${version}-microsoft"`).code) { echo( `failed to tag the commit with v${version}, are you sure this release wasn't made earlier?`, ); diff --git a/scripts/publish-npm.js b/scripts/publish-npm.js index 89c29a25ec..2aa66aeb35 100755 --- a/scripts/publish-npm.js +++ b/scripts/publish-npm.js @@ -13,6 +13,8 @@ * This script prepares a release version of react-native and may publish to NPM. * It is supposed to run in CI environment, not on a developer's machine. * + * [macOS] For React Native macOS, we have modified this script to not create Android Artifacts. + * * For a dry run (commitly), this script will: * * Version the commitly of the form `1000.0.0-` * * Create Android artifacts @@ -38,15 +40,18 @@ const { getCurrentCommit, isTaggedLatest, } = require('./scm-utils'); +/* [macOS We do not generate Android artifacts for React Native macOS const { generateAndroidArtifacts, publishAndroidArtifactsToMaven, } = require('./release-utils'); const fs = require('fs'); const path = require('path'); +macOS] */ const yargs = require('yargs'); -const buildTag = process.env.CIRCLE_TAG; +// [macOS] Use git to get the tag name, rather than relying on CircleCI environment variables. +const buildTag = exec('git tag --points-at HEAD'); const otp = process.env.NPM_CONFIG_OTP; const argv = yargs @@ -89,7 +94,7 @@ const rawVersion = nightlyBuild ? '0.0.0' : // For pre-release and stable releases, we use the git tag of the version we're releasing (set in set-rn-version) - buildTag; + buildTag.substring(0, str.indexOf('-microsft')); // [macOS] Strip off the "-microsoft" suffix from the tag name. let version, major, @@ -130,11 +135,13 @@ if (isCommitly) { } } +/* [macOS We do not generate Android artifacts for React Native macOS generateAndroidArtifacts(releaseVersion); // Write version number to the build folder const releaseVersionFile = path.join('build', '.version'); fs.writeFileSync(releaseVersionFile, releaseVersion); +macOS] */ if (dryRunBuild) { echo('Skipping `npm publish` because --dry-run is set.'); @@ -147,9 +154,11 @@ const isLatest = exitIfNotOnGit( 'Not in git. We do not want to publish anything', ); +/* [macOS We do not generate Android artifacts for React Native macOS // We first publish on Maven Central all the necessary artifacts. // NPM publishing is done just after. publishAndroidArtifactsToMaven(releaseVersion, nightlyBuild); +macOS] */ const releaseBranch = `${major}.${minor}-stable`; diff --git a/scripts/release-utils.js b/scripts/release-utils.js index 661b55f464..61c73a8375 100644 --- a/scripts/release-utils.js +++ b/scripts/release-utils.js @@ -136,7 +136,7 @@ function checkIfTagExists(version) { throw new Error('Failed to retrieve the list of tags'); } const tags = new Set(stdout.split('\n')); - return tags.has(`v${version}`); + return tags.has(`v${version}-microsoft`); // [macOS] We append `-microsoft` to the tag } module.exports = {