fix(ng-add): do not throw if custom builder is used for "test" (#14203)

* No longer throws an exception if someone runs `ng-add` but uses a custom builder for the `test` target. Since theme files are not necessarily mandatory for running tests, we should just show a warning instead of exiting the whole `ng-add` process.

Fixes #14176
This commit is contained in:
Paul Gschwendtner
2018-11-28 01:10:01 +01:00
committed by Jeremy Elbourn
parent 57fa085543
commit ee45aabb99
3 changed files with 66 additions and 24 deletions
+30
View File
@@ -207,6 +207,36 @@ describe('ng-add schematic', () => {
});
});
describe('custom project builders', () => {
/** Overwrites a target builder for the workspace in the given tree */
function overwriteTargetBuilder(tree: Tree, targetName: string, newBuilder: string) {
const workspace = getWorkspace(tree);
const project = getProjectFromWorkspace(workspace);
const targetConfig = project.architect && project.architect[targetName] ||
project.targets && project.targets[targetName];
targetConfig['builder'] = newBuilder;
tree.overwrite('/angular.json', JSON.stringify(workspace, null, 2));
}
it('should throw an error if the "build" target has been changed', () => {
overwriteTargetBuilder(appTree, 'build', 'thirdparty-builder');
expect(() => runner.runSchematic('ng-add-setup-project', {}, appTree))
.toThrowError(/not using the default builders.*build/);
});
it('should warn if the "test" target has been changed', () => {
overwriteTargetBuilder(appTree, 'test', 'thirdparty-test-builder');
spyOn(console, 'warn');
runner.runSchematic('ng-add-setup-project', {}, appTree);
expect(console.warn).toHaveBeenCalledWith(
jasmine.stringMatching(/not using the default builders.*cannot add the configured theme/));
});
});
describe('theme files', () => {
/** Path to the default prebuilt theme file that will be added when running ng-add. */
+36 -24
View File
@@ -8,7 +8,7 @@
import {normalize} from '@angular-devkit/core';
import {WorkspaceProject, WorkspaceSchema} from '@angular-devkit/core/src/workspace';
import {SchematicsException, Tree} from '@angular-devkit/schematics';
import {Tree} from '@angular-devkit/schematics';
import {
getProjectFromWorkspace,
getProjectStyleFile,
@@ -16,10 +16,10 @@ import {
} from '@angular/cdk/schematics';
import {InsertChange} from '@schematics/angular/utility/change';
import {getWorkspace} from '@schematics/angular/utility/config';
import {bold, red, yellow} from 'chalk';
import {join} from 'path';
import {Schema} from '../schema';
import {createCustomTheme} from './custom-theme';
import {red, bold, yellow} from 'chalk';
import {createCustomTheme} from './create-custom-theme';
/** Path segment that can be found in paths that refer to a prebuilt theme. */
const prebuiltThemePathSegment = '@angular/material/prebuilt-themes';
@@ -27,6 +27,12 @@ const prebuiltThemePathSegment = '@angular/material/prebuilt-themes';
/** Default file name of the custom theme that can be generated. */
const defaultCustomThemeFilename = 'custom-theme.scss';
/** Object that maps a CLI target to its default builder name. */
const defaultTargetBuilders = {
build: '@angular-devkit/build-angular:browser',
test: '@angular-devkit/build-angular:karma',
};
/** Add pre-built styles to the main project style file. */
export function addThemeToAppStyles(options: Schema): (host: Tree) => Tree {
return function(host: Tree): Tree {
@@ -34,10 +40,6 @@ export function addThemeToAppStyles(options: Schema): (host: Tree) => Tree {
const project = getProjectFromWorkspace(workspace, options.project);
const themeName = options.theme || 'indigo-pink';
// Because the build setup for the Angular CLI can be changed so dramatically, we can't know
// where to generate anything if the project is not using the default config for build and test.
assertDefaultBuildersConfigured(project);
if (themeName === 'custom') {
insertCustomTheme(project, options.project, host, workspace);
} else {
@@ -98,8 +100,12 @@ function insertPrebuiltTheme(project: WorkspaceProject, host: Tree, theme: strin
}
/** Adds a theming style entry to the given project target options. */
function addThemeStyleToTarget(project: WorkspaceProject, targetName: string, host: Tree,
assetPath: string, workspace: WorkspaceSchema) {
function addThemeStyleToTarget(project: WorkspaceProject, targetName: 'test' | 'build', host: Tree,
assetPath: string, workspace: WorkspaceSchema) {
// Do not update the builder options in case the target does not use the default CLI builder.
if (!validateDefaultTargetBuilder(project, targetName)) {
return;
}
const targetOptions = getProjectTargetOptions(project, targetName);
@@ -135,25 +141,31 @@ function addThemeStyleToTarget(project: WorkspaceProject, targetName: string, ho
host.overwrite('angular.json', JSON.stringify(workspace, null, 2));
}
/** Throws if the project is not using the default Angular devkit builders. */
function assertDefaultBuildersConfigured(project: WorkspaceProject) {
checkProjectTargetBuilder(project, 'build', '@angular-devkit/build-angular:browser');
checkProjectTargetBuilder(project, 'test', '@angular-devkit/build-angular:karma');
}
/**
* Checks if the specified project target is configured with the default builders which are
* provided by the Angular CLI.
* Validates that the specified project target is configured with the default builders which are
* provided by the Angular CLI. If the configured builder does not match the default builder,
* this function can either throw or just show a warning.
*/
function checkProjectTargetBuilder(project: WorkspaceProject, targetName: string,
defaultBuilder: string) {
function validateDefaultTargetBuilder(project: WorkspaceProject, targetName: 'build' | 'test') {
const defaultBuilder = defaultTargetBuilders[targetName];
const targetConfig = project.architect && project.architect[targetName] ||
project.targets && project.targets[targetName];
const isDefaultBuilder = targetConfig && targetConfig['builder'] === defaultBuilder;
if (!targetConfig || targetConfig['builder'] !== defaultBuilder) {
throw new SchematicsException(
`Your project is not using the default builders for "${targetName}". The Angular Material ` +
'schematics can only be used if the original builders from the Angular CLI are configured.');
// Because the build setup for the Angular CLI can be customized by developers, we can't know
// where to put the theme file in the workspace configuration if custom builders are being
// used. In case the builder has been changed for the "build" target, we throw an error and
// exit because setting up a theme is a primary goal of `ng-add`. Otherwise if just the "test"
// builder has been changed, we warn because a theme is not mandatory for running tests
// with Material. See: https://github.com/angular/material2/issues/14176
if (!isDefaultBuilder && targetName === 'build') {
throw new Error(`Your project is not using the default builders for "${targetName}". The ` +
`Angular Material schematics cannot add a theme to the workspace configuration if the ` +
`builder has been changed. Exiting..`);
} else if (!isDefaultBuilder) {
console.warn(`Your project is not using the default builders for "${targetName}". This ` +
`means that we cannot add the configured theme to the "${targetName}" target.`);
}
return isDefaultBuilder;
}