build(docs-infra): use local version of Zone.js when testing against local packages (#35858)

In some cases, we want to test the AIO app or docs examples against the
locally built Angular packages (for example to ensure that the changes
in a commit do not introduce a breaking change). In order to achieve
this, we have the `ng-packages-installer` script that handles updating
a project's `package.json` file to use the locally built Angular
packages (and appropriate versions for their (dev-/peer-)dependencies).

Previously, `ng-packages-installer` would only consider the locally
built Angular packages (from `dist/packages-dist/`). However, given that
Zone.js is now part of the `angular/angular` repo, it makes sense to
also use the locally built Zone.js package (from `dist/zone.js-dist/`).
Otherwise, the tests might fail for commits that update both the Angular
packages (and related docs examples) and the Zone.js package. An example
of such a simultaneous change (that would have broken tests) is #33838.

This commit updates the script to install the locally built Zone.js
package (in addition to the Angular ones). The commit ensures that the
Zone.js package will always be available alongside the Angular packages
(i.e. that the Zone.js package will be built by the same script that
builds the Angular packages and that the `dist/zone.js-dist/` directory
will be cached on CI).

Note: This problem was discovered while enabling docs examples unit
tests in #34374.

PR Close #35858
This commit is contained in:
George Kalpakas 2020-02-29 21:05:23 +02:00 committed by Matias Niemelä
parent 86a45ff561
commit 82a6fc5ef9
7 changed files with 144 additions and 80 deletions

View File

@ -465,12 +465,14 @@ jobs:
- when: - when:
condition: << parameters.ivy >> condition: << parameters.ivy >>
steps: steps:
# Rename the Ivy packages dist folder to "dist/packages-dist" as the AIO # Rename the "dist/*-dist-ivy-aot" packages directories (persisted to the workspace by
# package installer picks up the locally built packages from that location. # the `build-ivy-npm-packages` job) to "dist/*-dist" as the AIO package installer
# picks up the locally built packages from that location.
# *Note*: We could also adjust the packages installer, but given we won't have # *Note*: We could also adjust the packages installer, but given we won't have
# two different folders of Angular distributions in the future, we should keep # two different folders of Angular distributions in the future, we should keep
# the packages installer unchanged. # the packages installer unchanged.
- run: mv dist/packages-dist-ivy-aot dist/packages-dist - run: mv dist/packages-dist-ivy-aot dist/packages-dist
- run: mv dist/zone.js-dist-ivy-aot dist/zone.js-dist
# Run examples tests. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled. # Run examples tests. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled.
# Since the parallelism is set to "5", there will be five parallel CircleCI containers. # Since the parallelism is set to "5", there will be five parallel CircleCI containers.
# with either "0", "1", etc as node index. This can be passed to the "--shard" argument. # with either "0", "1", etc as node index. This can be passed to the "--shard" argument.
@ -552,6 +554,7 @@ jobs:
root: *workspace_location root: *workspace_location
paths: paths:
- ng/dist/packages-dist-ivy-aot - ng/dist/packages-dist-ivy-aot
- ng/dist/zone.js-dist-ivy-aot
# We run a subset of the integration tests outside of Bazel that track # We run a subset of the integration tests outside of Bazel that track
# payload size. # payload size.

View File

@ -14,11 +14,12 @@ const LOCAL_MARKER_PATH = 'node_modules/_local_.json';
const ANGULAR_ROOT_DIR = path.resolve(__dirname, '../../..'); const ANGULAR_ROOT_DIR = path.resolve(__dirname, '../../..');
const ANGULAR_DIST_PACKAGES_DIR = path.join(ANGULAR_ROOT_DIR, 'dist/packages-dist'); const ANGULAR_DIST_PACKAGES_DIR = path.join(ANGULAR_ROOT_DIR, 'dist/packages-dist');
const ZONEJS_DIST_PACKAGES_DIR = path.join(ANGULAR_ROOT_DIR, 'dist/zone.js-dist');
const DIST_PACKAGES_BUILD_SCRIPT = path.join(ANGULAR_ROOT_DIR, 'scripts/build/build-packages-dist.js'); const DIST_PACKAGES_BUILD_SCRIPT = path.join(ANGULAR_ROOT_DIR, 'scripts/build/build-packages-dist.js');
const DIST_PACKAGES_BUILD_CMD = `"${process.execPath}" "${DIST_PACKAGES_BUILD_SCRIPT}"`; const DIST_PACKAGES_BUILD_CMD = `"${process.execPath}" "${DIST_PACKAGES_BUILD_SCRIPT}"`;
/** /**
* A tool that can install Angular dependencies for a project from NPM or from the * A tool that can install Angular/Zone.js dependencies for a project from NPM or from the
* locally built distributables. * locally built distributables.
* *
* This tool is used to change dependencies of the `aio` application and the example * This tool is used to change dependencies of the `aio` application and the example
@ -33,7 +34,7 @@ class NgPackagesInstaller {
* @param {object} options - a hash of options for the install: * @param {object} options - a hash of options for the install:
* * `debug` (`boolean`) - whether to display debug messages. * * `debug` (`boolean`) - whether to display debug messages.
* * `force` (`boolean`) - whether to force a local installation even if there is a local marker file. * * `force` (`boolean`) - whether to force a local installation even if there is a local marker file.
* * `buildPackages` (`boolean`) - whether to build the local Angular packages before using them. * * `buildPackages` (`boolean`) - whether to build the local Angular/Zone.js packages before using them.
* (NOTE: Building the packages is currently not supported on Windows, so a message is printed instead.) * (NOTE: Building the packages is currently not supported on Windows, so a message is printed instead.)
* * `ignorePackages` (`string[]`) - a collection of names of packages that should not be copied over. * * `ignorePackages` (`string[]`) - a collection of names of packages that should not be copied over.
*/ */
@ -52,7 +53,7 @@ class NgPackagesInstaller {
/** /**
* Check whether the dependencies have been overridden with locally built * Check whether the dependencies have been overridden with locally built
* Angular packages. This is done by checking for the `_local_.json` marker file. * Angular/Zone.js packages. This is done by checking for the `_local_.json` marker file.
* This will emit a warning to the console if the dependencies have been overridden. * This will emit a warning to the console if the dependencies have been overridden.
*/ */
checkDependencies() { checkDependencies() {
@ -62,8 +63,8 @@ class NgPackagesInstaller {
} }
/** /**
* Install locally built Angular dependencies, overriding the dependencies in the package.json * Install locally built Angular/Zone.js dependencies, overriding the dependencies in the `package.json`.
* This will also write a "marker" file (`_local_.json`), which contains the overridden package.json * This will also write a "marker" file (`_local_.json`), which contains the overridden `package.json`
* contents and acts as an indicator that dependencies have been overridden. * contents and acts as an indicator that dependencies have been overridden.
*/ */
installLocalDependencies() { installLocalDependencies() {
@ -86,13 +87,13 @@ class NgPackagesInstaller {
// Prevent accidental publishing of the package, if something goes wrong. // Prevent accidental publishing of the package, if something goes wrong.
tmpConfig.private = true; tmpConfig.private = true;
// Overwrite project dependencies/devDependencies to Angular packages with local files. // Overwrite project dependencies/devDependencies to Angular/Zone.js packages with local files.
['dependencies', 'devDependencies'].forEach(prop => { ['dependencies', 'devDependencies'].forEach(prop => {
const deps = tmpConfig[prop] || {}; const deps = tmpConfig[prop] || {};
Object.keys(deps).forEach(key2 => { Object.keys(deps).forEach(key2 => {
const pkg2 = packages[key2]; const pkg2 = packages[key2];
if (pkg2) { if (pkg2) {
// point the core Angular packages at the distributable folder // point the local packages at the distributable folder
deps[key2] = `file:${pkg2.packageDir}`; deps[key2] = `file:${pkg2.packageDir}`;
this._log(`Overriding dependency of local ${key} with local package: ${key2}: ${deps[key2]}`); this._log(`Overriding dependency of local ${key} with local package: ${key2}: ${deps[key2]}`);
} }
@ -125,8 +126,8 @@ class NgPackagesInstaller {
fs.writeFileSync(pathToPackageConfig, packageConfigFile); fs.writeFileSync(pathToPackageConfig, packageConfigFile);
} }
} finally { } finally {
// Restore local Angular packages dependencies to other Angular packages. // Restore local Angular/Zone.js packages dependencies to other Angular packages.
this._log(`Restoring original ${PACKAGE_JSON} for local Angular packages.`); this._log(`Restoring original ${PACKAGE_JSON} for local packages.`);
Object.keys(packages).forEach(key => { Object.keys(packages).forEach(key => {
const pkg = packages[key]; const pkg = packages[key];
fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(pkg.config, null, 2)); fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(pkg.config, null, 2));
@ -167,7 +168,7 @@ class NgPackagesInstaller {
} }
/** /**
* Build the local Angular packages. * Build the local Angular/Zone.js packages.
* *
* NOTE: * NOTE:
* Building the packages is currently not supported on Windows, so a message is printed instead, prompting the user to * Building the packages is currently not supported on Windows, so a message is printed instead, prompting the user to
@ -177,14 +178,14 @@ class NgPackagesInstaller {
const canBuild = process.platform !== 'win32'; const canBuild = process.platform !== 'win32';
if (canBuild) { if (canBuild) {
this._log(`Building the Angular packages with: ${DIST_PACKAGES_BUILD_SCRIPT}`); this._log(`Building the local packages with: ${DIST_PACKAGES_BUILD_SCRIPT}`);
shelljs.exec(DIST_PACKAGES_BUILD_CMD); shelljs.exec(DIST_PACKAGES_BUILD_CMD);
} else { } else {
this._warn([ this._warn([
'Automatically building the local Angular packages is currently not supported on Windows.', 'Automatically building the local Angular/Zone.js packages is currently not supported on Windows.',
`Please, ensure '${ANGULAR_DIST_PACKAGES_DIR}' exists and is up-to-date (e.g. by running ` + `Please, ensure '${ANGULAR_DIST_PACKAGES_DIR}' and '${ZONEJS_DIST_PACKAGES_DIR}' exist and are up-to-date ` +
`'${DIST_PACKAGES_BUILD_SCRIPT}' in Git Bash for Windows, Windows Subsystem for Linux or a Linux docker ` + `(e.g. by running '${DIST_PACKAGES_BUILD_SCRIPT}' in Git Bash for Windows, Windows Subsystem for Linux or ` +
'container or VM).', 'a Linux docker container or VM).',
'', '',
'Proceeding anyway...', 'Proceeding anyway...',
].join('\n')); ].join('\n'));
@ -204,7 +205,7 @@ class NgPackagesInstaller {
// grab peer dependencies // grab peer dependencies
const sourcePackagePeerDeps = sourcePackage.config.peerDependencies || {}; const sourcePackagePeerDeps = sourcePackage.config.peerDependencies || {};
Object.keys(sourcePackagePeerDeps) Object.keys(sourcePackagePeerDeps)
// ignore peerDependencies which are already core Angular packages // ignore peerDependencies which are already core Angular/Zone.js packages
.filter(key => !packages[key]) .filter(key => !packages[key])
.forEach(key => peerDependencies[key] = sourcePackagePeerDeps[key]); .forEach(key => peerDependencies[key] = sourcePackagePeerDeps[key]);
} }
@ -214,11 +215,13 @@ class NgPackagesInstaller {
} }
/** /**
* A hash of Angular package configs. * A hash of Angular/Zone.js package configs.
* (Detected as directories in '/dist/packages-dist/' that contain a top-level 'package.json' file.) * (Detected as directories in '/dist/packages-dist/' and '/dist/zone.js-dist/' that contain a top-level
* 'package.json' file.)
*/ */
_getDistPackages() { _getDistPackages() {
this._log(`Angular distributable directory: ${ANGULAR_DIST_PACKAGES_DIR}.`); this._log(`Angular distributable directory: ${ANGULAR_DIST_PACKAGES_DIR}.`);
this._log(`Zone.js distributable directory: ${ZONEJS_DIST_PACKAGES_DIR}.`);
if (this.buildPackages) { if (this.buildPackages) {
this._buildDistPackages(); this._buildDistPackages();
@ -254,7 +257,10 @@ class NgPackagesInstaller {
return packages; return packages;
}; };
const packageConfigs = collectPackages(ANGULAR_DIST_PACKAGES_DIR); const packageConfigs = {
...collectPackages(ANGULAR_DIST_PACKAGES_DIR),
...collectPackages(ZONEJS_DIST_PACKAGES_DIR),
};
this._log('Found the following Angular distributables:', Object.keys(packageConfigs).map(key => `\n - ${key}`)); this._log('Found the following Angular distributables:', Object.keys(packageConfigs).map(key => `\n - ${key}`));
return packageConfigs; return packageConfigs;
@ -343,7 +349,7 @@ class NgPackagesInstaller {
// Log a warning. // Log a warning.
this._warn([ this._warn([
`The project at "${absoluteProjectDir}" is running against the local Angular build.`, `The project at "${absoluteProjectDir}" is running against the local Angular/Zone.js build.`,
'', '',
'To restore the npm packages run:', 'To restore the npm packages run:',
'', '',
@ -396,10 +402,10 @@ function main() {
.option('debug', { describe: 'Print additional debug information.', default: false }) .option('debug', { describe: 'Print additional debug information.', default: false })
.option('force', { describe: 'Force the command to execute even if not needed.', default: false }) .option('force', { describe: 'Force the command to execute even if not needed.', default: false })
.option('build-packages', { describe: 'Build the local Angular packages, before using them.', default: false }) .option('build-packages', { describe: 'Build the local Angular/Zone.js packages, before using them.', default: false })
.option('ignore-packages', { describe: 'List of Angular packages that should not be used in local mode.', default: [], array: true }) .option('ignore-packages', { describe: 'List of Angular/Zone.js packages that should not be used in local mode.', default: [], array: true })
.command('overwrite <projectDir> [--force] [--debug] [--ignore-packages package1 package2]', 'Install dependencies from the locally built Angular distributables.', () => {}, argv => { .command('overwrite <projectDir> [--force] [--debug] [--ignore-packages package1 package2]', 'Install dependencies from the locally built Angular/Zone.js distributables.', () => {}, argv => {
createInstaller(argv).installLocalDependencies(); createInstaller(argv).installLocalDependencies();
}) })
.command('restore <projectDir> [--debug]', 'Install dependencies from the npm registry.', () => {}, argv => { .command('restore <projectDir> [--debug]', 'Install dependencies from the npm registry.', () => {}, argv => {

View File

@ -15,6 +15,7 @@ describe('NgPackagesInstaller', () => {
const yarnLockPath = path.resolve(absoluteProjectDir, 'yarn.lock'); const yarnLockPath = path.resolve(absoluteProjectDir, 'yarn.lock');
const ngRootDir = path.resolve(__dirname, '../../..'); const ngRootDir = path.resolve(__dirname, '../../..');
const packagesDir = path.join(ngRootDir, 'dist/packages-dist'); const packagesDir = path.join(ngRootDir, 'dist/packages-dist');
const zoneJsDir = path.join(ngRootDir, 'dist/zone.js-dist');
const toolsDir = path.join(ngRootDir, 'dist/tools/@angular'); const toolsDir = path.join(ngRootDir, 'dist/tools/@angular');
let installer; let installer;
@ -51,7 +52,7 @@ describe('NgPackagesInstaller', () => {
describe('installLocalDependencies()', () => { describe('installLocalDependencies()', () => {
const copyJsonObj = obj => JSON.parse(JSON.stringify(obj)); const copyJsonObj = obj => JSON.parse(JSON.stringify(obj));
let dummyNgPackages, dummyPackage, dummyPackageJson, expectedModifiedPackage, expectedModifiedPackageJson; let dummyLocalPackages, dummyPackage, dummyPackageJson, expectedModifiedPackage, expectedModifiedPackageJson;
beforeEach(() => { beforeEach(() => {
spyOn(installer, '_checkLocalMarker'); spyOn(installer, '_checkLocalMarker');
@ -60,17 +61,18 @@ describe('NgPackagesInstaller', () => {
spyOn(installer, '_parseLockfile').and.returnValue({ spyOn(installer, '_parseLockfile').and.returnValue({
'rxjs@^6.3.0': {version: '6.3.3'}, 'rxjs@^6.3.0': {version: '6.3.3'},
'zone.js@^0.8.26': {version: '0.8.27'} 'rxjs-dev@^6.3.0': {version: '6.4.2'}
}); });
// These are the packages that are "found" in the dist directory // These are the packages that are "found" in the dist directory
dummyNgPackages = { dummyLocalPackages = {
'@angular/core': { '@angular/core': {
packageDir: `${packagesDir}/core`, packageDir: `${packagesDir}/core`,
packageJsonPath: `${packagesDir}/core/package.json`, packageJsonPath: `${packagesDir}/core/package.json`,
config: { config: {
peerDependencies: { peerDependencies: {
'rxjs': '^6.4.0', 'rxjs': '^6.4.0',
'rxjs-dev': '^6.4.0',
'some-package': '5.0.1', 'some-package': '5.0.1',
'zone.js': '~0.8.26' 'zone.js': '~0.8.26'
} }
@ -101,32 +103,40 @@ describe('NgPackagesInstaller', () => {
devDependencies: { '@angular/common': '4.4.4-1ab23cd4' }, devDependencies: { '@angular/common': '4.4.4-1ab23cd4' },
peerDependencies: { tsickle: '^1.4.0' } peerDependencies: { tsickle: '^1.4.0' }
} }
} },
'zone.js': {
packageDir: `${zoneJsDir}/zone.js`,
packageJsonPath: `${zoneJsDir}/zone.js/package.json`,
config: {
devDependencies: { typescript: '^2.4.2' }
}
},
}; };
spyOn(installer, '_getDistPackages').and.callFake(() => copyJsonObj(dummyNgPackages)); spyOn(installer, '_getDistPackages').and.callFake(() => copyJsonObj(dummyLocalPackages));
// This is the package.json in the "test" folder // This is the package.json in the "test" folder
dummyPackage = { dummyPackage = {
dependencies: { dependencies: {
'@angular/core': '4.4.1', '@angular/core': '4.4.1',
'@angular/common': '4.4.1', '@angular/common': '4.4.1',
rxjs: '^6.3.0' rxjs: '^6.3.0',
'zone.js': '^0.8.26'
}, },
devDependencies: { devDependencies: {
'@angular/compiler-cli': '4.4.1', '@angular/compiler-cli': '4.4.1',
'zone.js': '^0.8.26' 'rxjs-dev': '^6.3.0'
} }
}; };
dummyPackageJson = JSON.stringify(dummyPackage); dummyPackageJson = JSON.stringify(dummyPackage);
fs.readFileSync.and.returnValue(dummyPackageJson); fs.readFileSync.and.returnValue(dummyPackageJson);
// This is the package.json that is temporarily written to the "test" folder // This is the package.json that is temporarily written to the "test" folder
// Note that the Angular (dev)dependencies have been modified to use a "file:" path // Note that the Angular/Zone.js (dev)dependencies have been modified to use a "file:" path
// And that the peerDependencies from `dummyNgPackages` have been updated or added as // and that the peerDependencies from `dummyLocalPackages` have been updated or added as
// (dev)dependencies (unless the current version in lockfile satisfies semver). // (dev)dependencies (unless the current version in lockfile satisfies semver).
// //
// For example, `zone.js@0.8.27` (from lockfile) satisfies `zone.js@~0.8.26` (from // For example, `rxjs-dev@6.4.2` (from lockfile) satisfies `rxjs-dev@^6.4.0` (from
// `@angular/core`), thus `zone.js: ^0.8.26` (from original `package.json`) is retained. // `@angular/core`), thus `rxjs-dev: ^6.3.0` (from original `package.json`) is retained.
// In contrast, `rxjs@6.3.3` (from lockfile) does not satisfy `rxjs@^6.4.0 (from // In contrast, `rxjs@6.3.3` (from lockfile) does not satisfy `rxjs@^6.4.0 (from
// `@angular/core`), thus `rxjs: ^6.3.0` (from original `package.json`) is replaced with // `@angular/core`), thus `rxjs: ^6.3.0` (from original `package.json`) is replaced with
// `rxjs: ^6.4.0` (from `@angular/core`). // `rxjs: ^6.4.0` (from `@angular/core`).
@ -134,11 +144,12 @@ describe('NgPackagesInstaller', () => {
dependencies: { dependencies: {
'@angular/core': `file:${packagesDir}/core`, '@angular/core': `file:${packagesDir}/core`,
'@angular/common': `file:${packagesDir}/common`, '@angular/common': `file:${packagesDir}/common`,
'rxjs': '^6.4.0' 'rxjs': '^6.4.0',
'zone.js': `file:${zoneJsDir}/zone.js`,
}, },
devDependencies: { devDependencies: {
'@angular/compiler-cli': `file:${toolsDir}/compiler-cli`, '@angular/compiler-cli': `file:${toolsDir}/compiler-cli`,
'zone.js': '^0.8.26', 'rxjs-dev': '^6.3.0',
'some-package': '5.0.1', 'some-package': '5.0.1',
typescript: '^2.4.2' typescript: '^2.4.2'
}, },
@ -182,31 +193,56 @@ describe('NgPackagesInstaller', () => {
}); });
it('should temporarily overwrite the package.json files of local Angular packages', () => { it('should temporarily overwrite the package.json files of local Angular packages', () => {
const pkgJsonFor = pkgName => dummyNgPackages[`@angular/${pkgName}`].packageJsonPath; const pkgJsonPathFor = pkgName => dummyLocalPackages[pkgName].packageJsonPath;
const pkgConfigFor = pkgName => copyJsonObj(dummyNgPackages[`@angular/${pkgName}`].config); const pkgConfigFor = pkgName => copyJsonObj(dummyLocalPackages[pkgName].config);
const overwriteConfigFor = (pkgName, newProps) => Object.assign(pkgConfigFor(pkgName), newProps); const overwriteConfigFor = (pkgName, newProps) => Object.assign(pkgConfigFor(pkgName), newProps);
const stringifyConfig = config => JSON.stringify(config, null, 2); const stringifyConfig = config => JSON.stringify(config, null, 2);
const allArgs = fs.writeFileSync.calls.allArgs(); const allArgs = fs.writeFileSync.calls.allArgs();
const firstFiveArgs = allArgs.slice(0, 5); const firstSixArgs = allArgs.slice(0, 6);
const lastFiveArgs = allArgs.slice(-5); const lastSixArgs = allArgs.slice(-6);
expect(firstFiveArgs).toEqual([ expect(firstSixArgs).toEqual([
[pkgJsonFor('core'), stringifyConfig(overwriteConfigFor('core', {private: true}))], [
[pkgJsonFor('common'), stringifyConfig(overwriteConfigFor('common', {private: true}))], pkgJsonPathFor('@angular/core'),
[pkgJsonFor('compiler'), stringifyConfig(overwriteConfigFor('compiler', {private: true}))], stringifyConfig(overwriteConfigFor('@angular/core', {private: true})),
[pkgJsonFor('compiler-cli'), stringifyConfig(overwriteConfigFor('compiler-cli', { ],
private: true, [
dependencies: { '@angular/tsc-wrapped': `file:${toolsDir}/tsc-wrapped` } pkgJsonPathFor('@angular/common'),
}))], stringifyConfig(overwriteConfigFor('@angular/common', {private: true})),
[pkgJsonFor('tsc-wrapped'), stringifyConfig(overwriteConfigFor('tsc-wrapped', { ],
private: true, [
devDependencies: { '@angular/common': `file:${packagesDir}/common` } pkgJsonPathFor('@angular/compiler'),
}))], stringifyConfig(overwriteConfigFor('@angular/compiler', {private: true})),
],
[
pkgJsonPathFor('@angular/compiler-cli'),
stringifyConfig(overwriteConfigFor('@angular/compiler-cli', {
private: true,
dependencies: { '@angular/tsc-wrapped': `file:${toolsDir}/tsc-wrapped` },
})),
],
[
pkgJsonPathFor('@angular/tsc-wrapped'),
stringifyConfig(overwriteConfigFor('@angular/tsc-wrapped', {
private: true,
devDependencies: { '@angular/common': `file:${packagesDir}/common` },
})),
],
[
pkgJsonPathFor('zone.js'),
stringifyConfig(overwriteConfigFor('zone.js', {private: true})),
],
]); ]);
expect(lastFiveArgs).toEqual(['core', 'common', 'compiler', 'compiler-cli', 'tsc-wrapped'] expect(lastSixArgs).toEqual([
.map(pkgName => [pkgJsonFor(pkgName), stringifyConfig(pkgConfigFor(pkgName))])); '@angular/core',
'@angular/common',
'@angular/compiler',
'@angular/compiler-cli',
'@angular/tsc-wrapped',
'zone.js',
].map(pkgName => [pkgJsonPathFor(pkgName), stringifyConfig(pkgConfigFor(pkgName))]));
}); });
it('should load the package.json', () => { it('should load the package.json', () => {
@ -280,7 +316,7 @@ describe('NgPackagesInstaller', () => {
expect(shelljs.exec).not.toHaveBeenCalled(); expect(shelljs.exec).not.toHaveBeenCalled();
expect(warning).toContain( expect(warning).toContain(
'Automatically building the local Angular packages is currently not supported on Windows.'); 'Automatically building the local Angular/Zone.js packages is currently not supported on Windows.');
expect(warning).toContain('Git Bash for Windows'); expect(warning).toContain('Git Bash for Windows');
expect(warning).toContain('Windows Subsystem for Linux'); expect(warning).toContain('Windows Subsystem for Linux');
expect(warning).toContain('Linux docker container or VM'); expect(warning).toContain('Linux docker container or VM');
@ -309,8 +345,8 @@ describe('NgPackagesInstaller', () => {
expect(installer._buildDistPackages).not.toHaveBeenCalled(); expect(installer._buildDistPackages).not.toHaveBeenCalled();
}); });
it('should include top level Angular packages', () => { it('should include top level Angular and Zone.js packages', () => {
const ngPackages = installer._getDistPackages(); const localPackages = installer._getDistPackages();
const expectedValue = jasmine.objectContaining({ const expectedValue = jasmine.objectContaining({
packageDir: jasmine.any(String), packageDir: jasmine.any(String),
packageJsonPath: jasmine.any(String), packageJsonPath: jasmine.any(String),
@ -318,28 +354,30 @@ describe('NgPackagesInstaller', () => {
}); });
// For example... // For example...
expect(ngPackages['@angular/common']).toEqual(expectedValue); expect(localPackages['@angular/common']).toEqual(expectedValue);
expect(ngPackages['@angular/core']).toEqual(expectedValue); expect(localPackages['@angular/core']).toEqual(expectedValue);
expect(ngPackages['@angular/router']).toEqual(expectedValue); expect(localPackages['@angular/router']).toEqual(expectedValue);
expect(ngPackages['@angular/upgrade']).toEqual(expectedValue); expect(localPackages['@angular/upgrade']).toEqual(expectedValue);
expect(localPackages['zone.js']).toEqual(expectedValue);
expect(ngPackages['@angular/upgrade/static']).not.toBeDefined(); expect(localPackages['@angular/upgrade/static']).not.toBeDefined();
}); });
it('should store each package\'s directory', () => { it('should store each package\'s directory', () => {
const ngPackages = installer._getDistPackages(); const localPackages = installer._getDistPackages();
// For example... // For example...
expect(ngPackages['@angular/core'].packageDir).toBe(path.join(packagesDir, 'core')); expect(localPackages['@angular/core'].packageDir).toBe(path.join(packagesDir, 'core'));
expect(ngPackages['@angular/router'].packageDir).toBe(path.join(packagesDir, 'router')); expect(localPackages['@angular/router'].packageDir).toBe(path.join(packagesDir, 'router'));
expect(localPackages['zone.js'].packageDir).toBe(path.join(zoneJsDir, 'zone.js'));
}); });
it('should not include packages that have been ignored', () => { it('should not include packages that have been ignored', () => {
installer = new NgPackagesInstaller(projectDir, { ignorePackages: ['@angular/router'] }); installer = new NgPackagesInstaller(projectDir, { ignorePackages: ['@angular/router'] });
const ngPackages = installer._getDistPackages(); const localPackages = installer._getDistPackages();
expect(ngPackages['@angular/common']).toBeDefined(); expect(localPackages['@angular/common']).toBeDefined();
expect(ngPackages['@angular/router']).toBeUndefined(); expect(localPackages['@angular/router']).toBeUndefined();
}); });
}); });
@ -480,7 +518,7 @@ describe('NgPackagesInstaller', () => {
describe('_printWarning()', () => { describe('_printWarning()', () => {
it('should mention the message passed in the warning', () => { it('should mention the message passed in the warning', () => {
installer._printWarning(); installer._printWarning();
expect(console.warn.calls.argsFor(0)[0]).toContain('is running against the local Angular build'); expect(console.warn.calls.argsFor(0)[0]).toContain('is running against the local Angular/Zone.js build');
}); });
it('should mention the command to restore the Angular packages in any warning', () => { it('should mention the command to restore the Angular packages in any warning', () => {

View File

@ -9,8 +9,18 @@
'use strict'; 'use strict';
const {buildZoneJsPackage} = require('./zone-js-builder');
const {buildTargetPackages} = require('./package-builder'); const {buildTargetPackages} = require('./package-builder');
// Build the ivy packages into `dist/packages-dist-ivy-aot/`. // Build the ivy packages into `dist/packages-dist-ivy-aot/`.
buildTargetPackages('dist/packages-dist-ivy-aot', true, 'Ivy AOT'); buildTargetPackages('dist/packages-dist-ivy-aot', true, 'Ivy AOT');
// Build the `zone.js` npm package into `dist/zone.js-dist-ivy-aot/`, because it might be needed by
// other scripts/tests.
//
// NOTE:
// The `-ivy-aot` suffix is only used to differentiate from the packages built by the
// `build-packages-dist.js` script, so that there is no conflict when persisting them to the
// workspace on CI.
buildZoneJsPackage('dist/zone.js-dist-ivy-aot');

View File

@ -19,7 +19,7 @@ buildTargetPackages('dist/packages-dist', false, 'Production');
// Build the `zone.js` npm package into `dist/zone.js-dist/`, because it might be needed by other // Build the `zone.js` npm package into `dist/zone.js-dist/`, because it might be needed by other
// scripts/tests. // scripts/tests.
buildZoneJsPackage(); buildZoneJsPackage('dist/zone.js-dist');
// Build the `angular-dev-infra` npm package into `dist/packages-dist/@angular/dev-infra-private` // Build the `angular-dev-infra` npm package into `dist/packages-dist/@angular/dev-infra-private`
buildDevInfraPackage(); buildDevInfraPackage();

View File

@ -51,7 +51,7 @@ module.exports = {
}; };
/** /**
* Build the packages. * Build the Angular packages.
* *
* @param {string} destPath Path to the output directory into which we copy the npm packages. * @param {string} destPath Path to the output directory into which we copy the npm packages.
* This path should either be absolute or relative to the project root. * This path should either be absolute or relative to the project root.

View File

@ -8,7 +8,8 @@
'use strict'; 'use strict';
const {chmod, cp, mkdir, rm} = require('shelljs'); const {resolve} = require('path');
const {chmod, cp, mkdir, rm, test} = require('shelljs');
const {baseDir, bazelBin, bazelCmd, exec, scriptPath} = require('./package-builder'); const {baseDir, bazelBin, bazelCmd, exec, scriptPath} = require('./package-builder');
@ -18,27 +19,33 @@ module.exports = {
/** /**
* Build the `zone.js` npm package into `dist/bin/packages/zone.js/npm_package/` and copy it to * Build the `zone.js` npm package into `dist/bin/packages/zone.js/npm_package/` and copy it to
* `dist/zone.js-dist/` for other scripts/tests to use. * `destPath` for other scripts/tests to use.
* *
* NOTE: The `zone.js` package is not built as part of `package-builder`'s `buildTargetPackages()` * NOTE: The `zone.js` package is not built as part of `package-builder`'s `buildTargetPackages()`
* nor is it copied into the same directory as the Angular packages (e.g. * nor is it copied into the same directory as the Angular packages (e.g.
* `dist/packages-dist/`) despite its source's being inside `packages/`, because it is not * `dist/packages-dist/`) despite its source's being inside `packages/`, because it is not
* published to npm under the `@angular` scope (as happens for the rest of the packages). * published to npm under the `@angular` scope (as happens for the rest of the packages).
*
* @param {string} destPath Path to the output directory into which we copy the npm package.
* This path should either be absolute or relative to the project root.
*/ */
function buildZoneJsPackage() { function buildZoneJsPackage(destPath) {
console.info('##############################'); console.info('##############################');
console.info(`${scriptPath}:`); console.info(`${scriptPath}:`);
console.info(' Building zone.js npm package'); console.info(' Building zone.js npm package');
console.info('##############################'); console.info('##############################');
exec(`${bazelCmd} build //packages/zone.js:npm_package`); exec(`${bazelCmd} build //packages/zone.js:npm_package`);
// Copy artifacts to `dist/zone.js-dist/`, so they can be easier persisted on CI and used by // Create the output directory.
// non-bazel scripts/tests. const absDestPath = resolve(baseDir, destPath);
if (!test('-d', absDestPath)) mkdir('-p', absDestPath);
// Copy artifacts to `destPath`, so they can be easier persisted on CI and used by non-bazel
// scripts/tests.
const buildOutputDir = `${bazelBin}/packages/zone.js/npm_package`; const buildOutputDir = `${bazelBin}/packages/zone.js/npm_package`;
const distTargetDir = `${baseDir}/dist/zone.js-dist/zone.js`; const distTargetDir = `${absDestPath}/zone.js`;
console.info(`# Copy artifacts to ${distTargetDir}`); console.info(`# Copy artifacts to ${distTargetDir}`);
mkdir('-p', distTargetDir);
rm('-rf', distTargetDir); rm('-rf', distTargetDir);
cp('-R', buildOutputDir, distTargetDir); cp('-R', buildOutputDir, distTargetDir);
chmod('-R', 'u+w', distTargetDir); chmod('-R', 'u+w', distTargetDir);