diff --git a/addon/ng2/blueprints/ng2/files/angular-cli.json b/addon/ng2/blueprints/ng2/files/angular-cli.json index 5b96ba0ba88c..518f71e2de1e 100644 --- a/addon/ng2/blueprints/ng2/files/angular-cli.json +++ b/addon/ng2/blueprints/ng2/files/angular-cli.json @@ -27,6 +27,7 @@ "sourceDir": "<%= sourceDir %>", "styleExt": "<%= styleExt %>", "prefixInterfaces": false, - "lazyRoutePrefix": "+" + "lazyRoutePrefix": "+", + "outputPath": "<%= outputPath %>" } } diff --git a/addon/ng2/blueprints/ng2/index.js b/addon/ng2/blueprints/ng2/index.js index 827a95b443e0..eb9e868e452a 100644 --- a/addon/ng2/blueprints/ng2/index.js +++ b/addon/ng2/blueprints/ng2/index.js @@ -51,7 +51,8 @@ module.exports = { styleExt: this.styleExt, refToTypings: refToTypings, isMobile: options.mobile, - stylePackage: stylePackage + stylePackage: stylePackage, + outputPath: options.outputPath }; }, diff --git a/addon/ng2/commands/build.ts b/addon/ng2/commands/build.ts new file mode 100644 index 000000000000..c5ba83e709ff --- /dev/null +++ b/addon/ng2/commands/build.ts @@ -0,0 +1,12 @@ +import * as CommandHelper from '../utilities/command-helper'; +import * as BuildCommand from 'ember-cli/lib/commands/build'; + +module.exports = BuildCommand.extend({ + + beforeRun: function() { + CommandHelper.loadDefaults(this); + }, + +}); + +module.exports.overrideCore = true; diff --git a/addon/ng2/commands/github-pages-deploy.ts b/addon/ng2/commands/github-pages-deploy.ts index 8ac1478c1e6f..47bee3168862 100644 --- a/addon/ng2/commands/github-pages-deploy.ts +++ b/addon/ng2/commands/github-pages-deploy.ts @@ -9,6 +9,7 @@ import * as path from 'path'; import * as BuildTask from 'ember-cli/lib/tasks/build'; import * as win from 'ember-cli/lib/utilities/windows-admin'; import * as CreateGithubRepo from '../tasks/create-github-repo'; +import * as CommandHelper from '../utilities/command-helper'; const fsReadFile = Promise.denodeify(fs.readFile); const fsWriteFile = Promise.denodeify(fs.writeFile); @@ -54,6 +55,10 @@ module.exports = Command.extend({ description: 'Github username' }], + beforeRun: function() { + CommandHelper.loadDefaults(this); + }, + run: function(options, rawArgs) { var ui = this.ui; var root = this.project.root; @@ -77,7 +82,7 @@ module.exports = Command.extend({ var buildOptions = { environment: options.environment, - outputPath: 'dist/' + outputPath: options.outputPath }; var createGithubRepoTask = new CreateGithubRepo({ @@ -97,7 +102,7 @@ module.exports = Command.extend({ .then(saveStartingBranchName) .then(createGitHubRepoIfNeeded) .then(checkoutGhPages) - .then(copyFiles) + .then(() => copyFiles(options.outputPath)) .then(updateBaseHref) .then(addAndCommit) .then(returnStartingBranch) @@ -156,14 +161,14 @@ module.exports = Command.extend({ .then(() => execPromise(`git commit -m \"initial ${ghPagesBranch} commit\"`)); } - function copyFiles() { - return fsReadDir('dist') + function copyFiles(outputPath) { + return fsReadDir(outputPath) .then((files) => Promise.all(files.map((file) => { if (file === '.gitignore'){ // don't overwrite the .gitignore file return Promise.resolve(); } - return fsCopy(path.join('dist', file), path.join('.', file)) + return fsCopy(path.join(outputPath, file), path.join('.', file)) }))); } diff --git a/addon/ng2/commands/init.js b/addon/ng2/commands/init.js index f77a1c2852b7..116d57536af7 100644 --- a/addon/ng2/commands/init.js +++ b/addon/ng2/commands/init.js @@ -25,7 +25,8 @@ module.exports = Command.extend({ { name: 'source-dir', type: String, default: 'src', aliases: ['sd'] }, { name: 'style', type: String, default: 'css' }, { name: 'prefix', type: String, default: 'app', aliases: ['p'] }, - { name: 'mobile', type: Boolean, default: false } + { name: 'mobile', type: Boolean, default: false }, + { name: 'output-path', type: String, default: 'dist/', aliases: ['o'] } ], anonymousOptions: [''], @@ -93,7 +94,7 @@ module.exports = Command.extend({ return Promise.reject(new SilentError(message)); } - + var blueprintOpts = { dryRun: commandOptions.dryRun, blueprint: commandOptions.blueprint || this._defaultBlueprint(), @@ -103,7 +104,8 @@ module.exports = Command.extend({ sourceDir: commandOptions.sourceDir, style: commandOptions.style, prefix: commandOptions.prefix, - mobile: commandOptions.mobile + mobile: commandOptions.mobile, + outputPath: commandOptions.outputPath }; if (!validProjectName(packageName)) { diff --git a/addon/ng2/commands/new.ts b/addon/ng2/commands/new.ts index 685e4e3e1124..bd95cd329e1d 100644 --- a/addon/ng2/commands/new.ts +++ b/addon/ng2/commands/new.ts @@ -25,6 +25,7 @@ const NewCommand = Command.extend({ { name: 'style', type: String, default: 'css' }, { name: 'prefix', type: String, default: 'app', aliases: ['p'] }, { name: 'mobile', type: Boolean, default: false } + { name: 'output-path', type: String, default: 'dist/', aliases: ['o'] }, ], run: function (commandOptions, rawArgs) { diff --git a/addon/ng2/commands/serve.ts b/addon/ng2/commands/serve.ts new file mode 100644 index 000000000000..ac575eb1fb56 --- /dev/null +++ b/addon/ng2/commands/serve.ts @@ -0,0 +1,12 @@ +import * as CommandHelper from '../utilities/command-helper'; +import * as ServeCommand from 'ember-cli/lib/commands/serve'; + +module.exports = ServeCommand.extend({ + + beforeRun: function() { + CommandHelper.loadDefaults(this); + }, + +}); + +module.exports.overrideCore = true; diff --git a/addon/ng2/commands/test.js b/addon/ng2/commands/test.js index a171d0399722..bbe84fe2ac96 100644 --- a/addon/ng2/commands/test.js +++ b/addon/ng2/commands/test.js @@ -7,7 +7,7 @@ var BuildTask = require('ember-cli/lib/tasks/build'); var BuildWatchTask = require('ember-cli/lib/tasks/build-watch'); const config = require('../models/config'); var TestTask = require('../tasks/test'); - +var CommandHelper = require('../utilities/command-helper'); module.exports = TestCommand.extend({ availableOptions: [ @@ -20,6 +20,10 @@ module.exports = TestCommand.extend({ { name: 'build', type: Boolean, default: true } ], + beforeRun: function() { + CommandHelper.loadDefaults(this); + }, + run: function (commandOptions) { this.project.ngConfig = this.project.ngConfig || config.CliConfig.fromProject(); @@ -42,9 +46,9 @@ module.exports = TestCommand.extend({ var buildOptions = { environment: 'development', - outputPath: 'dist/' + outputPath: commandOptions.outputPath }; - + // If not building, mock/suppress build tasks. if (!commandOptions.build) { buildTask = { @@ -54,7 +58,7 @@ module.exports = TestCommand.extend({ }; buildWatchTask = buildTask; } - + if (commandOptions.watch) { return win.checkWindowsElevation(this.ui) .then( diff --git a/addon/ng2/index.js b/addon/ng2/index.js index cb5a3b548acc..fa70606a30a3 100644 --- a/addon/ng2/index.js +++ b/addon/ng2/index.js @@ -22,6 +22,8 @@ module.exports = { 'completion': require('./commands/completion'), 'doc': require('./commands/doc'), 'github-pages-deploy': require('./commands/github-pages-deploy'), + 'build': require('./commands/build'), + 'serve': require('./commands/serve'), // Easter eggs. 'make-this-awesome': require('./commands/easter-egg')('make-this-awesome'), diff --git a/addon/ng2/utilities/command-helper.ts b/addon/ng2/utilities/command-helper.ts new file mode 100644 index 000000000000..da03167de2a3 --- /dev/null +++ b/addon/ng2/utilities/command-helper.ts @@ -0,0 +1,23 @@ +import * as config from '../models/config'; + +export function loadDefaults(command) { + command.project.ngConfig = command.project.ngConfig || config.CliConfig.fromProject(); + + let defaultSettings = command.project.ngConfig.defaults || {}; + + // output path should always have a default value + // some commands use it but its not an available flag + let outputPathKey = 'outputPath'; + if (!command.settings[outputPathKey]) { + command.settings[outputPathKey] = defaultSettings[outputPathKey] || 'dist/'; + } + + let commandOptions = command.availableOptions.map(option => option.key); + + commandOptions.forEach(key => { + // only load defaults that are relevant to the command + if (defaultSettings[key]) { + command.settings[key] = defaultSettings[key]; + } + }); +} diff --git a/addon/ng2/utilities/completion.sh b/addon/ng2/utilities/completion.sh index ebb5227cd06b..457839bebea7 100644 --- a/addon/ng2/utilities/completion.sh +++ b/addon/ng2/utilities/completion.sh @@ -1,4 +1,4 @@ -###-begin-ng-completion### +###-begin-ng-completion### # # ng command completion script # @@ -6,8 +6,8 @@ # ng_opts='new init build serve generate autocomplete e2e lint test version' -init_opts='--dry-run --verbose --blueprint --skip-npm --skip-bower --name' -new_opts='--dry-run --verbose --blueprint --skip-npm --skip-bower --skip-git --directory' +init_opts='--dry-run --verbose --blueprint --skip-npm --skip-bower --name --output-path' +new_opts='--dry-run --verbose --blueprint --skip-npm --skip-bower --skip-git --directory --output-path' build_opts='--environment --output-path --watch --watcher' serve_opts='--port --host --proxy --insecure-proxy --watcher --live-reload --live-reload-host --live-reload-port --environment --output-path --ssl --ssl-key --ssl-cert' @@ -53,7 +53,7 @@ elif type compctl &>/dev/null; then g|generate) opts=$generate_opts ;; test) opts=$test_opts ;; esac - + setopt shwordsplit reply=($opts) unset shwordsplit diff --git a/lib/config/schema.json b/lib/config/schema.json index d8598052dd14..c924bc0de5dc 100644 --- a/lib/config/schema.json +++ b/lib/config/schema.json @@ -95,6 +95,9 @@ }, "lazyRoutePrefix": { "type": "string" + }, + "outputPath": { + "type": "string" } }, "additionalProperties": false diff --git a/tests/acceptance/init.spec.js b/tests/acceptance/init.spec.js index f6d7f07f4801..5a8d749ceac0 100644 --- a/tests/acceptance/init.spec.js +++ b/tests/acceptance/init.spec.js @@ -17,6 +17,7 @@ var unique = require('lodash/uniq'); var forEach = require('lodash/forEach'); var any = require('lodash/some'); var EOL = require('os').EOL; +var fs = require('fs'); var defaultIgnoredFiles = Blueprint.ignoredFiles; @@ -59,7 +60,7 @@ describe('Acceptance: ng init', function () { expected[index] = expected[index].replace(/__styleext__/g, 'css'); expected[index] = expected[index].replace(/__path__/g, 'src'); }); - + if (isMobile) { expected = expected.filter(p => p.indexOf('tmp.component.html') < 0); expected = expected.filter(p => p.indexOf('tmp.component.css') < 0); @@ -108,7 +109,10 @@ describe('Acceptance: ng init', function () { 'init', '--skip-npm', '--skip-bower' - ]).then(confirmBlueprinted); + ]).then(confirmBlueprinted).then(() => { + const settings = fs.readFileSync(path.join(process.cwd(), 'angular-cli.json'), 'utf-8'); + expect(settings).to.include('"outputPath": "dist/"'); + }); }); it('ng init --mobile', () => { @@ -200,4 +204,19 @@ describe('Acceptance: ng init', function () { }) .then(confirmBlueprinted); }); + + it('ng init --output-path not-dist/', function () { + var customOutputPath = 'not-dist/' + return ng([ + 'init', + '--skip-npm', + '--skip-bower', + '--output-path', + customOutputPath + ]).then(confirmBlueprinted) + .then(() => { + const settings = fs.readFileSync(path.join(process.cwd(), 'angular-cli.json'), 'utf-8'); + expect(settings).to.include('"outputPath": "'+customOutputPath+'"'); + }); + }); }); diff --git a/tests/e2e/e2e_workflow.spec.js b/tests/e2e/e2e_workflow.spec.js index 3c90073b84fe..2b12840cebc2 100644 --- a/tests/e2e/e2e_workflow.spec.js +++ b/tests/e2e/e2e_workflow.spec.js @@ -282,6 +282,60 @@ describe('Basic end-to-end Workflow', function () { }); }); + it('Can set the default output path', function () { + this.timeout(10000); + + const customOutputPath = 'not-dist/'; + + var setArgs = [ + 'set', + 'defaults.outputPath', + customOutputPath + ]; + + return ng(setArgs).then(() => { + const settings = fs.readFileSync(path.join(process.cwd(), 'angular-cli.json'), 'utf-8'); + expect(settings).to.include('"outputPath": "'+customOutputPath+'"'); + }) + .catch(err => { + throw new Error(err) + }); + }); + + it('`ng test` will build files in outputPath when default is set', function () { + this.timeout(420000); + + const tmpFileLocation = path.join(process.cwd(), 'not-dist/', 'test.abc'); + + return ng(testArgs).then(result => { + const exitCode = typeof result === 'object' ? result.exitCode : result; + expect(exitCode).to.be.equal(0); + }).then(() => { + expect(existsSync(tmpFileLocation)).to.be.equal(true); + }) + .catch(err => { + throw new Error(err) + }) + }); + + it('Can remove the default output path', function () { + this.timeout(10000); + + var setArgs = [ + 'set', + 'defaults.outputPath', + '--remove' + ]; + + return ng(setArgs).then(() => { + const settings = fs.readFileSync(path.join(process.cwd(), 'angular-cli.json'), 'utf-8'); + expect(settings).to.not.include('"outputPath":'); + }) + .catch(err => { + throw new Error(err) + }); + }); + it.skip('Installs sass support successfully', function() { this.timeout(420000);