diff --git a/package.json b/package.json index f1f0ceecd407..01b6eec8f688 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@types/hammerjs": "^2.0.30", "@types/jasmine": "^2.2.31", "@types/merge2": "0.0.28", + "@types/minimist": "^1.1.28", "@types/node": "^6.0.34", "@types/run-sequence": "0.0.27", "browserstacktunnel-wrapper": "^1.4.2", @@ -68,6 +69,7 @@ "karma-sauce-launcher": "^1.0.0", "madge": "^0.6.0", "merge2": "^1.0.2", + "minimist": "^1.2.0", "node-sass": "^3.4.2", "protractor": "^3.3.0", "protractor-accessibility-plugin": "0.1.1", diff --git a/tools/gulp/tasks/release.ts b/tools/gulp/tasks/release.ts index f9a92d6727b2..95a1fd4724bc 100644 --- a/tools/gulp/tasks/release.ts +++ b/tools/gulp/tasks/release.ts @@ -1,12 +1,15 @@ -import {execSync} from 'child_process'; -import {readdirSync, statSync} from 'fs'; +import {spawn} from 'child_process'; +import {existsSync, readdirSync, statSync} from 'fs'; import {task} from 'gulp'; import gulpRunSequence = require('run-sequence'); import path = require('path'); +import minimist = require('minimist'); import {execTask} from '../task_helpers'; import {DIST_COMPONENTS_ROOT} from '../constants'; +const argv = minimist(process.argv.slice(3)); + task('build:release', function(done: () => void) { // Synchronously run those tasks. @@ -27,24 +30,64 @@ task(':publish:whoami', execTask('npm', ['whoami'], { task(':publish:logout', execTask('npm', ['logout'])); -task(':publish', function() { - const label = process.argv.slice(2)[1]; // [0] would be ':publish' - const labelArg = label ? `--tag ${label}` : ''; - const currentDir = process.cwd(); - readdirSync(DIST_COMPONENTS_ROOT) - .forEach(dirName => { - const componentPath = path.join(DIST_COMPONENTS_ROOT, dirName); - const stat = statSync(componentPath); +function _execNpmPublish(componentName: string, label: string): Promise { + const componentPath = path.join(DIST_COMPONENTS_ROOT, componentName); + const stat = statSync(componentPath); - if (!stat.isDirectory()) { - return; - } + if (!stat.isDirectory()) { + return; + } + + if (!existsSync(path.join(componentPath, 'package.json'))) { + console.log(`Skipping ${componentPath} as it does not have a package.json.`); + return; + } + + process.chdir(componentPath); + console.log(`Publishing ${componentName}...`); + + const command = 'npm'; + const args = ['publish', '--access', 'public', label ? `--tag` : undefined, label || undefined]; + return new Promise((resolve, reject) => { + console.log(`Executing "${command} ${args.join(' ')}"...`); + + const childProcess = spawn(command, args); + childProcess.stdout.on('data', (data: Buffer) => { + console.log(`stdout: ${data.toString().split(/[\n\r]/g).join('\n ')}`); + }); + childProcess.stderr.on('data', (data: Buffer) => { + console.error(`stderr: ${data.toString().split(/[\n\r]/g).join('\n ')}`); + }); - process.chdir(componentPath); - execSync(`npm publish --access public ${labelArg}`); + childProcess.on('close', (code: number) => { + if (code == 0) { + resolve(); + } else { + reject(new Error(`Component ${componentName} did not publish, status: ${code}.`)); + } }); - process.chdir(currentDir); + }); +} + +task(':publish', function(done: (err?: any) => void) { + const label = argv['tag']; + const currentDir = process.cwd(); + + if (!label) { + console.log('You can use a label with --tag=labelName.'); + console.log('Publishing using the latest tag.'); + } else { + console.log(`Publishing using the ${label} tag.`); + } + console.log('\n\n'); + + // Build a promise chain that publish each component. + readdirSync(DIST_COMPONENTS_ROOT) + .reduce((prev, dirName) => prev.then(() => _execNpmPublish(dirName, label)), Promise.resolve()) + .then(() => done()) + .catch((err: Error) => done(err)) + .then(() => process.chdir(currentDir)); }); task('publish', function(done: () => void) {