Skip to content

Commit

Permalink
feat: Add a notification after auto-installing a new version of Lexic…
Browse files Browse the repository at this point in the history
…al (#81)
  • Loading branch information
Blond11516 authored May 8, 2024
1 parent bfb2071 commit 9d401b9
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

- Added the "Rebuild code search index" which instructs Lexical to rebuild the
code search index for the current project.
- Added a notification after automatic installation of a new version of Lexical.
This notification can be disabled through the ǹew
`lexical.notifyOnServerAutoUpdate` configuration setting.

## [0.0.15]

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ script (assumed to be `start_lexical.sh`) or any executable launcher script.
The path should look something like
`/home/username/Projects/lexical/_build/dev/package/lexical/bin/start_lexical.sh`.

### lexical.notifyOnServerAutoUpdate

Controls whether notifications are shown after automatic installs of new Lexcial
versions. Defaults to `true`.

### Erlang and Elixir version compatibility

#### Erlang
Expand Down
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@
"scope": "window",
"type": "string",
"markdownDescription": "A subdirectory of the current workspace in which to start Lexical."
},
"lexical.notifyOnServerAutoUpdate": {
"scope": "window",
"type": "boolean",
"default": true,
"markdownDescription": "Whether to notify when a new release of Lexical is installed automatically."
}
}
},
Expand Down Expand Up @@ -184,6 +190,7 @@
"jest-extended": "4.0.2",
"ovsx": "0.8.3",
"prettier": "3.2.5",
"synchronous-promise": "2.0.17",
"ts-jest": "29.1.2",
"typescript": "5.4.5",
"vscode-uri": "3.0.8"
Expand Down
6 changes: 6 additions & 0 deletions src/auto-installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import * as fs from "fs";
import Zip from "./zip";
import Paths from "./paths";
import Logger from "./logger";
import Notifications from "./notifications";
import Configuration from "./configuration";

namespace AutoInstaller {
export function isInstalledReleaseLatest(
Expand Down Expand Up @@ -41,6 +43,10 @@ namespace AutoInstaller {
fs.writeFileSync(zipUri.fsPath, zipBuffer, "binary");

await Zip.extract(zipUri, releaseUri, latestRelease.version);

if (Configuration.getAutoInstallUpdateNotification()) {
Notifications.notifyAutoInstallSuccess(latestRelease.version);
}
}
}

Expand Down
16 changes: 15 additions & 1 deletion src/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path = require("path");
import type { workspace as vsWorkspace } from "vscode";
import { ConfigurationTarget, workspace as vsWorkspace } from "vscode";
import { URI } from "vscode-uri";
import Logger from "./logger";

namespace Configuration {
type GetConfig = (section: string) => unknown;
Expand All @@ -27,6 +28,19 @@ namespace Configuration {
return URI.file(workspacePath);
}
}

export function disableAutoInstallUpdateNotification(): void {
vsWorkspace
.getConfiguration("lexical")
.update("notifyOnServerAutoUpdate", false, ConfigurationTarget.Global)
.then(undefined, (e) => Logger.error(e.toString()));
}

export function getAutoInstallUpdateNotification(): boolean {
return vsWorkspace
.getConfiguration("lexical")
.get("notifyOnServerAutoUpdate", true);
}
}

export default Configuration;
22 changes: 22 additions & 0 deletions src/notifications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { window } from "vscode";
import ReleaseVersion from "./release/version";
import Configuration from "./configuration";

namespace Notifications {
export function notifyAutoInstallSuccess(version: ReleaseVersion.T): void {
const disableNotificationMessage = "Disable this notification";
const serializedVersion = ReleaseVersion.serialize(version);
const releaseUrl = `https://github.com/lexical-lsp/lexical/releases/tag/v${serializedVersion}`;
const message = `Lexical was automatically updated to version ${serializedVersion}. See [what's new](${releaseUrl}).`;

window
.showInformationMessage(message, disableNotificationMessage)
.then((fulfilledValue) => {
if (fulfilledValue === disableNotificationMessage) {
Configuration.disableAutoInstallUpdateNotification();
}
});
}
}

