diff --git a/package-lock.json b/package-lock.json index c36c4d1ef..261e8b706 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,14 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "js-tokens": { @@ -651,6 +659,14 @@ "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "chardet": { @@ -1296,12 +1312,6 @@ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, "escodegen": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", @@ -1403,6 +1413,14 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "debug": { @@ -2059,6 +2077,14 @@ "dev": true, "requires": { "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "file-entry-cache": { @@ -3365,6 +3391,14 @@ "ansi-styles": "^3.1.0", "escape-string-regexp": "^1.0.5", "supports-color": "^4.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "has-flag": { @@ -4049,6 +4083,12 @@ "ms": "2.0.0" } }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, "has-flag": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", @@ -4561,6 +4601,13 @@ "dev": true, "optional": true }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "optional": true + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -5382,6 +5429,14 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "chardet": { @@ -6044,6 +6099,14 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } } }, "is-fullwidth-code-point": { diff --git a/package.json b/package.json index 4d3852226..686331dbe 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "lint:js:fix": "eslint . --fix", "lint:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\"", "prepack": "npm run build", - "version": "scripts/version.js", + "release": "scripts/release/release.sh", + "version": "scripts/release/update-changelog-release-date.js && scripts/release/update-ethpm-version.js", "test": "npm run compile && scripts/test.sh" }, "repository": { diff --git a/scripts/release/release.sh b/scripts/release/release.sh new file mode 100755 index 000000000..c96f9ea55 --- /dev/null +++ b/scripts/release/release.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash + +# Exit script as soon as a command fails. +set -o errexit + +log() { + # Print to stderr to prevent this from being 'returned' + echo "$@" > /dev/stderr +} + +current_version() { + echo "v$(node --print --eval "require('./package.json').version")" +} + +current_release_branch() { + v="$(current_version)" + echo "release-${v%%-rc.*}" +} + +assert_current_branch() { + current_branch="$(git symbolic-ref --short HEAD)" + expected_branch="$1" + if [[ "$current_branch" != "$expected_branch" ]]; then + log "Current branch '$current_branch' is not '$expected_branch'" + exit 1 + fi +} + +push_release_branch_and_tag() { + git push upstream "$(current_release_branch)" "$(current_version)" +} + +push_and_publish() { + dist_tag="$1" + + log "Pushing release branch and tags to upstream" + push_release_branch_and_tag + + log "Publishing package on npm" + npm publish --tag "$dist_tag" --otp "$(prompt_otp)" + + if [[ "$dist_tag" == "latest" ]]; then + npm dist-tag rm --otp "$(prompt_otp)" openzeppelin-solidity next + fi +} + +prompt_otp() { + log -n "Enter npm 2FA token: " + read -r otp + echo "$otp" +} + +environment_check() { + if ! git remote get-url upstream &> /dev/null; then + log "No 'upstream' remote found" + exit 1 + fi + + if npm whoami &> /dev/null; then + log "Will publish as '$(npm whoami)'" + else + log "Not logged in into npm, run 'npm login' first" + exit 1 + fi +} + +environment_check + +if [[ "$*" == "start minor" ]]; then + log "Creating new minor pre-release" + + assert_current_branch master + + # Create temporary release branch + git checkout -b release-temp + + # This bumps minor and adds rc suffix, commits the changes, and tags the commit + npm version preminor --preid=rc + + # Rename the release branch + git branch --move "$(current_release_branch)" + + push_and_publish next + +elif [[ "$*" == "rc" ]]; then + log "Bumping pre-release" + + assert_current_branch "$(current_release_branch)" + + # Bumps rc number, commits and tags + npm version prelease + + push_and_publish next + +elif [[ "$*" == "final" ]]; then + # Update changelog release date, remove rc suffix, tag, push to git, publish in npm, remove next dist-tag + log "Creating final release" + + assert_current_branch "$(current_release_branch)" + + # This will remove the -rc suffix from the version + npm version patch + + push_release_branch_and_tag + + push_and_publish latest + + log "Remember to merge the release branch into master and push upstream" + +else + log "Unknown command: '$*'" + exit 1 +fi diff --git a/scripts/release/update-changelog-release-date.js b/scripts/release/update-changelog-release-date.js new file mode 100755 index 000000000..f169846f3 --- /dev/null +++ b/scripts/release/update-changelog-release-date.js @@ -0,0 +1,33 @@ +#!/usr/bin/env node + +// Sets the release date of the current release in the changelog. +// This is run automatically when npm version is run. + +const fs = require('fs'); +const cp = require('child_process'); +const moment = require('moment'); + +const pkg = require('../../package.json'); +if (pkg.version.indexOf('-rc') !== -1) { + process.exit(0); +} + +const version = pkg.version.replace(/-.*/, ''); // Remove the rc suffix + +const changelog = fs.readFileSync('CHANGELOG.md', 'utf8'); + +// The changelog entry to be updated looks like this: +// ## 2.5.3 (unreleased) +// We need to add the date in a YYYY-MM-DD format, so that it looks like this: +// ## 2.5.3 (2019-04-25) + +if (changelog.indexOf(`## ${version} (unreleased)`) === -1) { + throw Error(`Found no changelog entry for version ${version}`); +} + +fs.writeFileSync('CHANGELOG.md', changelog.replace( + `## ${version} (unreleased)`, + `## ${version} (${new Date().toISOString().split('T')[0]})`) +); + +cp.execSync('git add CHANGELOG.md', { stdio: 'inherit' }); diff --git a/scripts/version.js b/scripts/release/update-ethpm-version.js similarity index 67% rename from scripts/version.js rename to scripts/release/update-ethpm-version.js index 1fcc07354..3ddc6c7b5 100755 --- a/scripts/version.js +++ b/scripts/release/update-ethpm-version.js @@ -1,13 +1,13 @@ #!/usr/bin/env node // Synchronizes ethpm.json version number with package.json. -// Useful to run as an npm script alogn with `npm version`. +// This is run automatically when npm version is run. const fs = require('fs'); const cp = require('child_process'); -const pkg = require('../package.json'); -const ethpm = require('../ethpm.json'); +const pkg = require('../../package.json'); +const ethpm = require('../../ethpm.json'); ethpm.version = pkg.version;