mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-14 09:37:18 +08:00
394 lines
13 KiB
TypeScript
394 lines
13 KiB
TypeScript
import { readFile, writeFile, replaceInFile } from './fs';
|
|
import { execAndWaitForOutputToMatch, npm, silentNpm, ng } from './process';
|
|
import { getGlobalVariable } from './env';
|
|
|
|
const packages = require('../../../../lib/packages').packages;
|
|
|
|
|
|
const tsConfigPath = 'tsconfig.json';
|
|
|
|
|
|
export function updateJsonFile(filePath: string, fn: (json: any) => any | void) {
|
|
return readFile(filePath)
|
|
.then(tsConfigJson => {
|
|
const tsConfig = JSON.parse(tsConfigJson);
|
|
const result = fn(tsConfig) || tsConfig;
|
|
|
|
return writeFile(filePath, JSON.stringify(result, null, 2));
|
|
});
|
|
}
|
|
|
|
|
|
export function updateTsConfig(fn: (json: any) => any | void) {
|
|
return updateJsonFile(tsConfigPath, fn);
|
|
}
|
|
|
|
|
|
export function ngServe(...args: string[]) {
|
|
return execAndWaitForOutputToMatch('ng',
|
|
['serve', ...args],
|
|
/: Compiled successfully./);
|
|
}
|
|
|
|
|
|
export function createProject(name: string, ...args: string[]) {
|
|
const argv: any = getGlobalVariable('argv');
|
|
|
|
return Promise.resolve()
|
|
.then(() => process.chdir(getGlobalVariable('tmp-root')))
|
|
.then(() => ng('new', name, '--skip-install', ...args))
|
|
.then(() => process.chdir(name))
|
|
.then(() => useBuiltPackages())
|
|
.then(() => useCIChrome('e2e'))
|
|
.then(() => useCIChrome('src'))
|
|
.then(() => useDevKitSnapshots())
|
|
.then(() => argv['ng2'] ? useNg2() : Promise.resolve())
|
|
.then(() => argv['ng4'] ? useNg4() : Promise.resolve())
|
|
.then(() => argv['ng-snapshots'] || argv['ng-tag'] ? useSha() : Promise.resolve())
|
|
.then(() => console.log(`Project ${name} created... Installing npm.`))
|
|
.then(() => silentNpm('install'))
|
|
.then(() => useCIDefaults(name));
|
|
}
|
|
|
|
|
|
export function useDevKit(devkitRoot: string) {
|
|
return Promise.resolve()
|
|
.then(() => {
|
|
// Load the packages info for devkit.
|
|
const devkitPackages = require(devkitRoot + '/lib/packages').packages;
|
|
|
|
return updateJsonFile('package.json', json => {
|
|
if (!json['dependencies']) {
|
|
json['dependencies'] = {};
|
|
}
|
|
if (!json['devDependencies']) {
|
|
json['devDependencies'] = {};
|
|
}
|
|
|
|
for (const packageName of Object.keys(devkitPackages)) {
|
|
if (json['dependencies'].hasOwnProperty(packageName)) {
|
|
json['dependencies'][packageName] = devkitPackages[packageName].tar;
|
|
} else if (json['devDependencies'].hasOwnProperty(packageName)) {
|
|
json['devDependencies'][packageName] = devkitPackages[packageName].tar;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
export function useDevKitSnapshots() {
|
|
return updateJsonFile('package.json', json => {
|
|
// TODO: actually add these.
|
|
// These were not working on any test that ran `npm i`.
|
|
// json['devDependencies']['@angular-devkit/build-angular'] =
|
|
// 'github:angular/angular-devkit-build-angular-builds';
|
|
// // By adding build-ng-packagr preemptively, adding a lib will not update it.
|
|
// json['devDependencies']['@angular-devkit/build-ng-packagr'] =
|
|
// 'github:angular/angular-devkit-build-ng-packagr-builds';
|
|
});
|
|
}
|
|
|
|
export function useBuiltPackages() {
|
|
return Promise.resolve()
|
|
.then(() => updateJsonFile('package.json', json => {
|
|
if (!json['dependencies']) {
|
|
json['dependencies'] = {};
|
|
}
|
|
if (!json['devDependencies']) {
|
|
json['devDependencies'] = {};
|
|
}
|
|
|
|
for (const packageName of Object.keys(packages)) {
|
|
if (json['dependencies'].hasOwnProperty(packageName)) {
|
|
json['dependencies'][packageName] = packages[packageName].tar;
|
|
} else if (json['devDependencies'].hasOwnProperty(packageName)) {
|
|
json['devDependencies'][packageName] = packages[packageName].tar;
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
export function useSha() {
|
|
const argv = getGlobalVariable('argv');
|
|
if (argv['ng-snapshots'] || argv['ng-tag']) {
|
|
// We need more than the sha here, version is also needed. Examples of latest tags:
|
|
// 7.0.0-beta.4+dd2a650
|
|
// 6.1.6+4a8d56a
|
|
const label = argv['ng-tag'] ? argv['ng-tag'] : '';
|
|
return updateJsonFile('package.json', json => {
|
|
// Install over the project with snapshot builds.
|
|
Object.keys(json['dependencies'] || {})
|
|
.filter(name => name.match(/^@angular\//))
|
|
.forEach(name => {
|
|
const pkgName = name.split(/\//)[1];
|
|
if (pkgName == 'cli') {
|
|
return;
|
|
}
|
|
json['dependencies'][`@angular/${pkgName}`]
|
|
= `github:angular/${pkgName}-builds${label}`;
|
|
});
|
|
|
|
Object.keys(json['devDependencies'] || {})
|
|
.filter(name => name.match(/^@angular\//))
|
|
.forEach(name => {
|
|
const pkgName = name.split(/\//)[1];
|
|
if (pkgName == 'cli') {
|
|
return;
|
|
}
|
|
json['devDependencies'][`@angular/${pkgName}`]
|
|
= `github:angular/${pkgName}-builds${label}`;
|
|
});
|
|
|
|
json['devDependencies']['typescript'] = '~3.0.1';
|
|
});
|
|
} else {
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
|
|
export function useNgVersion(version: string) {
|
|
return updateJsonFile('package.json', json => {
|
|
// Install over the project with specific versions.
|
|
Object.keys(json['dependencies'] || {})
|
|
.filter(name => name.match(/^@angular\//))
|
|
.forEach(name => {
|
|
const pkgName = name.split(/\//)[1];
|
|
if (pkgName == 'cli') {
|
|
return;
|
|
}
|
|
json['dependencies'][`@angular/${pkgName}`] = version;
|
|
});
|
|
|
|
Object.keys(json['devDependencies'] || {})
|
|
.filter(name => name.match(/^@angular\//))
|
|
.forEach(name => {
|
|
const pkgName = name.split(/\//)[1];
|
|
if (pkgName == 'cli') {
|
|
return;
|
|
}
|
|
json['devDependencies'][`@angular/${pkgName}`] = version;
|
|
});
|
|
// TODO: determine the appropriate version for the Angular version
|
|
if (version.startsWith('^5')) {
|
|
json['devDependencies']['typescript'] = '~2.5.0';
|
|
json['dependencies']['rxjs'] = '5.5.8';
|
|
} else {
|
|
json['devDependencies']['typescript'] = '~2.7.0';
|
|
json['dependencies']['rxjs'] = '6.0.0-rc.0';
|
|
}
|
|
});
|
|
}
|
|
|
|
export function useCIDefaults(projectName = 'test-project') {
|
|
return updateJsonFile('angular.json', workspaceJson => {
|
|
// Disable progress reporting on CI to reduce spam.
|
|
const appTargets = workspaceJson.projects[projectName].targets;
|
|
appTargets.build.options.progress = false;
|
|
appTargets.test.options.progress = false;
|
|
// Disable auto-updating webdriver in e2e.
|
|
const e2eTargets = workspaceJson.projects[projectName + '-e2e'].targets;
|
|
e2eTargets.e2e.options.webdriverUpdate = false;
|
|
})
|
|
.then(() => updateJsonFile('package.json', json => {
|
|
// We want to always use the same version of webdriver but can only do so on CircleCI.
|
|
// Appveyor and Travis will use latest Chrome stable.
|
|
// CircleCI (via ngcontainer:0.1.1) uses Chrome 63.0.3239.84.
|
|
// Appveyor (via chocolatey) cannot use older versions of Chrome at all:
|
|
// https://github.com/chocolatey/chocolatey-coreteampackages/tree/master/automatic/googlechrome
|
|
// webdriver 2.33 matches Chrome 63.0.3239.84.
|
|
// webdriver 2.37 matches Chrome 65.0.3325.18100 (latest stable).
|
|
// The webdriver versions for latest stable will need to be manually updated.
|
|
const webdriverVersion = process.env['CIRCLECI'] ? '2.33' : '2.37';
|
|
const driverOption = process.env['CHROMEDRIVER_VERSION_ARG']
|
|
|| `--versions.chrome ${webdriverVersion}`;
|
|
json['scripts']['webdriver-update'] = 'webdriver-manager update' +
|
|
` --standalone false --gecko false ${driverOption}`;
|
|
}))
|
|
.then(() => npm('run', 'webdriver-update'));
|
|
}
|
|
|
|
export function useCIChrome(projectDir: string) {
|
|
// There's a race condition happening in Chrome. Enabling logging in chrome used by
|
|
// protractor actually fixes it. Logging is piped to a file so it doesn't affect our setup.
|
|
// --no-sandbox is needed for Circle CI.
|
|
// Travis can use headless chrome, but not appveyor.
|
|
return Promise.resolve()
|
|
.then(() => replaceInFile(`${projectDir}/protractor.conf.js`,
|
|
`'browserName': 'chrome'`,
|
|
`'browserName': 'chrome',
|
|
chromeOptions: {
|
|
args: [
|
|
"--enable-logging",
|
|
// "--no-sandbox",
|
|
// "--headless"
|
|
]
|
|
}
|
|
`))
|
|
// Not a problem if the file can't be found.
|
|
// .catch(() => null)
|
|
// .then(() => replaceInFile(`${projectDir}/karma.conf.js`, `browsers: ['Chrome'],`,
|
|
// `browsers: ['ChromeCI'],
|
|
// customLaunchers: {
|
|
// ChromeCI: {
|
|
// base: 'ChromeHeadless',
|
|
// flags: ['--no-sandbox']
|
|
// }
|
|
// },
|
|
// `))
|
|
.catch(() => null);
|
|
}
|
|
|
|
// Convert a Angular 5 project to Angular 2.
|
|
export function useNg2() {
|
|
const ng2Deps: any = {
|
|
'dependencies': {
|
|
'@angular/common': '^2.4.0',
|
|
'@angular/compiler': '^2.4.0',
|
|
'@angular/core': '^2.4.0',
|
|
'@angular/forms': '^2.4.0',
|
|
'@angular/http': '^2.4.0',
|
|
'@angular/platform-browser': '^2.4.0',
|
|
'@angular/platform-browser-dynamic': '^2.4.0',
|
|
'@angular/router': '^3.4.0',
|
|
'zone.js': '^0.7.4'
|
|
},
|
|
'devDependencies': {
|
|
'@angular/compiler-cli': '^2.4.0',
|
|
'@types/jasmine': '~2.2.0',
|
|
'@types/jasminewd2': undefined,
|
|
'typescript': '~2.0.0'
|
|
}
|
|
};
|
|
|
|
const tsconfigAppJson: any = {
|
|
'compilerOptions': {
|
|
'sourceMap': true,
|
|
'declaration': false,
|
|
'moduleResolution': 'node',
|
|
'emitDecoratorMetadata': true,
|
|
'experimentalDecorators': true,
|
|
'target': 'es5',
|
|
'lib': [
|
|
'es2017',
|
|
'dom'
|
|
],
|
|
'outDir': '../out-tsc/app',
|
|
'module': 'es2015',
|
|
'baseUrl': '',
|
|
'types': []
|
|
},
|
|
'exclude': [
|
|
'test.ts',
|
|
'**/*.spec.ts'
|
|
]
|
|
};
|
|
|
|
const tsconfigSpecJson: any = {
|
|
'compilerOptions': {
|
|
'sourceMap': true,
|
|
'declaration': false,
|
|
'moduleResolution': 'node',
|
|
'emitDecoratorMetadata': true,
|
|
'experimentalDecorators': true,
|
|
'lib': [
|
|
'es2017',
|
|
'dom'
|
|
],
|
|
'outDir': '../out-tsc/spec',
|
|
'module': 'commonjs',
|
|
'target': 'es5',
|
|
'baseUrl': '',
|
|
'types': [
|
|
'jasmine',
|
|
'node'
|
|
]
|
|
},
|
|
'files': [
|
|
'test.ts'
|
|
],
|
|
'include': [
|
|
'**/*.spec.ts',
|
|
'**/*.d.ts'
|
|
]
|
|
};
|
|
|
|
const tsconfigE2eJson: any = {
|
|
'compilerOptions': {
|
|
'sourceMap': true,
|
|
'declaration': false,
|
|
'moduleResolution': 'node',
|
|
'emitDecoratorMetadata': true,
|
|
'experimentalDecorators': true,
|
|
'lib': [
|
|
'es2017'
|
|
],
|
|
'outDir': '../out-tsc/e2e',
|
|
'module': 'commonjs',
|
|
'target': 'es5',
|
|
'types': [
|
|
'jasmine',
|
|
'node'
|
|
]
|
|
}
|
|
};
|
|
|
|
|
|
return Promise.resolve()
|
|
.then(() => updateJsonFile('package.json', json => {
|
|
Object.keys(ng2Deps['dependencies']).forEach(pkgName => {
|
|
json['dependencies'][pkgName] = ng2Deps['dependencies'][pkgName];
|
|
});
|
|
Object.keys(ng2Deps['devDependencies']).forEach(pkgName => {
|
|
json['devDependencies'][pkgName] = ng2Deps['devDependencies'][pkgName];
|
|
});
|
|
console.log(JSON.stringify(json));
|
|
}))
|
|
.then(() => updateJsonFile('src/tsconfig.app.json', json =>
|
|
Object.assign(json, tsconfigAppJson)))
|
|
.then(() => updateJsonFile('src/tsconfig.spec.json', json =>
|
|
Object.assign(json, tsconfigSpecJson)))
|
|
.then(() => updateJsonFile('e2e/tsconfig.e2e.json', json =>
|
|
Object.assign(json, tsconfigE2eJson)))
|
|
.then(() => replaceInFile('src/test.ts', 'import \'zone.js/dist/zone-testing\';', `
|
|
import 'zone.js/dist/long-stack-trace-zone';
|
|
import 'zone.js/dist/proxy.js';
|
|
import 'zone.js/dist/sync-test';
|
|
import 'zone.js/dist/jasmine-patch';
|
|
import 'zone.js/dist/async-test';
|
|
import 'zone.js/dist/fake-async-test';
|
|
`));
|
|
}
|
|
|
|
// Convert a Angular 5 project to Angular 4.
|
|
export function useNg4() {
|
|
const ng4Deps: any = {
|
|
'dependencies': {
|
|
'@angular/common': '^4.4.6',
|
|
'@angular/compiler': '^4.4.6',
|
|
'@angular/core': '^4.4.6',
|
|
'@angular/forms': '^4.4.6',
|
|
'@angular/http': '^4.4.6',
|
|
'@angular/platform-browser': '^4.4.6',
|
|
'@angular/platform-browser-dynamic': '^4.4.6',
|
|
'@angular/router': '^4.4.6',
|
|
'zone.js': '^0.8.14'
|
|
},
|
|
'devDependencies': {
|
|
'@angular/compiler-cli': '^4.4.6',
|
|
'typescript': '~2.3.3'
|
|
}
|
|
};
|
|
|
|
|
|
return Promise.resolve()
|
|
.then(() => updateJsonFile('package.json', json => {
|
|
Object.keys(ng4Deps['dependencies']).forEach(pkgName => {
|
|
json['dependencies'][pkgName] = ng4Deps['dependencies'][pkgName];
|
|
});
|
|
Object.keys(ng4Deps['devDependencies']).forEach(pkgName => {
|
|
json['devDependencies'][pkgName] = ng4Deps['devDependencies'][pkgName];
|
|
});
|
|
console.log(JSON.stringify(json));
|
|
}));
|
|
}
|