Skip to content

Commit

Permalink
Npm publish
Browse files Browse the repository at this point in the history
Summary:This work allows automated release deployment.

Previous semi-automation lived in release.sh and I split it into two pieces:
- test-manual-e2e.sh - that just tests that current commit is buildable and makes a quick e2e installation for manual testing
- publish-npm.js - that makes publish based on what current branch and tags are on commit that is tested/deployed by CI

This simplified `Releases.md` guide and requires you to just run
```
git checkout -b 0.22-stable
git tag v0.22.0-rc
git push origin 0.22-stable --tags
```
to have a successful npm release.
Closes facebook#6453

Reviewed By: mkonicek

Differential Revision: D3047938

Pulled By: bestander

fb-gh-sync-id: dbebf4c3a0bc2c2a0ef75c54595ab5654f91b8ea
shipit-source-id: dbebf4c3a0bc2c2a0ef75c54595ab5654f91b8ea
  • Loading branch information
bestander authored and Facebook Github Bot 1 committed Mar 15, 2016
1 parent d0cdabc commit ceb6bd5
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 107 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ buck-out
.gradle
local.properties
*.iml
/android/

# Node
node_modules
Expand Down
107 changes: 40 additions & 67 deletions Releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,54 @@ Release schedule:

- **0.21 branch cut**, 0.21.0-rc - **week of Feb 15**
- 0.21.0 - Feb 29
- **0.22 branch cut**, 0.22.0-rc - **week of Feb 29**
- 0.22.0 - Mar 14
- **0.23 branch cut**, 0.23.0-rc - **week of Mar 14**
- 0.23.0 - Mar 28
- **0.24 branch cut**, 0.23.0-rc - **week of Mar 28**
- 0.24.0 - Apr 11
- **0.22 branch cut**, 0.22.0-rc - **week of Mar 7**
- 0.22.0 - Mar 21
- **0.23 branch cut**, 0.23.0-rc - **week of Mar 21**
- 0.23.0 - Apr 4
- **0.24 branch cut**, 0.23.0-rc - **week of Apr 4**
- 0.24.0 - Apr 18
- ...

## One time setup

Set up Sinopia: https://github.com/facebook/react-native/tree/master/react-native-cli

## Cut a release branch
#### Check that everything works

