feat(ivy): show error when trying to publish NGCC'd packages (#32031)
Publishing of NGCC packages should not be allowed. It is easy for a user to publish an NGCC'd version of a library they have workspace libraries which are being used in a workspace application. If a users builds a library and afterwards the application, the library will be transformed with NGCC and since NGCC taints the distributed files that should be published. With this change we use the npm/yarn `prepublishOnly` hook to display and error and abort the process with a non zero error code when a user tries to publish an NGCC version of the package. More info: https://docs.npmjs.com/misc/scripts PR Close #32031
This commit is contained in:
parent
f7eebd0227
commit
46304a4f83
|
@ -57,6 +57,17 @@ export function markAsProcessed(
|
|||
processed[prop] = NGCC_VERSION;
|
||||
}
|
||||
|
||||
const scripts = packageJson.scripts || (packageJson.scripts = {});
|
||||
scripts.prepublishOnly__ivy_ngcc_bak =
|
||||
scripts.prepublishOnly__ivy_ngcc_bak || scripts.prepublishOnly;
|
||||
|
||||
scripts.prepublishOnly = 'node --eval \"console.error(\'' +
|
||||
'ERROR: Trying to publish a package that has been compiled by NGCC. This is not allowed.\\n' +
|
||||
'Please delete and rebuild the package, without compiling with NGCC, before attempting to publish.\\n' +
|
||||
'Note that NGCC may have been run by importing this package into another project that is being built with Ivy enabled.\\n' +
|
||||
'\')\" ' +
|
||||
'&& exit 1';
|
||||
|
||||
// Just in case this package.json was synthesized due to a custom configuration
|
||||
// we will ensure that the path to the containing folder exists before we write the file.
|
||||
fs.ensureDir(dirname(packageJsonPath));
|
||||
|
|
|
@ -55,7 +55,8 @@ export interface PackageJsonFormatProperties {
|
|||
*/
|
||||
export interface EntryPointPackageJson extends PackageJsonFormatProperties {
|
||||
name: string;
|
||||
__processed_by_ivy_ngcc__?: {[key: string]: string};
|
||||
scripts?: Record<string, string>;
|
||||
__processed_by_ivy_ngcc__?: Record<string, string>;
|
||||
}
|
||||
|
||||
export type EntryPointJsonProperty = Exclude<keyof PackageJsonFormatProperties, 'types'|'typings'>;
|
||||
|
|
|
@ -84,6 +84,7 @@ runInEachFileSystem(() => {
|
|||
const fs = getFileSystem();
|
||||
let pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH));
|
||||
expect(pkg.__processed_by_ivy_ngcc__).toBeUndefined();
|
||||
expect(pkg.scripts).toBeUndefined();
|
||||
|
||||
markAsProcessed(fs, pkg, COMMON_PACKAGE_PATH, ['fesm2015', 'fesm5']);
|
||||
pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH));
|
||||
|
@ -91,6 +92,7 @@ runInEachFileSystem(() => {
|
|||
expect(pkg.__processed_by_ivy_ngcc__.fesm5).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.__processed_by_ivy_ngcc__.esm2015).toBeUndefined();
|
||||
expect(pkg.__processed_by_ivy_ngcc__.esm5).toBeUndefined();
|
||||
expect(pkg.scripts.prepublishOnly).toBeDefined();
|
||||
|
||||
markAsProcessed(fs, pkg, COMMON_PACKAGE_PATH, ['esm2015', 'esm5']);
|
||||
pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH));
|
||||
|
@ -98,6 +100,7 @@ runInEachFileSystem(() => {
|
|||
expect(pkg.__processed_by_ivy_ngcc__.fesm5).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.__processed_by_ivy_ngcc__.esm2015).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.__processed_by_ivy_ngcc__.esm5).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.scripts.prepublishOnly).toBeDefined();
|
||||
});
|
||||
|
||||
it('should update the packageJson object in-place', () => {
|
||||
|
@ -105,18 +108,21 @@ runInEachFileSystem(() => {
|
|||
const fs = getFileSystem();
|
||||
const pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH));
|
||||
expect(pkg.__processed_by_ivy_ngcc__).toBeUndefined();
|
||||
expect(pkg.scripts).toBeUndefined();
|
||||
|
||||
markAsProcessed(fs, pkg, COMMON_PACKAGE_PATH, ['fesm2015', 'fesm5']);
|
||||
expect(pkg.__processed_by_ivy_ngcc__.fesm2015).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.__processed_by_ivy_ngcc__.fesm5).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.__processed_by_ivy_ngcc__.esm2015).toBeUndefined();
|
||||
expect(pkg.__processed_by_ivy_ngcc__.esm5).toBeUndefined();
|
||||
expect(pkg.scripts.prepublishOnly).toBeDefined();
|
||||
|
||||
markAsProcessed(fs, pkg, COMMON_PACKAGE_PATH, ['esm2015', 'esm5']);
|
||||
expect(pkg.__processed_by_ivy_ngcc__.fesm2015).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.__processed_by_ivy_ngcc__.fesm5).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.__processed_by_ivy_ngcc__.esm2015).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.__processed_by_ivy_ngcc__.esm5).toBe('0.0.0-PLACEHOLDER');
|
||||
expect(pkg.scripts.prepublishOnly).toBeDefined();
|
||||
});
|
||||
|
||||
it('should one perform one write operation for all updated properties', () => {
|
||||
|
@ -128,6 +134,19 @@ runInEachFileSystem(() => {
|
|||
markAsProcessed(fs, pkg, COMMON_PACKAGE_PATH, ['fesm2015', 'fesm5', 'esm2015', 'esm5']);
|
||||
expect(writeFileSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it(`should keep backup of existing 'prepublishOnly' script`, () => {
|
||||
const COMMON_PACKAGE_PATH = _('/node_modules/@angular/common/package.json');
|
||||
const fs = getFileSystem();
|
||||
const prepublishOnly = 'existing script';
|
||||
let pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH));
|
||||
pkg.scripts = {prepublishOnly};
|
||||
|
||||
markAsProcessed(fs, pkg, COMMON_PACKAGE_PATH, ['fesm2015']);
|
||||
pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH));
|
||||
expect(pkg.scripts.prepublishOnly).toContain('This is not allowed');
|
||||
expect(pkg.scripts.prepublishOnly__ivy_ngcc_bak).toBe(prepublishOnly);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasBeenProcessed', () => {
|
||||
|
|
Loading…
Reference in New Issue