Skip to content

Commit 6fa5ccf

Browse files
authored
feat(vscode): ensure CLI version is compatible (#752)
1 parent 4b5f964 commit 6fa5ccf

File tree

10 files changed

+219
-27
lines changed

10 files changed

+219
-27
lines changed

extensions/vscode/src/commands/install-cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const cp = require("child_process");
22

33
import { window, ProgressOptions } from "vscode";
4-
import { isDartFrogCLIInstalled } from "../utils/utils";
4+
import { isDartFrogCLIInstalled } from "../utils";
55

66
/**
77
* Installs Dart Frog CLI in the user's system if not already installed.

extensions/vscode/src/commands/update-cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const cp = require("child_process");
22

33
import { window, ProgressOptions } from "vscode";
4-
import { isDartFrogCLIInstalled } from "../utils/utils";
4+
import { isDartFrogCLIInstalled } from "../utils";
55

66
/**
77
* Update Dart Frog CLI in the user's system.

extensions/vscode/src/extension.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import * as vscode from "vscode";
22
import { installCLI, newRoute, newMiddleware, updateCLI } from "./commands";
3+
import {
4+
readDartFrogCLIVersion,
5+
isCompatibleDartFrogCLIVersion,
6+
} from "./utils";
37

48
/**
59
* This method is called when the extension is activated.
@@ -13,6 +17,7 @@ export function activate(
1317
context: vscode.ExtensionContext
1418
): vscode.ExtensionContext {
1519
installCLI();
20+
ensureCompatibleDartFrogCLI();
1621

1722
context.subscriptions.push(
1823
vscode.commands.registerCommand("extension.install-cli", installCLI),
@@ -22,3 +27,51 @@ export function activate(
2227
);
2328
return context;
2429
}
30+
31+
/**
32+
* Checks if the version of Dart Frog CLI installed in the user's system is
33+
* compatible with this extension, suggesting to install if it is not.
34+
*
35+
* This method should be called upon activation of the extension to ensure that
36+
* the version of Dart Frog CLI installed in the user's system is compatible
37+
* with this extension.
38+
*
39+
* If the version of Dart Frog CLI installed in the user's system is not
40+
* compatible with this extension, the user is prompted to update Dart Frog CLI
41+
* or ignore the warning. If the user chooses to update Dart Frog CLI, the
42+
* extension will attempt to update Dart Frog CLI. Otherwise, the user will
43+
* proceed to use the extension at their own risk.
44+
*
45+
* If Dart Frog CLI is not installed in the user's system, this method will
46+
* do nothing and returns immediately.
47+
*
48+
* @see {@link isCompatibleDartFrogCLIVersion}, to check if the version of
49+
* Dart Frog CLI installed in the user's system is compatible with this
50+
* extension.
51+
*/
52+
export async function ensureCompatibleDartFrogCLI(): Promise<void> {
53+
const version = readDartFrogCLIVersion();
54+
if (!version) {
55+
return;
56+
}
57+
58+
const versionIsCompatible = isCompatibleDartFrogCLIVersion(version);
59+
if (versionIsCompatible) {
60+
return;
61+
}
62+
63+
const selection = await vscode.window.showWarningMessage(
64+
`Dart Frog CLI version ${version} is not compatible with this extension.`,
65+
"Update Dart Frog CLI",
66+
"Ignore"
67+
);
68+
switch (selection) {
69+
case "Update Dart Frog CLI":
70+
updateCLI();
71+
break;
72+
case "Ignore":
73+
break;
74+
default:
75+
break;
76+
}
77+
}

extensions/vscode/src/test/suite/commands/install-cli.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ suite("install-cli command", () => {
3232
// eslint-disable-next-line @typescript-eslint/naming-convention
3333
child_process: childProcessStub,
3434
// eslint-disable-next-line @typescript-eslint/naming-convention
35-
"../utils/utils": utilsStub,
35+
"../utils": utilsStub,
3636
});
3737
});
3838

extensions/vscode/src/test/suite/commands/update-cli.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ suite("update-cli", () => {
3232
// eslint-disable-next-line @typescript-eslint/naming-convention
3333
child_process: childProcessStub,
3434
// eslint-disable-next-line @typescript-eslint/naming-convention
35-
"../utils/utils": utilsStub,
35+
"../utils": utilsStub,
3636
});
3737
});
3838

extensions/vscode/src/test/suite/extension.test.ts

