build(aio): fix overwriting with local Angular packages that depend on other local ones (#19600)

PR Close #19600
This commit is contained in:
George Kalpakas
2017-10-09 13:11:13 +03:00
committed by Chuck Jazdzewski
parent 173ccf03ab
commit dc22f4dc69
4 changed files with 141 additions and 31 deletions

View File

@ -79,7 +79,7 @@
"rollup-plugin-uglify": "^1.0.1", "rollup-plugin-uglify": "^1.0.1",
"source-map-explorer": "^1.3.2", "source-map-explorer": "^1.3.2",
"style-loader": "^0.13.1", "style-loader": "^0.13.1",
"ts-node": "~3.0.4", "ts-node": "^3.3.0",
"tslint": "^3.15.1", "tslint": "^3.15.1",
"typescript": "~2.3.2", "typescript": "~2.3.2",
"webpack": "2.2.1", "webpack": "2.2.1",

View File

@ -1390,6 +1390,14 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0" strip-ansi "^3.0.0"
supports-color "^2.0.0" supports-color "^2.0.0"
chalk@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
dependencies:
ansi-styles "^3.1.0"
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"
chalk@^2.0.1: chalk@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.0.1.tgz#dbec49436d2ae15f536114e76d14656cdbc0f44d" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.0.1.tgz#dbec49436d2ae15f536114e76d14656cdbc0f44d"
@ -2950,6 +2958,12 @@ home-or-tmp@^2.0.0:
os-homedir "^1.0.0" os-homedir "^1.0.0"
os-tmpdir "^1.0.1" os-tmpdir "^1.0.1"
homedir-polyfill@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc"
dependencies:
parse-passwd "^1.0.0"
hosted-git-info@^2.1.4: hosted-git-info@^2.1.4:
version "2.4.2" version "2.4.2"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67"
@ -4383,6 +4397,10 @@ parse-json@^2.2.0:
dependencies: dependencies:
error-ex "^1.2.0" error-ex "^1.2.0"
parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
parse5@^3.0.1: parse5@^3.0.1:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510"
@ -6101,19 +6119,19 @@ trim-right@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
ts-node@~3.0.4: ts-node@^3.3.0:
version "3.0.6" version "3.3.0"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-3.0.6.tgz#55127ff790c7eebf6ba68c1e6dde94b09aaa21e0" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-3.3.0.tgz#c13c6a3024e30be1180dd53038fc209289d4bf69"
dependencies: dependencies:
arrify "^1.0.0" arrify "^1.0.0"
chalk "^1.1.1" chalk "^2.0.0"
diff "^3.1.0" diff "^3.1.0"
make-error "^1.1.1" make-error "^1.1.1"
minimist "^1.2.0" minimist "^1.2.0"
mkdirp "^0.5.1" mkdirp "^0.5.1"
source-map-support "^0.4.0" source-map-support "^0.4.0"
tsconfig "^6.0.0" tsconfig "^6.0.0"
v8flags "^2.0.11" v8flags "^3.0.0"
yn "^2.0.0" yn "^2.0.0"
tsconfig@^6.0.0: tsconfig@^6.0.0:
@ -6341,12 +6359,18 @@ uuid@^3.0.0:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
v8flags@^2.0.10, v8flags@^2.0.11: v8flags@^2.0.10:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
dependencies: dependencies:
user-home "^1.1.1" user-home "^1.1.1"
v8flags@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.0.1.tgz#dce8fc379c17d9f2c9e9ed78d89ce00052b1b76b"
dependencies:
homedir-polyfill "^1.0.1"
validate-npm-package-license@^3.0.1: validate-npm-package-license@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"

View File

@ -66,27 +66,59 @@ class NgPackagesInstaller {
if (this._checkLocalMarker() !== true || this.force) { if (this._checkLocalMarker() !== true || this.force) {
const pathToPackageConfig = path.resolve(this.projectDir, PACKAGE_JSON); const pathToPackageConfig = path.resolve(this.projectDir, PACKAGE_JSON);
const packages = this._getDistPackages(); const packages = this._getDistPackages();
const packageConfigFile = fs.readFileSync(pathToPackageConfig);
const packageConfig = JSON.parse(packageConfigFile);
const [dependencies, peers] = this._collectDependencies(packageConfig.dependencies || {}, packages);
const [devDependencies, devPeers] = this._collectDependencies(packageConfig.devDependencies || {}, packages);
this._assignPeerDependencies(peers, dependencies, devDependencies);
this._assignPeerDependencies(devPeers, dependencies, devDependencies);
const localPackageConfig = Object.assign(Object.create(null), packageConfig, { dependencies, devDependencies });
localPackageConfig.__angular = { local: true };
const localPackageConfigJson = JSON.stringify(localPackageConfig, null, 2);
try { try {
this._log(`Writing temporary local ${PACKAGE_JSON} to ${pathToPackageConfig}`); // Overwrite local Angular packages dependencies to other Angular packages with local files.
fs.writeFileSync(pathToPackageConfig, localPackageConfigJson); Object.keys(packages).forEach(key => {
this._installDeps('--no-lockfile', '--check-files'); const pkg = packages[key];
this._setLocalMarker(localPackageConfigJson); const tmpConfig = JSON.parse(JSON.stringify(pkg.config));
// Prevent accidental publishing of the package, if something goes wrong.
tmpConfig.private = true;
// Overwrite project dependencies to Angular packages with local files.
const deps = tmpConfig.dependencies || {};
Object.keys(deps).forEach(key2 => {
const pkg2 = packages[key2];
if (pkg2) {
// point the core Angular packages at the distributable folder
deps[key2] = `file:${pkg2.parentDir}/${key2.replace('@angular/', '')}`;
this._log(`Overriding dependency of local ${key} with local package: ${key2}: ${deps[key2]}`);
}
});
fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(tmpConfig));
});
const packageConfigFile = fs.readFileSync(pathToPackageConfig);
const packageConfig = JSON.parse(packageConfigFile);
const [dependencies, peers] = this._collectDependencies(packageConfig.dependencies || {}, packages);
const [devDependencies, devPeers] = this._collectDependencies(packageConfig.devDependencies || {}, packages);
this._assignPeerDependencies(peers, dependencies, devDependencies);
this._assignPeerDependencies(devPeers, dependencies, devDependencies);
const localPackageConfig = Object.assign(Object.create(null), packageConfig, { dependencies, devDependencies });
localPackageConfig.__angular = { local: true };
const localPackageConfigJson = JSON.stringify(localPackageConfig, null, 2);
try {
this._log(`Writing temporary local ${PACKAGE_JSON} to ${pathToPackageConfig}`);
fs.writeFileSync(pathToPackageConfig, localPackageConfigJson);
this._installDeps('--no-lockfile', '--check-files');
this._setLocalMarker(localPackageConfigJson);
} finally {
this._log(`Restoring original ${PACKAGE_JSON} to ${pathToPackageConfig}`);
fs.writeFileSync(pathToPackageConfig, packageConfigFile);
}
} finally { } finally {
this._log(`Restoring original ${PACKAGE_JSON} to ${pathToPackageConfig}`); // Restore local Angular packages dependencies to other Angular packages.
fs.writeFileSync(pathToPackageConfig, packageConfigFile); this._log(`Restoring original ${PACKAGE_JSON} for local Angular packages.`);
Object.keys(packages).forEach(key => {
const pkg = packages[key];
fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(pkg.config));
});
} }
} }
} }
@ -152,7 +184,11 @@ class NgPackagesInstaller {
const packageName = `@angular/${packagePath.slice(0, -PACKAGE_JSON.length -1)}`; const packageName = `@angular/${packagePath.slice(0, -PACKAGE_JSON.length -1)}`;
if (this.ignorePackages.indexOf(packageName) === -1) { if (this.ignorePackages.indexOf(packageName) === -1) {
const packageConfig = require(path.resolve(distDir, packagePath)); const packageConfig = require(path.resolve(distDir, packagePath));
packageConfigs[packageName] = {parentDir: distDir, config: packageConfig}; packageConfigs[packageName] = {
parentDir: distDir,
packageJsonPath: path.resolve(distDir, packagePath),
config: packageConfig
};
} else { } else {
this._log('Ignoring package', packageName); this._log('Ignoring package', packageName);
} }

View File

@ -47,6 +47,7 @@ describe('NgPackagesInstaller', () => {
}); });
describe('installLocalDependencies()', () => { describe('installLocalDependencies()', () => {
const copyJsonObj = obj => JSON.parse(JSON.stringify(obj));
let dummyNgPackages, dummyPackage, dummyPackageJson, expectedModifiedPackage, expectedModifiedPackageJson; let dummyNgPackages, dummyPackage, dummyPackageJson, expectedModifiedPackage, expectedModifiedPackageJson;
beforeEach(() => { beforeEach(() => {
@ -54,12 +55,36 @@ describe('NgPackagesInstaller', () => {
// These are the packages that are "found" in the dist directory // These are the packages that are "found" in the dist directory
dummyNgPackages = { dummyNgPackages = {
'@angular/core': { parentDir: packagesDir, config: { peerDependencies: { rxjs: '5.0.1' } } }, '@angular/core': {
'@angular/common': { parentDir: packagesDir, config: { peerDependencies: { '@angular/core': '4.4.1' } } }, parentDir: packagesDir,
'@angular/compiler': { parentDir: packagesDir, config: { } }, packageJsonPath: `${packagesDir}/core/package.json`,
'@angular/compiler-cli': { parentDir: toolsDir, config: { peerDependencies: { typescript: '^2.4.2', '@angular/compiler': '4.3.2' } } } config: { peerDependencies: { rxjs: '5.0.1' } }
},
'@angular/common': {
parentDir: packagesDir,
packageJsonPath: `${packagesDir}/common/package.json`,
config: { peerDependencies: { '@angular/core': '4.4.4-1ab23cd4' } }
},
'@angular/compiler': {
parentDir: packagesDir,
packageJsonPath: `${packagesDir}/compiler/package.json`,
config: { peerDependencies: { '@angular/common': '4.4.4-1ab23cd4' } }
},
'@angular/compiler-cli': {
parentDir: toolsDir,
packageJsonPath: `${toolsDir}/compiler-cli/package.json`,
config: {
dependencies: { '@angular/tsc-wrapped': '4.4.4-1ab23cd4' },
peerDependencies: { typescript: '^2.4.2', '@angular/compiler': '4.4.4-1ab23cd4' }
}
},
'@angular/tsc-wrapped': {
parentDir: toolsDir,
packageJsonPath: `${toolsDir}/tsc-wrapped/package.json`,
config: { peerDependencies: { tsickle: '^1.4.0' } }
}
}; };
spyOn(installer, '_getDistPackages').and.returnValue(dummyNgPackages); spyOn(installer, '_getDistPackages').and.callFake(() => copyJsonObj(dummyNgPackages));
// This is the package.json in the "test" folder // This is the package.json in the "test" folder
dummyPackage = { dummyPackage = {
@ -118,6 +143,30 @@ describe('NgPackagesInstaller', () => {
expect(installer._getDistPackages).toHaveBeenCalled(); expect(installer._getDistPackages).toHaveBeenCalled();
}); });
it('should temporarily overwrite the package.json files of local Angular packages', () => {
const pkgJsonFor = pkgName => dummyNgPackages[`@angular/${pkgName}`].packageJsonPath;
const pkgConfigFor = pkgName => copyJsonObj(dummyNgPackages[`@angular/${pkgName}`].config);
const overwriteConfigFor = (pkgName, newProps) => Object.assign(pkgConfigFor(pkgName), newProps);
const allArgs = fs.writeFileSync.calls.allArgs();
const firstFiveArgs = allArgs.slice(0, 5);
const lastFiveArgs = allArgs.slice(-5);
expect(firstFiveArgs).toEqual([
[pkgJsonFor('core'), JSON.stringify(overwriteConfigFor('core', {private: true}))],
[pkgJsonFor('common'), JSON.stringify(overwriteConfigFor('common', {private: true}))],
[pkgJsonFor('compiler'), JSON.stringify(overwriteConfigFor('compiler', {private: true}))],
[pkgJsonFor('compiler-cli'), JSON.stringify(overwriteConfigFor('compiler-cli', {
private: true,
dependencies: { '@angular/tsc-wrapped': `file:${toolsDir}/tsc-wrapped` }
}))],
[pkgJsonFor('tsc-wrapped'), JSON.stringify(overwriteConfigFor('tsc-wrapped', {private: true}))],
]);
expect(lastFiveArgs).toEqual(['core', 'common', 'compiler', 'compiler-cli', 'tsc-wrapped']
.map(pkgName => [pkgJsonFor(pkgName), JSON.stringify(pkgConfigFor(pkgName))]));
});
it('should load the package.json', () => { it('should load the package.json', () => {
expect(fs.readFileSync).toHaveBeenCalledWith(packageJsonPath); expect(fs.readFileSync).toHaveBeenCalledWith(packageJsonPath);
}); });
@ -157,6 +206,7 @@ describe('NgPackagesInstaller', () => {
const ngPackages = installer._getDistPackages(); const ngPackages = installer._getDistPackages();
const expectedValue = jasmine.objectContaining({ const expectedValue = jasmine.objectContaining({
parentDir: jasmine.any(String), parentDir: jasmine.any(String),
packageJsonPath: jasmine.any(String),
config: jasmine.any(Object), config: jasmine.any(Object),
}); });