export default Notifications;
24 changes: 24 additions & 0 deletions src/test/auto-installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import * as fs from "fs";
import * as os from "os";
import Zip from "../zip";
import Release from "../release";
import Notifications from "../notifications";
import Configuration from "../configuration";

jest.mock("fs", () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand All @@ -26,6 +28,8 @@ jest.mock("fs", () => {
describe("AutoInstaller", () => {
beforeEach(() => {
mockResolvedValue(Zip, "extract");
mockReturnValue(Notifications, "notifyAutoInstallSuccess");
mockReturnValue(Configuration, "getAutoInstallUpdateNotification", false);
});

describe("isInstalledReleaseLatest", () => {
Expand Down Expand Up @@ -110,6 +114,26 @@ describe("AutoInstaller", () => {
A_RELEASE.version,
);
});

test("notifies the user of the newly installed version", async () => {
mockReturnValue(Configuration, "getAutoInstallUpdateNotification", true);
mockReturnValue(Notifications, "notifyAutoInstallSuccess");
givenDownloadedZip();
await AutoInstaller.install(A_PROGRESS, A_RELEASE, A_RELEASE_URI);

expect(Notifications.notifyAutoInstallSuccess).toHaveBeenCalledWith(
ReleaseVersion.deserialize(ReleaseVersion.serialize(A_RELEASE.version)),
);
});

test("given auto-install notifications are disabled, it does not notify user of the newly installed version", async () => {
mockReturnValue(Configuration, "getAutoInstallUpdateNotification", false);
mockReturnValue(Notifications, "notifyAutoInstallSuccess");
givenDownloadedZip();
await AutoInstaller.install(A_PROGRESS, A_RELEASE, A_RELEASE_URI);

expect(Notifications.notifyAutoInstallSuccess).not.toHaveBeenCalled();
});
});
});

Expand Down
2 changes: 0 additions & 2 deletions src/test/configuration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ describe("Configuration", () => {
workspace,
);

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
expect(projectDirUri).toEqual(workspace.workspaceFolders![0].uri);
});

Expand All @@ -24,7 +23,6 @@ describe("Configuration", () => {
workspace,
);

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
expect(projectDirUri).toEqual(URI.file("/stub/subdirectory"));
});
});
58 changes: 58 additions & 0 deletions src/test/notifications.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { describe, expect, test } from "@jest/globals";
import { mockReturnValue } from "./utils/strict-mocks";
import { MessageItem, window } from "vscode";
import { SynchronousPromise } from "synchronous-promise";
import Notifications from "../notifications";
import ReleaseVersion from "../release/version";
import Configuration from "../configuration";

describe("notifyAutoInstallSuccess", () => {
test("sends an information message with the installed version", () => {
mockReturnValue(
window,
"showInformationMessage",
Promise.resolve(undefined),
);

Notifications.notifyAutoInstallSuccess(ReleaseVersion.deserialize("1.2.3"));

expect(window.showInformationMessage).toHaveBeenCalledWith(
expect.stringContaining("version 1.2.3"),
"Disable this notification",
);
});

test("when user requests to disable the notification, it updates the configuration", () => {
mockReturnValue(Configuration, "disableAutoInstallUpdateNotification");
mockReturnValue(
window,
"showInformationMessage",
SynchronousPromise.resolve(
"Disable this notification" as unknown as MessageItem,
),
);

Notifications.notifyAutoInstallSuccess(ReleaseVersion.deserialize("1.2.3"));

expect(
Configuration.disableAutoInstallUpdateNotification,
).toHaveBeenCalled();
});

test("notification should include a link to the release notes", () => {
mockReturnValue(
window,
"showInformationMessage",
Promise.resolve(undefined),
);

Notifications.notifyAutoInstallSuccess(ReleaseVersion.deserialize("1.2.3"));

expect(window.showInformationMessage).toHaveBeenCalledWith(
expect.stringContaining(
"https://github.com/lexical-lsp/lexical/releases/tag/v1.2.3",
),
"Disable this notification",
);
});
});

0 comments on commit 9d401b9

Please sign in to comment.