Merge branch 'main' into koesie10/move-database-commands
This commit is contained in:
@@ -69,6 +69,7 @@ import {
|
|||||||
showInformationMessageWithAction,
|
showInformationMessageWithAction,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
tmpDirDisposal,
|
tmpDirDisposal,
|
||||||
|
prepareCodeTour,
|
||||||
} from "./helpers";
|
} from "./helpers";
|
||||||
import {
|
import {
|
||||||
asError,
|
asError,
|
||||||
@@ -527,6 +528,14 @@ async function installOrUpdateThenTryActivate(
|
|||||||
): Promise<CodeQLExtensionInterface | Record<string, never>> {
|
): Promise<CodeQLExtensionInterface | Record<string, never>> {
|
||||||
await installOrUpdateDistribution(ctx, distributionManager, config);
|
await installOrUpdateDistribution(ctx, distributionManager, config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await prepareCodeTour();
|
||||||
|
} catch (e: unknown) {
|
||||||
|
void extLogger.log(
|
||||||
|
`Could not open tutorial workspace automatically: ${getErrorMessage(e)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Display the warnings even if the extension has already activated.
|
// Display the warnings even if the extension has already activated.
|
||||||
const distributionResult =
|
const distributionResult =
|
||||||
await getDistributionDisplayingDistributionWarnings(distributionManager);
|
await getDistributionDisplayingDistributionWarnings(distributionManager);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
window as Window,
|
window as Window,
|
||||||
workspace,
|
workspace,
|
||||||
env,
|
env,
|
||||||
|
commands,
|
||||||
} from "vscode";
|
} from "vscode";
|
||||||
import { CodeQLCliServer, QlpacksInfo } from "./cli";
|
import { CodeQLCliServer, QlpacksInfo } from "./cli";
|
||||||
import { UserCancellationException } from "./commandRunner";
|
import { UserCancellationException } from "./commandRunner";
|
||||||
@@ -25,6 +26,7 @@ import { telemetryListener } from "./telemetry";
|
|||||||
import { RedactableError } from "./pure/errors";
|
import { RedactableError } from "./pure/errors";
|
||||||
import { getQlPackPath } from "./pure/ql";
|
import { getQlPackPath } from "./pure/ql";
|
||||||
import { dbSchemeToLanguage } from "./common/query-language";
|
import { dbSchemeToLanguage } from "./common/query-language";
|
||||||
|
import { isCodespacesTemplate } from "./config";
|
||||||
|
|
||||||
// Shared temporary folder for the extension.
|
// Shared temporary folder for the extension.
|
||||||
export const tmpDir = dirSync({
|
export const tmpDir = dirSync({
|
||||||
@@ -266,6 +268,51 @@ export function isFolderAlreadyInWorkspace(folderName: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check if the current workspace is the CodeTour and open the workspace folder.
|
||||||
|
* Without this, we can't run the code tour correctly.
|
||||||
|
**/
|
||||||
|
export async function prepareCodeTour(): Promise<void> {
|
||||||
|
if (workspace.workspaceFolders?.length) {
|
||||||
|
const currentFolder = workspace.workspaceFolders[0].uri.fsPath;
|
||||||
|
|
||||||
|
const tutorialWorkspacePath = join(
|
||||||
|
currentFolder,
|
||||||
|
"tutorial.code-workspace",
|
||||||
|
);
|
||||||
|
const toursFolderPath = join(currentFolder, ".tours");
|
||||||
|
|
||||||
|
/** We're opening the tutorial workspace, if we detect it.
|
||||||
|
* This will only happen if the following three conditions are met:
|
||||||
|
* - the .tours folder exists
|
||||||
|
* - the tutorial.code-workspace file exists
|
||||||
|
* - the CODESPACES_TEMPLATE setting doesn't exist (it's only set if the user has already opened
|
||||||
|
* the tutorial workspace so it's a good indicator that the user is in the folder but has ignored
|
||||||
|
* the prompt to open the workspace)
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
(await pathExists(tutorialWorkspacePath)) &&
|
||||||
|
(await pathExists(toursFolderPath)) &&
|
||||||
|
!isCodespacesTemplate()
|
||||||
|
) {
|
||||||
|
const answer = await showBinaryChoiceDialog(
|
||||||
|
"We've detected you're in the CodeQL Tour repo. We will need to open the workspace file to continue. Reload?",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!answer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tutorialWorkspaceUri = Uri.parse(tutorialWorkspacePath);
|
||||||
|
|
||||||
|
void extLogger.log(
|
||||||
|
`In prepareCodeTour() method, going to open the tutorial workspace file: ${tutorialWorkspacePath}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
await commands.executeCommand("vscode.openFolder", tutorialWorkspaceUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a utility method to invoke a function only if a minimum time interval has elapsed since
|
* Provides a utility method to invoke a function only if a minimum time interval has elapsed since
|
||||||
* the last invocation of that function.
|
* the last invocation of that function.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[
|
[
|
||||||
"v2.12.4",
|
"v2.12.5",
|
||||||
"v2.11.6",
|
"v2.11.6",
|
||||||
"v2.7.6",
|
"v2.7.6",
|
||||||
"v2.8.5",
|
"v2.8.5",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
commands,
|
||||||
EnvironmentVariableCollection,
|
EnvironmentVariableCollection,
|
||||||
EnvironmentVariableMutator,
|
EnvironmentVariableMutator,
|
||||||
Event,
|
Event,
|
||||||
@@ -15,7 +16,14 @@ import {
|
|||||||
import { dump } from "js-yaml";
|
import { dump } from "js-yaml";
|
||||||
import * as tmp from "tmp";
|
import * as tmp from "tmp";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { writeFileSync, mkdirSync, ensureDirSync, symlinkSync } from "fs-extra";
|
import {
|
||||||
|
writeFileSync,
|
||||||
|
mkdirSync,
|
||||||
|
ensureDirSync,
|
||||||
|
symlinkSync,
|
||||||
|
writeFile,
|
||||||
|
mkdir,
|
||||||
|
} from "fs-extra";
|
||||||
import { DirResult } from "tmp";
|
import { DirResult } from "tmp";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -24,6 +32,7 @@ import {
|
|||||||
isFolderAlreadyInWorkspace,
|
isFolderAlreadyInWorkspace,
|
||||||
isLikelyDatabaseRoot,
|
isLikelyDatabaseRoot,
|
||||||
isLikelyDbLanguageFolder,
|
isLikelyDbLanguageFolder,
|
||||||
|
prepareCodeTour,
|
||||||
showBinaryChoiceDialog,
|
showBinaryChoiceDialog,
|
||||||
showBinaryChoiceWithUrlDialog,
|
showBinaryChoiceWithUrlDialog,
|
||||||
showInformationMessageWithAction,
|
showInformationMessageWithAction,
|
||||||
@@ -31,6 +40,7 @@ import {
|
|||||||
} from "../../../src/helpers";
|
} from "../../../src/helpers";
|
||||||
import { reportStreamProgress } from "../../../src/commandRunner";
|
import { reportStreamProgress } from "../../../src/commandRunner";
|
||||||
import { QueryLanguage } from "../../../src/common/query-language";
|
import { QueryLanguage } from "../../../src/common/query-language";
|
||||||
|
import { Setting } from "../../../src/config";
|
||||||
|
|
||||||
describe("helpers", () => {
|
describe("helpers", () => {
|
||||||
describe("Invocation rate limiter", () => {
|
describe("Invocation rate limiter", () => {
|
||||||
@@ -559,3 +569,113 @@ describe("isFolderAlreadyInWorkspace", () => {
|
|||||||
expect(isFolderAlreadyInWorkspace("/third/path")).toBe(false);
|
expect(isFolderAlreadyInWorkspace("/third/path")).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("prepareCodeTour", () => {
|
||||||
|
let dir: tmp.DirResult;
|
||||||
|
let showInformationMessageSpy: jest.SpiedFunction<
|
||||||
|
typeof window.showInformationMessage
|
||||||
|
>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
dir = tmp.dirSync();
|
||||||
|
|
||||||
|
const mockWorkspaceFolders = [
|
||||||
|
{
|
||||||
|
uri: Uri.file(dir.name),
|
||||||
|
name: "test",
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
] as WorkspaceFolder[];
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(workspace, "workspaceFolders", "get")
|
||||||
|
.mockReturnValue(mockWorkspaceFolders);
|
||||||
|
|
||||||
|
showInformationMessageSpy = jest
|
||||||
|
.spyOn(window, "showInformationMessage")
|
||||||
|
.mockResolvedValue({ title: "Yes" });
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
dir.removeCallback();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("if we're in the tour repo", () => {
|
||||||
|
describe("if the workspace is not already open", () => {
|
||||||
|
it("should open the tutorial workspace", async () => {
|
||||||
|
// set up directory to have a 'tutorial.code-workspace' file
|
||||||
|
const tutorialWorkspacePath = join(dir.name, "tutorial.code-workspace");
|
||||||
|
await writeFile(tutorialWorkspacePath, "{}");
|
||||||
|
|
||||||
|
// set up a .tours directory to indicate we're in the tour codespace
|
||||||
|
const tourDirPath = join(dir.name, ".tours");
|
||||||
|
await mkdir(tourDirPath);
|
||||||
|
|
||||||
|
// spy that we open the workspace file by calling the 'vscode.openFolder' command
|
||||||
|
const commandSpy = jest.spyOn(commands, "executeCommand");
|
||||||
|
commandSpy.mockImplementation(() => Promise.resolve());
|
||||||
|
|
||||||
|
await prepareCodeTour();
|
||||||
|
|
||||||
|
expect(showInformationMessageSpy).toHaveBeenCalled();
|
||||||
|
expect(commandSpy).toHaveBeenCalledWith(
|
||||||
|
"vscode.openFolder",
|
||||||
|
expect.objectContaining({
|
||||||
|
path: Uri.parse(tutorialWorkspacePath).fsPath,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("if the workspace is already open", () => {
|
||||||
|
it("should not open the tutorial workspace", async () => {
|
||||||
|
// Set isCodespaceTemplate to true to indicate the workspace has already been opened
|
||||||
|
jest.spyOn(Setting.prototype, "getValue").mockReturnValue(true);
|
||||||
|
|
||||||
|
// set up directory to have a 'tutorial.code-workspace' file
|
||||||
|
const tutorialWorkspacePath = join(dir.name, "tutorial.code-workspace");
|
||||||
|
await writeFile(tutorialWorkspacePath, "{}");
|
||||||
|
|
||||||
|
// set up a .tours directory to indicate we're in the tour codespace
|
||||||
|
const tourDirPath = join(dir.name, ".tours");
|
||||||
|
await mkdir(tourDirPath);
|
||||||
|
|
||||||
|
// spy that we open the workspace file by calling the 'vscode.openFolder' command
|
||||||
|
const commandSpy = jest.spyOn(commands, "executeCommand");
|
||||||
|
commandSpy.mockImplementation(() => Promise.resolve());
|
||||||
|
|
||||||
|
await prepareCodeTour();
|
||||||
|
|
||||||
|
expect(commandSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("if we're in a different tour repo", () => {
|
||||||
|
it("should not open the tutorial workspace", async () => {
|
||||||
|
// set up a .tours directory
|
||||||
|
const tourDirPath = join(dir.name, ".tours");
|
||||||
|
await mkdir(tourDirPath);
|
||||||
|
|
||||||
|
// spy that we open the workspace file by calling the 'vscode.openFolder' command
|
||||||
|
const commandSpy = jest.spyOn(commands, "executeCommand");
|
||||||
|
commandSpy.mockImplementation(() => Promise.resolve());
|
||||||
|
|
||||||
|
await prepareCodeTour();
|
||||||
|
|
||||||
|
expect(commandSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("if we're in a different repo with no tour", () => {
|
||||||
|
it("should not open the tutorial workspace", async () => {
|
||||||
|
// spy that we open the workspace file by calling the 'vscode.openFolder' command
|
||||||
|
const commandSpy = jest.spyOn(commands, "executeCommand");
|
||||||
|
commandSpy.mockImplementation(() => Promise.resolve());
|
||||||
|
|
||||||
|
await prepareCodeTour();
|
||||||
|
|
||||||
|
expect(commandSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user