diff --git a/release b/release index a321119e6..0689f8f41 100755 --- a/release +++ b/release @@ -1,53 +1,54 @@ #!/usr/bin/env node (function () { 'use strict'; + const strip = require('cli-color/strip'); + const prompt = require('prompt-sync')(); + const {mkdirSync} = require('temp'); + const {writeFileSync, readdirSync, statSync, readFile, writeFile} = require('fs'); + const {execSync} = require('child_process'); + const {relative, sep, join} = require('path'); + const isYes = matches.bind(this, 'yes'); + const colors = require('colors'); const REPO_TITLE = 'Angular Flex-Layout'; const SOURCE_REPO = 'flex-layout'; // Source repository with Demo-app and wiki docs const SOURCE_WIKI = 'flex-layout.wiki'; // Source repository with Demo-app and wiki docs - const DEPLOY_REPO = `${SOURCE_REPO}-builds`; // Build repository used for npm publish and travis CI - - var ORIGIN_SOURCE = `git@github.com:angular/${SOURCE_REPO}.git`; - var ORIGIN_WIKI = `git@github.com:angular/${SOURCE_WIKI}.git`; - var ORIGIN_DEPLOY = `git@github.com:angular/${DEPLOY_REPO}.git`; - - + const DEPLOY_REPO = `${SOURCE_REPO}-builds`; // Build repository used for npm publish and travis CI const NPM_RELEASES = 'scripts/release/releases.json'; - - var lineWidth = 80; - var defaultOptions = { encoding: 'utf-8' }; - var colors = require('colors'); - var strip = require('cli-color/strip'); - var fs = require('fs'); - var prompt = require('prompt-sync')(); - var child_process = require('child_process'); - var releases = require(`./${NPM_RELEASES}`); - var oldVersion = require('./package.json').version; - var path = require('path'); - var temp = require('temp'); - - const WIKI_PATH = 'docs/documentation'; - const WIKI_LOCAL = temp.mkdirSync(`${SOURCE_REPO}.wiki`); - - var cleanupCmds = [ 'rm -rf flex-layout-builds' ]; - var pushCmds = [ 'rm ./abort ./push' ]; - var abortCmds = [ 'rm ./abort ./push', 'git reset --hard', 'git checkout master' ]; - - var newVersion = ""; - var lastMajorVer = releases.latest; - var isYes = matches.bind(this, "yes"); - var isDryRun = isYes(prompt(`Is this a dry-run? ${"[yes/no]".cyan} `)); - var skipOnDryRun = isDryRun ? '## -- ' : ''; - - let msg = `What would you like the old version to be? (default: ${oldVersion.cyan}) `; - oldVersion = prompt(msg) || oldVersion; - newVersion = getNewVersion(); - - let validated = isDryRun || validate(); - if ( validated ) { + const ORIGIN_SOURCE = `git@github.com:angular/${SOURCE_REPO}.git`; + const ORIGIN_WIKI = `git@github.com:angular/${SOURCE_WIKI}.git`; + const ORIGIN_DEPLOY = `git@github.com:angular/${DEPLOY_REPO}.git`; + + const LINE_WIDTH = 80; + const DEFAULT_OPTIONS = { encoding: 'utf-8' }; + const WIKI_PATH = 'docs/documentation'; + const WIKI_LOCAL = mkdirSync(`${SOURCE_REPO}.wiki`); + const IS_DRY_RUN = isYes(prompt(`Is this a dry-run? ${'[yes/no]'.cyan} `)); + const OLD_VERSION_PACKAGE = require('./package.json').version; + const MSG = `What would you like the old version to be? (default: ${OLD_VERSION_PACKAGE.cyan}) `; + const OLD_VERSION = prompt(MSG) || OLD_VERSION_PACKAGE; + const NEW_VERSION = getNewVersion(); + const SKIP_ON_DRY_RUN = IS_DRY_RUN ? '## -- ' : ''; + + let cleanupCmds = ['rm -rf flex-layout-builds']; + let pushCmds = ['rm ./abort ./push']; + let abortCmds = ['rm ./abort ./push', 'git reset --hard', 'git checkout master']; + + const validated = IS_DRY_RUN || validate(); + if (validated) { build(); } + function stringifyFunction (method) { + return method + .toString() + .split('\n') + .slice(1, -1) + .map(line => line.trim() ) + .join(' ') + .replace(/"/g, '\\"'); + } + // ******************************************************** // Scripts and Utils // ******************************************************** @@ -55,7 +56,7 @@ /** start the build script */ function build () { - let hint = "git add CHANGELOG.md; git commit --amend --no-edit;"; + const hint = 'git add CHANGELOG.md; git commit --amend --no-edit;'; line(); @@ -73,31 +74,31 @@ line(); - log(`Your repo is ${"ready".cyan} to be pushed.`); - log(`Please look over ${"CHANGELOG.md".cyan} and make any changes.`); + log(`Your repo is ${'ready'.cyan} to be pushed.`); + log(`Please look over ${'CHANGELOG.md'.cyan} and make any changes.`); log(`! ------------ `); log(`! NOTE: If you make changes to the CHANGELOG, use `); log(`! ${hint.red} `); - log(`! before proceeding with "${"./push".cyan}"`); + log(`! before proceeding with '${'./push'.cyan}'`); log(`! ------------ `); - log(`If you would like to cancel this release, please run "${"./abort".cyan}"`); - log(`When you are ready, please run "${"./push".cyan}" to finish the process.`); + log(`If you would like to cancel this release, please run '${'./abort'.cyan}'`); + log(`When you are ready, please run '${'./push'.cyan}' to finish the process.`); } /** confirms that you will be able to perform the release before attempting */ function validate () { const err = (msg) => { - var str = 'Error: ' + msg; + let str = 'Error: ' + msg; log(str.red); - } + }; - if ( process.argv[2] == '--force' ) { + if (process.argv[2] === '--force' || process.argv[3] === '--force') { return true; } else if (exec('npm whoami') !== 'angular') { - err('You must be authenticated with npm as "angular" to perform a release.'); + err(`You must be authenticated with npm as 'angular' to perform a release.`); } else if (exec('git rev-parse --abbrev-ref HEAD') !== 'staging') { - err('Releases must be performed from a "staging" branch.'); + err(`Releases must be performed from a 'staging' branch.`); err('Please checkout the lastest source: `git checkout -B staging`.'); } else { return true; @@ -111,33 +112,35 @@ */ function matches(options, value) { value = value.toLowerCase(); - if ( typeof options === 'string' ) options = [options]; + if (typeof options === 'string') { + options = [options]; + } options = [' '].concat(options); return options.reduce((prev, curr)=>{ return !prev ? curr.indexOf(value) > -1 : true; - },false); + }, false); } /** creates the version branch and adds abort steps */ function checkoutVersionBranch () { - exec(`git branch -q -D release/${newVersion}`); - exec(`git checkout -q -b release/${newVersion}`); + exec(`git branch -q -D release/${NEW_VERSION}`); + exec(`git checkout -q -b release/${NEW_VERSION}`); - pushCmds.push(`# build release/${newVersion} branch...`); + pushCmds.push(`# build release/${NEW_VERSION} branch...`); abortCmds.push('git checkout staging -q'); } /** writes the new version to package.json */ function updateVersion() { - start(`Updating ${"package.json".cyan} version from ${oldVersion.cyan} to ${newVersion.cyan}...`); + start(`Updating ${'package.json'.cyan} version from ${OLD_VERSION.cyan} to ${NEW_VERSION.cyan}...`); updatePackageVersions(); done(); } /** generates the changelog from the commits since the last release */ function createChangelog () { - start(`Generating changelog from ${oldVersion.cyan} to ${newVersion.cyan}...`); + start(`Generating changelog from ${OLD_VERSION.cyan} to ${NEW_VERSION.cyan}...`); // Use the current CHANGELOG.md (that is on #master and now this branch) exec(`./scripts/release/changelog.js`); @@ -148,48 +151,49 @@ function updateReleasesJson () { const RELEASE_PATH = './scripts/release/releases.json'; - const config = require( RELEASE_PATH ); + const config = require(RELEASE_PATH); - config.versions.unshift(newVersion); - config.latest = newVersion; + config.versions.unshift(NEW_VERSION); + config.latest = NEW_VERSION; - require('fs').writeFileSync(RELEASE_PATH, JSON.stringify(config, null, 2)); + writeFileSync(RELEASE_PATH, JSON.stringify(config, null, 2)); } /** utility method for clearing the terminal */ function clear () { - write("\u001b[2J\u001b[0;0H"); + write('\u001b[2J\u001b[0;0H'); } /** prompts the user for the new version */ function getNewVersion () { - var options = getVersionOptions(oldVersion), key, type, version; + let options = getVersionOptions(OLD_VERSION), key, type, version; header(); - log(`The current version is ${oldVersion.cyan}.`); + log(`The current version is ${OLD_VERSION.cyan}.`); log(''); log('What should the next version be?'); - for (key in options) { log((+key + 1) + ') ' + options[ key ].cyan); } + for (key in options) { + log((+key + 1) + ') ' + options[key].cyan); + } log(''); type = prompt('Please select a new version: '); - if (options[ type - 1 ]) version = options[ type - 1 ]; - else version = type; + version = options[type - 1] ? options[type - 1] : type; // else if (type.match(/^\d+\.\d+\.\d+(-rc\.?\d+)?$/)) version = type; // else throw new Error('Your entry was invalid.'); log(''); log('The new version will be ' + version.cyan + '.'); - return isYes(prompt(`Is this correct? ${"[yes/no]".cyan} `)) ? version : getNewVersion(); + return isYes(prompt(`Is this correct? ${'[yes/no]'.cyan} `)) ? version : getNewVersion(); function getVersionOptions (version) { - return version.match(/-alpha\.?\d+$/) ? [ increment(version, 'alpha'), addBeta(increment(version, 'minor')) ] : - version.match(/-beta\.?\d+$/) ? [ increment(version, 'beta'), increment(version, 'rc') ] : - version.match(/-rc\.?\d+$/) ? [ increment(version, 'rc'), increment(version, 'patch') ] : - [ increment(version, 'patch'), increment(version, 'minor') ]; + return version.match(/-alpha\.?\d+$/) ? [increment(version, 'alpha'), addBeta(increment(version, 'minor'))] : + version.match(/-beta\.?\d+$/) ? [increment(version, 'beta'), increment(version, 'rc')] : + version.match(/-rc\.?\d+$/) ? [increment(version, 'rc'), increment(version, 'patch')] : + [increment(version, 'patch'), increment(version, 'minor')]; function increment (versionString, type) { - var version = parseVersion(versionString); + let version = parseVersion(versionString); switch (type) { case 'alpha': case 'beta' : @@ -204,8 +208,8 @@ return buildVersionString(version); function parseVersion (version) { - var hasBeta = version.indexOf("-beta") > -1; - var parts = version.split(/\-beta\.|\-rc\.|\./g); + let hasBeta = version.indexOf('-beta') > -1; + let parts = version.split(/\-beta\.|\-rc\.|\./g); return { string: version, major: parts[ 0 ], @@ -217,19 +221,27 @@ } function buildVersionString (version) { - var str = version.major + '.' + version.minor + '.' + version.patch; - str += version.rc ? `-rc.${version.rc}` : - version.beta ? `-beta.${version.beta}` : - version.alpha ? `-alpha.${version.alpha}` : ""; + let str = version.major + '.' + version.minor + '.' + version.patch; + str += version.rc ? `-rc.${version.rc}` : + version.beta ? `-beta.${version.beta}` : + version.alpha ? `-alpha.${version.alpha}` : ''; return str; } function resetVersionParts() { switch (type) { - case 'minor' : version.patch = 0; - case 'patch' : version.rc = 0; - case 'rc' : version.beta = 0; - case 'beta' : version.alpha = 0; + case 'minor': + version.patch = 0; + break; + case 'patch': + version.rc = 0; + break; + case 'rc': + version.beta = 0; + break; + case 'beta': + version.alpha = 0; + break; } } } @@ -247,8 +259,8 @@ function tagRelease () { pushCmds.push( - `git tag v${newVersion} -f`, - `${skipOnDryRun} git push --tags ${ORIGIN_SOURCE}` + `git tag v${NEW_VERSION} -f`, + `${SKIP_ON_DRY_RUN} git push --tags ${ORIGIN_SOURCE}` ); } @@ -256,7 +268,7 @@ /** amends the commit to include local changes (ie. changelog) */ function commitChanges () { start('Committing changes...'); - exec(`git commit -am "build(release): version ${newVersion}"`); + exec(`git commit -am "build(release): version ${NEW_VERSION}"`); done(); // Now any other changes (on the release branch will @@ -267,7 +279,7 @@ /** utility method for cloning github repos */ function cloneDeployRepo () { - let deployPath = "./"+DEPLOY_REPO; + const deployPath = `./${DEPLOY_REPO}`; start(`Cloning ${deployPath.cyan} from Github...`); exec(`rm -Rf ${deployPath}`); exec(`git clone git@github.com:angular/${DEPLOY_REPO}.git --depth=1`); @@ -275,15 +287,14 @@ cleanupCmds.push( 'rm -rf dist', - `${skipOnDryRun} rm -Rf ${deployPath}`, - `${skipOnDryRun} git branch -D release/${newVersion}` + `${SKIP_ON_DRY_RUN} rm -Rf ${deployPath}`, + `${SKIP_ON_DRY_RUN} git branch -D release/${NEW_VERSION}` ); - } /** writes an array of commands to a bash script */ function writeScript (name, cmds) { - fs.writeFileSync(name, '#!/usr/bin/env bash\n\n' + cmds.join('\n')); + writeFileSync(name, '#!/usr/bin/env bash\n\n' + cmds.join('\n')); exec('chmod +x ' + name); } @@ -293,19 +304,19 @@ exec([ 'rm -rf dist', 'gulp flex-layout:build-release:clean' - ]); + ]); done(); // Execute the next commands relative to the nightly builds repo - let options = {cwd: "./"+DEPLOY_REPO}; + let options = {cwd: `./${DEPLOY_REPO}`}; start(`Copy files into ${options.cwd.cyan} repo...`); exec([ - `cp -Rf ../dist/@angular/${SOURCE_REPO}/* ./`, // local build output dir + `cp -Rf ../dist/@angular/${SOURCE_REPO}/* ./`, // local build output dir 'cp -f ../CHANGELOG.md .', // always over the CHANGELOG 'git add -A', - `git commit -m "build(deploy): release version ${newVersion}"` + `git commit -m "build(deploy): release version ${NEW_VERSION}"` ], options); done(); @@ -313,34 +324,24 @@ pushCmds.push( comment(`push to angular/${DEPLOY_REPO} (master and tag) and publish to npm`), `cd ./${DEPLOY_REPO}`, - `node -e "var newVersion = '${newVersion}'; ${stringifyFunction(updatePackageVersions)}"`, + `node -e "const NEW_VERSION = '${NEW_VERSION}'; ${stringifyFunction(updatePackageVersions)}"`, 'git add package.json', 'cp -f ../CHANGELOG.md .', // Copy Changelog from root (if changed) 'git add CHANGELOG.md', // re-add to the commit 'git commit --amend --no-edit', - `git tag -f v${newVersion}`, // Tag and update nightly builds + `git tag -f v${NEW_VERSION}`, // Tag and update nightly builds 'git pull --rebase --strategy=ours', - comment(!isDryRun ? '' : `Updating deploy repo @angular/${DEPLOY_REPO} with tag ${newVersion}`), - `${skipOnDryRun} git push ${ORIGIN_DEPLOY} master`, - `${skipOnDryRun} git push --tags ${ORIGIN_DEPLOY} master`, + comment(!IS_DRY_RUN ? '' : `Updating deploy repo @angular/${DEPLOY_REPO} with tag ${NEW_VERSION}`), + `${SKIP_ON_DRY_RUN} git push ${ORIGIN_DEPLOY} master`, + `${SKIP_ON_DRY_RUN} git push --tags ${ORIGIN_DEPLOY} master`, - comment(!isDryRun ? '' : `Publishing @angular/${SOURCE_REPO} ${newVersion} to npm`), - `${skipOnDryRun} npm publish`, + comment(!IS_DRY_RUN ? '' : `Publishing @angular/${SOURCE_REPO} ${NEW_VERSION} to npm`), + `${SKIP_ON_DRY_RUN} npm publish${(process.argv[2] === '--next' || process.argv[3] === '--next') ? ' --tag next' : ''}`, 'cd ../' ); - - function stringifyFunction (method) { - return method - .toString() - .split('\n') - .slice(1, -1) - .map((line) => line.trim() ) - .join(' ') - .replace(/"/g, '\\"'); - } } /** @@ -351,10 +352,10 @@ * ./scripts/release/package.json == package for the deployed npm build */ function updatePackageVersions () { - [ './package.json'].forEach(filePath => { + ['./package.json'].forEach(filePath => { let json = require(filePath); - json.version = newVersion; - require('fs').writeFileSync(filePath, JSON.stringify(json, null, 2)); + json.version = NEW_VERSION; + writeFileSync(filePath, JSON.stringify(json, null, 2)); }); } @@ -367,26 +368,16 @@ */ function updateMaster () { pushCmds.push( - comment('update package.json in master'), - 'git checkout master -q', - `git checkout release/${newVersion} -- CHANGELOG.md`, - `node -e "var newVersion = '${newVersion}'; ${stringifyFunction(updatePackageVersions)}"`, - 'git add package.json', - `node -e "var newVersion = '${newVersion}'; ${stringifyFunction(updateReleasesJson)}"`, - `git add ${NPM_RELEASES}`, - `git commit -m "chore(version): update version number in package.json to ${newVersion}"`, - `${skipOnDryRun} git push ${ORIGIN_SOURCE} master` + comment('update package.json in master'), + 'git checkout master -q', + `git checkout release/${NEW_VERSION} -- CHANGELOG.md`, + `node -e "const NEW_VERSION = '${NEW_VERSION}'; ${stringifyFunction(updatePackageVersions)}"`, + 'git add package.json', + `node -e "const NEW_VERSION = '${NEW_VERSION}'; ${stringifyFunction(updateReleasesJson)}"`, + `git add ${NPM_RELEASES}`, + `git commit -m "chore(version): update version number in package.json to ${NEW_VERSION}"`, + `${SKIP_ON_DRY_RUN} git push ${ORIGIN_SOURCE} master` ); - - function stringifyFunction (method) { - return method - .toString() - .split('\n') - .slice(1, -1) - .map((line) => line.trim() ) - .join(' ') - .replace(/"/g, '\\"'); - } } /** @@ -399,8 +390,8 @@ comment('push docs to Wiki'), `cd ${WIKI_LOCAL}`, 'git add .', - `git commit -m "docs(wiki): update to version ${newVersion}"`, - `${skipOnDryRun} git push ${ORIGIN_WIKI} master` + `git commit -m "docs(wiki): update to version ${NEW_VERSION}"`, + `${SKIP_ON_DRY_RUN} git push ${ORIGIN_WIKI} master` ) } @@ -409,20 +400,20 @@ * be copied */ function readDocFiles(directory, filelist) { - if(directory[directory.length - 1] != `${path.sep}`) { - directory = directory.concat(`${path.sep}`); + if (directory[directory.length - 1] !== `${sep}`) { + directory = directory.concat(`${sep}`); } - const files = fs.readdirSync(directory); + const files = readdirSync(directory); filelist = filelist || []; files.forEach((file) => { - if (fs.statSync(directory + file).isDirectory()) { - filelist = readDocFiles(directory + file + `${path.sep}`, filelist); + if (statSync(directory + file).isDirectory()) { + filelist = readDocFiles(directory + file + `${sep}`, filelist); } else { const originalPath = directory + file; - const newPath = path.join(WIKI_LOCAL, originalPath - .replace(WIKI_PATH + `${path.sep}`, '') - .replace(`${path.sep}`, '-')); + const newPath = join(WIKI_LOCAL, originalPath + .replace(WIKI_PATH + `${sep}`, '') + .replace(`${sep}`, '-')); filelist.push({ originalPath, newPath }); } @@ -442,10 +433,10 @@ function checkNameLinks(files) { return files.reduce((pValue, cValue) => { const oldName = cValue.originalPath - .replace(WIKI_PATH + `${path.sep}`, '') + .replace(WIKI_PATH + `${sep}`, '') .replace('.md', '') - .replace(`${path.sep}`, '/'); - const newName = '(' + cValue.newPath.split(`${path.sep}`).slice(-1).pop().replace('.md', '') + ')'; + .replace(`${sep}`, '/'); + const newName = '(' + cValue.newPath.split(`${sep}`).slice(-1).pop().replace('.md', '') + ')'; if (oldName !== newName) { pValue.push({ oldName, @@ -457,11 +448,11 @@ } function copyDocFile(from, to, linksToReplace) { - from = path.relative(process.cwd(), from); - to = path.relative(process.cwd(), to); + from = relative(process.cwd(), from); + to = relative(process.cwd(), to); const replaceHyphen = new RegExp('-', 'gi'); return new Promise((resolve, reject) => { - fs.readFile(from, (error, data) => { + readFile(from, (error, data) => { if (error) { reject(error); } @@ -471,7 +462,7 @@ const r = new RegExp(str, 'gi'); fileData = fileData.replace(r, link.newName); }); - fs.writeFile(to, fileData, (error2) => { + writeFile(to, fileData, (error2) => { if (error2) { reject(error2); } @@ -491,10 +482,10 @@ /** outputs a centered message in the terminal */ function center (msg) { - msg = ' ' + msg.trim() + ' '; - var length = msg.length; - var spaces = Math.floor((lineWidth - length) / 2); - return Array(spaces + 1).join('-') + msg.green + Array(lineWidth - msg.length - spaces + 1).join('-'); + msg = ` ${msg.trim()} `; + let length = msg.length; + let spaces = Math.floor((LINE_WIDTH - length) / 2); + return Array(spaces + 1).join('-') + msg.green + Array(LINE_WIDTH - msg.length - spaces + 1).join('-'); } /** outputs done text when a task is completed */ @@ -505,12 +496,14 @@ /** utility method for executing terminal commands */ function exec (cmd, userOptions) { if (cmd instanceof Array) { - return cmd.map( (cmd) => exec(cmd, userOptions) ); + return cmd.map((cmd) => exec(cmd, userOptions)); } try { - var options = Object.create(defaultOptions); - for (var key in userOptions) options[ key ] = userOptions[ key ]; - return child_process.execSync(cmd + ' 2> /dev/null', options).toString().trim(); + let options = Object.create(DEFAULT_OPTIONS); + for (let key in userOptions) { + options[key] = userOptions[key]; + } + return execSync(cmd + ' 2> /dev/null', options).toString().trim(); } catch (err) { return err; } @@ -518,13 +511,13 @@ /** returns a commented message for use in bash scripts */ function comment (msg) { - return '\n# ' + msg + '\n'; + return `\n# ${msg}\n`; } /** prints the left side of a task while it is being performed */ function start (msg) { - var msgLength = strip(msg).length, - diff = lineWidth - 4 - msgLength; + let msgLength = strip(msg).length, + diff = LINE_WIDTH - 4 - msgLength; write(msg + Array(diff + 1).join(' ')); } @@ -541,6 +534,6 @@ /** prints a horizontal line to the terminal */ function line () { - log(Array(lineWidth + 1).join('-')); + log(Array(LINE_WIDTH + 1).join('-')); } })();