diff --git a/packages/schematics/update/update/index.ts b/packages/schematics/update/update/index.ts index e56e18cc6f..8a9bcb14ac 100644 --- a/packages/schematics/update/update/index.ts +++ b/packages/schematics/update/update/index.ts @@ -76,7 +76,8 @@ interface PackageInfo { } interface UpdateMetadata { - packageGroup: string[]; + packageGroupName?: string; + packageGroup: { [ packageName: string ]: string }; requirements: { [packageName: string]: string }; migrations?: string; } @@ -88,9 +89,9 @@ function _updatePeerVersion(infoMap: Map, name: string, ran return range; } if (maybePackageInfo.target) { - name = maybePackageInfo.target.updateMetadata.packageGroup[0] || name; + name = maybePackageInfo.target.updateMetadata.packageGroupName || name; } else { - name = maybePackageInfo.installed.updateMetadata.packageGroup[0] || name; + name = maybePackageInfo.installed.updateMetadata.packageGroupName || name; } const maybeTransform = peerCompatibleWhitelist[name]; @@ -353,7 +354,7 @@ function _getUpdateMetadata( const metadata = packageJson['ng-update']; const result: UpdateMetadata = { - packageGroup: [], + packageGroup: {}, requirements: {}, }; @@ -363,15 +364,28 @@ function _getUpdateMetadata( if (metadata['packageGroup']) { const packageGroup = metadata['packageGroup']; - // Verify that packageGroup is an array of strings. This is not an error but we still warn - // the user and ignore the packageGroup keys. - if (!Array.isArray(packageGroup) || packageGroup.some(x => typeof x != 'string')) { + // Verify that packageGroup is an array of strings or an map of versions. This is not an error + // but we still warn the user and ignore the packageGroup keys. + if (Array.isArray(packageGroup) && packageGroup.every(x => typeof x == 'string')) { + result.packageGroup = packageGroup.reduce((group, name) => { + group[name] = packageJson.version; + + return group; + }, result.packageGroup); + } else if (typeof packageGroup == 'object' && packageGroup + && Object.values(packageGroup).every(x => typeof x == 'string')) { + result.packageGroup = packageGroup; + } else { logger.warn( `packageGroup metadata of package ${packageJson.name} is malformed. Ignoring.`, ); - } else { - result.packageGroup = packageGroup; } + + result.packageGroupName = Object.keys(result.packageGroup)[0]; + } + + if (typeof metadata['packageGroupName'] == 'string') { + result.packageGroupName = metadata['packageGroupName']; } if (metadata['requirements']) { @@ -654,22 +668,34 @@ function _addPackageGroup( return; } - const packageGroup = ngUpdateMetadata['packageGroup']; + let packageGroup = ngUpdateMetadata['packageGroup']; if (!packageGroup) { return; } - if (!Array.isArray(packageGroup) || packageGroup.some(x => typeof x != 'string')) { + if (Array.isArray(packageGroup) && !packageGroup.some(x => typeof x != 'string')) { + packageGroup = packageGroup.reduce((acc, curr) => { + acc[curr] = maybePackage; + + return acc; + }, {} as { [name: string]: string }); + } + + // Only need to check if it's an object because we set it right the time before. + if (typeof packageGroup != 'object' + || packageGroup === null + || Object.values(packageGroup).some(v => typeof v != 'string') + ) { logger.warn(`packageGroup metadata of package ${npmPackageJson.name} is malformed.`); return; } - packageGroup + Object.keys(packageGroup) .filter(name => !packages.has(name)) // Don't override names from the command line. .filter(name => allDependencies.has(name)) // Remove packages that aren't installed. .forEach(name => { - packages.set(name, maybePackage); - }); + packages.set(name, packageGroup[name]); + }); } /** diff --git a/packages/schematics/update/update/index_spec.ts b/packages/schematics/update/update/index_spec.ts index b1c7c936eb..e91a726e03 100644 --- a/packages/schematics/update/update/index_spec.ts +++ b/packages/schematics/update/update/index_spec.ts @@ -222,6 +222,40 @@ describe('@schematics/update', () => { ).toPromise().then(done, done.fail); }, 45000); + it('uses packageGroup for versioning', async () => { + // Add the basic migration package. + const content = virtualFs.fileBufferToString(host.sync.read(normalize('/package.json'))); + const packageJson = JSON.parse(content); + const dependencies = packageJson['dependencies']; + dependencies['@angular-devkit-tests/update-package-group-1'] = '1.0.0'; + dependencies['@angular-devkit-tests/update-package-group-2'] = '1.0.0'; + host.sync.write( + normalize('/package.json'), + virtualFs.stringToFileBuffer(JSON.stringify(packageJson)), + ); + + await schematicRunner.runSchematicAsync('update', { + packages: ['@angular-devkit-tests/update-package-group-1'], + }, appTree).pipe( + map(tree => { + const packageJson = JSON.parse(tree.readContent('/package.json')); + const deps = packageJson['dependencies']; + expect(deps['@angular-devkit-tests/update-package-group-1']).toBe('1.2.0'); + expect(deps['@angular-devkit-tests/update-package-group-2']).toBe('2.0.0'); + + // Check install task. + expect(schematicRunner.tasks).toEqual([ + { + name: 'node-package', + options: jasmine.objectContaining({ + command: 'install', + }), + }, + ]); + }), + ).toPromise(); + }, 45000); + it('can migrate only', done => { // Add the basic migration package. const content = virtualFs.fileBufferToString(host.sync.read(normalize('/package.json'))); diff --git a/tests/schematics/update/packages/README.md b/tests/schematics/update/packages/README.md new file mode 100644 index 0000000000..83526f2cd7 --- /dev/null +++ b/tests/schematics/update/packages/README.md @@ -0,0 +1,14 @@ + +## Update Package Group packages + +* `update-package-group-1@1.0.0` -> `update-package-group2@^1` +* `update-package-group-2@1.0.0` -> `update-package-group1@1.0.0` +---- + +* `update-package-group-1@1.0.0` -> `update-package-group2@^1` +* `update-package-group-2@1.1.0` -> `update-package-group1@1.0.0` +---- + +* `update-package-group-1@1.2.0` -> `update-package-group2@^2` +* `update-package-group-2@2.0.0` -> `update-package-group1@^1` +---- diff --git a/tests/schematics/update/packages/update-package-group-1/package.json b/tests/schematics/update/packages/update-package-group-1/package.json new file mode 100644 index 0000000000..58a55973dd --- /dev/null +++ b/tests/schematics/update/packages/update-package-group-1/package.json @@ -0,0 +1,11 @@ +{ + "name": "@angular-devkit-tests/update-package-group-1", + "version": "1.2.0", + "description": "Tests", + "ng-update": { + "packageGroup": { + "@angular-devkit-tests/update-package-group-1": "", + "@angular-devkit-tests/update-package-group-2": "^2" + } + } +} diff --git a/tests/schematics/update/packages/update-package-group-2/package.json b/tests/schematics/update/packages/update-package-group-2/package.json new file mode 100644 index 0000000000..39231fc6a1 --- /dev/null +++ b/tests/schematics/update/packages/update-package-group-2/package.json @@ -0,0 +1,11 @@ +{ + "name": "@angular-devkit-tests/update-package-group-2", + "version": "2.0.0", + "description": "Tests", + "ng-update": { + "packageGroup": { + "@angular-devkit-tests/update-package-group-1": "^1", + "@angular-devkit-tests/update-package-group-2": "" + } + } +}