To cut a release branch and check that everything works, you'll need Mac OS with the [Android dev environment set up](https://github.com/facebook/react-native/blob/master/ReactAndroid/README.md).
Make absolutely sure a basic iOS and Android workflow works on the commit you are going to use for release.
Make sure CI systems [Travis](https://travis-ci.org/facebook/react-native) and [Circle](https://circleci.com/gh/facebook/react-native)
are green and then run

Run:
```
./scripts/test-manual-e2e.sh
```

cd react-native
./scripts/release.sh version_you_are_releasing # e.g. ./scripts/release.sh 0.22
This script runs end to end with a proxy npm repository on local PC and asks to check that Chrome Debugging works.

#### Check that everything works
## Cut a release branch and push to github

Make absolutely sure a basic iOS and Android workflow works on the release branch you've just created, see the instructions printed by `release.sh`.

#### Push to github
To cut a release branch and check that everything works, you'll need Mac OS with the
[Android dev environment set up](https://github.com/facebook/react-native/blob/master/ReactAndroid/README.md).

- Check git history, the last commit should be "[0.22-rc] Bump version numbers" (with the correct version)
- `git push origin 0.version_you_are_releasing-stable # e.g. git push origin 0.22-stable`
Run:

```
git checkout -b <version_you_are_releasing>-stable # e.g. git checkout -b 0.22-stable
git tag v<version_you_are_releasing>.0-rc # e.g. git tag v0.22.0-rc
git push origin <version_you_are_releasing>-stable --tags # e.g. git push origin 0.22-stable --tags
```

Circle CI will run the tests and publish to npm with version `0.22.0-rc` and tag `next` meaning that
this version will not be installed for users by default.

** Note ** CI won't publish to npm if the `last` commit on the new branch does not have a tag `v<branch-name-without-stable>.0-[rc]`.

## Make sure we have release notes

Post that we're ready to release so a voluteer can write release notes:
https://github.com/facebook/react-native/releases

To go through all the commits that went into a release, one way is to use the GitHub compare view: https://github.com/facebook/react-native/compare/0.18-stable...0.19-stable

## Do an RC release (e.g. 0.22.0-rc)

IMPORTANT: `npm publish` will automatically set the latest tag. **When doing an RC release**, run `npm publish --tag next` - this way people need to opt in to get the RC release.
To go through all the commits that went into a release, one way is to use the GitHub compare view: https://github.com/facebook/react-native/compare/0.21-stable...0.22-stable

## IMPORTANT: Track bug reports from the community during the following two weeks and make sure they get fixed

Expand All @@ -56,73 +64,38 @@ We should only be tracking bugs with small and non-risky fixes. Don't pick new f

## Do a release (e.g. 0.22.0, 0.22.1)

Roughly two weeks after the branch cut (see the release schedule above) it's time to promote the RC to a real realease.
Roughly two weeks after the branch cut (see the release schedule above) it's time to promote the RC to a real release.

Make sure you know which bug fixes should definitely be cheery-picked, example: https://github.com/facebook/react-native/issues/6087

We should only cherry-pick small and non-risky bug fixes. Don't pick new features into the release as this greatly increases the risk of something breaking. The main point of the RC is to let people to use it for two weeks and fix the most serious bugs.

Do the following:

**NOTE: Most of these steps are similar to what the script `release.sh` does. The script is used to cut the release branch only, can be made more generic to help with this step too.**

```
cd react-native
git checkout master
git pull
git checkout 0.version_you_are_releasing-stable # e.g. git checkout 0.22-stable
git pull origin 0.version_you_are_releasing-stable # e.g. git pull origin 0.22-stable
# Cherry-pick those commits, test everything again using Sinopia
# Cherry-pick those commits
git cherry-pick commitHash1
# Create the 'android' folder to be published to npm.
./gradlew :ReactAndroid:installArchives
# Check that it's there: `ls android`
...
npm set registry http://localhost:4873
sinopia
# change versions in package.json and React.podspec
npm publish
cd /tmp
react-native init TestAapp
cd TestApp
react-native run-ios
# Check that you can Reload JS and the Chrome debugger works
# Kill packager
open ios/TestApp.xcodeproj
# Click run
# Check that you can Reload JS and the Chrome debugger works
cd android && ./gradlew dependencies
# Double check the react-native dep has the correct version
cd ..
react-native run-android
# Check that you can Reload JS and the Chrome debugger works
```
If everything worked:
# test everything again using sinopia
./scripts/test-manual-e2e.sh
```
npm set registry https://registry.npmjs.org
npm publish
# Check that you can Reload JS and the Chrome debugger works
```

Tag the release in Git:
If everything worked:

```
git tag v-version_you_are_releasing # e.g. git tag v0.22.0, git tag v0.22.1
git push --tags
```

To update the [website](https://facebook.github.io/react-native), move the `latest` tag and push to the `0.x-stable` branch. CircleCI will build and deploy the latest docs to the website.

```
git tag -d latest
git push origin :latest
git tag latest
git push origin version_you_are_releasing-stable --tags # e.g git push origin 0.22-stable --tags
git tag latest # for docs [website](https://facebook.github.io/react-native) to be generated
git push origin 0.22-stable --tags
```

Once you see the version in the top left corner of the website has been updated:
Move the release notes to the tag you've just created. We want single release notes per version, for example if there is v0.22.0-rc and later we release v0.22.0, the release notes should live on v0.22.0:
Move the release notes to the tag you've just created. We want single release notes per version,
for example if there is v0.22.0-rc and later we release v0.22.0, the release notes should live on v0.22.0:
https://github.com/facebook/react-native/tags

Uncheck the box "This is a pre-release" and publish the notes.
Expand Down
6 changes: 5 additions & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ dependencies:
- "buck-out/bin"
- "website/node_modules"
override:
# CIRCLE_NPM_TOKEN is in React Native project settings in Circle CI.
# It was generated for bestander user, easy to replace with anyone's else
- echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc
- npm config set spin=false
- npm config set progress=false
- npm install
Expand Down Expand Up @@ -80,11 +83,12 @@ test:
#- find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;

deployment:
website:
stable:
branch: [/.*-stable/, /master/]
commands:
# generate docs website
- git config --global user.email "[email protected]"
- git config --global user.name "Website Deployment Script"
- echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc
- cd website && GIT_USER=reactjs-bot npm run gh-pages
- node ./scripts/publish-npm.js
5 changes: 5 additions & 0 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
"flow-bin": "0.22.0",
"jest-cli": "0.9.2",
"portfinder": "0.4.0",
"react": "^0.14.5"
"react": "^0.14.5",
"shelljs": "^0.6.0"
}
}
153 changes: 153 additions & 0 deletions scripts/publish-npm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';

/**
* This script publishes a new version of react-native to NPM.
* It is supposed to run in CI environment, not on a developer's machine.
*
* To make it easier for developers it uses some logic to identify with which version to publish the package.
*
* To cut a branch (and release RC):
* - Developer: `git checkout -b 0.XY-stable`
* - Developer: `git tag v0.XY.0-rc` and `git push --tags` to [email protected]:facebook/react-native.git
* - CI: test and deploy to npm (run this script) with version 0.XY.0-rc with tag "next"
*
* To update RC release:
* - Developer: `git checkout 0.XY-stable`
* - Developer: cherry-pick whatever changes needed
* - Developer: `git tag v0.XY.0-rc1` and `git push --tags` to [email protected]:facebook/react-native.git
* - CI: test and deploy to npm (run this script) with version 0.XY.0-rc1 with tag "next"
*
* To publish a release:
* - Developer: `git checkout 0.XY-stable`
* - Developer: cherry-pick whatever changes needed
* - Developer: `git tag latest`
* - Developer: `git tag v0.XY.0`
* - Developer: `git push --tags` to [email protected]:facebook/react-native.git
* - CI: test and deploy to npm (run this script) with version 0.XY.0 with and not tag (latest is implied by npm)
*
* To patch old release:
* - Developer: `git checkout 0.XY-stable`
* - Developer: cherry-pick whatever changes needed
* - Developer: `git tag v0.XY.Z`
* - Developer: `git push` to [email protected]:facebook/react-native.git (or merge as pull request)
* - CI: test and deploy to npm (run this script) with version 0.XY.Z with no tag, npm will not mark it as latest if
* there is a version higher than XY
*
* Important tags:
* If tag v0.XY.0-rcZ is present on the commit then publish to npm with version 0.XY.0-rcZ and tag next
* If tag v0.XY.Z is present on the commit then publish to npm with version 0.XY.Z and no tag (npm will consider it latest)
*/

/*eslint-disable no-undef */
require(`shelljs/global`);

const buildBranch = process.env.CIRCLE_BRANCH;
const requiredJavaVersion = `1.7`;

let branchVersion;
if (buildBranch.indexOf(`-stable`) !== -1) {
branchVersion = buildBranch.slice(0, buildBranch.indexOf(`-stable`));
} else {
echo(`Error: We publish only from stable branches`);
exit(0);
}

// ['latest', 'v0.33.0', 'v0.33.0-rc', 'v0.33.0-rc1', 'v0.33.0-rc2', 'v0.34.0', '']
const tagsWithVersion = exec(`git tag -l --points-at HEAD`).stdout.split(/\s/)
// ['v0.33.0', 'v0.33.0-rc', 'v0.33.0-rc1', 'v0.33.0-rc2', 'v0.34.0']
.filter(version => !!version && version.indexOf(`v${branchVersion}`) === 0)
// ['v0.33.0', 'v0.33.0-rc', 'v0.33.0-rc1', 'v0.33.0-rc2']
.filter(version => version.indexOf(branchVersion) !== -1);

if (tagsWithVersion.length === 0) {
echo(`Error: Can't find version tag in current commit. To deploy to NPM you must add tag v0.XY.Z[-rc] to your commit`);
exit(1);
}
let releaseVersion;
if (tagsWithVersion[0].indexOf(`-rc`) === -1) {
// if first tag on this commit is non -rc then we are making a stable release
// '0.33.0'
releaseVersion = tagsWithVersion[0].slice(1);
} else {
// otherwise pick last -rc tag alphabetically
// 0.33.0-rc2
releaseVersion = tagsWithVersion[tagsWithVersion.length - 1].slice(1);
}

// -------- Generating Android Artifacts with JavaDoc
// Java -version outputs to stderr 0_o
const javaVersion = exec(`java -version`).stderr;
if (javaVersion.indexOf(requiredJavaVersion) === -1) {
echo(`Java version must be 1.7.x in order to generate Javadoc. Check: java -version`);
exit(1);
}

if (sed(`-i`, /^VERSION_NAME=[0-9\.]*-SNAPSHOT/, `VERSION_NAME=${releaseVersion}`, `ReactAndroid/gradle.properties`).code) {
echo(`Couldn't update version for Gradle`);
exit(1);
}

// Uncomment Javadoc generation
if (sed(`-i`, `// archives androidJavadocJar`, `archives androidJavadocJar`, `ReactAndroid/release.gradle`).code) {
echo(`Couldn't enable Javadoc generation`);
exit(1);
}

if (exec(`./gradlew :ReactAndroid:installArchives`).code) {
echo(`Couldn't generate artifacts`);
exit(1);
}

echo("Generated artifacts for Maven");

let artifacts = ['-javadoc.jar', '-sources.jar', '.aar', '.pom'].map((suffix) => {
return `react-native-${releaseVersion}${suffix}`;
});

artifacts.forEach((name) => {
if (!test(`-e`, `./android/com/facebook/react/react-native/${releaseVersion}/${name}`)) {
echo(`file ${name} was not generated`);
exit(1);
}
});

// ----------- Reverting changes to local files

exec(`git checkout ReactAndroid/gradle.properties`);
exec(`git checkout ReactAndroid/release.gradle`);


if (exec(`npm version --no-git-tag-version ${releaseVersion}`).code) {
echo(`Couldn't update version for npm`);
exit(1);
}
if (sed(`-i`, `s.version = "0.0.1-master"`, `s.version = \"${releaseVersion}\"`, `React.podspec`).code) {
echo(`Couldn't update version for React.podspec`);
exit(1);
}

// shrinkwrapping without dev dependencies
exec(`npm shrinkwrap`);
if (releaseVersion.indexOf(`-rc`) === -1) {
// release, package will be installed by default
exec(`npm publish`);
} else {
// RC release, package will be installed only if users specifically do it
exec(`npm publish --tag next`);
}

exec(`git checkout package.json`);
exec(`git checkout React.podspec`);

echo(`Published to npm ${releaseVersion}`);

exit(0);
/*eslint-enable no-undef */
Loading

0 comments on commit ceb6bd5

Please sign in to comment.