From 0bf1fae2feea2c3b83cef499e2407600aca10624 Mon Sep 17 00:00:00 2001 From: Andrew Eisenberg Date: Fri, 16 Dec 2022 09:14:49 -0800 Subject: [PATCH] Remove LGTM references and commands LGTM has been decommissioned. All code and tests for downloading LGTM databases should be removed. --- extensions/ql-vscode/media/dark/lgtm-plus.svg | 5 - .../ql-vscode/media/light/lgtm-plus.svg | 5 - extensions/ql-vscode/package.json | 27 --- extensions/ql-vscode/src/databaseFetcher.ts | 189 ------------------ extensions/ql-vscode/src/databases-ui.ts | 23 --- extensions/ql-vscode/src/extension.ts | 10 - .../cli-integration/databases.test.ts | 25 --- .../no-workspace/databaseFetcher.test.ts | 96 --------- 8 files changed, 380 deletions(-) delete mode 100644 extensions/ql-vscode/media/dark/lgtm-plus.svg delete mode 100644 extensions/ql-vscode/media/light/lgtm-plus.svg diff --git a/extensions/ql-vscode/media/dark/lgtm-plus.svg b/extensions/ql-vscode/media/dark/lgtm-plus.svg deleted file mode 100644 index cfa1bb7a9..000000000 --- a/extensions/ql-vscode/media/dark/lgtm-plus.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/extensions/ql-vscode/media/light/lgtm-plus.svg b/extensions/ql-vscode/media/light/lgtm-plus.svg deleted file mode 100644 index 4ca2d548f..000000000 --- a/extensions/ql-vscode/media/light/lgtm-plus.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 6e24d078b..5cd9b16a6 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -48,7 +48,6 @@ "onCommand:codeQLDatabases.chooseDatabaseArchive", "onCommand:codeQLDatabases.chooseDatabaseInternet", "onCommand:codeQLDatabases.chooseDatabaseGithub", - "onCommand:codeQLDatabases.chooseDatabaseLgtm", "onCommand:codeQL.setCurrentDatabase", "onCommand:codeQL.viewAst", "onCommand:codeQL.viewCfg", @@ -58,7 +57,6 @@ "onCommand:codeQL.chooseDatabaseArchive", "onCommand:codeQL.chooseDatabaseInternet", "onCommand:codeQL.chooseDatabaseGithub", - "onCommand:codeQL.chooseDatabaseLgtm", "onCommand:codeQLDatabases.chooseDatabase", "onCommand:codeQLDatabases.setCurrentDatabase", "onCommand:codeQLDatabasesExperimental.openConfigFile", @@ -410,14 +408,6 @@ "dark": "media/dark/github.svg" } }, - { - "command": "codeQLDatabases.chooseDatabaseLgtm", - "title": "Download from LGTM", - "icon": { - "light": "media/light/lgtm-plus.svg", - "dark": "media/dark/lgtm-plus.svg" - } - }, { "command": "codeQL.setCurrentDatabase", "title": "CodeQL: Set Current Database" @@ -486,10 +476,6 @@ "command": "codeQL.chooseDatabaseGithub", "title": "CodeQL: Download Database from GitHub" }, - { - "command": "codeQL.chooseDatabaseLgtm", - "title": "CodeQL: Download Database from LGTM" - }, { "command": "codeQLDatabases.sortByName", "title": "Sort by Name", @@ -728,11 +714,6 @@ "when": "view == codeQLDatabases", "group": "navigation" }, - { - "command": "codeQLDatabases.chooseDatabaseLgtm", - "when": "config.codeQL.canary && view == codeQLDatabases", - "group": "navigation" - }, { "command": "codeQLQueryHistory.openQuery", "when": "view == codeQLQueryHistory", @@ -997,10 +978,6 @@ "command": "codeQL.viewCfg", "when": "resourceScheme == codeql-zip-archive && config.codeQL.canary" }, - { - "command": "codeQL.chooseDatabaseLgtm", - "when": "config.codeQL.canary" - }, { "command": "codeQLDatabasesExperimental.openConfigFile", "when": "false" @@ -1061,10 +1038,6 @@ "command": "codeQLDatabases.chooseDatabaseGithub", "when": "false" }, - { - "command": "codeQLDatabases.chooseDatabaseLgtm", - "when": "false" - }, { "command": "codeQLDatabases.upgradeDatabase", "when": "false" diff --git a/extensions/ql-vscode/src/databaseFetcher.ts b/extensions/ql-vscode/src/databaseFetcher.ts index 8c5b55425..f3d46e370 100644 --- a/extensions/ql-vscode/src/databaseFetcher.ts +++ b/extensions/ql-vscode/src/databaseFetcher.ts @@ -153,74 +153,6 @@ export async function promptImportGithubDatabase( return; } -/** - * Prompts a user to fetch a database from lgtm. - * User enters a project url and then the user is asked which language - * to download (if there is more than one) - * - * @param databaseManager the DatabaseManager - * @param storagePath where to store the unzipped database. - */ -export async function promptImportLgtmDatabase( - databaseManager: DatabaseManager, - storagePath: string, - progress: ProgressCallback, - token: CancellationToken, - cli?: CodeQLCliServer, -): Promise { - progress({ - message: "Choose project", - step: 1, - maxStep: 2, - }); - const lgtmUrl = await window.showInputBox({ - prompt: - "Enter the project slug or URL on LGTM (e.g., g/github/codeql or https://lgtm.com/projects/g/github/codeql)", - }); - if (!lgtmUrl) { - return; - } - - if (looksLikeLgtmUrl(lgtmUrl)) { - const databaseUrl = await convertLgtmUrlToDatabaseUrl(lgtmUrl, progress); - if (databaseUrl) { - const item = await databaseArchiveFetcher( - databaseUrl, - {}, - databaseManager, - storagePath, - undefined, - progress, - token, - cli, - ); - if (item) { - await commands.executeCommand("codeQLDatabases.focus"); - void showAndLogInformationMessage( - "Database downloaded and imported successfully.", - ); - } - return item; - } - } else { - throw new Error(`Invalid LGTM URL: ${lgtmUrl}`); - } - return; -} - -export async function retrieveCanonicalRepoName(lgtmUrl: string) { - const givenRepoName = extractProjectSlug(lgtmUrl); - const response = await checkForFailingResponse( - await fetch(`https://api.github.com/repos/${givenRepoName}`), - "Failed to locate the repository on github", - ); - const repo = await response.json(); - if (!repo || !repo.full_name) { - return; - } - return repo.full_name; -} - /** * Imports a database from a local archive. * @@ -552,127 +484,6 @@ export async function convertGithubNwoToDatabaseUrl( } } -/** - * The URL pattern is https://lgtm.com/projects/{provider}/{org}/{name}/{irrelevant-subpages}. - * There are several possibilities for the provider: in addition to GitHub.com (g), - * LGTM currently hosts projects from Bitbucket (b), GitLab (gl) and plain git (git). - * - * This function accepts any url that matches the pattern above. It also accepts the - * raw project slug, e.g., `g/myorg/myproject` - * - * After the `{provider}/{org}/{name}` path components, there may be the components - * related to sub pages. - * - * @param lgtmUrl The URL to the lgtm project - * - * @return true if this looks like an LGTM project url - */ -// exported for testing -export function looksLikeLgtmUrl( - lgtmUrl: string | undefined, -): lgtmUrl is string { - if (!lgtmUrl) { - return false; - } - - if (convertRawLgtmSlug(lgtmUrl)) { - return true; - } - - try { - const uri = Uri.parse(lgtmUrl, true); - if (uri.scheme !== "https") { - return false; - } - - if (uri.authority !== "lgtm.com" && uri.authority !== "www.lgtm.com") { - return false; - } - - const paths = uri.path.split("/").filter((segment: string) => segment); - return paths.length >= 4 && paths[0] === "projects"; - } catch (e) { - return false; - } -} - -function convertRawLgtmSlug(maybeSlug: string): string | undefined { - if (!maybeSlug) { - return; - } - const segments = maybeSlug.split("/"); - const providers = ["g", "gl", "b", "git"]; - if (segments.length === 3 && providers.includes(segments[0])) { - return `https://lgtm.com/projects/${maybeSlug}`; - } - return; -} - -function extractProjectSlug(lgtmUrl: string): string | undefined { - // Only matches the '/g/' provider (github) - const re = new RegExp("https://lgtm.com/projects/g/(.*[^/])"); - const match = lgtmUrl.match(re); - if (!match) { - return; - } - return match[1]; -} - -// exported for testing -export async function convertLgtmUrlToDatabaseUrl( - lgtmUrl: string, - progress: ProgressCallback, -) { - try { - lgtmUrl = convertRawLgtmSlug(lgtmUrl) || lgtmUrl; - let projectJson = await downloadLgtmProjectMetadata(lgtmUrl); - - if (projectJson.code === 404) { - // fallback check for github repositories with same name but different case - // will fail for other providers - let canonicalName = await retrieveCanonicalRepoName(lgtmUrl); - if (!canonicalName) { - throw new Error(`Project was not found at ${lgtmUrl}.`); - } - canonicalName = convertRawLgtmSlug(`g/${canonicalName}`); - projectJson = await downloadLgtmProjectMetadata(canonicalName); - if (projectJson.code === 404) { - throw new Error("Failed to download project from LGTM."); - } - } - - const languages = - projectJson?.languages?.map( - (lang: { language: string }) => lang.language, - ) || []; - - const language = await promptForLanguage(languages, progress); - if (!language) { - return; - } - return `https://lgtm.com/${[ - "api", - "v1.0", - "snapshots", - projectJson.id, - language, - ].join("/")}`; - } catch (e) { - void extLogger.log(`Error: ${getErrorMessage(e)}`); - throw new Error(`Invalid LGTM URL: ${lgtmUrl}`); - } -} - -async function downloadLgtmProjectMetadata(lgtmUrl: string): Promise { - const uri = Uri.parse(lgtmUrl, true); - const paths = ["api", "v1.0"] - .concat(uri.path.split("/").filter((segment: string) => segment)) - .slice(0, 6); - const projectUrl = `https://lgtm.com/${paths.join("/")}`; - const projectResponse = await fetch(projectUrl); - return projectResponse.json(); -} - async function promptForLanguage( languages: string[], progress: ProgressCallback, diff --git a/extensions/ql-vscode/src/databases-ui.ts b/extensions/ql-vscode/src/databases-ui.ts index 0f13731ab..80f7ac2de 100644 --- a/extensions/ql-vscode/src/databases-ui.ts +++ b/extensions/ql-vscode/src/databases-ui.ts @@ -33,7 +33,6 @@ import { importArchiveDatabase, promptImportGithubDatabase, promptImportInternetDatabase, - promptImportLgtmDatabase, } from "./databaseFetcher"; import { asyncFilter, getErrorMessage } from "./pure/helpers-pure"; import { Credentials } from "./authentication"; @@ -308,15 +307,6 @@ export class DatabaseUI extends DisposableObject { }, ), ); - this.push( - commandRunnerWithProgress( - "codeQLDatabases.chooseDatabaseLgtm", - this.handleChooseDatabaseLgtm, - { - title: "Adding database from LGTM", - }, - ), - ); this.push( commandRunner( "codeQLDatabases.setCurrentDatabase", @@ -491,19 +481,6 @@ export class DatabaseUI extends DisposableObject { ); }; - handleChooseDatabaseLgtm = async ( - progress: ProgressCallback, - token: CancellationToken, - ): Promise => { - return await promptImportLgtmDatabase( - this.databaseManager, - this.storagePath, - progress, - token, - this.queryServer?.cliServer, - ); - }; - async tryUpgradeCurrentDatabase( progress: ProgressCallback, token: CancellationToken, diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 66331dd16..abf49939b 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1369,16 +1369,6 @@ async function activateWithInstalledDistribution( }, ), ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.chooseDatabaseLgtm", - (progress: ProgressCallback, token: CancellationToken) => - databaseUI.handleChooseDatabaseLgtm(progress, token), - { - title: "Adding database from LGTM", - }, - ), - ); ctx.subscriptions.push( commandRunnerWithProgress( "codeQL.chooseDatabaseInternet", diff --git a/extensions/ql-vscode/src/vscode-tests/cli-integration/databases.test.ts b/extensions/ql-vscode/src/vscode-tests/cli-integration/databases.test.ts index 2ecbb9a8c..15fd96e01 100644 --- a/extensions/ql-vscode/src/vscode-tests/cli-integration/databases.test.ts +++ b/extensions/ql-vscode/src/vscode-tests/cli-integration/databases.test.ts @@ -5,7 +5,6 @@ import { CodeQLExtensionInterface } from "../../extension"; import { CodeQLCliServer } from "../../cli"; import { DatabaseManager } from "../../databases"; import { - promptImportLgtmDatabase, importArchiveDatabase, promptImportInternetDatabase, } from "../../databaseFetcher"; @@ -17,9 +16,6 @@ jest.setTimeout(60_000); * Run various integration tests for databases */ describe("Databases", () => { - const LGTM_URL = - "https://lgtm.com/projects/g/aeisenberg/angular-bind-notifier/"; - let databaseManager: DatabaseManager; let inputBoxStub: jest.SpiedFunction; let cli: CodeQLCliServer; @@ -71,27 +67,6 @@ describe("Databases", () => { expect(dbItem.databaseUri.fsPath).toBe(join(storagePath, "db", "db")); }); - it("should add a database from lgtm with only one language", async () => { - inputBoxStub.mockResolvedValue(LGTM_URL); - let dbItem = await promptImportLgtmDatabase( - databaseManager, - storagePath, - progressCallback, - {} as CancellationToken, - cli, - ); - expect(dbItem).toBeDefined(); - dbItem = dbItem!; - expect(dbItem.name).toBe("aeisenberg_angular-bind-notifier_106179a"); - expect(dbItem.databaseUri.fsPath).toBe( - join( - storagePath, - "javascript", - "aeisenberg_angular-bind-notifier_106179a", - ), - ); - }); - it("should add a database from a url", async () => { inputBoxStub.mockResolvedValue(DB_URL); diff --git a/extensions/ql-vscode/src/vscode-tests/no-workspace/databaseFetcher.test.ts b/extensions/ql-vscode/src/vscode-tests/no-workspace/databaseFetcher.test.ts index 32c6455b1..15d7e4018 100644 --- a/extensions/ql-vscode/src/vscode-tests/no-workspace/databaseFetcher.test.ts +++ b/extensions/ql-vscode/src/vscode-tests/no-workspace/databaseFetcher.test.ts @@ -5,8 +5,6 @@ import { QuickPickItem, window } from "vscode"; import { convertGithubNwoToDatabaseUrl, - convertLgtmUrlToDatabaseUrl, - looksLikeLgtmUrl, findDirWithFile, } from "../../databaseFetcher"; import * as Octokit from "@octokit/rest"; @@ -131,64 +129,6 @@ describe("databaseFetcher", () => { }); }); - describe("convertLgtmUrlToDatabaseUrl", () => { - let quickPickSpy: jest.SpiedFunction; - const progressSpy = jest.fn(); - - beforeEach(() => { - quickPickSpy = jest - .spyOn(window, "showQuickPick") - .mockResolvedValue(undefined); - }); - - it("should convert a project url to a database url", async () => { - quickPickSpy.mockResolvedValue("javascript" as unknown as QuickPickItem); - const lgtmUrl = "https://lgtm.com/projects/g/github/codeql"; - const dbUrl = await convertLgtmUrlToDatabaseUrl(lgtmUrl, progressSpy); - - expect(dbUrl).toBe( - "https://lgtm.com/api/v1.0/snapshots/1506465042581/javascript", - ); - expect(quickPickSpy).toHaveBeenNthCalledWith( - 1, - expect.arrayContaining(["javascript", "python"]), - expect.anything(), - ); - }); - - it("should convert a project url to a database url with extra path segments", async () => { - quickPickSpy.mockResolvedValue("python" as unknown as QuickPickItem); - const lgtmUrl = - "https://lgtm.com/projects/g/github/codeql/subpage/subpage2?query=xxx"; - const dbUrl = await convertLgtmUrlToDatabaseUrl(lgtmUrl, progressSpy); - - expect(dbUrl).toBe( - "https://lgtm.com/api/v1.0/snapshots/1506465042581/python", - ); - expect(progressSpy).toBeCalledTimes(1); - }); - - it("should convert a raw slug to a database url with extra path segments", async () => { - quickPickSpy.mockResolvedValue("python" as unknown as QuickPickItem); - const lgtmUrl = "g/github/codeql"; - const dbUrl = await convertLgtmUrlToDatabaseUrl(lgtmUrl, progressSpy); - - expect(dbUrl).toBe( - "https://lgtm.com/api/v1.0/snapshots/1506465042581/python", - ); - expect(progressSpy).toBeCalledTimes(1); - }); - - it("should fail on a nonexistent project", async () => { - quickPickSpy.mockResolvedValue("javascript" as unknown as QuickPickItem); - const lgtmUrl = "https://lgtm.com/projects/g/github/hucairz"; - await expect( - convertLgtmUrlToDatabaseUrl(lgtmUrl, progressSpy), - ).rejects.toThrow(/Invalid LGTM URL/); - expect(progressSpy).toBeCalledTimes(0); - }); - }); - describe("looksLikeGithubRepo", () => { it("should handle invalid urls", () => { expect(looksLikeGithubRepo("")).toBe(false); @@ -208,42 +148,6 @@ describe("databaseFetcher", () => { }); }); - describe("looksLikeLgtmUrl", () => { - it("should handle invalid urls", () => { - expect(looksLikeLgtmUrl("")).toBe(false); - expect(looksLikeLgtmUrl("http://lgtm.com/projects/g/github/codeql")).toBe( - false, - ); - expect( - looksLikeLgtmUrl("https://ww.lgtm.com/projects/g/github/codeql"), - ).toBe(false); - expect(looksLikeLgtmUrl("https://ww.lgtm.com/projects/g/github")).toBe( - false, - ); - expect(looksLikeLgtmUrl("g/github")).toBe(false); - expect(looksLikeLgtmUrl("ggg/github/myproj")).toBe(false); - }); - - it("should handle valid urls", () => { - expect( - looksLikeLgtmUrl("https://lgtm.com/projects/g/github/codeql"), - ).toBe(true); - expect( - looksLikeLgtmUrl("https://www.lgtm.com/projects/g/github/codeql"), - ).toBe(true); - expect( - looksLikeLgtmUrl("https://lgtm.com/projects/g/github/codeql/sub/pages"), - ).toBe(true); - expect( - looksLikeLgtmUrl( - "https://lgtm.com/projects/g/github/codeql/sub/pages?query=string", - ), - ).toBe(true); - expect(looksLikeLgtmUrl("g/github/myproj")).toBe(true); - expect(looksLikeLgtmUrl("git/github/myproj")).toBe(true); - }); - }); - describe("findDirWithFile", () => { let dir: tmp.DirResult; beforeEach(() => {