From 99dc990615d08e4a3ce6e42357c9d1d2920038ba Mon Sep 17 00:00:00 2001 From: Shawn Allen Date: Mon, 9 Oct 2017 23:09:04 -0700 Subject: [PATCH 1/7] move generator-primer-module to /tools/ --- script/new-module | 2 +- {modules => tools}/generator-primer-module/README.md | 0 {modules => tools}/generator-primer-module/app/index.js | 0 .../generator-primer-module/app/lib/capitalize.js | 0 .../generator-primer-module/app/lib/strip-prefix.js | 0 {modules => tools}/generator-primer-module/app/options.js | 0 .../generator-primer-module/app/templates/.npmignore | 0 .../generator-primer-module/app/templates/LICENSE | 0 .../generator-primer-module/app/templates/README.md | 0 .../generator-primer-module/app/templates/index.scss | 0 .../generator-primer-module/app/templates/lib/module.scss | 0 .../generator-primer-module/app/templates/package.json | 0 {modules => tools}/generator-primer-module/package.json | 0 .../generator-primer-module/test/fixtures/docs.md | 0 .../generator-primer-module/test/generator.spec.js | 0 {modules => tools}/generator-primer-module/test/lib/generate.js | 0 16 files changed, 1 insertion(+), 1 deletion(-) rename {modules => tools}/generator-primer-module/README.md (100%) rename {modules => tools}/generator-primer-module/app/index.js (100%) rename {modules => tools}/generator-primer-module/app/lib/capitalize.js (100%) rename {modules => tools}/generator-primer-module/app/lib/strip-prefix.js (100%) rename {modules => tools}/generator-primer-module/app/options.js (100%) rename {modules => tools}/generator-primer-module/app/templates/.npmignore (100%) rename {modules => tools}/generator-primer-module/app/templates/LICENSE (100%) rename {modules => tools}/generator-primer-module/app/templates/README.md (100%) rename {modules => tools}/generator-primer-module/app/templates/index.scss (100%) rename {modules => tools}/generator-primer-module/app/templates/lib/module.scss (100%) rename {modules => tools}/generator-primer-module/app/templates/package.json (100%) rename {modules => tools}/generator-primer-module/package.json (100%) rename {modules => tools}/generator-primer-module/test/fixtures/docs.md (100%) rename {modules => tools}/generator-primer-module/test/generator.spec.js (100%) rename {modules => tools}/generator-primer-module/test/lib/generate.js (100%) diff --git a/script/new-module b/script/new-module index 0db84c4df5..f1d89efdfb 100755 --- a/script/new-module +++ b/script/new-module @@ -3,7 +3,7 @@ set -e function generate() { pushd modules > /dev/null - ../node_modules/.bin/yo ./generator-primer-module/app "$@" + ../node_modules/.bin/yo ../tools/generator-primer-module/app "$@" popd > /dev/null } diff --git a/modules/generator-primer-module/README.md b/tools/generator-primer-module/README.md similarity index 100% rename from modules/generator-primer-module/README.md rename to tools/generator-primer-module/README.md diff --git a/modules/generator-primer-module/app/index.js b/tools/generator-primer-module/app/index.js similarity index 100% rename from modules/generator-primer-module/app/index.js rename to tools/generator-primer-module/app/index.js diff --git a/modules/generator-primer-module/app/lib/capitalize.js b/tools/generator-primer-module/app/lib/capitalize.js similarity index 100% rename from modules/generator-primer-module/app/lib/capitalize.js rename to tools/generator-primer-module/app/lib/capitalize.js diff --git a/modules/generator-primer-module/app/lib/strip-prefix.js b/tools/generator-primer-module/app/lib/strip-prefix.js similarity index 100% rename from modules/generator-primer-module/app/lib/strip-prefix.js rename to tools/generator-primer-module/app/lib/strip-prefix.js diff --git a/modules/generator-primer-module/app/options.js b/tools/generator-primer-module/app/options.js similarity index 100% rename from modules/generator-primer-module/app/options.js rename to tools/generator-primer-module/app/options.js diff --git a/modules/generator-primer-module/app/templates/.npmignore b/tools/generator-primer-module/app/templates/.npmignore similarity index 100% rename from modules/generator-primer-module/app/templates/.npmignore rename to tools/generator-primer-module/app/templates/.npmignore diff --git a/modules/generator-primer-module/app/templates/LICENSE b/tools/generator-primer-module/app/templates/LICENSE similarity index 100% rename from modules/generator-primer-module/app/templates/LICENSE rename to tools/generator-primer-module/app/templates/LICENSE diff --git a/modules/generator-primer-module/app/templates/README.md b/tools/generator-primer-module/app/templates/README.md similarity index 100% rename from modules/generator-primer-module/app/templates/README.md rename to tools/generator-primer-module/app/templates/README.md diff --git a/modules/generator-primer-module/app/templates/index.scss b/tools/generator-primer-module/app/templates/index.scss similarity index 100% rename from modules/generator-primer-module/app/templates/index.scss rename to tools/generator-primer-module/app/templates/index.scss diff --git a/modules/generator-primer-module/app/templates/lib/module.scss b/tools/generator-primer-module/app/templates/lib/module.scss similarity index 100% rename from modules/generator-primer-module/app/templates/lib/module.scss rename to tools/generator-primer-module/app/templates/lib/module.scss diff --git a/modules/generator-primer-module/app/templates/package.json b/tools/generator-primer-module/app/templates/package.json similarity index 100% rename from modules/generator-primer-module/app/templates/package.json rename to tools/generator-primer-module/app/templates/package.json diff --git a/modules/generator-primer-module/package.json b/tools/generator-primer-module/package.json similarity index 100% rename from modules/generator-primer-module/package.json rename to tools/generator-primer-module/package.json diff --git a/modules/generator-primer-module/test/fixtures/docs.md b/tools/generator-primer-module/test/fixtures/docs.md similarity index 100% rename from modules/generator-primer-module/test/fixtures/docs.md rename to tools/generator-primer-module/test/fixtures/docs.md diff --git a/modules/generator-primer-module/test/generator.spec.js b/tools/generator-primer-module/test/generator.spec.js similarity index 100% rename from modules/generator-primer-module/test/generator.spec.js rename to tools/generator-primer-module/test/generator.spec.js diff --git a/modules/generator-primer-module/test/lib/generate.js b/tools/generator-primer-module/test/lib/generate.js similarity index 100% rename from modules/generator-primer-module/test/lib/generate.js rename to tools/generator-primer-module/test/lib/generate.js From bcf156cfb2915e139d8b78a798210d25ee262ff9 Mon Sep 17 00:00:00 2001 From: Shawn Allen Date: Tue, 10 Oct 2017 11:41:41 -0700 Subject: [PATCH 2/7] a new suite of RC tools --- package.json | 5 ++ script/get-packages | 31 +++++++ script/get-release-version | 28 ++++++ script/release-candidate | 177 ++++++++++++++++++++++++++----------- script/revert-packages | 30 +++++++ 5 files changed, 218 insertions(+), 53 deletions(-) create mode 100755 script/get-packages create mode 100755 script/get-release-version create mode 100755 script/revert-packages diff --git a/package.json b/package.json index 2df6ce7006..7c9899ccbe 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,12 @@ "babel-preset-react": "^6.24.1", "commit-status": "^4.1.0", "css-loader": "^0.28.4", + "execa": "^0.8.0", + "fs-extra": "^4.0.2", "glob": "^7.1.2", + "globby": "^6.1.0", "html-to-react": "^1.2.11", + "isomorphic-fetch": "^2.2.1", "lerna": "^2.0.0", "node-sass": "^4.5.3", "npm-run-all": "^4.0.2", @@ -38,6 +42,7 @@ "react": "^15.6.1", "react-dom": "^15.6.1", "react-svg-inline": "^2.0.0", + "registry-url": "^3.1.0", "remark": "^8.0.0", "sass-loader": "^6.0.6", "semver": "^5.3.0", diff --git a/script/get-packages b/script/get-packages new file mode 100755 index 0000000000..671d7b3784 --- /dev/null +++ b/script/get-packages @@ -0,0 +1,31 @@ +#!/usr/bin/env node +const fs = require('fs') +const globby = require('globby') +const path = require('path') + +const getPackages = (debug) => { + const lernaConfig = require('../lerna.json') + const packageGlobs = lernaConfig.packages + return globby(packageGlobs) + .then(packagePaths => { + return packagePaths.filter(pkg => { + try { + require.resolve(`../${pkg}/package.json`) + return true + } catch (error) { + if (debug) { + console.warn('No package.json in %s', pkg) + } + } + }) + }) +} + +if (module.parent) { + module.exports = getPackages +} else { + getPackages(true).then(packages => { + console.warn('%d packages:', packages.length) + packages.forEach(pkg => console.log(pkg)) + }) +} diff --git a/script/get-release-version b/script/get-release-version new file mode 100755 index 0000000000..a23154a22b --- /dev/null +++ b/script/get-release-version @@ -0,0 +1,28 @@ +#!/usr/bin/env node + +const RELEASE_PREFIX = 'release-' + +const getReleaseVersion = (pkg, branch) => { + const version = require(`../modules/${pkg}/package.json`).version + + if (branch && branch.indexOf(RELEASE_PREFIX) === 0) { + const release = branch.replace(RELEASE_PREFIX, '') + if (release !== version) { + console.warn('⚠️ Release branch version mismatch:') + console.warn(' "%s" should be "%s" in %s/package.json', version, release, pkg) + } + return release + } else { + return version + } +} + +if (module.parent) { + module.exports = getReleaseVersion +} else { + const args = process.argv.slice(2) + const pkg = args.shift() || 'primer-css' + const branch = args.shift() || process.env.TRAVIS_BRANCH + const version = getReleaseVersion(pkg, branch) + console.log(version) +} diff --git a/script/release-candidate b/script/release-candidate index b6570f21f8..8ff69b9ffb 100755 --- a/script/release-candidate +++ b/script/release-candidate @@ -1,64 +1,135 @@ -#!/bin/bash -set -e -echo "👌 Publishing release candidate..." +#!/usr/bin/env node +const execa = require('execa') +const fetch = require('isomorphic-fetch') +const fse = require('fs-extra') +const registryUrl = require('registry-url') +const semver = require('semver') -package=primer-css -npm_tag=rc +const bin = 'node_modules/.bin/' +const lernaBin = `${bin}lerna` +const getPackages = require('./get-packages') +const getReleaseVersion = require('./get-release-version') +const revertPackages = require('./revert-packages') -# get the version we're publishing as a release candidate -local_version=$(jq -r .version modules/$package/package.json) -if [[ $local_version =~ "-" ]]; then - echo "❌ Found pre-release version: $package@$local_version; bailing!" - exit 1 -else - echo "🏔 Local version: $package@$local_version" -fi - -# get the version most recently published to the rc dist-tag -rc_version=$(npm info $package@$npm_tag version) -echo "📦 Published version for $package@$npm_tag: $rc_version" -rc_release=${rc_version%-*} -if [[ $local_version != $rc_release ]]; then - rc_version=$local_version -fi - -# determine the -next_version=$( - $(npm bin)/semver --increment prerelease --preid $npm_tag $rc_version +const PRERELEASE = 'prerelease' +const DIST_TAG = 'rc' +const PRIMER_CSS = 'primer-css' +const RELEASE_VERSION = getReleaseVersion( + PRIMER_CSS, + process.env.TRAVIS_BRANCH ) -echo "🤜 Next version: $package@$next_version" -# strip the pre-release version, yielding just major.minor.patch -pre_version=${next_version:${#local_version}} -echo " Prerelease suffix: '$pre_version'" +const depFields = [ + 'dependencies', + 'devDependencies', + 'optionalDependencies', + 'peerDependencies', +] + +const getUpdated = (args) => { + return execa(lernaBin, ['updated', '--json']) + .then(res => JSON.parse(res.stdout)) + .then(updated => updated.map(pkg => pkg.name)) +} -# if this is the same version, we need to bump the prerelease -# for all of the modules using the same prerelease identifier -echo "Updating all module versions in place..." -echo -module_dirs=modules/primer-* -for module_dir in $module_dirs; do - pushd $module_dir > /dev/null - module=$(basename $module_dir) +const writePackage = (pkg) => { + const {dir} = pkg + delete pkg.dir + const json = JSON.stringify(pkg, null, ' ') + '\n' + pkg.dir = dir + return fse.writeFile(`${pkg.dir}/package.json`, json, 'utf8') + .then(() => pkg) +} - # determine the local version (in git) - module_version=$(jq -r .version package.json) - # strip the rc version, just in case - module_version=${module_version%-*} - module_next_version="$module_version$pre_version" +const bump = (pkg, by, preid) => { + if (pkg.name === PRIMER_CSS) { + pkg.version = RELEASE_VERSION + } - echo "$module@$module_version => $module_next_version" - # "upgrade" to the most recent RC version so that - # `npm version prerelease` can increment automatically - npm version --no-git --quiet "$module_next_version" + const original = pkg.version + let version = increment(pkg.version, by, preid) + return getPackageInfo(pkg.name) + .then(info => { + while (version in info.versions) { + version = increment(version, by, preid) + } + console.warn('%s %s -> %s', pkg.name, original, version) + pkg.version = version + return writePackage(pkg) + }) +} - popd > /dev/null -done +const getPackageInfo = (name) => { + const url = registryUrl() + name + return fetch(url).then(res => res.json()) +} -# publish all the things! -$(dirname $0)/notify pending +const increment = (version, by, preid) => { + const {major, minor, patch} = semver(version) + const prev = [major, minor, patch].join('.') + const next = semver.inc(version, by, preid) + // if this is a prerelease, "revert" major.minor.patch + // so that only the prerelease id is incremented + return by === PRERELEASE + ? next.replace(/^\d+\.\d+\.\d+/, prev) + : next +} -# note: this should NOT fail, so --bail=true applies -$(npm bin)/lerna exec -- npm publish --tag=$npm_tag +const updateDependants = (pkg, pkgs) => { + return pkgs.filter(other => { + return depFields.some(field => { + if (other[field] && (pkg.name in other[field])) { + other[field][pkg.name] = pkg.version + return true + } + }) + }) +} -$(dirname $0)/notify success +revertPackages() + .then(() => getPackages()) + .then(dirs => { + return dirs.map(dir => { + const pkg = require(`../${dir}/package.json`) + pkg.dir = dir + return pkg + }) + }) + .then(pkgs => { + const by = PRERELEASE + const preid = DIST_TAG + return getUpdated() + .then(updated => { + console.warn('%d packages updated...', updated.length) + return pkgs.filter(pkg => updated.includes(pkg.name)) + }) + .then(updated => { + const changed = new Set(updated.map(pkg => pkg.name)) + return Promise.all(updated.map(pkg => { + return bump(pkg, by, preid) + .then(pkg => updateDependants(pkg, pkgs)) + .then(dependants => { + dependants.forEach(dep => changed.add(dep.name)) + }) + })) + .then(() => { + const tasks = Array.from(changed) + .map(name => pkgs.filter(pkg => pkg.name === name)[0]) + .map(writePackage) + return Promise.all(tasks) + }) + .then(updated => { + const tasks = updated.map(pkg => { + return execa('npm', ['pack', '--tag', DIST_TAG], { + cwd: pkg.dir, + stdio: 'inherit', + }) + }) + return Promise.all(tasks) + }) + }) + }) + .catch(error => { + console.error('Error:', error) + process.exit(1) + }) diff --git a/script/revert-packages b/script/revert-packages new file mode 100755 index 0000000000..0c55add5d8 --- /dev/null +++ b/script/revert-packages @@ -0,0 +1,30 @@ +#!/usr/bin/env node +const execa = require('execa') +const fse = require('fs-extra') +const globby = require('globby') + +const revertPackages = () => { + const lernaConfig = require('../lerna.json') + const globs = lernaConfig.packages + const jsons = globs.map(glob => glob + '/package.json') + const tarballs = globs.map(glob => glob + '/*.tgz') + const opts = {stdio: 'inherit'} + return Promise.all([ + execa('git', ['checkout', '--'].concat(globs), opts), + globby(tarballs) + .then(paths => { + if (paths.length) { + console.warn('deleting %d tarball(s)', paths.length) + return Promise.all( + paths.map(tgz => fse.remove(tgz)) + ) + } + }), + ]) +} + +if (module.parent) { + module.exports = revertPackages +} else { + revertPackages().then(() => process.exit(0)) +} From 7413bcf71339dc465f6684e468a42fe2933c257d Mon Sep 17 00:00:00 2001 From: Shawn Allen Date: Wed, 11 Oct 2017 21:07:27 -0700 Subject: [PATCH 3/7] add commit status notifications --- script/release-candidate | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/script/release-candidate b/script/release-candidate index 8ff69b9ffb..e1efc4474d 100755 --- a/script/release-candidate +++ b/script/release-candidate @@ -32,6 +32,13 @@ const getUpdated = (args) => { .then(updated => updated.map(pkg => pkg.name)) } +const notify = status => { + return execa('script/notify', ['error']) + .catch(error => { + console.error('notify error:', error) + }) +} + const writePackage = (pkg) => { const {dir} = pkg delete pkg.dir @@ -127,9 +134,12 @@ revertPackages() }) return Promise.all(tasks) }) + .then(() => notify('success')) }) }) .catch(error => { console.error('Error:', error) - process.exit(1) + process.exitCode = 1 + return notify('error') }) + .then(() => process.exit()) From 2a44a633fbe8f8527464030e9034e63bf00a4a6b Mon Sep 17 00:00:00 2001 From: Shawn Allen Date: Wed, 11 Oct 2017 21:14:23 -0700 Subject: [PATCH 4/7] really publish to npm --- script/release-candidate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/release-candidate b/script/release-candidate index e1efc4474d..3f976bf317 100755 --- a/script/release-candidate +++ b/script/release-candidate @@ -127,7 +127,7 @@ revertPackages() }) .then(updated => { const tasks = updated.map(pkg => { - return execa('npm', ['pack', '--tag', DIST_TAG], { + return execa('npm', ['publish', '--tag', DIST_TAG], { cwd: pkg.dir, stdio: 'inherit', }) From 0883140ee78fa2f0e08c8ef8d71c131373dec53f Mon Sep 17 00:00:00 2001 From: Shawn Allen Date: Wed, 11 Oct 2017 21:15:55 -0700 Subject: [PATCH 5/7] pass env vars to script/notify --- script/release-candidate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/release-candidate b/script/release-candidate index 3f976bf317..3b0eac8f52 100755 --- a/script/release-candidate +++ b/script/release-candidate @@ -33,7 +33,7 @@ const getUpdated = (args) => { } const notify = status => { - return execa('script/notify', ['error']) + return execa('script/notify', ['error'], {env: process.env}) .catch(error => { console.error('notify error:', error) }) From db7474c370f722b35587a45a9457f8711e664264 Mon Sep 17 00:00:00 2001 From: Shawn Allen Date: Wed, 11 Oct 2017 21:20:50 -0700 Subject: [PATCH 6/7] just put objects in the changed Set --- script/release-candidate | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/script/release-candidate b/script/release-candidate index 3b0eac8f52..8aa0ca0ee1 100755 --- a/script/release-candidate +++ b/script/release-candidate @@ -111,17 +111,16 @@ revertPackages() return pkgs.filter(pkg => updated.includes(pkg.name)) }) .then(updated => { - const changed = new Set(updated.map(pkg => pkg.name)) + const changed = new Set(updated) return Promise.all(updated.map(pkg => { return bump(pkg, by, preid) .then(pkg => updateDependants(pkg, pkgs)) .then(dependants => { - dependants.forEach(dep => changed.add(dep.name)) + dependants.forEach(dep => changed.add(dep)) }) })) .then(() => { const tasks = Array.from(changed) - .map(name => pkgs.filter(pkg => pkg.name === name)[0]) .map(writePackage) return Promise.all(tasks) }) From 21d19f030f8ee60b33b737db61381b5fd1be75e9 Mon Sep 17 00:00:00 2001 From: Shawn Allen Date: Wed, 11 Oct 2017 21:47:54 -0700 Subject: [PATCH 7/7] update compare-published to work w/multiple module dirs --- script/compare-published | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/script/compare-published b/script/compare-published index 2f637c674e..df2cb2762c 100755 --- a/script/compare-published +++ b/script/compare-published @@ -5,9 +5,7 @@ set -e # script/compare-published [tag] tag=${1:-${NPM_TAG:-latest}} -# this is way faster than `lerna exec npm info . .name` -# (but will skip modules that don't have "primer-" in them) -modules=`ls -1 modules | egrep primer-` +packages=$($(dirname $0)/get-packages) # tabular output separator for column(1) s=, @@ -15,9 +13,10 @@ s=, echo "📦 Comparing Primer modules published @${tag}..." ( echo "module${s}tag${s}published${s}local" - for module in $modules; do - v_published=`npm info ${module}@${tag} .version` - v_local=`jq -Mr .version modules/${module}/package.json` + for package in $packages; do + module=$(jq -r .name "$package/package.json") + v_published=$(npm info "$module@$tag" .version) + v_local=$(jq -Mr .version "$package/package.json") echo "${module}${s}${tag}${s}${v_published:-x}${s}${v_local}" done ) | column -t -s=${s}