From 01ef50f20ac780e1a3f88e779c02434156b138b2 Mon Sep 17 00:00:00 2001 From: Robert Knight Date: Fri, 8 Jul 2016 10:25:54 +0100 Subject: [PATCH] Add scripts for releasing a new version (#26) Add a set of `npm version` scripts which can be used to tag and publish a new release of the client with: npm version major|minor|patch npm publish Where most releases will use `npm version minor`. --- .npmrc | 1 + package.json | 7 +++- scripts/create-github-release.js | 65 ++++++++++++++++++++++++++++++++ scripts/update-changelog.js | 29 ++++++++++++++ 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 .npmrc create mode 100755 scripts/create-github-release.js create mode 100755 scripts/update-changelog.js diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..af941b49c24 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +sign-git-tag=true diff --git a/package.json b/package.json index 687ee9328ec..439838ae2d1 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "raf": "^3.1.0", "raven-js": "^2.0.2", "redux": "^3.5.2", - "request": "^2.71.0", + "request": "^2.72.0", "retry": "^0.8.0", "scroll-into-view": "^1.3.1", "seamless-immutable": "^6.0.1", @@ -135,6 +135,9 @@ "scripts": { "build": "gulp build-app", "deps": "check-dependencies", - "test": "gulp test-app" + "test": "gulp test-app", + "preversion": "npm run test", + "version": "make clean all && ./scripts/update-changelog.js && git add CHANGELOG.md", + "postversion": "git push && git push --tags && ./scripts/create-github-release.js" } } diff --git a/scripts/create-github-release.js b/scripts/create-github-release.js new file mode 100755 index 00000000000..95f092a1779 --- /dev/null +++ b/scripts/create-github-release.js @@ -0,0 +1,65 @@ +#!/usr/bin/env node + +/** + * Creates a GitHub release for the repository. + * + * This should be run just after a released is tagged with the tag name + * `v` where is the `version` field in package.json. + */ + +const fs = require('fs'); +const request = require('request'); + +const pkg = require('../package.json'); + +/** + * Extract the release notes for a given version from a markdown changelog in + * the format recommended by http://keepachangelog.com + */ +function extractReleaseNotes(changelog, version) { + const notes = changelog + .split(/(\n|^)## /) + .find(section => section.indexOf(`[${version}]`) === 0); + + if (!notes) { + throw new Error(`Failed to find release notes for v${pkg.version}`); + } + + return notes.split('\n').slice(1).join('\n'); +} + +// See https://github.com/docker/docker/issues/679 +const GITHUB_ORG_REPO_PAT = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/; + +if (!pkg.repository || !pkg.repository.match(GITHUB_ORG_REPO_PAT)) { + throw new Error(`package.json is missing a "repository" field of the form :owner/:repo`); +} + +if (!process.env.GITHUB_TOKEN) { + throw new Error(`GITHUB_TOKEN env var is not set`); +} + +const changelog = fs.readFileSync(require.resolve('../CHANGELOG.md')).toString(); +const release = { + tag_name: `v${pkg.version}`, + name: `v${pkg.version}`, + body: extractReleaseNotes(changelog, pkg.version), + draft: false, + prerelease: true, +}; + +request.post({ + uri: `https://api.github.com/repos/${pkg.repository}/releases`, + body: release, + json: true, + headers: { + Authorization: `token ${process.env.GITHUB_TOKEN}`, + 'User-Agent': `${pkg.repository} Release Script`, + }, +}, (err, rsp, body) => { + if (err || rsp.statusCode !== 201) { + const msg = err ? err.message : `${rsp.statusCode}: ${JSON.stringify(body)}`; + throw new Error(`Creating GitHub release failed: ${msg}`); + } + console.info(`Created GitHub release for v${pkg.version}`); +}); diff --git a/scripts/update-changelog.js b/scripts/update-changelog.js new file mode 100755 index 00000000000..f1bb48c1fae --- /dev/null +++ b/scripts/update-changelog.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node + +/** + * Replaces the "[Unreleased]" header for changes in the next release with the + * current package version from package.json + */ + +'use strict'; + +const fs = require('fs'); + +const pkg = require('../package.json'); + +const dateStr = new Date().toISOString().slice(0,10); +const versionLine = `## [${pkg.version}] - ${dateStr}`; + +const changelogPath = require.resolve('../CHANGELOG.md'); +const changelog = fs.readFileSync(changelogPath).toString(); +const updatedChangelog = changelog.split('\n') + .map(ln => ln.match(/\[Unreleased\]/) ? versionLine : ln) + .join('\n'); + +if (updatedChangelog === changelog) { + console.error('Failed to find "Unreleased" section in changelog'); + process.exit(1); +} + +fs.writeFileSync(changelogPath, updatedChangelog); +