Skip to content

Commit 2d6c2f3

Browse files
Added support for upgrading [email protected] projects
1 parent c4bd2bb commit 2d6c2f3

168 files changed

Lines changed: 3779 additions & 7 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/manual/docs/cmd/spfx/project/project-upgrade.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ Option|Description
2323

2424
## Remarks
2525

26-
The `spfx project upgrade` command helps you upgrade your SharePoint Framework project to the specified version. If no version is specified, the command will upgrade to the latest version of the SharePoint Framework it supports (v1.7.0).
26+
The `spfx project upgrade` command helps you upgrade your SharePoint Framework project to the specified version. If no version is specified, the command will upgrade to the latest version of the SharePoint Framework it supports (v1.7.1).
2727

2828
This command doesn't change your project files. Instead, it gives you a report with all steps necessary to upgrade your project to the specified version of the SharePoint Framework. Changing project files is error-prone, especially when it comes to updating your solution's code. This is why at this moment, this command produces a report that you can use yourself to perform the necessary updates and verify that everything is working as expected.
2929

30-
Using this command you can upgrade SharePoint Framework projects built using versions: 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, 1.1.3, 1.2.0, 1.3.0, 1.3.1, 1.3.2, 1.3.4, 1.4.0, 1.4.1, 1.5.0, 1.5.1 and 1.6.0.
30+
Using this command you can upgrade SharePoint Framework projects built using versions: 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, 1.1.3, 1.2.0, 1.3.0, 1.3.1, 1.3.2, 1.3.4, 1.4.0, 1.4.1, 1.5.0, 1.5.1, 1.6.0 and 1.7.0.
3131

3232
## Examples
3333

src/o365/spfx/commands/project/project-upgrade.spec.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,68 @@ describe(commands.PROJECT_UPGRADE, () => {
14021402
});
14031403
//#endregion
14041404

