Browse Source

Release automation (#1720)

* Create autoamtic release script.

* Add changelog update date script.

* Improve release scripts.

* Apply suggestions from code review

Co-Authored-By: nventuro <nicolas.venturo@gmail.com>

* Apply suggestions from code review

Co-Authored-By: nventuro <nicolas.venturo@gmail.com>

* Remove moment dependency.
Nicolás Venturo 6 years ago
parent
commit
412cdfd0be

+ 69 - 6
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": {

+ 2 - 1
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": {

+ 113 - 0
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

+ 33 - 0
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' });

+ 3 - 3
scripts/version.js → 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;