From e5efdc577be913870b29173345b8194b87420474 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Thu, 29 May 2025 09:24:14 -0400 Subject: [PATCH 1/7] fix(@angular/build): also disable outputMode in vitest unit-tests Application defined entry points (`browser`/`server`) are disabled when using the experimental unit-test builder. This allows the unit test files themselves to become the entry points for testing purposes. Previously, the `outputMode` option was not also disabled. This lead to errors if it was present in the build target configuration used for `unit-test` due to the `outputMode` option requiring the `server` option. (cherry picked from commit 020527e9dbfe09980b9d79442cb4e60b0bb8c34f) --- packages/angular/build/src/builders/unit-test/builder.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/angular/build/src/builders/unit-test/builder.ts b/packages/angular/build/src/builders/unit-test/builder.ts index 1fb1aa06a1b2..84b41f1a280a 100644 --- a/packages/angular/build/src/builders/unit-test/builder.ts +++ b/packages/angular/build/src/builders/unit-test/builder.ts @@ -122,6 +122,7 @@ export async function* execute( index: false, browser: undefined, server: undefined, + outputMode: undefined, localize: false, budgets: [], serviceWorker: false, From 525ddcbd290525e4dac2547c352cf6c774d728a2 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Thu, 29 May 2025 12:31:54 -0400 Subject: [PATCH 2/7] fix(@schematics/angular): only overwrite JSON file if actually changed The JSON file helper utility used within the Angular schematics now contains additional checks when attempting to modify a file to avoid overwriting a file if no actual changes will occur after a modify request. (cherry picked from commit 664e6c7286c13e61eadfd693162edac4e471ab5b) --- packages/schematics/angular/utility/json-file.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/schematics/angular/utility/json-file.ts b/packages/schematics/angular/utility/json-file.ts index dffb7a94f997..e7c767745b90 100644 --- a/packages/schematics/angular/utility/json-file.ts +++ b/packages/schematics/angular/utility/json-file.ts @@ -95,9 +95,16 @@ export class JSONFile { }, }); - this.content = applyEdits(this.content, edits); - this.host.overwrite(this.path, this.content); - this._jsonAst = undefined; + if (edits.length > 0) { + const editedContent = applyEdits(this.content, edits); + + // Update the file content if it changed + if (editedContent !== this.content) { + this.content = editedContent; + this.host.overwrite(this.path, editedContent); + this._jsonAst = undefined; + } + } } remove(jsonPath: JSONPath): void { From 83c820e5ab55d01662417a51e4cc8d094e409fc6 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Thu, 29 May 2025 10:15:56 -0400 Subject: [PATCH 3/7] fix(@schematics/angular): remove karma config devkit package usages during application migration When performing an `ng update` to Angular v20, the application migration will detect the usage of the `karma` builder's `karmaConfig` option and attempt to remove usages of the no longer needed `@angular-devkit/build-angular` karma framework and plugin usage. While the karma framework usage will be specifically ignored when using the `@angular/build:karma` builder, the plugin usage leverages a direct `require` within the configuration file. Regardless of the ability of the builder to ignore, neither usage is needed with `@angular/build:karma` and removing the code aligns with what would be generated by `ng generate config karma`. (cherry picked from commit a2aba4c4b90e3ea227b3c3c74b8faba7de01fe22) --- .../use-application-builder/migration.ts | 38 +++++++- .../use-application-builder/migration_spec.ts | 97 +++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/packages/schematics/angular/migrations/use-application-builder/migration.ts b/packages/schematics/angular/migrations/use-application-builder/migration.ts index 396ba48430d2..6a59c212fa21 100644 --- a/packages/schematics/angular/migrations/use-application-builder/migration.ts +++ b/packages/schematics/angular/migrations/use-application-builder/migration.ts @@ -232,6 +232,8 @@ function updateProjects(tree: Tree, context: SchematicContext) { // Use @angular/build directly if there is no devkit package usage if (!hasAngularDevkitUsage) { + const karmaConfigFiles = new Set(); + for (const [, target] of allWorkspaceTargets(workspace)) { switch (target.builder) { case Builders.Application: @@ -245,9 +247,15 @@ function updateProjects(tree: Tree, context: SchematicContext) { break; case Builders.Karma: target.builder = '@angular/build:karma'; - // Remove "builderMode" option since the builder will always use "application" for (const [, karmaOptions] of allTargetOptions(target)) { + // Remove "builderMode" option since the builder will always use "application" delete karmaOptions['builderMode']; + + // Collect custom karma configurations for @angular-devkit/build-angular plugin removal + const karmaConfig = karmaOptions['karmaConfig']; + if (karmaConfig && typeof karmaConfig === 'string') { + karmaConfigFiles.add(karmaConfig); + } } break; case Builders.NgPackagr: @@ -292,6 +300,34 @@ function updateProjects(tree: Tree, context: SchematicContext) { }), ); } + + for (const karmaConfigFile of karmaConfigFiles) { + if (!tree.exists(karmaConfigFile)) { + continue; + } + + try { + const originalKarmaConfigText = tree.readText(karmaConfigFile); + const updatedKarmaConfigText = originalKarmaConfigText + .replaceAll(`require('@angular-devkit/build-angular/plugins/karma'),`, '') + .replaceAll(`require('@angular-devkit/build-angular/plugins/karma')`, ''); + + if (updatedKarmaConfigText.includes('@angular-devkit/build-angular/plugins')) { + throw new Error( + 'Migration does not support found usage of "@angular-devkit/build-angular".', + ); + } else { + tree.overwrite(karmaConfigFile, updatedKarmaConfigText); + } + } catch (error) { + const reason = error instanceof Error ? `Reason: ${error.message}` : ''; + context.logger.warn( + `Unable to update custom karma configuration file ("${karmaConfigFile}"). ` + + reason + + '\nReferences to the "@angular-devkit/build-angular" package within the file may need to be removed manually.', + ); + } + } } return chain(rules); diff --git a/packages/schematics/angular/migrations/use-application-builder/migration_spec.ts b/packages/schematics/angular/migrations/use-application-builder/migration_spec.ts index 3adef7d419eb..a8d50193958e 100644 --- a/packages/schematics/angular/migrations/use-application-builder/migration_spec.ts +++ b/packages/schematics/angular/migrations/use-application-builder/migration_spec.ts @@ -130,6 +130,103 @@ describe(`Migration to use the application builder`, () => { expect(builderMode).toBeUndefined(); }); + it(`should update file for 'karmaConfig' karma option (no require trailing comma)`, async () => { + addWorkspaceTarget(tree, 'test', { + 'builder': Builders.Karma, + 'options': { + 'karmaConfig': './karma.conf.js', + 'polyfills': ['zone.js', 'zone.js/testing'], + 'tsConfig': 'projects/app-a/tsconfig.spec.json', + }, + }); + tree.create( + './karma.conf.js', + ` + module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ] + }); + };`, + ); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { app }, + } = JSON.parse(newTree.readContent('/angular.json')); + + const { karmaConfig } = app.architect['test'].options; + expect(karmaConfig).toBe('./karma.conf.js'); + + const karmaConfigText = newTree.readText('./karma.conf.js'); + expect(karmaConfigText).not.toContain(`require('@angular-devkit/build-angular/plugins/karma')`); + }); + + it(`should update file for 'karmaConfig' karma option (require trailing comma)`, async () => { + addWorkspaceTarget(tree, 'test', { + 'builder': Builders.Karma, + 'options': { + 'karmaConfig': './karma.conf.js', + 'polyfills': ['zone.js', 'zone.js/testing'], + 'tsConfig': 'projects/app-a/tsconfig.spec.json', + }, + }); + tree.create( + './karma.conf.js', + ` + module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma'), + ] + }); + };`, + ); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { app }, + } = JSON.parse(newTree.readContent('/angular.json')); + + const { karmaConfig } = app.architect['test'].options; + expect(karmaConfig).toBe('./karma.conf.js'); + + const karmaConfigText = newTree.readText('./karma.conf.js'); + expect(karmaConfigText).not.toContain(`require('@angular-devkit/build-angular/plugins/karma')`); + }); + + it(`should ignore missing file for 'karmaConfig' karma option`, async () => { + addWorkspaceTarget(tree, 'test', { + 'builder': Builders.Karma, + 'options': { + 'karmaConfig': './karma.conf.js', + 'polyfills': ['zone.js', 'zone.js/testing'], + 'tsConfig': 'projects/app-a/tsconfig.spec.json', + }, + }); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { + projects: { app }, + } = JSON.parse(newTree.readContent('/angular.json')); + + const { karmaConfig } = app.architect['test'].options; + expect(karmaConfig).toBe('./karma.conf.js'); + }); + it('should remove tilde prefix from CSS @import specifiers', async () => { // Replace outputPath tree.create( From 5814393dbb2f9227ce10f1df77a8deee06c7d1c5 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 2 Jun 2025 12:27:47 -0400 Subject: [PATCH 4/7] fix(@angular/build): resolve junit karma reporter output to workspace root To maintain behavior with the Webpack-based karma unit-testing available via `@angular-devkit/build-angular`, the application build system based karma testing will now resolve the output directory location of the junit karma reporter to the same workspace root location. This is only performed if the `junit` reporter is enabled and the reporter's `outputDir` option is not an absolute path. (cherry picked from commit bec42f70c518144917999f7efdcee11554a34755) --- .../src/builders/karma/application_builder.ts | 29 +++++++++++++++++++ .../e2e/tests/test/karma-junit-output.ts | 27 +++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/legacy-cli/e2e/tests/test/karma-junit-output.ts diff --git a/packages/angular/build/src/builders/karma/application_builder.ts b/packages/angular/build/src/builders/karma/application_builder.ts index fc92ed59dbc0..55a10b37c54e 100644 --- a/packages/angular/build/src/builders/karma/application_builder.ts +++ b/packages/angular/build/src/builders/karma/application_builder.ts @@ -577,6 +577,35 @@ async function initializeApplication( parsedKarmaConfig.reporters ??= []; parsedKarmaConfig.reporters.push(AngularPolyfillsPlugin.NAME); + // Adjust karma junit reporter outDir location to maintain previous (devkit) behavior + // The base path for the reporter was previously the workspace root. + // To keep the files in the same location, the reporter's output directory is adjusted + // to be relative to the workspace root when using junit. + if (parsedKarmaConfig.reporters?.some((reporter) => reporter === 'junit')) { + if ('junitReporter' in parsedKarmaConfig) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const junitReporterOptions = (parsedKarmaConfig as any)['junitReporter'] as { + outputDir?: unknown; + }; + if (junitReporterOptions.outputDir == undefined) { + junitReporterOptions.outputDir = context.workspaceRoot; + } else if ( + typeof junitReporterOptions.outputDir === 'string' && + !path.isAbsolute(junitReporterOptions.outputDir) + ) { + junitReporterOptions.outputDir = path.join( + context.workspaceRoot, + junitReporterOptions.outputDir, + ); + } + } else { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (parsedKarmaConfig as any)['junitReporter'] = { + outputDir: context.workspaceRoot, + }; + } + } + // When using code-coverage, auto-add karma-coverage. // This was done as part of the karma plugin for webpack. if ( diff --git a/tests/legacy-cli/e2e/tests/test/karma-junit-output.ts b/tests/legacy-cli/e2e/tests/test/karma-junit-output.ts new file mode 100644 index 000000000000..056adea26ab3 --- /dev/null +++ b/tests/legacy-cli/e2e/tests/test/karma-junit-output.ts @@ -0,0 +1,27 @@ +import { expectFileMatchToExist, replaceInFile } from '../../utils/fs'; +import { installPackage } from '../../utils/packages'; +import { silentNg } from '../../utils/process'; + +const E2E_CUSTOM_LAUNCHER = ` + customLaunchers: { + ChromeHeadlessNoSandbox: { + base: 'ChromeHeadless', + flags: ['--no-sandbox', '--headless', '--disable-gpu', '--disable-dev-shm-usage'], + }, + }, + restartOnFileChange: true, +`; + +export default async function () { + await installPackage('karma-junit-reporter'); + await silentNg('generate', 'config', 'karma'); + + await replaceInFile('karma.conf.js', 'karma-jasmine-html-reporter', 'karma-junit-reporter'); + await replaceInFile('karma.conf.js', `'kjhtml'`, `'junit'`); + + await replaceInFile('karma.conf.js', `restartOnFileChange: true`, E2E_CUSTOM_LAUNCHER); + + await silentNg('test', '--no-watch'); + + await expectFileMatchToExist('.', /TESTS\-.+\.xml/); +} From 87266b38a09ce783ac6d18f532ebe1f8ae5954c0 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Thu, 29 May 2025 16:48:32 -0400 Subject: [PATCH 5/7] fix(@schematics/angular): skip zone.js dependency for zoneless applications A newly generated application no longer adds the `zone.js` dependency to the workspace if the `zoneless` option is enabled. (cherry picked from commit 7ca250a5617379eff57f5b50b0b55d0df31cc1af) --- .../schematics/angular/application/index.ts | 8 ++++ .../angular/application/index_spec.ts | 42 +++++++++++++++++++ packages/schematics/angular/library/index.ts | 13 ++++-- .../schematics/angular/library/index_spec.ts | 7 ++++ .../workspace/files/package.json.template | 3 +- .../angular/workspace/index_spec.ts | 1 - 6 files changed, 68 insertions(+), 6 deletions(-) diff --git a/packages/schematics/angular/application/index.ts b/packages/schematics/angular/application/index.ts index 825f98c04158..14c0688cf334 100644 --- a/packages/schematics/angular/application/index.ts +++ b/packages/schematics/angular/application/index.ts @@ -149,6 +149,14 @@ function addDependenciesToPackageJson(options: ApplicationOptions) { }, ].forEach((dependency) => addPackageJsonDependency(host, dependency)); + if (!options.zoneless) { + addPackageJsonDependency(host, { + type: NodeDependencyType.Default, + name: 'zone.js', + version: latestVersions['zone.js'], + }); + } + if (!options.skipInstall) { context.addTask(new NodePackageInstallTask()); } diff --git a/packages/schematics/angular/application/index_spec.ts b/packages/schematics/angular/application/index_spec.ts index 458f91d6eef0..60700c9f45ff 100644 --- a/packages/schematics/angular/application/index_spec.ts +++ b/packages/schematics/angular/application/index_spec.ts @@ -268,6 +268,48 @@ describe('Application Schematic', () => { expect(pkg.devDependencies['typescript']).toEqual(latestVersions['typescript']); }); + it('should include zone.js if "zoneless" option is false', async () => { + const tree = await schematicRunner.runSchematic( + 'application', + { + ...defaultOptions, + zoneless: false, + }, + workspaceTree, + ); + + const pkg = JSON.parse(tree.readContent('/package.json')); + expect(pkg.dependencies['zone.js']).toEqual(latestVersions['zone.js']); + }); + + it('should include zone.js if "zoneless" option is not present', async () => { + const tree = await schematicRunner.runSchematic( + 'application', + { + ...defaultOptions, + zoneless: undefined, + }, + workspaceTree, + ); + + const pkg = JSON.parse(tree.readContent('/package.json')); + expect(pkg.dependencies['zone.js']).toEqual(latestVersions['zone.js']); + }); + + it('should not include zone.js if "zoneless" option is true', async () => { + const tree = await schematicRunner.runSchematic( + 'application', + { + ...defaultOptions, + zoneless: true, + }, + workspaceTree, + ); + + const pkg = JSON.parse(tree.readContent('/package.json')); + expect(pkg.dependencies['zone.js']).toBeUndefined(); + }); + it(`should not override existing users dependencies`, async () => { const oldPackageJson = workspaceTree.readContent('package.json'); workspaceTree.overwrite( diff --git a/packages/schematics/angular/library/index.ts b/packages/schematics/angular/library/index.ts index b409d986dd57..d96cc8b505a8 100644 --- a/packages/schematics/angular/library/index.ts +++ b/packages/schematics/angular/library/index.ts @@ -22,7 +22,11 @@ import { } from '@angular-devkit/schematics'; import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; import { join } from 'node:path/posix'; -import { NodeDependencyType, addPackageJsonDependency } from '../utility/dependencies'; +import { + NodeDependencyType, + addPackageJsonDependency, + getPackageJsonDependency, +} from '../utility/dependencies'; import { JSONFile } from '../utility/json-file'; import { latestVersions } from '../utility/latest-versions'; import { relativePathToWorkspaceRoot } from '../utility/paths'; @@ -96,6 +100,7 @@ function addLibToWorkspaceFile( options: LibraryOptions, projectRoot: string, projectName: string, + hasZoneDependency: boolean, ): Rule { return updateWorkspace((workspace) => { workspace.projects.add({ @@ -121,7 +126,7 @@ function addLibToWorkspaceFile( builder: Builders.BuildKarma, options: { tsConfig: `${projectRoot}/tsconfig.spec.json`, - polyfills: ['zone.js', 'zone.js/testing'], + polyfills: hasZoneDependency ? ['zone.js', 'zone.js/testing'] : undefined, }, }, }, @@ -172,9 +177,11 @@ export default function (options: LibraryOptions): Rule { move(libDir), ]); + const hasZoneDependency = getPackageJsonDependency(host, 'zone.js') !== null; + return chain([ mergeWith(templateSource), - addLibToWorkspaceFile(options, libDir, packageName), + addLibToWorkspaceFile(options, libDir, packageName, hasZoneDependency), options.skipPackageJson ? noop() : addDependenciesToPackageJson(), options.skipTsConfig ? noop() : updateTsConfig(packageName, './' + distRoot), options.skipTsConfig diff --git a/packages/schematics/angular/library/index_spec.ts b/packages/schematics/angular/library/index_spec.ts index 1d5503d70b38..97e517767f1f 100644 --- a/packages/schematics/angular/library/index_spec.ts +++ b/packages/schematics/angular/library/index_spec.ts @@ -195,6 +195,13 @@ describe('Library Schematic', () => { expect(workspace.projects.foo.prefix).toEqual('pre'); }); + it(`should not add zone.js to test polyfills when no zone.js dependency`, async () => { + const tree = await schematicRunner.runSchematic('library', defaultOptions, workspaceTree); + + const workspace = getJsonFileContent(tree, '/angular.json'); + expect(workspace.projects.foo.architect.test.options.polyfills).toBeUndefined(); + }); + it('should handle a pascalCasedName', async () => { const options = { ...defaultOptions, name: 'pascalCasedName' }; const tree = await schematicRunner.runSchematic('library', options, workspaceTree); diff --git a/packages/schematics/angular/workspace/files/package.json.template b/packages/schematics/angular/workspace/files/package.json.template index 4ee0cdd9ab73..dcbe6939829d 100644 --- a/packages/schematics/angular/workspace/files/package.json.template +++ b/packages/schematics/angular/workspace/files/package.json.template @@ -17,8 +17,7 @@ "@angular/platform-browser": "<%= latestVersions.Angular %>", "@angular/router": "<%= latestVersions.Angular %>", "rxjs": "<%= latestVersions['rxjs'] %>", - "tslib": "<%= latestVersions['tslib'] %>", - "zone.js": "<%= latestVersions['zone.js'] %>" + "tslib": "<%= latestVersions['tslib'] %>" }, "devDependencies": { "@angular/cli": "<%= '^' + version %>", diff --git a/packages/schematics/angular/workspace/index_spec.ts b/packages/schematics/angular/workspace/index_spec.ts index 520452e71b89..21efd7275b82 100644 --- a/packages/schematics/angular/workspace/index_spec.ts +++ b/packages/schematics/angular/workspace/index_spec.ts @@ -58,7 +58,6 @@ describe('Workspace Schematic', () => { const pkg = JSON.parse(tree.readContent('/package.json')); expect(pkg.dependencies['@angular/core']).toEqual(latestVersions.Angular); expect(pkg.dependencies['rxjs']).toEqual(latestVersions['rxjs']); - expect(pkg.dependencies['zone.js']).toEqual(latestVersions['zone.js']); expect(pkg.devDependencies['typescript']).toEqual(latestVersions['typescript']); }); From 0883248cbdebcad09393349a0a5d9487b2a452ae Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:53:57 +0000 Subject: [PATCH 6/7] fix(@angular/cli): improve Node.js version check and error messages Enhances the Node.js version validation to include Node.js 22.12 (cherry picked from commit abe69ddb1ab3ec303a4d867a89853a75f2773067) --- packages/angular/cli/bin/ng.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/angular/cli/bin/ng.js b/packages/angular/cli/bin/ng.js index 392578c684cb..e0f5eb36a2ef 100755 --- a/packages/angular/cli/bin/ng.js +++ b/packages/angular/cli/bin/ng.js @@ -31,7 +31,6 @@ try { } const rawCommandName = process.argv[2]; - if (rawCommandName === '--get-yargs-completions' || rawCommandName === 'completion') { // Skip Node.js supported checks when running ng completion. // A warning at this stage could cause a broken source action (`source <(ng completion script)`) when in the shell init script. @@ -43,8 +42,9 @@ if (rawCommandName === '--get-yargs-completions' || rawCommandName === 'completi // This node version check ensures that extremely old versions of node are not used. // These may not support ES2015 features such as const/let/async/await/etc. // These would then crash with a hard to diagnose error message. -var version = process.versions.node.split('.').map((part) => Number(part)); -if (version[0] % 2 === 1) { +const [major, minor] = process.versions.node.split('.', 2).map((part) => Number(part)); + +if (major % 2 === 1) { // Allow new odd numbered releases with a warning (currently v17+) console.warn( 'Node.js version ' + @@ -55,13 +55,13 @@ if (version[0] % 2 === 1) { ); require('./bootstrap'); -} else if (version[0] < 20 || (version[0] === 20 && version[1] < 11)) { - // Error and exit if less than 20.11 +} else if (major < 20 || (major === 20 && minor < 19) || (major === 22 && minor < 12)) { + // Error and exit if less than 20.19 or 22.12 console.error( 'Node.js version ' + process.version + ' detected.\n' + - 'The Angular CLI requires a minimum Node.js version of v20.11.\n\n' + + 'The Angular CLI requires a minimum Node.js version of v20.19 or v22.12.\n\n' + 'Please update your Node.js version or visit https://nodejs.org/ for additional instructions.\n', ); From 4e7e0b073f866eedf58bd1fc43be57b1b849cd88 Mon Sep 17 00:00:00 2001 From: Doug Parker Date: Wed, 4 Jun 2025 10:23:05 -0700 Subject: [PATCH 7/7] release: cut the v20.0.1 release --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b1ee5c38a4..503b2567d3fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ + + +# 20.0.1 (2025-06-04) + +### @angular/cli + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ------------------------------------------------ | +| [0883248cb](https://github.com/angular/angular-cli/commit/0883248cbdebcad09393349a0a5d9487b2a452ae) | fix | improve Node.js version check and error messages | + +### @schematics/angular + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------------------- | +| [525ddcbd2](https://github.com/angular/angular-cli/commit/525ddcbd290525e4dac2547c352cf6c774d728a2) | fix | only overwrite JSON file if actually changed | +| [83c820e5a](https://github.com/angular/angular-cli/commit/83c820e5ab55d01662417a51e4cc8d094e409fc6) | fix | remove karma config devkit package usages during application migration | +| [87266b38a](https://github.com/angular/angular-cli/commit/87266b38a09ce783ac6d18f532ebe1f8ae5954c0) | fix | skip zone.js dependency for zoneless applications | + +### @angular/build + +| Commit | Type | Description | +| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------- | +| [e5efdc577](https://github.com/angular/angular-cli/commit/e5efdc577be913870b29173345b8194b87420474) | fix | also disable outputMode in vitest unit-tests | +| [5814393db](https://github.com/angular/angular-cli/commit/5814393dbb2f9227ce10f1df77a8deee06c7d1c5) | fix | resolve junit karma reporter output to workspace root | + + + # 20.0.0 (2025-05-28) diff --git a/package.json b/package.json index af8ea1d9c5fe..d21b5262a7a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/devkit-repo", - "version": "20.0.0", + "version": "20.0.1", "private": true, "description": "Software Development Kit for Angular", "keywords": [