1405+
//#region 1.7.0
1406+
it('e2e: shows correct number of findings for upgrading application customizer 1.7.0 project to 1.7.1', () => {
1407+
sinon.stub(command as any, 'getProjectRoot').callsFake(_ => path.join(process.cwd(), 'src/o365/spfx/commands/project/project-upgrade/test-projects/spfx-170-applicationcustomizer'));
1408+
1409+
cmdInstance.action = command.action();
1410+
cmdInstance.action({ options: { toVersion: '1.7.1', output: 'json' } }, (err?: any) => {
1411+
const findings: Finding[] = log[0];
1412+
assert.equal(findings.length, 11);
1413+
});
1414+
});
1415+
1416+
it('e2e: shows correct number of findings for upgrading field customizer react 1.7.0 project to 1.7.1', () => {
1417+
sinon.stub(command as any, 'getProjectRoot').callsFake(_ => path.join(process.cwd(), 'src/o365/spfx/commands/project/project-upgrade/test-projects/spfx-170-fieldcustomizer-react'));
1418+
1419+
cmdInstance.action = command.action();
1420+
cmdInstance.action({ options: { toVersion: '1.7.1', output: 'json' } }, (err?: any) => {
1421+
const findings: Finding[] = log[0];
1422+
assert.equal(findings.length, 11);
1423+
});
1424+
});
1425+
1426+
it('e2e: shows correct number of findings for upgrading list view command set 1.7.0 project to 1.7.1', () => {
1427+
sinon.stub(command as any, 'getProjectRoot').callsFake(_ => path.join(process.cwd(), 'src/o365/spfx/commands/project/project-upgrade/test-projects/spfx-170-listviewcommandset'));
1428+
1429+
cmdInstance.action = command.action();
1430+
cmdInstance.action({ options: { toVersion: '1.7.1', output: 'json' } }, (err?: any) => {
1431+
const findings: Finding[] = log[0];
1432+
assert.equal(findings.length, 11);
1433+
});
1434+
});
1435+
1436+
it('e2e: shows correct number of findings for upgrading ko web part 1.7.0 project to 1.7.1', () => {
1437+
sinon.stub(command as any, 'getProjectRoot').callsFake(_ => path.join(process.cwd(), 'src/o365/spfx/commands/project/project-upgrade/test-projects/spfx-170-webpart-ko'));
1438+
1439+
cmdInstance.action = command.action();
1440+
cmdInstance.action({ options: { toVersion: '1.7.1', output: 'json' } }, (err?: any) => {
1441+
const findings: Finding[] = log[0];
1442+
assert.equal(findings.length, 11);
1443+
});
1444+
});
1445+
1446+
it('e2e: shows correct number of findings for upgrading no framework web part 1.7.0 project to 1.7.1', () => {
1447+
sinon.stub(command as any, 'getProjectRoot').callsFake(_ => path.join(process.cwd(), 'src/o365/spfx/commands/project/project-upgrade/test-projects/spfx-170-webpart-nolib'));
1448+
1449+
cmdInstance.action = command.action();
1450+
cmdInstance.action({ options: { toVersion: '1.7.1', output: 'json' } }, (err?: any) => {
1451+
const findings: Finding[] = log[0];
1452+
assert.equal(findings.length, 11);
1453+
});
1454+
});
1455+
1456+
it('e2e: shows correct number of findings for upgrading react web part 1.7.0 project to 1.7.1', () => {
1457+
sinon.stub(command as any, 'getProjectRoot').callsFake(_ => path.join(process.cwd(), 'src/o365/spfx/commands/project/project-upgrade/test-projects/spfx-170-webpart-react'));
1458+
1459+
cmdInstance.action = command.action();
1460+
cmdInstance.action({ options: { toVersion: '1.7.1', output: 'json' } }, (err?: any) => {
1461+
const findings: Finding[] = log[0];
1462+
assert.equal(findings.length, 12);
1463+
});
1464+
});
1465+
//#endregion
1466+
14051467
it('shows all information with output format json', () => {
14061468
sinon.stub(command as any, 'getProjectRoot').callsFake(_ => path.join(process.cwd(), 'src/o365/spfx/commands/project/project-upgrade/test-projects/spfx-151-fieldcustomizer-react'));
14071469

src/o365/spfx/commands/project/project-upgrade.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ class SpfxProjectUpgradeCommand extends Command {
4646
'1.5.0',
4747
'1.5.1',
4848
'1.6.0',
49-
'1.7.0'
49+
'1.7.0',
50+
'1.7.1'
5051
];
5152

5253
public static ERROR_NO_PROJECT_ROOT_FOLDER: number = 1;
@@ -589,7 +590,7 @@ ${f.resolution}
589590
The ${this.name} command helps you upgrade your SharePoint Framework
590591
project to the specified version. If no version is specified, the command
591592
will upgrade to the latest version of the SharePoint Framework it supports
592-
(v1.7.0).
593+
(v1.7.1).
593594
594595
This command doesn't change your project files. Instead, it gives you
595596
a report with all steps necessary to upgrade your project to the specified
@@ -601,7 +602,7 @@ ${f.resolution}
601602
602603
Using this command you can upgrade SharePoint Framework projects built using
603604
versions: 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, 1.1.3, 1.2.0, 1.3.0, 1.3.1,
604-
1.3.2, 1.3.4, 1.4.0, 1.4.1, 1.5.0, 1.5.1 and 1.6.0.
605+
1.3.2, 1.3.4, 1.4.0, 1.4.1, 1.5.0, 1.5.1, 1.6.0 and 1.7.0.
605606
606607
Examples:
607608

src/o365/spfx/commands/project/project-upgrade/model/PackageJson.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ import { Hash } from "../";
33
export interface PackageJson {
44
dependencies: Hash;
55
devDependencies?: Hash;
6+
resolutions?: Hash;
67
}
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1+
import { Hash } from "../Hash";
2+
13
export interface VsCodeLaunchJson {
24
version: string;
3-
configurations?: any[];
5+
configurations?: VsCodeLaunchJsonConfiguration[];
6+
}
7+
8+
export interface VsCodeLaunchJsonConfiguration {
9+
sourceMapPathOverrides?: Hash;
410
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import * as assert from 'assert';
2+
import * as fs from 'fs';
3+
import { Finding } from '../Finding';
4+
import { Project } from '../model';
5+
import { FN014006_CODE_launch_sourceMapPathOverrides } from './FN014006_CODE_launch_sourceMapPathOverrides';
6+
import Utils from '../../../../../../Utils';
7+
8+
describe('FN014006_CODE_launch_sourceMapPathOverrides', () => {
9+
let findings: Finding[];
10+
let rule: FN014006_CODE_launch_sourceMapPathOverrides;
11+
afterEach(() => {
12+
Utils.restore(fs.existsSync);
13+
});
14+
15+
beforeEach(() => {
16+
findings = [];
17+
rule = new FN014006_CODE_launch_sourceMapPathOverrides('webpack:///.././src/*', '${webRoot}/src/*');
18+
});
19+
20+
it('doesn\'t return notifications if vscode folder doesn\'t exist', () => {
21+
const project: Project = {
22+
path: '/usr/tmp'
23+
};
24+
rule.visit(project, findings);
25+
assert.equal(findings.length, 0);
26+
});
27+
28+
it('doesn\'t return notifications if vscode launch file doesn\'t exist', () => {
29+
const project: Project = {
30+
path: '/usr/tmp',
31+
vsCode: {}
32+
};
33+
rule.visit(project, findings);
34+
assert.equal(findings.length, 0);
35+
});
36+
37+
it('doesn\'t return notifications if vscode launch file doesn\'t contain configurations', () => {
38+
const project: Project = {
39+
path: '/usr/tmp',
40+
vsCode: {
41+
launchJson: {
42+
version: '1.0'
43+
}
44+
}
45+
};
46+
rule.visit(project, findings);
47+
assert.equal(findings.length, 0);
48+
});
49+
50+
it('doesn\'t return notifications if none of the configurations contains sourceMapPathOverrides', () => {
51+
const project: Project = {
52+
path: '/usr/tmp',
53+
vsCode: {
54+
launchJson: {
55+
version: '1.0',
56+
configurations: [{
57+
}]
58+
}
59+
}
60+
};
61+
rule.visit(project, findings);
62+
assert.equal(findings.length, 0);
63+
});
64+
65+
it('doesn\'t return notifications if the configuration already contains the specified override', () => {
66+
const project: Project = {
67+
path: '/usr/tmp',
68+
vsCode: {
69+
launchJson: {
70+
version: '1.0',
71+
configurations: [{
72+
sourceMapPathOverrides: {
73+
'webpack:///.././src/*': '${webRoot}/src/*'
74+
}
75+
}]
76+
}
77+
}
78+
};
79+
rule.visit(project, findings);
80+
assert.equal(findings.length, 0);
81+
});
82+
});
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { Finding, Occurrence } from "../";
2+
import { Project } from "../model";
3+
import { Rule } from "./Rule";
4+
import * as path from 'path';
5+
6+
export class FN014006_CODE_launch_sourceMapPathOverrides extends Rule {
7+
constructor(private overrideKey: string, private overrideValue: string) {
8+
super();
9+
}
10+
11+
get id(): string {
12+
return 'FN014006';
13+
}
14+
15+
get title(): string {
16+
return 'sourceMapPathOverrides in .vscode/launch.json';
17+
}
18+
19+
get description(): string {
20+
return `In the .vscode/launch.json file, for each configuration, in the sourceMapPathOverrides property, add "${this.overrideKey}": "${this.overrideValue}"`;
21+
};
22+
23+
get resolution(): string {
24+
return `{
25+
"configurations": [
26+
{
27+
"sourceMapPathOverrides": {
28+
"${this.overrideKey}": "${this.overrideValue}"
29+
}
30+
}
31+
]
32+
}`;
33+
};
34+
35+
get resolutionType(): string {
36+
return 'json';
37+
};
38+
39+
get severity(): string {
40+
return 'Recommended';
41+
};
42+
43+
get file(): string {
44+
return '.vscode/launch.json';
45+
};
46+
47+
visit(project: Project, findings: Finding[]): void {
48+
if (!project.vsCode ||
49+
!project.vsCode.launchJson ||
50+
!project.vsCode.launchJson.configurations) {
51+
return;
52+
}
53+
54+
const occurrences: Occurrence[] = [];
55+
project.vsCode.launchJson.configurations.forEach(configuration => {
56+
if (configuration.sourceMapPathOverrides &&
57+
!configuration.sourceMapPathOverrides[this.overrideKey]) {
58+
occurrences.push({
59+
file: path.relative(project.path, this.file),
60+
resolution: this.resolution
61+
});
62+
}
63+
});
64+
65+
if (occurrences.length > 0) {
66+
this.addFindingWithOccurrences(occurrences, findings);
67+
}
68+
}
69+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Project } from "../model";
2+
import { Utils } from "../";
3+
import { ResolutionRule } from "./ResolutionRule";
4+
5+
export class FN020001_RES_types_react extends ResolutionRule {
6+
constructor(packageVersion: string) {
7+
/* istanbul ignore next */
8+
super('@types/react', packageVersion);
9+
}
10+
11+
get id(): string {
12+
return 'FN020001';
13+
}
14+
15+
customCondition(project: Project): boolean {
16+
return Utils.isReactProject(project);
17+
}
18+
}

src/o365/spfx/commands/project/project-upgrade/rules/ManifestRule.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Rule } from "./Rule";
22
import { Occurrence } from "../";
3-
import * as path from 'path'
3+
import * as path from 'path';
44

55
export abstract class ManifestRule extends Rule {
66
get resolutionType(): string {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { ResolutionRule } from './ResolutionRule';
2+
import * as assert from 'assert';
3+
import { Finding } from '../Finding';
4+
import { Project } from '../model';
5+
6+
class ResRule extends ResolutionRule {
7+
constructor() {
8+
super('test-package', '1.0.0');
9+
}
10+
11+
get id(): string {
12+
return 'FN000000';
13+
}
14+
}
15+
16+
class ResRule2 extends ResolutionRule {
17+
constructor() {
18+
super('test-package', '1.0.0');
19+
}
20+
21+
get id(): string {
22+
return 'FN000000';
23+
}
24+
25+
customCondition(project: Project): boolean {
26+
return true;
27+
}
28+
}
29+
30+
describe('ResolutionRule', () => {
31+
let depRule: ResRule;
32+
let depRule2: ResRule;
33+
let findings: Finding[];
34+
35+
before(() => {
36+
depRule = new ResRule();
37+
depRule2 = new ResRule2();
38+
});
39+
40+
beforeEach(() => {
41+
findings = [];
42+
})
43+
44+
it('doesn\'t return any notifications if package.json not found', () => {
45+
const project: Project = {
46+
path: '/usr/tmp'
47+
};
48+
depRule.visit(project, findings);
49+
assert.equal(findings.length, 0);
50+
});
51+
52+
it('doesn\'t return any notifications if the custom condition fails', () => {
53+
const project: Project = {
54+
path: '/usr/tmp',
55+
packageJson: {
56+
dependencies: {}
57+
}
58+
};
59+
depRule.visit(project, findings);
60+
assert.equal(findings.length, 0);
61+
});
62+
63+
it('doesn\'t return notification if the resolution is already up-to-date', () => {
64+
const project: Project = {
65+
path: '/usr/tmp',
66+
packageJson: {
67+
dependencies: {},
68+
resolutions: {
69+
'test-package': '1.0.0'
70+
}
71+
}
72+
};
73+
depRule2.visit(project, findings);
74+
assert.equal(findings.length, 0);
75+
});
76+
});

0 commit comments

Comments
 (0)