fix(ngcc): update package.json
deterministically (#34870)
Ngcc adds properties to the `package.json` files of the entry-points it processes to mark them as processed for a format and point to the created Ivy entry-points (in case of `--create-ivy-entry-points`). When running ngcc in parallel mode (which is the default for the standalone ngcc command), multiple formats can be processed simultaneously for the same entry-point and the order of completion is not deterministic. Previously, ngcc would append new properties at the end of the target object in `package.json` as soon as the format processing was completed. As a result, the order of properties in the resulting `package.json` (when processing multiple formats for an entry-point in parallel) was not deterministic. For tools that use file hashes for caching purposes (such as Bazel), this lead to a high probability of cache misses. This commit fixes the problem by ensuring that the position of properties added to `package.json` files is deterministic and independent of the order in which each format is processed. Jira issue: [FW-1801](https://angular-team.atlassian.net/browse/FW-1801) Fixes #34635 PR Close #34870
This commit is contained in:

committed by
Andrew Kushnir

parent
8215b345e3
commit
a10d2a8dc4
@ -8,6 +8,7 @@
|
||||
import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system';
|
||||
import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
||||
import {loadTestFiles} from '../../../test/helpers';
|
||||
import {JsonObject} from '../../src/packages/entry_point';
|
||||
import {DirectPackageJsonUpdater, PackageJsonUpdater} from '../../src/writing/package_json_updater';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
@ -151,5 +152,137 @@ runInEachFileSystem(() => {
|
||||
expect(() => update.writeChanges(_('/bar/package.json')))
|
||||
.toThrowError('Trying to apply a `PackageJsonUpdate` that has already been applied.');
|
||||
});
|
||||
|
||||
describe('(property positioning)', () => {
|
||||
// Helpers
|
||||
const createJsonFile = (jsonObj: JsonObject) => {
|
||||
const jsonPath = _('/foo/package.json');
|
||||
loadTestFiles([{name: jsonPath, contents: JSON.stringify(jsonObj)}]);
|
||||
return jsonPath;
|
||||
};
|
||||
const expectJsonEquals = (jsonFilePath: AbsoluteFsPath, jsonObj: JsonObject) =>
|
||||
expect(fs.readFile(jsonFilePath).trim()).toBe(JSON.stringify(jsonObj, null, 2));
|
||||
|
||||
it('should not change property positioning by default', () => {
|
||||
const jsonPath = createJsonFile({
|
||||
p2: '2',
|
||||
p1: {p12: '1.2', p11: '1.1'},
|
||||
});
|
||||
|
||||
updater.createUpdate()
|
||||
.addChange(['p1', 'p11'], '1.1-updated')
|
||||
.addChange(['p1', 'p10'], '1.0-added')
|
||||
.addChange(['p2'], '2-updated')
|
||||
.addChange(['p0'], '0-added')
|
||||
.writeChanges(jsonPath);
|
||||
|
||||
expectJsonEquals(jsonPath, {
|
||||
p2: '2-updated',
|
||||
p1: {p12: '1.2', p11: '1.1-updated', p10: '1.0-added'},
|
||||
p0: '0-added',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not change property positioning with `positioning: unimportant`', () => {
|
||||
const jsonPath = createJsonFile({
|
||||
p2: '2',
|
||||
p1: {p12: '1.2', p11: '1.1'},
|
||||
});
|
||||
|
||||
updater.createUpdate()
|
||||
.addChange(['p1', 'p11'], '1.1-updated', 'unimportant')
|
||||
.addChange(['p1', 'p10'], '1.0-added', 'unimportant')
|
||||
.addChange(['p2'], '2-updated', 'unimportant')
|
||||
.addChange(['p0'], '0-added', 'unimportant')
|
||||
.writeChanges(jsonPath);
|
||||
|
||||
expectJsonEquals(jsonPath, {
|
||||
p2: '2-updated',
|
||||
p1: {p12: '1.2', p11: '1.1-updated', p10: '1.0-added'},
|
||||
p0: '0-added',
|
||||
});
|
||||
});
|
||||
|
||||
it('should position added/updated properties alphabetically with `positioning: alphabetic`',
|
||||
() => {
|
||||
const jsonPath = createJsonFile({
|
||||
p2: '2',
|
||||
p1: {p12: '1.2', p11: '1.1'},
|
||||
});
|
||||
|
||||
updater.createUpdate()
|
||||
.addChange(['p1', 'p11'], '1.1-updated', 'alphabetic')
|
||||
.addChange(['p1', 'p10'], '1.0-added', 'alphabetic')
|
||||
.addChange(['p0'], '0-added', 'alphabetic')
|
||||
.addChange(['p3'], '3-added', 'alphabetic')
|
||||
.writeChanges(jsonPath);
|
||||
|
||||
expectJsonEquals(jsonPath, {
|
||||
p0: '0-added',
|
||||
p2: '2',
|
||||
p1: {p10: '1.0-added', p11: '1.1-updated', p12: '1.2'},
|
||||
p3: '3-added',
|
||||
});
|
||||
});
|
||||
|
||||
it('should position added/updated properties correctly with `positioning: {before: ...}`',
|
||||
() => {
|
||||
const jsonPath = createJsonFile({
|
||||
p2: '2',
|
||||
p1: {p12: '1.2', p11: '1.1'},
|
||||
});
|
||||
|
||||
updater.createUpdate()
|
||||
.addChange(['p0'], '0-added', {before: 'p1'})
|
||||
.addChange(['p1', 'p10'], '1.0-added', {before: 'p11'})
|
||||
.addChange(['p1', 'p12'], '1.2-updated', {before: 'p11'})
|
||||
.writeChanges(jsonPath);
|
||||
|
||||
expectJsonEquals(jsonPath, {
|
||||
p2: '2',
|
||||
p0: '0-added',
|
||||
p1: {p10: '1.0-added', p12: '1.2-updated', p11: '1.1'},
|
||||
});
|
||||
|
||||
// Verify that trying to add before non-existent property, puts updated property at the
|
||||
// end.
|
||||
updater.createUpdate()
|
||||
.addChange(['p3'], '3-added', {before: 'non-existent'})
|
||||
.addChange(['p1', 'p10'], '1.0-updated', {before: 'non-existent'})
|
||||
.writeChanges(jsonPath);
|
||||
|
||||
expectJsonEquals(jsonPath, {
|
||||
p2: '2',
|
||||
p0: '0-added',
|
||||
p1: {p12: '1.2-updated', p11: '1.1', p10: '1.0-updated'},
|
||||
p3: '3-added',
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore positioning when updating an in-memory representation', () => {
|
||||
const jsonObj = {
|
||||
p20: '20',
|
||||
p10: {p102: '10.2', p101: '10.1'},
|
||||
};
|
||||
const jsonPath = createJsonFile(jsonObj);
|
||||
|
||||
updater.createUpdate()
|
||||
.addChange(['p0'], '0-added', 'alphabetic')
|
||||
.addChange(['p1'], '1-added', 'unimportant')
|
||||
.addChange(['p2'], '2-added')
|
||||
.addChange(['p20'], '20-updated', 'alphabetic')
|
||||
.addChange(['p10', 'p103'], '10.3-added', {before: 'p102'})
|
||||
.addChange(['p10', 'p102'], '10.2-updated', {before: 'p103'})
|
||||
.writeChanges(jsonPath, jsonObj);
|
||||
|
||||
expect(JSON.stringify(jsonObj)).toBe(JSON.stringify({
|
||||
p20: '20-updated',
|
||||
p10: {p102: '10.2-updated', p101: '10.1', p103: '10.3-added'},
|
||||
p0: '0-added',
|
||||
p1: '1-added',
|
||||
p2: '2-added',
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user