diff --git a/.circleci/config.yml b/.circleci/config.yml index 0bc5d3191015d2..49c899f1571d18 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1361,6 +1361,9 @@ jobs: latest: type: boolean default: false + dryrun: + type: boolean + default: false executor: reactnativeios steps: - checkout_code_with_cache @@ -1373,13 +1376,15 @@ jobs: - run: name: "Set new react-native version and commit changes" command: | - node ./scripts/prepare-package-for-release.js -v << parameters.version >> -l << parameters.latest >> + node ./scripts/prepare-package-for-release.js -v << parameters.version >> -l << parameters.latest >> --dry-run << parameters.dryrun >> build_npm_package: parameters: - publish_npm_args: - type: string - default: --dry-run + release_type: + description: The type of release to build. Must be one of "nightly", "release", "dry-run". + type: enum + enum: ["nightly", "release", "dry-run"] + default: "dry-run" executor: reactnativeandroid environment: - HERMES_WS_DIR: *hermes_workspace_root @@ -1422,8 +1427,8 @@ jobs: - when: condition: or: - - equal: [ --release, << parameters.publish_npm_args >> ] - - equal: [ --nightly, << parameters.publish_npm_args >> ] + - equal: [ "release", << parameters.release_type >> ] + - equal: [ "nightly", << parameters.release_type >> ] steps: - run: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc - run: | @@ -1432,7 +1437,7 @@ jobs: echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc # END: Stables and nightlies - - run: node ./scripts/publish-npm.js << parameters.publish_npm_args >> + - run: node ./scripts/publish-npm.js --<< parameters.release_type >> - run: name: Zip Hermes Native Symbols command: zip -r /tmp/hermes-native-symbols.zip ~/react-native/ReactAndroid/hermes-engine/build/intermediates/cmake/ @@ -1443,7 +1448,7 @@ jobs: # Provide a react-native package for this commit as a Circle CI release artifact. - when: condition: - equal: [ --dry-run, << parameters.publish_npm_args >> ] + equal: [ "dry-run", << parameters.release_type >> ] steps: - run: name: Build release package as a job artifact @@ -1475,7 +1480,7 @@ jobs: # START: Stable releases - when: condition: - equal: [ --release, << parameters.publish_npm_args >> ] + equal: [ "release", << parameters.release_type >> ] steps: - run: name: Update rn-diff-purge to generate upgrade-support diff @@ -1484,15 +1489,44 @@ jobs: -H "Accept: application/vnd.github.v3+json" \ -u "$PAT_USERNAME:$PAT_TOKEN" \ -d "{\"event_type\": \"publish\", \"client_payload\": { \"version\": \"${CIRCLE_TAG:1}\" }}" + # END: Stable releases + + # START: Stables and commitlies + - when: + condition: + or: + - equal: [ "release", << parameters.release_type >> ] + - equal: [ "dry-run", << parameters.release_type >> ] + steps: - run: name: Install dependencies command: apt update && apt install -y jq jo - run: name: Create draft GitHub Release and upload Hermes binaries command: | - ARTIFACTS=("$HERMES_WS_DIR/hermes-runtime-darwin/hermes-runtime-darwin-$CIRCLE_TAG.tar.gz") - ./scripts/circleci/create_github_release.sh $CIRCLE_TAG $CIRCLE_PROJECT_USERNAME $CIRCLE_PROJECT_REPONAME $GITHUB_TOKEN "${ARTIFACTS[@]}" - # END: Stable releases + RELEASE_VERSION=$(cat build/.version) + if [[ << parameters.release_type >> == "release" ]]; then + GIT_TAG=$CIRCLE_TAG + elif [[ << parameters.release_type >> == "dry-run" ]]; then + GIT_TAG=v1000.0.0 + fi + + ARTIFACTS=("") + for build_type in "Debug" "Release"; do + TARBALL_FILENAME=$(node ./scripts/hermes/get-tarball-name.js \ + --buildType $build_type \ + --releaseVersion $RELEASE_VERSION) + + ARTIFACTS+=("$HERMES_WS_DIR/hermes-runtime-darwin/$TARBALL_FILENAME") + done + + ./scripts/circleci/create_github_release.sh \ + << parameters.release_type >> \ + $GIT_TAG \ + $RELEASE_VERSION \ + $GITHUB_TOKEN \ + "${ARTIFACTS[@]}" + # END: Stable and commitlies # ------------------------- # JOBS: Nightly @@ -1551,7 +1585,7 @@ workflows: - prepare_hermes_workspace - build_npm_package: # Build a release package on every untagged commit, but do not publish to npm. - publish_npm_args: --dry-run + release_type: "dry-run" requires: - build_hermesc_linux - build_hermes_macos @@ -1639,13 +1673,44 @@ workflows: - build_npm_package: name: build_and_publish_npm_package context: react-native-bot - publish_npm_args: --release + release_type: "release" filters: *only_release_tags requires: - build_hermesc_linux - build_hermes_macos - build_hermesc_windows + package_and_publish_release_dryrun: + jobs: + - prepare_package_for_release: + name: prepare_package_for_release + version: 'v1000.0.1' + latest : false + dryrun: true + - prepare_hermes_workspace: + requires: + - prepare_package_for_release + - build_hermesc_linux: + requires: + - prepare_hermes_workspace + - build_hermes_macos: + requires: + - prepare_hermes_workspace + matrix: + parameters: + flavor: ["Debug", "Release"] + - build_hermesc_windows: + requires: + - prepare_hermes_workspace + - build_npm_package: + name: build_and_publish_npm_package + context: react-native-bot + release_type: "dry-run" + requires: + - build_hermesc_linux + - build_hermes_macos + - build_hermesc_windows + analysis: unless: << pipeline.parameters.run_package_release_workflow_only >> jobs: @@ -1684,7 +1749,7 @@ workflows: requires: - prepare_hermes_workspace - build_npm_package: - publish_npm_args: --nightly + release_type: "nightly" requires: - build_hermesc_linux - build_hermes_macos diff --git a/scripts/__tests__/create_github_release_test.sh b/scripts/__tests__/create_github_release_test.sh deleted file mode 100755 index da66c1bb684fb9..00000000000000 --- a/scripts/__tests__/create_github_release_test.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# 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. - -# Add your own Personal Access Token here. -# Create it at https://github.com/settings/tokens -GITHUB_TOKEN="" - -# Setup Circle CI envvars -CIRCLE_TAG="" -CIRCLE_PROJECT_USERNAME="" -CIRCLE_PROJECT_REPONAME="" - -if [ -z "$GITHUB_TOKEN" ] -then - echo "\$GITHUB_TOKEN is empty" - exit 1 -fi -if [ -z "$CIRCLE_TAG" ] -then - echo "\$CIRCLE_TAG is empty" - exit 1 -fi -if [ -z "$CIRCLE_PROJECT_USERNAME" ] -then - echo "\$CIRCLE_PROJECT_USERNAME is empty" - exit 1 -fi -if [ -z "$CIRCLE_PROJECT_REPONAME" ] -then - echo "\$CIRCLE_PROJECT_REPONAME is empty" - exit 1 -fi - -# Dummy artifacts to upload -ARTIFACTS=("hermes-runtime-darwin-$CIRCLE_TAG.tar.gz") -for ARTIFACT_PATH in "${ARTIFACTS[@]}" -do - : - head -c 1024 "$ARTIFACT_PATH" -done - -../circleci/create_github_release.sh "$CIRCLE_TAG" "$CIRCLE_PROJECT_USERNAME" "$CIRCLE_PROJECT_REPONAME" "$GITHUB_TOKEN" "${ARTIFACTS[@]}" diff --git a/scripts/circleci/create_github_release.sh b/scripts/circleci/create_github_release.sh index 27681b83f47c5c..e77f5b42fe3817 100755 --- a/scripts/circleci/create_github_release.sh +++ b/scripts/circleci/create_github_release.sh @@ -4,9 +4,21 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +# This script creates a draft GitHub Release using RELEASE_TEMPLATE.md +# as a template and will upload the provided artifacts to the release. + +# Install dependencies: +# apt update && apt install -y jq jo + +THIS_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +REACT_NATIVE_PATH="$THIS_DIR/../.." + +GITHUB_OWNER=${CIRCLE_PROJECT_USERNAME:-facebook} +GITHUB_REPO=${CIRCLE_PROJECT_REPONAME:-react-native} + +RELEASE_TYPE="$1"; shift GIT_TAG="$1"; shift -GITHUB_OWNER="$1"; shift -GITHUB_REPO="$1"; shift +RELEASE_VERSION="$1"; shift GITHUB_TOKEN="$1"; shift ARTIFACTS=("$@") @@ -18,63 +30,94 @@ describe () { printf "\\n\\n%s\\n\\n" "$1" } -# Format our desired React Native version strings based on incoming git tag parameter. -# GIT_TAG=v0.69.0-rc.4 -# 0.69.0-rc.4 -RN_VERSION=${GIT_TAG:1} -# 0690rc4 -RN_SHORT_VERSION=${RN_VERSION//[.-]/} +echoerr () { + echo "$@" 1>&2 +} -PRERELEASE=false -if [[ "$RN_VERSION" == *"rc"* ]]; then - PRERELEASE=true +if [[ $RELEASE_TYPE == "release" ]]; then + describe_header "Preparing to create a GitHub release." +elif [[ $RELEASE_TYPE == "dry-run" ]]; then + describe_header "Preparing to create a GitHub release as a dry-run." +elif [[ $RELEASE_TYPE == "nightly" ]]; then + describe "GitHub Releases are not used with nightlies. Skipping." + exit 0 +else + echoerr "Unrecognized release type: $RELEASE_TYPE" + exit 1 fi -RELEASE_TEMPLATE_PATH=../../.github/RELEASE_TEMPLATE.md +# Derive short version string for use in the sample command used +# to create a new RN app in RELEASE_TEMPLATE.md +# 0.69.0-rc.4 -> 0690rc4 +RN_SHORT_VERSION=${RELEASE_VERSION//[.-]/} + +PRERELEASE=false +if [[ "$RELEASE_VERSION" == *"rc"* ]]; then + PRERELEASE=true +fi -# Replace placeholders in template with actual RN version strings -RELEASE_BODY=$(sed -e "s/__VERSION__/$RN_VERSION/g" -e "s/__SHORT_VERSION__/$RN_SHORT_VERSION/g" $RELEASE_TEMPLATE_PATH) +RELEASE_TEMPLATE_PATH="$REACT_NATIVE_PATH/.github/RELEASE_TEMPLATE.md" +if [[ -f $RELEASE_TEMPLATE_PATH ]]; then + # Replace placeholders in template with actual RN version strings + RELEASE_BODY=$(sed -e "s/__VERSION__/$RELEASE_VERSION/g" -e "s/__SHORT_VERSION__/$RN_SHORT_VERSION/g" "$RELEASE_TEMPLATE_PATH") +else + describe "Could not load GitHub Release template. Falling back to placeholder text." + RELEASE_BODY="" +fi # Format and encode JSON payload -RELEASE_DATA=$(jo tag_name="$GIT_TAG" name="$RN_VERSION" body="$RELEASE_BODY" draft=true prerelease="$PRERELEASE" generate_release_notes=false) +RELEASE_DATA=$(jo tag_name="$GIT_TAG" name="$RELEASE_VERSION" body="$RELEASE_BODY" draft=true prerelease="$PRERELEASE" generate_release_notes=false) +if [[ ! $RELEASE_DATA ]]; then + echoerr "Could not format release data." + exit 1 +fi -# Create prerelease GitHub Release draft +# Create GitHub Release draft describe_header "Creating GitHub release." describe "Release payload: $RELEASE_DATA" -CREATE_RELEASE_RESPONSE=$(curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: Bearer $GITHUB_TOKEN" \ - -d "$RELEASE_DATA" \ - "https://api.github.com/repos/$GITHUB_OWNER/$GITHUB_REPO/releases" -) -STATUS=$? -if [ $STATUS == 0 ]; then - describe "Created GitHub release successfully." -else - describe "Could not create GitHub release, request failed with $STATUS." +if [[ $RELEASE_TYPE == "release" ]]; then + CREATE_RELEASE_RESPONSE=$(curl -X POST \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -d "$RELEASE_DATA" \ + "https://api.github.com/repos/$GITHUB_OWNER/$GITHUB_REPO/releases" + ) + STATUS=$? + if [ $STATUS == 0 ]; then + describe "Created GitHub Release successfully." + RELEASE_ID=$(echo "$CREATE_RELEASE_RESPONSE" | jq '.id') + else + echoerr "Could not create GitHub release, request failed with $STATUS:\n\n$CREATE_RELEASE_RESPONSE" + exit 1 + fi +elif [[ $RELEASE_TYPE == "dry-run" ]]; then + describe "Skipping creating GitHub release because dry-run." fi -RELEASE_ID=$(echo "$CREATE_RELEASE_RESPONSE" | jq '.id') - # Upload artifacts +describe_header "Uploading artifacts to GitHub release." for ARTIFACT_PATH in "${ARTIFACTS[@]}" do : # Upload Hermes artifacts to GitHub Release ARTIFACT_NAME=$(basename "$ARTIFACT_PATH") - describe_header "Uploading $ARTIFACT_NAME..." - - if curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: Bearer $GITHUB_TOKEN" \ - -H "Content-Length: $(wc -c "$ARTIFACT_PATH" | awk '{print $1}')" \ - -H "Content-Type: application/gzip" \ - -T "$ARTIFACT_PATH" \ - --progress-bar \ - "https://uploads.github.com/repos/$GITHUB_OWNER/$GITHUB_REPO/releases/$RELEASE_ID/assets?name=$ARTIFACT_NAME"; then + describe "Uploading $ARTIFACT_NAME..." + + if [[ $RELEASE_TYPE == "release" ]]; then + if curl -X POST \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Content-Length: $(wc -c "$ARTIFACT_PATH" | awk '{print $1}')" \ + -H "Content-Type: application/gzip" \ + -T "$ARTIFACT_PATH" \ + --progress-bar \ + "https://uploads.github.com/repos/$GITHUB_OWNER/$GITHUB_REPO/releases/$RELEASE_ID/assets?name=$ARTIFACT_NAME"; then describe "Uploaded $ARTIFACT_NAME." - else + else describe "Could not upload $ARTIFACT_NAME to GitHub release." + fi + elif [[ $RELEASE_TYPE == "dry-run" ]]; then + describe "Skipping $ARTIFACT_NAME upload because dry-run." fi done diff --git a/scripts/circleci/post-artifacts-link.sh b/scripts/circleci/post-artifacts-link.sh index 6318dc1e0f624d..21771e4fd493fa 100755 --- a/scripts/circleci/post-artifacts-link.sh +++ b/scripts/circleci/post-artifacts-link.sh @@ -7,5 +7,6 @@ GITHUB_OWNER=${CIRCLE_PROJECT_USERNAME:-facebook} \ GITHUB_REPO=${CIRCLE_PROJECT_REPONAME:-react-native} \ GITHUB_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" \ +GITHUB_REF=${CIRCLE_BRANCH} \ GITHUB_SHA=${CIRCLE_SHA1} \ exec node packages/react-native-bots/post-artifacts-link.js diff --git a/scripts/prepare-package-for-release.js b/scripts/prepare-package-for-release.js index 845303ff8e06b5..4f89743c618827 100755 --- a/scripts/prepare-package-for-release.js +++ b/scripts/prepare-package-for-release.js @@ -36,16 +36,25 @@ const argv = yargs alias: 'latest', type: 'boolean', default: false, + }) + .option('d', { + alias: 'dry-run', + type: 'boolean', + default: false, }).argv; const branch = process.env.CIRCLE_BRANCH; const remote = argv.remote; const releaseVersion = argv.toVersion; const isLatest = argv.latest; +const isDryRun = argv.dryRun; -if (!isReleaseBranch(branch)) { +if (branch && !isReleaseBranch(branch) && !isDryRun) { console.error(`This needs to be on a release branch. On branch: ${branch}`); exit(1); +} else if (!branch && !isDryRun) { + console.error('This needs to be on a release branch.'); + exit(1); } const {version} = parseVersion(releaseVersion); @@ -67,6 +76,12 @@ if (exec('source scripts/update_podfile_lock.sh && update_pods').code) { exit(1); } +echo(`Local checkout has been prepared for release version ${version}.`); +if (isDryRun) { + echo('Changes will not be committed because --dry-run was set to true.'); + exit(0); +} + // Make commit [0.21.0-rc] Bump version numbers if (exec(`git commit -a -m "[${version}] Bump version numbers"`).code) { echo('failed to commit'); diff --git a/scripts/publish-npm.js b/scripts/publish-npm.js index 5de46b96e1651a..2b4834e8de0361 100755 --- a/scripts/publish-npm.js +++ b/scripts/publish-npm.js @@ -186,6 +186,10 @@ if (isCommitly) { generateAndroidArtifacts(releaseVersion, tmpPublishingFolder); +// Write version number to the build folder +const releaseVersionFile = path.join('build', '.version'); +fs.writeFileSync(releaseVersionFile, releaseVersion); + if (dryRunBuild) { echo('Skipping `npm publish` because --dry-run is set.'); exit(0);