Lines changed: 129 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,26 @@ suite("activate", () => {
2626
registerCommand: sinon.stub(),
2727
},
2828
};
29+
30+
const utilsStub = {
31+
readDartFrogCLIVersion: sinon.stub(),
32+
isCompatibleDartFrogCLIVersion: sinon.stub(),
33+
isDartFrogCLIInstalled: sinon.stub(),
34+
};
35+
utilsStub.readDartFrogCLIVersion.returns("0.0.0");
36+
utilsStub.isCompatibleDartFrogCLIVersion.returns(true);
37+
utilsStub.isDartFrogCLIInstalled.returns(true);
38+
2939
const childProcessStub = {
3040
execSync: sinon.stub(),
3141
};
42+
3243
extension = proxyquire("../../extension", {
3344
vscode: vscodeStub,
3445
// eslint-disable-next-line @typescript-eslint/naming-convention
3546
child_process: childProcessStub,
47+
// eslint-disable-next-line @typescript-eslint/naming-convention
48+
"./utils": utilsStub,
3649
});
3750
context = { subscriptions: [] };
3851
});
@@ -41,7 +54,7 @@ suite("activate", () => {
4154
sinon.restore();
4255
});
4356

44-
test("install-cli", async () => {
57+
test("install-cli", () => {
4558
extension.activate(context);
4659

4760
sinon.assert.calledWith(
@@ -51,7 +64,7 @@ suite("activate", () => {
5164
);
5265
});
5366

54-
test("update-cli", async () => {
67+
test("update-cli", () => {
5568
extension.activate(context);
5669

5770
sinon.assert.calledWith(
@@ -61,7 +74,7 @@ suite("activate", () => {
6174
);
6275
});
6376

64-
test("new-route", async () => {
77+
test("new-route", () => {
6578
extension.activate(context);
6679

6780
sinon.assert.calledWith(
@@ -71,7 +84,7 @@ suite("activate", () => {
7184
);
7285
});
7386

74-
test("new-middleware", async () => {
87+
test("new-middleware", () => {
7588
extension.activate(context);
7689

7790
sinon.assert.calledWith(
@@ -82,22 +95,129 @@ suite("activate", () => {
8295
});
8396
});
8497

85-
test("calls installCLI", async () => {
98+
test("calls installCLI", () => {
8699
const vscodeStub = {
87100
commands: {
88101
registerCommand: sinon.stub(),
89102
},
90103
};
91-
const installCLIStub = sinon.stub();
104+
105+
const utilsStub = {
106+
readDartFrogCLIVersion: sinon.stub(),
107+
isCompatibleDartFrogCLIVersion: sinon.stub(),
108+
isDartFrogCLIInstalled: sinon.stub(),
109+
};
110+
utilsStub.readDartFrogCLIVersion.returns("0.0.0");
111+
utilsStub.isCompatibleDartFrogCLIVersion.returns(true);
112+
utilsStub.isDartFrogCLIInstalled.returns(true);
113+
114+
const commandsStub = {
115+
installCLI: sinon.stub(),
116+
};
117+
92118
const extension = proxyquire("../../extension", {
93119
vscode: vscodeStub,
94120
// eslint-disable-next-line @typescript-eslint/naming-convention
95-
"./commands": { installCLI: installCLIStub },
121+
"./utils": utilsStub,
122+
// eslint-disable-next-line @typescript-eslint/naming-convention
123+
"./commands": commandsStub,
96124
});
97-
const context = { subscriptions: [] };
98125

126+
const context = { subscriptions: [] };
99127
extension.activate(context);
100128

101-
sinon.assert.calledOnce(installCLIStub);
129+
sinon.assert.calledOnce(commandsStub.installCLI);
130+
});
131+
});
132+
133+
suite("ensureCompatibleDartFrogCLI", () => {
134+
let vscodeStub: any;
135+
let utilsStub: any;
136+
let commandsStub: any;
137+
let extension: any;
138+
139+
beforeEach(() => {
140+
vscodeStub = {
141+
window: {
142+
showWarningMessage: sinon.stub(),
143+
},
144+
};
145+
146+
utilsStub = {
147+
readDartFrogCLIVersion: sinon.stub(),
148+
isCompatibleDartFrogCLIVersion: sinon.stub(),
149+
};
150+
commandsStub = {
151+
updateCLI: sinon.stub(),
152+
};
153+
154+
extension = proxyquire("../../extension", {
155+
vscode: vscodeStub,
156+
// eslint-disable-next-line @typescript-eslint/naming-convention
157+
"./utils": utilsStub,
158+
// eslint-disable-next-line @typescript-eslint/naming-convention
159+
"./commands": commandsStub,
160+
});
161+
});
162+
163+
afterEach(() => {
164+
sinon.restore();
165+
});
166+
167+
test("does not show warning when CLI is not installed", async () => {
168+
utilsStub.readDartFrogCLIVersion.returns(undefined);
169+
170+
await extension.ensureCompatibleDartFrogCLI();
171+
172+
sinon.assert.notCalled(vscodeStub.window.showWarningMessage);
173+
});
174+
175+
test("does not show warning when CLI is compatible", async () => {
176+
utilsStub.readDartFrogCLIVersion.returns("1.0.0");
177+
utilsStub.isCompatibleDartFrogCLIVersion.returns(true);
178+
179+
await extension.ensureCompatibleDartFrogCLI();
180+
181+
sinon.assert.notCalled(vscodeStub.window.showWarningMessage);
182+
});
183+
184+
suite("incompatible CLI", () => {
185+
const version = "0.0.0";
186+
187+
beforeEach(() => {
188+
utilsStub.readDartFrogCLIVersion.returns(version);
189+
utilsStub.isCompatibleDartFrogCLIVersion.returns(false);
190+
});
191+
192+
afterEach(() => {
193+
sinon.restore();
194+
});
195+
196+
test("shows warning", async () => {
197+
await extension.ensureCompatibleDartFrogCLI();
198+
199+
sinon.assert.calledOnceWithExactly(
200+
vscodeStub.window.showWarningMessage,
201+
`Dart Frog CLI version ${version} is not compatible with this extension.`,
202+
"Update Dart Frog CLI",
203+
"Ignore"
204+
);
205+
});
206+
207+
test("updates CLI when selected", async () => {
208+
vscodeStub.window.showWarningMessage.returns("Update Dart Frog CLI");
209+
210+
await extension.ensureCompatibleDartFrogCLI();
211+
212+
sinon.assert.calledOnce(commandsStub.updateCLI);
213+
});
214+
215+
test("does not update CLI when ignored", async () => {
216+
vscodeStub.window.showWarningMessage.returns("Ignore");
217+
218+
await extension.ensureCompatibleDartFrogCLI();
219+
220+
sinon.assert.notCalled(commandsStub.updateCLI);
221+
});
102222
});
103223
});

extensions/vscode/src/test/suite/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export function run(): Promise<void> {
1313
const mocha = new Mocha({
1414
ui: "tdd",
1515
color: true,
16+
timeout: 60000,
1617
});
1718

1819
const testsRoot = path.resolve(__dirname, "..");

extensions/vscode/src/test/suite/utils/cli-version.test.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ var proxyquire = require("proxyquire");
44
import { afterEach, beforeEach } from "mocha";
55
import * as assert from "assert";
66

7-
suite("readDartFrogVersion", () => {
7+
suite("readDartFrogCLIVersion", () => {
88
let cpStub: any;
99
let cliVersion: any;
1010

@@ -24,32 +24,48 @@ suite("readDartFrogVersion", () => {
2424
});
2525

2626
test("returns the version of Dart Frog CLI installed in the user's system", () => {
27-
cpStub.execSync.returns("0.3.7");
27+
const dartFrogVersionCommandResult = "0.3.7\n";
28+
const encoededDartFrogVersionCommandResult = new TextEncoder().encode(
29+
dartFrogVersionCommandResult
30+
);
31+
cpStub.execSync.returns(encoededDartFrogVersionCommandResult);
2832

29-
assert.strictEqual(cliVersion.readDartFrogVersion(), "0.3.7");
33+
assert.strictEqual(cliVersion.readDartFrogCLIVersion(), "0.3.7");
3034
});
3135

3236
test("returns undefined if Dart Frog CLI is not installed", () => {
3337
cpStub.execSync.throws();
3438

35-
assert.strictEqual(cliVersion.readDartFrogVersion(), undefined);
39+
assert.strictEqual(cliVersion.readDartFrogCLIVersion(), undefined);
3640
});
3741
});
3842

39-
suite("isCompatibleCLIVersion", () => {
43+
suite("isCompatibleDartFrogCLIVersion", () => {
4044
let cliVersion: any;
4145

4246
beforeEach(() => {
4347
cliVersion = proxyquire("../../../utils/cli-version", {});
4448
});
4549

4650
test("returns true if the version of Dart Frog CLI installed in the user's system is compatible with this extension", () => {
47-
assert.strictEqual(cliVersion.isCompatibleCLIVersion("0.3.8"), true);
48-
assert.strictEqual(cliVersion.isCompatibleCLIVersion("0.3.7"), true);
51+
assert.strictEqual(
52+
cliVersion.isCompatibleDartFrogCLIVersion("0.3.8"),
53+
true
54+
);
55+
assert.strictEqual(
56+
cliVersion.isCompatibleDartFrogCLIVersion("0.3.7"),
57+
true
58+
);
4959
});
5060

5161
test("returns false if the version of Dart Frog CLI installed in the user's system is not compatible with this extension", () => {
52-
assert.strictEqual(cliVersion.isCompatibleCLIVersion("1.0.0"), false);
53-
assert.strictEqual(cliVersion.isCompatibleCLIVersion("0.3.6"), false);
62+
assert.strictEqual(
63+
cliVersion.isCompatibleDartFrogCLIVersion("1.0.0"),
64+
false
65+
);
66+
assert.strictEqual(
67+
cliVersion.isCompatibleDartFrogCLIVersion("0.3.6"),
68+
false
69+
);
5470
});
5571
});

0 commit comments

Comments
 (0)