diff --git a/.vscode/launch.json b/.vscode/launch.json index 21d3c6d8fd2..7e816b25572 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,10 +5,10 @@ "name": "Launch", "type": "node", "request": "launch", - "program": "node_modules/gulp/bin/gulp.js", + "program": "${workspaceRoot}/scripts/publish.js", "stopOnEntry": false, "args": [], - "cwd": ".", + "cwd": "${workspaceRoot}", "runtimeExecutable": null, "runtimeArgs": [ "--nolazy" diff --git a/changes/testbump-guid.json b/changes/testbump-guid.json new file mode 100644 index 00000000000..f7995416895 --- /dev/null +++ b/changes/testbump-guid.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@microsoft/gulp-core-serve", + "type": "patch", + "comments": [ + "Republishing a package from new repo." + ] + } + ] +} \ No newline at end of file diff --git a/common/npm-shrinkwrap.json b/common/npm-shrinkwrap.json index d8760dfe5ad..ebda5065af2 100644 --- a/common/npm-shrinkwrap.json +++ b/common/npm-shrinkwrap.json @@ -67,21 +67,9 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" }, "accepts": { - "version": "1.1.4", - "from": "accepts@1.1.4", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.1.4.tgz", - "dependencies": { - "mime-db": { - "version": "1.12.0", - "from": "mime-db@>=1.12.0 <1.13.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz" - }, - "mime-types": { - "version": "2.0.14", - "from": "mime-types@>=2.0.4 <2.1.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz" - } - } + "version": "1.3.3", + "from": "accepts@1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz" }, "acorn": { "version": "3.3.0", @@ -269,9 +257,9 @@ "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz" }, "base64-arraybuffer": { - "version": "0.1.2", - "from": "base64-arraybuffer@0.1.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz" + "version": "0.1.5", + "from": "base64-arraybuffer@0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz" }, "base64-js": { "version": "1.2.0", @@ -330,9 +318,9 @@ "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz" }, "binary-extensions": { - "version": "1.6.0", + "version": "1.7.0", "from": "binary-extensions@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.6.0.tgz" + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.7.0.tgz" }, "binaryextensions": { "version": "1.0.1", @@ -459,9 +447,9 @@ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz" }, "caniuse-db": { - "version": "1.0.30000541", + "version": "1.0.30000547", "from": "caniuse-db@>=1.0.30000488 <2.0.0", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000541.tgz" + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000547.tgz" }, "cardinal": { "version": "1.0.0", @@ -837,9 +825,9 @@ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz" }, "deasync": { - "version": "0.1.7", + "version": "0.1.8", "from": "deasync@>=0.1.7 <0.2.0", - "resolved": "https://registry.npmjs.org/deasync/-/deasync-0.1.7.tgz" + "resolved": "https://registry.npmjs.org/deasync/-/deasync-0.1.8.tgz" }, "debug": { "version": "2.2.0", @@ -977,9 +965,9 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" }, "emojis-list": { - "version": "2.0.1", + "version": "2.1.0", "from": "emojis-list@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.0.1.tgz" + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz" }, "encodeurl": { "version": "1.0.1", @@ -999,26 +987,19 @@ } }, "engine.io": { - "version": "1.6.11", - "from": "engine.io@1.6.11", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.6.11.tgz" + "version": "1.7.0", + "from": "engine.io@1.7.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.7.0.tgz" }, "engine.io-client": { - "version": "1.6.11", - "from": "engine.io-client@1.6.11", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.6.11.tgz", - "dependencies": { - "ws": { - "version": "1.0.1", - "from": "ws@1.0.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.0.1.tgz" - } - } + "version": "1.7.0", + "from": "engine.io-client@1.7.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.7.0.tgz" }, "engine.io-parser": { - "version": "1.2.4", - "from": "engine.io-parser@1.2.4", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.2.4.tgz", + "version": "1.3.0", + "from": "engine.io-parser@1.3.0", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.0.tgz", "dependencies": { "has-binary": { "version": "0.1.6", @@ -1057,19 +1038,7 @@ "errorhandler": { "version": "1.4.3", "from": "errorhandler@>=1.4.2 <1.5.0", - "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.4.3.tgz", - "dependencies": { - "accepts": { - "version": "1.3.3", - "from": "accepts@>=1.3.0 <1.4.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz" - }, - "negotiator": { - "version": "0.6.1", - "from": "negotiator@0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz" - } - } + "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.4.3.tgz" }, "es5-ext": { "version": "0.10.12", @@ -1186,19 +1155,7 @@ "express": { "version": "4.14.0", "from": "express@>=4.14.0 <4.15.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.14.0.tgz", - "dependencies": { - "accepts": { - "version": "1.3.3", - "from": "accepts@>=1.3.3 <1.4.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz" - }, - "negotiator": { - "version": "0.6.1", - "from": "negotiator@0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz" - } - } + "resolved": "https://registry.npmjs.org/express/-/express-4.14.0.tgz" }, "express-session": { "version": "1.11.3", @@ -1342,16 +1299,9 @@ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.2.tgz" }, "fined": { - "version": "1.0.1", + "version": "1.0.2", "from": "fined@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.0.1.tgz", - "dependencies": { - "lodash.isarray": { - "version": "4.0.0", - "from": "lodash.isarray@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-4.0.0.tgz" - } - } + "resolved": "https://registry.npmjs.org/fined/-/fined-1.0.2.tgz" }, "first-chunk-stream": { "version": "1.0.0", @@ -1394,9 +1344,9 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.0.1.tgz" }, "lodash": { - "version": "4.16.2", + "version": "4.16.4", "from": "lodash@>=4.8.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.2.tgz" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.4.tgz" } } }, @@ -1900,9 +1850,9 @@ "resolved": "https://registry.npmjs.org/gulp-istanbul/-/gulp-istanbul-0.10.4.tgz", "dependencies": { "lodash": { - "version": "4.16.2", + "version": "4.16.4", "from": "lodash@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.2.tgz" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.4.tgz" } } }, @@ -2333,9 +2283,9 @@ "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz" }, "ieee754": { - "version": "1.1.6", + "version": "1.1.8", "from": "ieee754@>=1.1.4 <2.0.0", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.6.tgz" + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz" }, "in-publish": { "version": "2.0.0", @@ -2465,9 +2415,9 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz" }, "is-my-json-valid": { - "version": "2.14.0", + "version": "2.15.0", "from": "is-my-json-valid@>=2.12.4 <3.0.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.14.0.tgz" + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz" }, "is-number": { "version": "2.1.0", @@ -2739,9 +2689,9 @@ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" }, "jsonpointer": { - "version": "2.0.0", - "from": "jsonpointer@2.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" + "version": "4.0.0", + "from": "jsonpointer@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.0.tgz" }, "jsprim": { "version": "1.3.1", @@ -2803,9 +2753,9 @@ "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.2.tgz", "dependencies": { "lodash": { - "version": "4.16.2", + "version": "4.16.4", "from": "lodash@>=4.0.1 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.2.tgz" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.4.tgz" } } }, @@ -3421,9 +3371,9 @@ "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz" }, "negotiator": { - "version": "0.4.9", - "from": "negotiator@0.4.9", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.9.tgz" + "version": "0.6.1", + "from": "negotiator@0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz" }, "node-emoji": { "version": "1.4.1", @@ -3598,6 +3548,11 @@ "from": "temp_modules/npmx-node-library-build", "resolved": "file:temp_modules/npmx-node-library-build" }, + "npmx-web-build-tools-scripts": { + "version": "0.0.0", + "from": "temp_modules/npmx-web-build-tools-scripts", + "resolved": "file:temp_modules/npmx-web-build-tools-scripts" + }, "npmx-web-library-build": { "version": "0.0.0", "from": "temp_modules/npmx-web-library-build", @@ -3855,14 +3810,14 @@ "resolved": "https://registry.npmjs.org/phantomjs-polyfill/-/phantomjs-polyfill-0.0.2.tgz" }, "phantomjs-prebuilt": { - "version": "2.1.12", + "version": "2.1.13", "from": "phantomjs-prebuilt@>=2.1.6 <2.2.0", - "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.12.tgz", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.13.tgz", "dependencies": { "es6-promise": { - "version": "3.2.1", - "from": "es6-promise@>=3.2.1 <3.3.0", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz" + "version": "4.0.5", + "from": "es6-promise@>=4.0.3 <4.1.0", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz" }, "fs-extra": { "version": "0.30.0", @@ -4230,9 +4185,9 @@ "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.1.2.tgz", "dependencies": { "lodash": { - "version": "4.16.2", + "version": "4.16.4", "from": "lodash@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.2.tgz" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.4.tgz" }, "yargs": { "version": "4.8.1", @@ -4346,9 +4301,9 @@ "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" }, "socket.io": { - "version": "1.4.8", + "version": "1.5.0", "from": "socket.io@>=1.4.5 <2.0.0", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.4.8.tgz" + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.5.0.tgz" }, "socket.io-adapter": { "version": "0.4.0", @@ -4370,9 +4325,9 @@ } }, "socket.io-client": { - "version": "1.4.8", - "from": "socket.io-client@1.4.8", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.4.8.tgz", + "version": "1.5.0", + "from": "socket.io-client@1.5.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.5.0.tgz", "dependencies": { "component-emitter": { "version": "1.2.0", @@ -4415,9 +4370,9 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz" }, "spdx-expression-parse": { - "version": "1.0.3", + "version": "1.0.4", "from": "spdx-expression-parse@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.3.tgz" + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz" }, "spdx-license-ids": { "version": "1.2.2", @@ -4873,11 +4828,6 @@ } } }, - "utf8": { - "version": "2.1.0", - "from": "utf8@2.1.0", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.0.tgz" - }, "util": { "version": "0.10.3", "from": "util@>=0.10.3 <1.0.0", @@ -5133,9 +5083,14 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" }, "ws": { - "version": "1.1.0", - "from": "ws@1.1.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.0.tgz" + "version": "1.1.1", + "from": "ws@1.1.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz" + }, + "wtf-8": { + "version": "1.0.0", + "from": "wtf-8@1.0.0", + "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz" }, "xmlhttprequest-ssl": { "version": "1.5.1", diff --git a/common/package.json b/common/package.json index e08876a5f35..77739543404 100644 --- a/common/package.json +++ b/common/package.json @@ -8,7 +8,8 @@ "npmx-gulp-core-build-typescript": "file:./temp_modules/npmx-gulp-core-build-typescript", "npmx-gulp-core-build-webpack": "file:./temp_modules/npmx-gulp-core-build-webpack", "npmx-node-library-build": "file:./temp_modules/npmx-node-library-build", - "npmx-web-library-build": "file:./temp_modules/npmx-web-library-build" + "npmx-web-library-build": "file:./temp_modules/npmx-web-library-build", + "npmx-web-build-tools-scripts": "file:./temp_modules/npmx-web-build-tools-scripts" }, "description": "Temporary file generated by the NPMX tool", "name": "npmx-common", diff --git a/common/temp_modules/npmx-web-build-tools-scripts/package.json b/common/temp_modules/npmx-web-build-tools-scripts/package.json new file mode 100644 index 00000000000..17ea786f687 --- /dev/null +++ b/common/temp_modules/npmx-web-build-tools-scripts/package.json @@ -0,0 +1,9 @@ +{ + "name": "npmx-web-build-tools-scripts", + "version": "0.0.0", + "private": true, + "dependencies": { + "rimraf": "^2.5.4", + "semver": "^5.3.0" + } +} diff --git a/npmx.json b/npmx.json index d5029a0df57..fda6eb54c0e 100644 --- a/npmx.json +++ b/npmx.json @@ -61,6 +61,10 @@ { "packageName": "@microsoft/web-library-build", "projectFolder": "web-library-build" + }, + { + "packageName": "web-build-tools-scripts", + "projectFolder": "scripts" } ] } \ No newline at end of file diff --git a/scripts/enumerate.js b/scripts/enumerate.js new file mode 100644 index 00000000000..db7d397e524 --- /dev/null +++ b/scripts/enumerate.js @@ -0,0 +1,99 @@ +'use strict'; + +let fs = require('fs'); +let path = require('path'); +let fileExists = require('./utils').fileExists; +let directoryExists = require('./utils').directoryExists; + +let rootPackagePath = path.resolve('./package.json'); + +function findPackagesSync(dir, results) { + let excludes = [ + '.git', + 'node_modules', + 'typings', + 'lib', + 'src', + 'dist', + 'coverage', + 'common' + ]; + + results = results || []; + let list = fs.readdirSync(dir).filter(file => excludes.indexOf(file) === -1); + + list.forEach((file) => { + let fullPath = path.resolve(dir, file); + + if (directoryExists(fullPath)) { + findPackagesSync(fullPath, results); + + } else if (fullPath !== rootPackagePath && fileExists(fullPath) && path.basename(file) === 'package.json') { + results.push(fullPath); + } + }); + + return results; +} + +function forEachPackage(dir, cb) { + let packageCount = 0; + let packageLocations = findPackagesSync('.'); + + packageLocations.forEach(packageLocation => { + // crack open packages. + let data = fs.readFileSync(packageLocation, 'utf8'); + let pkg = JSON.parse(data); + + cb(pkg, packageLocation); + }); +} + +function getAllProjects() { + let allProjects = {}; + + forEachPackage('.', (pkg, location) => { + allProjects[pkg.name] = { + package: pkg, + path: location + }; + }); + + return allProjects; +} + +function findReposSync(dir, results) { + let excludes = [ + 'node_modules' + ]; + results = results || []; + + let list = fs.readdirSync(dir); + + list = list.filter(file => excludes.indexOf(file) === -1); + + list.forEach((file) => { + let fullPath = path.resolve(dir, file); + if (directoryExists(fullPath)) { + if (file === '.git') { + results.push(dir); + } else { + findReposSync(fullPath, results); + } + } + }); + + return results; +} + +function forEachRepo(dir, cb) { + findReposSync('.').forEach(repoPath => cb(repoPath)); +} + +module.exports = { + findPackagesSync, + forEachPackage, + getAllProjects, + findReposSync, + forEachRepo +}; diff --git a/scripts/package.json b/scripts/package.json new file mode 100644 index 00000000000..ba41752f785 --- /dev/null +++ b/scripts/package.json @@ -0,0 +1,15 @@ +{ + "name": "web-build-tools-scripts", + "version": "1.0.0", + "description": "", + "main": "enumerate.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "rimraf": "^2.5.4", + "semver": "^5.3.0" + } +} diff --git a/scripts/publish.js b/scripts/publish.js new file mode 100644 index 00000000000..f40c29f6d4c --- /dev/null +++ b/scripts/publish.js @@ -0,0 +1,258 @@ +'use strict'; + +let fs = require('fs'); +let os = require('os'); +let path = require('path'); +let semver = require('semver'); +let deleteFile = require('./utils').deleteFile; +let execSync = require('child_process').execSync; +let forEachPackage = require('./enumerate').forEachPackage; +let getAllProjects = require('./enumerate').getAllProjects; + +let _downstreamDeps = getDownstreamDependencies(); +let _allPackages = getAllProjects(); +let _changeTypes = { + major: 3, + minor: 2, + patch: 1, + dependency: 0, + 3: 'major', + 2: 'minor', + 1: 'patch', + 0: 'dependency' +}; + +let _shouldCommit = process.argv.indexOf('--commit') >= 0; + +/* Find all changes and return parsed change definitions. */ +function findChangesSync() { + let changeFiles = []; + let allChanges = {}; + let changesPath = path.join(process.cwd(), 'changes'); + + console.log(`Finding changes in: ${changesPath}`); + + try { + changeFiles = fs.readdirSync(changesPath).filter(filename => filename.indexOf('.json') >= 0); + } catch (e) { } + + // Add the minimum changes defined by the change descriptions. + changeFiles.forEach((file) => { + let fullPath = path.resolve('./changes', file); + let changeDescription = JSON.parse(fs.readFileSync(fullPath, 'utf8')); + + for (let i = 0; i < changeDescription.changes.length; i++) { + let change = changeDescription.changes[i]; + + addChange(allChanges, change); + } + }); + + let packages = Object.keys(allChanges); + let updatedDeps = {}; + + // Update orders so that downstreams are marked to come after upstreams. + for (let packageName in allChanges) { + let change = allChanges[packageName]; + let pkg = _allPackages[packageName].package; + let deps = _downstreamDeps[packageName]; + + // Write the new version expected for the change. + change.newVersion = (change.changeType > _changeTypes.dependency) ? semver.inc(pkg.version, _changeTypes[change.changeType]) : pkg.version; + + if (deps) { + for (let depName of deps) { + let depChange = allChanges[depName]; + + if (depChange) { + depChange.order = Math.max(change.order + 1, depChange.order); + } + } + } + } + + return allChanges; +} + +/** Add a change request to the allChanges dictionary if necessary. */ +function addChange(allChanges, change) { + let packageName = change.packageName; + let pkgEntry = _allPackages[packageName]; + let pkg = pkgEntry.package; + let currentChange; + + if (!allChanges[packageName]) { + currentChange = allChanges[packageName] = { + packageName, + packagePath: pkgEntry.path, + changeType: _changeTypes[change.type], + comments: change.comments || [], + order: 0, + changes: [change] + }; + } else { + currentChange = allChanges[packageName]; + currentChange.changeType = Math.max(currentChange.changeType, _changeTypes[change.type]); + currentChange.comments = currentChange.comments.concat(change.comments); + currentChange.changes.push(change); + } + + currentChange.newVersion = currentChange.changeType > 0 ? semver.inc(pkg.version, _changeTypes[currentChange.changeType]) : pkg.version; + currentChange.newVersionRange = `>=${currentChange.newVersion} <${semver.inc(currentChange.newVersion, 'major')}`; + + updateDownstreamDependencies(allChanges, packageName, currentChange.newVersionRange); +} + +/** Build a downstream dependencies lookup table. */ +function getDownstreamDependencies() { + let downstreamDeps = {}; + + forEachPackage('.', (pkg, location) => { + for (let depName in pkg.dependencies) { + if (!downstreamDeps[depName]) { + downstreamDeps[depName] = []; + } + downstreamDeps[depName].push(pkg.name); + } + }); + + return downstreamDeps; +} + +function updateDownstreamDependencies(allChanges, packageName, newVersionRange) { + let change = allChanges[packageName]; + let downstreamNames = _downstreamDeps[packageName]; + + // Iterate through all downstream dependencies for the package. + if (downstreamNames) { + for (let depName of downstreamNames) { + let pkgEntry = _allPackages[depName]; + let pkg = pkgEntry.package; + let requiredVersion = pkgEntry.package.dependencies[packageName]; + + // If the version range has not yet been updated to this version, update it. + if (requiredVersion !== newVersionRange) { + pkgEntry.package.dependencies[packageName] = newVersionRange; + + // Either it already satisfies the new version, or doesn't. If not, the downstream dep needs to be republished. + let changeType = semver.satisfies(change.newVersion, requiredVersion) ? _changeTypes.dependency : _changeTypes.patch; + + addChange(allChanges, { + packageName: pkg.name, + type: _changeTypes[changeType], + comments: [`Updating ${packageName}: ${newVersionRange} (was ${ requiredVersion })`] + }); + } + } + } +} + +/** Update the package.json for a given change. */ +function updatePackage(change, allChanges) { + console.log(os.EOL + `* Applying ${_changeTypes[change.changeType]} update for ${change.packageName} to ${change.newVersion}`); + + let pkg = _allPackages[change.packageName].package; + + pkg.version = change.newVersion; + + change.changes.forEach(subChange => subChange.comments.forEach(comment => console.log( ` - [${subChange.type}] ${comment}`))); + + if (_shouldCommit) { + fs.writeFileSync(change.packagePath, JSON.stringify(pkg, null, 2), 'utf8'); + } +} + +function execCommand(commandLine, workingPath, isDisabled) { + workingPath = workingPath || process.cwd(); + + console.log(`Executing: "${commandLine}" from ${workingPath}`); + + if (_shouldCommit && !isDisabled) { + execSync(commandLine, { + cwd: workingPath + }); + } +} + +function gitAddChanges() { + execCommand('git add .'); +} + +function gitAddTags(allChanges) { + for (let packageName in allChanges) { + let change = allChanges[packageName]; + + if (change.changeType > _changeTypes.dependency) { + let tagName = packageName + '_v' + change.newVersion; + + execCommand(`git tag ${tagName}`); + } + } +} + +function gitCommit() { + execCommand('git commit -m "Applying package updates."'); +} + +function gitPush() { + execCommand('git push --follow-tags'); +} + +function publishPackage(change) { + execCommand(`npm publish`, change.packagePath); +} + +function deleteChangeFiles() { + let changesPath = path.join(process.cwd(), 'changes'); + let changeFiles = []; + + try { + changeFiles = fs.readdirSync(changesPath).filter(filename => filename.indexOf('.json') >= 0); + } catch (e) { } + + if (changeFiles.length) { + console.log(os.EOL + `Deleting ${changeFiles.length} change file(s).`); + + for (let fileName of changeFiles) { + let filePath = path.join(changesPath, fileName); + + console.log(` - ${filePath}`); + + if (_shouldCommit) { + deleteFile(filePath); + } + } + } +} + +/** Apply set of changes. */ +function applyChanges(allChanges) { + let orderedChanges = ( + Object + .keys(allChanges) + .map(key => allChanges[key]) + .sort((a, b) => a.order < b.order ? -1 : 1)); + + if (orderedChanges.length > 1) { + for (let change of orderedChanges) { + updatePackage(change, allChanges); + } + + deleteChangeFiles(); + gitAddChanges(allChanges); + gitCommit(); + gitAddTags(allChanges); + gitPush(); + + for (let change of orderedChanges) { + if (change.changeType > _changeTypes.dependency) { + publishPackage(change); + } + } + } +} + + +let changes = findChangesSync(); + +applyChanges(changes); \ No newline at end of file diff --git a/scripts/utils.js b/scripts/utils.js new file mode 100644 index 00000000000..aaa3216fb91 --- /dev/null +++ b/scripts/utils.js @@ -0,0 +1,50 @@ +'use strict'; + +let fs = require('fs'); +let rimraf = require('rimraf'); + +function fileExists(path) { + let exists = false; + try { + let lstat = fs.lstatSync(path); + exists = lstat.isFile(); + } catch (e) { } + + return exists; +} + +function directoryExists(path) { + let exists = false; + try { + let lstat = fs.lstatSync(path); + exists = lstat.isDirectory(); + } catch (e) { } + + return exists; +} + +function deleteFile(filePath) { + if (fileExists(filePath)) { + console.log(`Deleting: ${filePath}`); + fs.unlinkSync(filePath); + } + return Promise.resolve(); +} + +function deleteDirectory(directoryPath) { + return new Promise(done => { + if (directoryExists(directoryPath)) { + console.log(`Deleting: ${directoryPath}`); + rimraf(directoryPath, done); + } else { + done(); + } + }); +} + +module.exports = { + fileExists, + directoryExists, + deleteFile, + deleteDirectory +};