Skip to content

Commit 894e008

Browse files
clydinhansl
authored andcommitted
fix(@angular/cli): migrate legacy global config when present
1 parent be87e0b commit 894e008

File tree

3 files changed

+130
-9
lines changed

3 files changed

+130
-9
lines changed

packages/@angular/cli/commands/config.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import { writeFileSync } from 'fs';
22
import { Command, Option } from '../models/command';
3-
import { getWorkspace, getWorkspaceRaw, validateWorkspace } from '../utilities/config';
3+
import {
4+
getWorkspace,
5+
getWorkspaceRaw,
6+
migrateLegacyGlobalConfig,
7+
validateWorkspace,
8+
} from '../utilities/config';
49
import {
510
JsonValue,
611
JsonArray,
712
JsonObject,
813
JsonParseMode,
914
experimental,
1015
parseJson,
16+
tags,
1117
} from '@angular-devkit/core';
1218

1319
const SilentError = require('silent-error');
@@ -165,10 +171,22 @@ export default class ConfigCommand extends Command {
165171
public run(options: ConfigOptions) {
166172
const level = options.global ? 'global' : 'local';
167173

168-
if (options.value == undefined) {
169-
const config =
174+
let config =
170175
(getWorkspace(level) as {} as { _workspace: experimental.workspace.WorkspaceSchema });
171176

177+
if (options.global && !config) {
178+
try {
179+
if (migrateLegacyGlobalConfig()) {
180+
config =
181+
(getWorkspace(level) as {} as { _workspace: experimental.workspace.WorkspaceSchema });
182+
this.logger.info(tags.oneLine`
183+
We found a global configuration that was used in Angular CLI 1.
184+
It has been automatically migrated.`);
185+
}
186+
} catch {}
187+
}
188+
189+
if (options.value == undefined) {
172190
if (!config) {
173191
throw new SilentError('No config found.');
174192
}

packages/@angular/cli/utilities/config.ts

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import {
77
JsonValue,
88
experimental,
99
normalize,
10+
parseJson,
1011
parseJsonAst,
1112
virtualFs,
13+
JsonObject,
1214
} from '@angular-devkit/core';
1315
import { NodeJsSyncHost } from '@angular-devkit/core/node';
1416
import { findUp } from './find-up';
@@ -165,6 +167,58 @@ export function getPackageManager(): string {
165167
return 'npm';
166168
}
167169

170+
export function migrateLegacyGlobalConfig(): boolean {
171+
const homeDir = os.homedir();
172+
if (homeDir) {
173+
const legacyGlobalConfigPath = path.join(homeDir, '.angular-cli.json');
174+
if (existsSync(legacyGlobalConfigPath)) {
175+
const content = readFileSync(legacyGlobalConfigPath, 'utf-8');
176+
const legacy = parseJson(content, JsonParseMode.Loose);
177+
if (!legacy || typeof legacy != 'object' || Array.isArray(legacy)) {
178+
return false;
179+
}
180+
181+
const cli: JsonObject = {};
182+
183+
if (legacy.packageManager && typeof legacy.packageManager == 'string'
184+
&& legacy.packageManager !== 'default') {
185+
cli['packageManager'] = legacy.packageManager;
186+
}
187+
188+
if (legacy.defaults && typeof legacy.defaults == 'object' && !Array.isArray(legacy.defaults)
189+
&& legacy.defaults.schematics && typeof legacy.defaults.schematics == 'object'
190+
&& !Array.isArray(legacy.defaults.schematics)
191+
&& typeof legacy.defaults.schematics.collection == 'string') {
192+
cli['defaultCollection'] = legacy.defaults.schematics.collection;
193+
}
194+
195+
if (legacy.warnings && typeof legacy.warnings == 'object'
196+
&& !Array.isArray(legacy.warnings)) {
197+
198+
let warnings: JsonObject = {};
199+
if (typeof legacy.warnings.versionMismatch == 'boolean') {
200+
warnings['versionMismatch'] = legacy.warnings.versionMismatch;
201+
}
202+
if (typeof legacy.warnings.typescriptMismatch == 'boolean') {
203+
warnings['typescriptMismatch'] = legacy.warnings.typescriptMismatch;
204+
}
205+
206+
if (Object.getOwnPropertyNames(warnings).length > 0) {
207+
cli['warnings'] = warnings;
208+
}
209+
}
210+
211+
if (Object.getOwnPropertyNames(cli).length > 0) {
212+
const globalPath = path.join(homeDir, globalFileName);
213+
writeFileSync(globalPath, JSON.stringify({ version: 1, cli }, null, 2));
214+
return true;
215+
}
216+
}
217+
}
218+
219+
return false;
220+
}
221+
168222
// Fallback, check for packageManager in config file in v1.* global config.
169223
function getLegacyPackageManager(): string | null {
170224
const homeDir = os.homedir();
@@ -173,14 +227,14 @@ function getLegacyPackageManager(): string | null {
173227
if (existsSync(legacyGlobalConfigPath)) {
174228
const content = readFileSync(legacyGlobalConfigPath, 'utf-8');
175229

176-
const ast = parseJsonAst(content, JsonParseMode.Loose);
177-
if (ast.kind != 'object') {
230+
const legacy = parseJson(content, JsonParseMode.Loose);
231+
if (!legacy || typeof legacy != 'object' || Array.isArray(legacy)) {
178232
return null;
179233
}
180-
const cfg = ast as JsonAstObject;
181-
if (cfg.value.packageManager && typeof cfg.value.packageManager === 'string' &&
182-
cfg.value.packageManager !== 'default') {
183-
return cfg.value.packageManager;
234+
235+
if (legacy.packageManager && typeof legacy.packageManager === 'string'
236+
&& legacy.packageManager !== 'default') {
237+
return legacy.packageManager;
184238
}
185239
}
186240
}

tests/acceptance/config.spec.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { migrateLegacyGlobalConfig } from '@angular/cli/utilities/config';
2+
import * as mockFs from 'mock-fs';
3+
import * as fs from 'fs';
4+
import * as os from 'os';
5+
import {join} from 'path';
6+
7+
8+
const homedir = os.homedir();
9+
describe('migrateLegacyGlobalConfig', () => {
10+
let validConfig: any;
11+
beforeEach(() => {
12+
validConfig = {
13+
packageManager: 'yarn',
14+
defaults: {
15+
schematics: {
16+
collection: 'collection name'
17+
}
18+
},
19+
warnings: {
20+
versionMismatch: true,
21+
typescriptMismatch: true
22+
}
23+
};
24+
});
25+
26+
afterEach(() => {
27+
mockFs.restore();
28+
});
29+
30+
it('should return false if old config does not exist', () => {
31+
mockFs({});
32+
const results = migrateLegacyGlobalConfig();
33+
expect(results).toEqual(false);
34+
});
35+
36+
it('should convert values to new config file', () => {
37+
mockFs({
38+
[join(homedir, '.angular-cli.json')]: JSON.stringify(validConfig)
39+
});
40+
const results = migrateLegacyGlobalConfig();
41+
expect(results).toEqual(true);
42+
const content = fs.readFileSync(join(homedir, '.angular-config.json'), 'utf-8');
43+
const newConfig = JSON.parse(content);
44+
expect(newConfig.cli.packageManager).toEqual('yarn');
45+
expect(newConfig.cli.defaultCollection).toEqual('collection name');
46+
expect(newConfig.cli.warnings.versionMismatch).toEqual(true);
47+
expect(newConfig.cli.warnings.typescriptMismatch).toEqual(true);
48+
});
49+
});

0 commit comments

Comments
 (0)