Circle CI: Upload both tarballs to releases, dry-run the release workflow on every commit (#35015)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/35015

React Native releases are cut every few months. Without testing, the workflow is prone to breakage.

Dry-run the release workflow on every commit in order to surface any issues as they are introduced instead of at release time.

Fixed issues that surfaced during testing of this workflow:
- Upload both Hermes tarballs

Changelog: [internal]

Reviewed By: mdvacca

Differential Revision: D40483764

fbshipit-source-id: 5ca6bd4dcdfd64c24882ffb202edbfd701efd462
This commit is contained in:
Héctor Ramos
2022-10-19 17:54:22 -07:00
committed by Facebook GitHub Bot
parent af0e6cdae5
commit e4b5d3eec9
6 changed files with 183 additions and 100 deletions
+80 -15
View File
@@ -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
@@ -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 </dev/urandom >"$ARTIFACT_PATH"
done
../circleci/create_github_release.sh "$CIRCLE_TAG" "$CIRCLE_PROJECT_USERNAME" "$CIRCLE_PROJECT_REPONAME" "$GITHUB_TOKEN" "${ARTIFACTS[@]}"
+82 -39
View File
@@ -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//[.-]/}
# 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)
PRERELEASE=false
if [[ "$RELEASE_VERSION" == *"rc"* ]]; then
PRERELEASE=true
fi
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="<!-- TODO: Fill this out using RELEASE_TEMPLATE.md -->"
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..."
describe "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
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
+1
View File
@@ -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
+16 -1
View File
@@ -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');
+4
View File
@@ -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);