Merge remote-tracking branch 'origin/main' into koesie10/find-github-repository
This commit is contained in:
@@ -2,6 +2,15 @@
|
||||
|
||||
## [UNRELEASED]
|
||||
|
||||
- Add new CodeQL views for managing databases and queries:
|
||||
1. A queries panel, to create and run queries in one place.
|
||||
2. A language selector, to quickly determine the language compatibility of databases and queries.
|
||||
|
||||
For more information, see the [documentation](https://codeql.github.com/docs/codeql-for-visual-studio-code/analyzing-your-projects/#filtering-databases-and-queries-by-language).
|
||||
- When adding a CodeQL database, we no longer add the database source folder to the workspace by default (since this caused bugs in single-folder workspaces). [#3047](https://github.com/github/vscode-codeql/pull/3047)
|
||||
- You can manually add individual database source folders to the workspace with the "Add Database Source to Workspace" right-click command in the databases view.
|
||||
- To restore the old behavior of adding all database source folders by default, set the `codeQL.addingDatabases.addDatabaseSourceToWorkspace` setting to `true`.
|
||||
- Rename the `codeQL.databaseDownload.allowHttp` setting to `codeQL.addingDatabases.allowHttp`, so that database-related settings are grouped together in the Settings UI. [#3047](https://github.com/github/vscode-codeql/pull/3047) & [#3069](https://github.com/github/vscode-codeql/pull/3069)
|
||||
- The "Sort by Language" action in the databases view now sorts by name within each language. [#3055](https://github.com/github/vscode-codeql/pull/3055)
|
||||
|
||||
## 1.9.4 - 6 November 2023
|
||||
|
||||
12
extensions/ql-vscode/package-lock.json
generated
12
extensions/ql-vscode/package-lock.json
generated
@@ -4392,9 +4392,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.0.tgz",
|
||||
"integrity": "sha512-PclQ6JGMTE9iUStpzMkwLCISFn/wDeRjkZFIKALpvJQNBGwDoYYi2fFvuHwssoQ1rXI5mfh6jgTgWuddeUzfWw=="
|
||||
"version": "19.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.2.tgz",
|
||||
"integrity": "sha512-8li32fUDUeml/ACRp/njCWTsk5t17cfTM1jp9n08pBrqs5cDFJubtjsSnuz56r5Tad6jdEPJld7LxNp9dNcyjQ=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "9.0.0",
|
||||
@@ -35269,9 +35269,9 @@
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.0.tgz",
|
||||
"integrity": "sha512-PclQ6JGMTE9iUStpzMkwLCISFn/wDeRjkZFIKALpvJQNBGwDoYYi2fFvuHwssoQ1rXI5mfh6jgTgWuddeUzfWw=="
|
||||
"version": "19.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.2.tgz",
|
||||
"integrity": "sha512-8li32fUDUeml/ACRp/njCWTsk5t17cfTM1jp9n08pBrqs5cDFJubtjsSnuz56r5Tad6jdEPJld7LxNp9dNcyjQ=="
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "9.0.0",
|
||||
|
||||
@@ -374,13 +374,23 @@
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "Downloading databases",
|
||||
"title": "Adding databases",
|
||||
"order": 6,
|
||||
"properties": {
|
||||
"codeQL.databaseDownload.allowHttp": {
|
||||
"codeQL.addingDatabases.allowHttp": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Allow database to be downloaded via HTTP. Warning: enabling this option will allow downloading from insecure servers."
|
||||
"description": "Allow databases to be downloaded via HTTP. Warning: enabling this option will allow downloading from insecure servers."
|
||||
},
|
||||
"codeQL.databaseDownload.allowHttp": {
|
||||
"type": "boolean",
|
||||
"markdownDeprecationMessage": "**Deprecated**: Please use `#codeQL.addingDatabases.allowHttp#` instead.",
|
||||
"deprecationMessage": "Deprecated: Please use codeQL.addingDatabases.allowHttp instead."
|
||||
},
|
||||
"codeQL.addingDatabases.addDatabaseSourceToWorkspace": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"markdownDescription": "When adding a CodeQL database, automatically add the database's source folder as a workspace folder. Warning: enabling this option in a single-folder workspace will cause the workspace to reload as a [multi-root workspace](https://code.visualstudio.com/docs/editor/multi-root-workspaces). This may cause query history and database lists to be reset."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1678,10 +1688,6 @@
|
||||
"command": "codeQL.mockGitHubApiServer.unloadScenario",
|
||||
"when": "config.codeQL.mockGitHubApiServer.enabled && codeQL.mockGitHubApiServer.scenarioLoaded"
|
||||
},
|
||||
{
|
||||
"command": "codeQL.createQuery",
|
||||
"when": "config.codeQL.codespacesTemplate || config.codeQL.canary && config.codeQL.queriesPanel"
|
||||
},
|
||||
{
|
||||
"command": "codeQLTests.acceptOutputContextTestItem",
|
||||
"when": "false"
|
||||
@@ -1766,8 +1772,7 @@
|
||||
"ql-container": [
|
||||
{
|
||||
"id": "codeQLLanguageSelection",
|
||||
"name": "Language",
|
||||
"when": "config.codeQL.canary && config.codeQL.showLanguageFilter"
|
||||
"name": "Language"
|
||||
},
|
||||
{
|
||||
"id": "codeQLDatabases",
|
||||
@@ -1775,8 +1780,7 @@
|
||||
},
|
||||
{
|
||||
"id": "codeQLQueries",
|
||||
"name": "Queries",
|
||||
"when": "config.codeQL.canary && config.codeQL.queriesPanel"
|
||||
"name": "Queries"
|
||||
},
|
||||
{
|
||||
"id": "codeQLVariantAnalysisRepositories",
|
||||
|
||||
@@ -641,12 +641,32 @@ export function isCodespacesTemplate() {
|
||||
return !!CODESPACES_TEMPLATE.getValue<boolean>();
|
||||
}
|
||||
|
||||
// Deprecated after v1.9.4. Can be removed in a few versions.
|
||||
const DATABASE_DOWNLOAD_SETTING = new Setting("databaseDownload", ROOT_SETTING);
|
||||
const DEPRECATED_ALLOW_HTTP_SETTING = new Setting(
|
||||
"allowHttp",
|
||||
DATABASE_DOWNLOAD_SETTING,
|
||||
);
|
||||
|
||||
const ALLOW_HTTP_SETTING = new Setting("allowHttp", DATABASE_DOWNLOAD_SETTING);
|
||||
const ADDING_DATABASES_SETTING = new Setting("addingDatabases", ROOT_SETTING);
|
||||
|
||||
const ALLOW_HTTP_SETTING = new Setting("allowHttp", ADDING_DATABASES_SETTING);
|
||||
|
||||
export function allowHttp(): boolean {
|
||||
return ALLOW_HTTP_SETTING.getValue<boolean>() || false;
|
||||
return (
|
||||
ALLOW_HTTP_SETTING.getValue<boolean>() ||
|
||||
DEPRECATED_ALLOW_HTTP_SETTING.getValue<boolean>() ||
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
const ADD_DATABASE_SOURCE_TO_WORKSPACE_SETTING = new Setting(
|
||||
"addDatabaseSourceToWorkspace",
|
||||
ADDING_DATABASES_SETTING,
|
||||
);
|
||||
|
||||
export function addDatabaseSourceToWorkspace(): boolean {
|
||||
return ADD_DATABASE_SOURCE_TO_WORKSPACE_SETTING.getValue<boolean>() || false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -690,15 +710,6 @@ export async function setAutogenerateQlPacks(choice: AutogenerateQLPacks) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A flag indicating whether to show the queries panel in the QL view container.
|
||||
*/
|
||||
const QUERIES_PANEL = new Setting("queriesPanel", ROOT_SETTING);
|
||||
|
||||
export function showQueriesPanel(): boolean {
|
||||
return !!QUERIES_PANEL.getValue<boolean>();
|
||||
}
|
||||
|
||||
const MODEL_SETTING = new Setting("model", ROOT_SETTING);
|
||||
const FLOW_GENERATION = new Setting("flowGeneration", MODEL_SETTING);
|
||||
const LLM_GENERATION = new Setting("llmGeneration", MODEL_SETTING);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Contains models and consts for the data we want to store in the database config.
|
||||
// Changes to these models should be done carefully and account for backwards compatibility of data.
|
||||
|
||||
import { DatabaseOrigin } from "../local-databases/database-origin";
|
||||
|
||||
export const DB_CONFIG_VERSION = 1;
|
||||
|
||||
export interface DbConfig {
|
||||
@@ -88,6 +90,7 @@ export interface LocalDatabase {
|
||||
name: string;
|
||||
dateAdded: number;
|
||||
language: string;
|
||||
origin: DatabaseOrigin;
|
||||
storagePath: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,11 @@ import {
|
||||
} from "../common/github-url-identifier-helper";
|
||||
import { Credentials } from "../common/authentication";
|
||||
import { AppCommandManager } from "../common/commands";
|
||||
import { allowHttp } from "../config";
|
||||
import { addDatabaseSourceToWorkspace, allowHttp } from "../config";
|
||||
import { showAndLogInformationMessage } from "../common/logging";
|
||||
import { AppOctokit } from "../common/octokit";
|
||||
import { getLanguageDisplayName } from "../common/query-language";
|
||||
import { DatabaseOrigin } from "./local-databases/database-origin";
|
||||
|
||||
/**
|
||||
* Prompts a user to fetch a database from a remote location. Database is assumed to be an archive file.
|
||||
@@ -62,6 +63,10 @@ export async function promptImportInternetDatabase(
|
||||
databaseManager,
|
||||
storagePath,
|
||||
undefined,
|
||||
{
|
||||
type: "url",
|
||||
url: databaseUrl,
|
||||
},
|
||||
progress,
|
||||
cli,
|
||||
);
|
||||
@@ -99,7 +104,7 @@ export async function promptImportGithubDatabase(
|
||||
cli?: CodeQLCliServer,
|
||||
language?: string,
|
||||
makeSelected = true,
|
||||
addSourceArchiveFolder = true,
|
||||
addSourceArchiveFolder = addDatabaseSourceToWorkspace(),
|
||||
): Promise<DatabaseItem | undefined> {
|
||||
const githubRepo = await askForGitHubRepo(progress);
|
||||
if (!githubRepo) {
|
||||
@@ -178,7 +183,7 @@ export async function downloadGitHubDatabase(
|
||||
cli?: CodeQLCliServer,
|
||||
language?: string,
|
||||
makeSelected = true,
|
||||
addSourceArchiveFolder = true,
|
||||
addSourceArchiveFolder = addDatabaseSourceToWorkspace(),
|
||||
): Promise<DatabaseItem | undefined> {
|
||||
const nwo = getNwoFromGitHubUrl(githubRepo) || githubRepo;
|
||||
if (!isValidGitHubNwo(nwo)) {
|
||||
@@ -199,7 +204,8 @@ export async function downloadGitHubDatabase(
|
||||
return;
|
||||
}
|
||||
|
||||
const { databaseUrl, name, owner } = result;
|
||||
const { databaseUrl, name, owner, databaseId, databaseCreatedAt, commitOid } =
|
||||
result;
|
||||
|
||||
/**
|
||||
* The 'token' property of the token object returned by `octokit.auth()`.
|
||||
@@ -221,6 +227,13 @@ export async function downloadGitHubDatabase(
|
||||
databaseManager,
|
||||
storagePath,
|
||||
`${owner}/${name}`,
|
||||
{
|
||||
type: "github",
|
||||
repository: nwo,
|
||||
databaseId,
|
||||
databaseCreatedAt,
|
||||
commitOid,
|
||||
},
|
||||
progress,
|
||||
cli,
|
||||
makeSelected,
|
||||
@@ -250,6 +263,10 @@ export async function importArchiveDatabase(
|
||||
databaseManager,
|
||||
storagePath,
|
||||
undefined,
|
||||
{
|
||||
type: "archive",
|
||||
path: databaseUrl,
|
||||
},
|
||||
progress,
|
||||
cli,
|
||||
);
|
||||
@@ -282,6 +299,7 @@ export async function importArchiveDatabase(
|
||||
* @param databaseManager the DatabaseManager
|
||||
* @param storagePath where to store the unzipped database.
|
||||
* @param nameOverride a name for the database that overrides the default
|
||||
* @param origin the origin of the database
|
||||
* @param progress callback to send progress messages to
|
||||
* @param makeSelected make the new database selected in the databases panel (default: true)
|
||||
* @param addSourceArchiveFolder whether to add a workspace folder containing the source archive to the workspace
|
||||
@@ -292,10 +310,11 @@ async function databaseArchiveFetcher(
|
||||
databaseManager: DatabaseManager,
|
||||
storagePath: string,
|
||||
nameOverride: string | undefined,
|
||||
origin: DatabaseOrigin,
|
||||
progress: ProgressCallback,
|
||||
cli?: CodeQLCliServer,
|
||||
makeSelected = true,
|
||||
addSourceArchiveFolder = true,
|
||||
addSourceArchiveFolder = addDatabaseSourceToWorkspace(),
|
||||
): Promise<DatabaseItem> {
|
||||
progress({
|
||||
message: "Getting database",
|
||||
@@ -336,6 +355,7 @@ async function databaseArchiveFetcher(
|
||||
|
||||
const item = await databaseManager.openDatabase(
|
||||
Uri.file(dbPath),
|
||||
origin,
|
||||
makeSelected,
|
||||
nameOverride,
|
||||
{
|
||||
@@ -476,7 +496,7 @@ async function checkForFailingResponse(
|
||||
return response;
|
||||
}
|
||||
|
||||
// An error downloading the database. Attempt to extract the resaon behind it.
|
||||
// An error downloading the database. Attempt to extract the reason behind it.
|
||||
const text = await response.text();
|
||||
let msg: string;
|
||||
try {
|
||||
@@ -533,16 +553,19 @@ export async function convertGithubNwoToDatabaseUrl(
|
||||
databaseUrl: string;
|
||||
owner: string;
|
||||
name: string;
|
||||
databaseId: number;
|
||||
databaseCreatedAt: string;
|
||||
commitOid: string | null;
|
||||
}
|
||||
| undefined
|
||||
> {
|
||||
try {
|
||||
const [owner, repo] = nwo.split("/");
|
||||
|
||||
const response = await octokit.request(
|
||||
"GET /repos/:owner/:repo/code-scanning/codeql/databases",
|
||||
{ owner, repo },
|
||||
);
|
||||
const response = await octokit.rest.codeScanning.listCodeqlDatabases({
|
||||
owner,
|
||||
repo,
|
||||
});
|
||||
|
||||
const languages = response.data.map((db: any) => db.language);
|
||||
|
||||
@@ -553,10 +576,20 @@ export async function convertGithubNwoToDatabaseUrl(
|
||||
}
|
||||
}
|
||||
|
||||
const databaseForLanguage = response.data.find(
|
||||
(db: any) => db.language === language,
|
||||
);
|
||||
if (!databaseForLanguage) {
|
||||
throw new Error(`No database found for language '${language}'`);
|
||||
}
|
||||
|
||||
return {
|
||||
databaseUrl: `https://api.github.com/repos/${owner}/${repo}/code-scanning/codeql/databases/${language}`,
|
||||
databaseUrl: databaseForLanguage.url,
|
||||
owner,
|
||||
name: repo,
|
||||
databaseId: databaseForLanguage.id,
|
||||
databaseCreatedAt: databaseForLanguage.created_at,
|
||||
commitOid: databaseForLanguage.commit_oid ?? null,
|
||||
};
|
||||
} catch (e) {
|
||||
void extLogger.log(`Error: ${getErrorMessage(e)}`);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// This file contains models that are used to represent the databases.
|
||||
|
||||
import { DatabaseOrigin } from "./local-databases/database-origin";
|
||||
|
||||
export enum DbItemKind {
|
||||
RootLocal = "RootLocal",
|
||||
LocalList = "LocalList",
|
||||
@@ -38,6 +40,7 @@ export interface LocalDatabaseDbItem {
|
||||
databaseName: string;
|
||||
dateAdded: number;
|
||||
language: string;
|
||||
origin: DatabaseOrigin;
|
||||
storagePath: string;
|
||||
parentListName?: string;
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ function createLocalDb(
|
||||
databaseName: db.name,
|
||||
dateAdded: db.dateAdded,
|
||||
language: db.language,
|
||||
origin: db.origin,
|
||||
storagePath: db.storagePath,
|
||||
selected: !!selected,
|
||||
parentListName: listName,
|
||||
|
||||
@@ -367,6 +367,9 @@ export class DatabaseUI extends DisposableObject {
|
||||
|
||||
await this.databaseManager.openDatabase(
|
||||
uri,
|
||||
{
|
||||
type: "folder",
|
||||
},
|
||||
makeSelected,
|
||||
nameOverride,
|
||||
{
|
||||
@@ -704,7 +707,9 @@ export class DatabaseUI extends DisposableObject {
|
||||
this.queryServer?.cliServer,
|
||||
);
|
||||
} else {
|
||||
await this.databaseManager.openDatabase(uri);
|
||||
await this.databaseManager.openDatabase(uri, {
|
||||
type: "folder",
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// rethrow and let this be handled by default error handling.
|
||||
@@ -819,7 +824,9 @@ export class DatabaseUI extends DisposableObject {
|
||||
if (byFolder) {
|
||||
const fixedUri = await this.fixDbUri(uri);
|
||||
// we are selecting a database folder
|
||||
return await this.databaseManager.openDatabase(fixedUri);
|
||||
return await this.databaseManager.openDatabase(fixedUri, {
|
||||
type: "folder",
|
||||
});
|
||||
} else {
|
||||
// we are selecting a database archive. Must unzip into a workspace-controlled area
|
||||
// before importing.
|
||||
|
||||
@@ -14,6 +14,7 @@ import { isLikelyDatabaseRoot } from "./db-contents-heuristics";
|
||||
import { stat } from "fs-extra";
|
||||
import { containsPath, pathsEqual } from "../../common/files";
|
||||
import { DatabaseContents } from "./database-contents";
|
||||
import { DatabaseOrigin } from "./database-origin";
|
||||
|
||||
export class DatabaseItemImpl implements DatabaseItem {
|
||||
// These are only public in the implementation, they are readonly in the interface
|
||||
@@ -61,6 +62,10 @@ export class DatabaseItemImpl implements DatabaseItem {
|
||||
return this.options.dateAdded;
|
||||
}
|
||||
|
||||
public get origin(): DatabaseOrigin | undefined {
|
||||
return this.options.origin;
|
||||
}
|
||||
|
||||
public resolveSourceFile(uriStr: string | undefined): vscode.Uri {
|
||||
const sourceArchive = this.sourceArchive;
|
||||
const uri = uriStr ? vscode.Uri.parse(uriStr, true) : undefined;
|
||||
|
||||
@@ -2,6 +2,7 @@ import vscode from "vscode";
|
||||
import * as cli from "../../codeql-cli/cli";
|
||||
import { DatabaseContents } from "./database-contents";
|
||||
import { DatabaseOptions } from "./database-options";
|
||||
import { DatabaseOrigin } from "./database-origin";
|
||||
|
||||
/** An item in the list of available databases */
|
||||
export interface DatabaseItem {
|
||||
@@ -25,6 +26,11 @@ export interface DatabaseItem {
|
||||
*/
|
||||
readonly dateAdded: number | undefined;
|
||||
|
||||
/**
|
||||
* The origin this database item was retrieved from or undefined if unknown.
|
||||
*/
|
||||
readonly origin: DatabaseOrigin | undefined;
|
||||
|
||||
/** If the database is invalid, describes why. */
|
||||
readonly error: Error | undefined;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { QueryRunner } from "../../query-server";
|
||||
import * as cli from "../../codeql-cli/cli";
|
||||
import { ProgressCallback, withProgress } from "../../common/vscode/progress";
|
||||
import {
|
||||
addDatabaseSourceToWorkspace,
|
||||
getAutogenerateQlPacks,
|
||||
isCodespacesTemplate,
|
||||
setAutogenerateQlPacks,
|
||||
@@ -34,6 +35,7 @@ import { DatabaseChangedEvent, DatabaseEventKind } from "./database-events";
|
||||
import { DatabaseResolver } from "./database-resolver";
|
||||
import { telemetryListener } from "../../common/vscode/telemetry";
|
||||
import { LanguageContextStore } from "../../language-context-store";
|
||||
import { DatabaseOrigin } from "./database-origin";
|
||||
|
||||
/**
|
||||
* The name of the key in the workspaceState dictionary in which we
|
||||
@@ -115,7 +117,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
this.languageContext.onLanguageContextChanged(async () => {
|
||||
if (
|
||||
this.currentDatabaseItem !== undefined &&
|
||||
!this.languageContext.isSelectedLanguage(
|
||||
!this.languageContext.shouldInclude(
|
||||
tryGetQueryLanguage(this.currentDatabaseItem.language),
|
||||
)
|
||||
) {
|
||||
@@ -131,14 +133,19 @@ export class DatabaseManager extends DisposableObject {
|
||||
*/
|
||||
public async openDatabase(
|
||||
uri: vscode.Uri,
|
||||
origin: DatabaseOrigin | undefined,
|
||||
makeSelected = true,
|
||||
displayName?: string,
|
||||
{
|
||||
isTutorialDatabase = false,
|
||||
addSourceArchiveFolder = true,
|
||||
addSourceArchiveFolder = addDatabaseSourceToWorkspace(),
|
||||
}: OpenDatabaseOptions = {},
|
||||
): Promise<DatabaseItem> {
|
||||
const databaseItem = await this.createDatabaseItem(uri, displayName);
|
||||
const databaseItem = await this.createDatabaseItem(
|
||||
uri,
|
||||
origin,
|
||||
displayName,
|
||||
);
|
||||
|
||||
return await this.addExistingDatabaseItem(
|
||||
databaseItem,
|
||||
@@ -158,7 +165,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
databaseItem: DatabaseItemImpl,
|
||||
makeSelected: boolean,
|
||||
isTutorialDatabase?: boolean,
|
||||
addSourceArchiveFolder = true,
|
||||
addSourceArchiveFolder = addDatabaseSourceToWorkspace(),
|
||||
): Promise<DatabaseItem> {
|
||||
const existingItem = this.findDatabaseItem(databaseItem.databaseUri);
|
||||
if (existingItem !== undefined) {
|
||||
@@ -189,6 +196,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
*/
|
||||
private async createDatabaseItem(
|
||||
uri: vscode.Uri,
|
||||
origin: DatabaseOrigin | undefined,
|
||||
displayName: string | undefined,
|
||||
): Promise<DatabaseItemImpl> {
|
||||
const contents = await DatabaseResolver.resolveDatabaseContents(uri);
|
||||
@@ -197,6 +205,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
displayName,
|
||||
dateAdded: Date.now(),
|
||||
language: await this.getPrimaryLanguage(uri.fsPath),
|
||||
origin,
|
||||
};
|
||||
const databaseItem = new DatabaseItemImpl(uri, contents, fullOptions);
|
||||
|
||||
@@ -212,6 +221,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
*/
|
||||
public async createOrOpenDatabaseItem(
|
||||
uri: vscode.Uri,
|
||||
origin: DatabaseOrigin | undefined,
|
||||
): Promise<DatabaseItem> {
|
||||
const existingItem = this.findDatabaseItem(uri);
|
||||
if (existingItem !== undefined) {
|
||||
@@ -220,7 +230,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
}
|
||||
|
||||
// We don't add this to the list automatically, but the user can add it later.
|
||||
return this.createDatabaseItem(uri, undefined);
|
||||
return this.createDatabaseItem(uri, origin, undefined);
|
||||
}
|
||||
|
||||
public async createSkeletonPacks(databaseItem: DatabaseItem) {
|
||||
@@ -355,6 +365,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
let displayName: string | undefined = undefined;
|
||||
let dateAdded = undefined;
|
||||
let language = undefined;
|
||||
let origin = undefined;
|
||||
if (state.options) {
|
||||
if (typeof state.options.displayName === "string") {
|
||||
displayName = state.options.displayName;
|
||||
@@ -363,6 +374,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
dateAdded = state.options.dateAdded;
|
||||
}
|
||||
language = state.options.language;
|
||||
origin = state.options.origin;
|
||||
}
|
||||
|
||||
const dbBaseUri = vscode.Uri.parse(state.uri, true);
|
||||
@@ -375,6 +387,7 @@ export class DatabaseManager extends DisposableObject {
|
||||
displayName,
|
||||
dateAdded,
|
||||
language,
|
||||
origin,
|
||||
};
|
||||
const item = new DatabaseItemImpl(dbBaseUri, undefined, fullOptions);
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { DatabaseOrigin } from "./database-origin";
|
||||
|
||||
export interface DatabaseOptions {
|
||||
displayName?: string;
|
||||
dateAdded?: number | undefined;
|
||||
language?: string;
|
||||
origin?: DatabaseOrigin;
|
||||
}
|
||||
|
||||
export interface FullDatabaseOptions extends DatabaseOptions {
|
||||
dateAdded: number | undefined;
|
||||
language: string | undefined;
|
||||
origin: DatabaseOrigin | undefined;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
interface DatabaseOriginFolder {
|
||||
type: "folder";
|
||||
}
|
||||
|
||||
interface DatabaseOriginArchive {
|
||||
type: "archive";
|
||||
path: string;
|
||||
}
|
||||
|
||||
interface DatabaseOriginGitHub {
|
||||
type: "github";
|
||||
repository: string;
|
||||
databaseId: number;
|
||||
databaseCreatedAt: string;
|
||||
commitOid: string | null;
|
||||
}
|
||||
|
||||
interface DatabaseOriginInternet {
|
||||
type: "url";
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface DatabaseOriginDebugger {
|
||||
type: "debugger";
|
||||
}
|
||||
|
||||
export type DatabaseOrigin =
|
||||
| DatabaseOriginFolder
|
||||
| DatabaseOriginArchive
|
||||
| DatabaseOriginGitHub
|
||||
| DatabaseOriginInternet
|
||||
| DatabaseOriginDebugger;
|
||||
@@ -105,7 +105,9 @@ class QLDebugAdapterTracker
|
||||
body: CodeQLProtocol.EvaluationStartedEvent["body"],
|
||||
): Promise<void> {
|
||||
const dbUri = Uri.file(this.configuration.database);
|
||||
const dbItem = await this.dbm.createOrOpenDatabaseItem(dbUri);
|
||||
const dbItem = await this.dbm.createOrOpenDatabaseItem(dbUri, {
|
||||
type: "debugger",
|
||||
});
|
||||
|
||||
// When cancellation is requested from the query history view, we just stop the debug session.
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdir, writeFile } from "fs-extra";
|
||||
import { ensureDir, writeFile } from "fs-extra";
|
||||
import { dump } from "js-yaml";
|
||||
import { dirname, join } from "path";
|
||||
import { Uri } from "vscode";
|
||||
@@ -76,7 +76,7 @@ export class QlPackGenerator {
|
||||
}
|
||||
|
||||
private async createWorkspaceFolder() {
|
||||
await mkdir(this.folderUri.fsPath);
|
||||
await ensureDir(this.folderUri.fsPath);
|
||||
}
|
||||
|
||||
private async createQlPackYaml() {
|
||||
|
||||
@@ -4,7 +4,6 @@ import { DisposableObject } from "../../common/disposable-object";
|
||||
import { MethodModelingViewProvider } from "./method-modeling-view-provider";
|
||||
import { Method } from "../method";
|
||||
import { ModelingStore } from "../modeling-store";
|
||||
import { ModelEditorViewTracker } from "../model-editor-view-tracker";
|
||||
import { ModelConfigListener } from "../../config";
|
||||
import { DatabaseItem } from "../../databases/local-databases";
|
||||
import { ModelingEvents } from "../modeling-events";
|
||||
@@ -16,7 +15,6 @@ export class MethodModelingPanel extends DisposableObject {
|
||||
app: App,
|
||||
modelingStore: ModelingStore,
|
||||
modelingEvents: ModelingEvents,
|
||||
editorViewTracker: ModelEditorViewTracker,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -29,7 +27,6 @@ export class MethodModelingPanel extends DisposableObject {
|
||||
app,
|
||||
modelingStore,
|
||||
modelingEvents,
|
||||
editorViewTracker,
|
||||
modelConfig,
|
||||
);
|
||||
this.push(
|
||||
|
||||
@@ -10,7 +10,6 @@ import { Method } from "../method";
|
||||
import { ModelingStore } from "../modeling-store";
|
||||
import { AbstractWebviewViewProvider } from "../../common/vscode/abstract-webview-view-provider";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
import { ModelEditorViewTracker } from "../model-editor-view-tracker";
|
||||
import { ModelConfigListener } from "../../config";
|
||||
import { DatabaseItem } from "../../databases/local-databases";
|
||||
import { ModelingEvents } from "../modeling-events";
|
||||
@@ -33,7 +32,6 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
|
||||
app: App,
|
||||
private readonly modelingStore: ModelingStore,
|
||||
private readonly modelingEvents: ModelingEvents,
|
||||
private readonly editorViewTracker: ModelEditorViewTracker,
|
||||
private readonly modelConfig: ModelConfigListener,
|
||||
) {
|
||||
super(app, "method-modeling");
|
||||
@@ -158,10 +156,10 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
|
||||
return;
|
||||
}
|
||||
|
||||
const view = this.editorViewTracker.getView(
|
||||
this.modelingEvents.fireRevealInModelEditorEvent(
|
||||
this.databaseItem.databaseUri.toString(),
|
||||
method,
|
||||
);
|
||||
await view?.revealMethod(method);
|
||||
}
|
||||
|
||||
private registerToModelingEvents(): void {
|
||||
|
||||
@@ -19,7 +19,6 @@ import { setUpPack } from "./model-editor-queries-setup";
|
||||
import { MethodModelingPanel } from "./method-modeling/method-modeling-panel";
|
||||
import { ModelingStore } from "./modeling-store";
|
||||
import { showResolvableLocation } from "../databases/local-databases/locations";
|
||||
import { ModelEditorViewTracker } from "./model-editor-view-tracker";
|
||||
import { ModelConfigListener } from "../config";
|
||||
import { ModelingEvents } from "./modeling-events";
|
||||
import { getModelsAsDataLanguage } from "./languages";
|
||||
@@ -30,7 +29,6 @@ export class ModelEditorModule extends DisposableObject {
|
||||
private readonly queryStorageDir: string;
|
||||
private readonly modelingStore: ModelingStore;
|
||||
private readonly modelingEvents: ModelingEvents;
|
||||
private readonly editorViewTracker: ModelEditorViewTracker<ModelEditorView>;
|
||||
private readonly methodsUsagePanel: MethodsUsagePanel;
|
||||
private readonly methodModelingPanel: MethodModelingPanel;
|
||||
private readonly modelConfig: ModelConfigListener;
|
||||
@@ -46,17 +44,11 @@ export class ModelEditorModule extends DisposableObject {
|
||||
this.queryStorageDir = join(baseQueryStorageDir, "model-editor-results");
|
||||
this.modelingEvents = new ModelingEvents(app);
|
||||
this.modelingStore = new ModelingStore(this.modelingEvents);
|
||||
this.editorViewTracker = new ModelEditorViewTracker();
|
||||
this.methodsUsagePanel = this.push(
|
||||
new MethodsUsagePanel(this.modelingStore, this.modelingEvents, cliServer),
|
||||
);
|
||||
this.methodModelingPanel = this.push(
|
||||
new MethodModelingPanel(
|
||||
app,
|
||||
this.modelingStore,
|
||||
this.modelingEvents,
|
||||
this.editorViewTracker,
|
||||
),
|
||||
new MethodModelingPanel(app, this.modelingStore, this.modelingEvents),
|
||||
);
|
||||
this.modelConfig = this.push(new ModelConfigListener());
|
||||
|
||||
@@ -144,12 +136,10 @@ export class ModelEditorModule extends DisposableObject {
|
||||
|
||||
const initialMode = definition.availableModes?.[0] ?? INITIAL_MODE;
|
||||
|
||||
const existingView = this.editorViewTracker.getView(
|
||||
db.databaseUri.toString(),
|
||||
);
|
||||
if (existingView) {
|
||||
await existingView.focusView();
|
||||
|
||||
if (this.modelingStore.isDbOpen(db.databaseUri.toString())) {
|
||||
this.modelingEvents.fireFocusModelEditorEvent(
|
||||
db.databaseUri.toString(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -218,12 +208,10 @@ export class ModelEditorModule extends DisposableObject {
|
||||
|
||||
// Check again just before opening the editor to ensure no model editor has been opened between
|
||||
// our first check and now.
|
||||
const existingView = this.editorViewTracker.getView(
|
||||
db.databaseUri.toString(),
|
||||
);
|
||||
if (existingView) {
|
||||
await existingView.focusView();
|
||||
|
||||
if (this.modelingStore.isDbOpen(db.databaseUri.toString())) {
|
||||
this.modelingEvents.fireFocusModelEditorEvent(
|
||||
db.databaseUri.toString(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -231,7 +219,6 @@ export class ModelEditorModule extends DisposableObject {
|
||||
this.app,
|
||||
this.modelingStore,
|
||||
this.modelingEvents,
|
||||
this.editorViewTracker,
|
||||
this.modelConfig,
|
||||
this.databaseManager,
|
||||
this.cliServer,
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { Method } from "./method";
|
||||
|
||||
interface ModelEditorViewInterface {
|
||||
databaseUri: string;
|
||||
|
||||
revealMethod(method: Method): Promise<void>;
|
||||
}
|
||||
|
||||
export class ModelEditorViewTracker<
|
||||
T extends ModelEditorViewInterface = ModelEditorViewInterface,
|
||||
> {
|
||||
private readonly views = new Map<string, T>();
|
||||
|
||||
constructor() {}
|
||||
|
||||
public registerView(view: T): void {
|
||||
const databaseUri = view.databaseUri;
|
||||
|
||||
if (this.views.has(databaseUri)) {
|
||||
throw new Error(`View for database ${databaseUri} already registered`);
|
||||
}
|
||||
|
||||
this.views.set(databaseUri, view);
|
||||
}
|
||||
|
||||
public unregisterView(view: T): void {
|
||||
this.views.delete(view.databaseUri);
|
||||
}
|
||||
|
||||
public getView(databaseUri: string): T | undefined {
|
||||
return this.views.get(databaseUri);
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,6 @@ import {
|
||||
import { AutoModeler } from "./auto-modeler";
|
||||
import { telemetryListener } from "../common/vscode/telemetry";
|
||||
import { ModelingStore } from "./modeling-store";
|
||||
import { ModelEditorViewTracker } from "./model-editor-view-tracker";
|
||||
import { ModelingEvents } from "./modeling-events";
|
||||
import { getModelsAsDataLanguage, ModelsAsDataLanguage } from "./languages";
|
||||
import { runGenerateQueries } from "./generate";
|
||||
@@ -60,7 +59,6 @@ export class ModelEditorView extends AbstractWebview<
|
||||
protected readonly app: App,
|
||||
private readonly modelingStore: ModelingStore,
|
||||
private readonly modelingEvents: ModelingEvents,
|
||||
private readonly viewTracker: ModelEditorViewTracker<ModelEditorView>,
|
||||
private readonly modelConfig: ModelConfigListener,
|
||||
private readonly databaseManager: DatabaseManager,
|
||||
private readonly cliServer: CodeQLCliServer,
|
||||
@@ -79,8 +77,6 @@ export class ModelEditorView extends AbstractWebview<
|
||||
this.registerToModelingEvents();
|
||||
this.registerToModelConfigEvents();
|
||||
|
||||
this.viewTracker.registerView(this);
|
||||
|
||||
this.autoModeler = new AutoModeler(
|
||||
app,
|
||||
cliServer,
|
||||
@@ -166,7 +162,7 @@ export class ModelEditorView extends AbstractWebview<
|
||||
}
|
||||
|
||||
protected onPanelDispose(): void {
|
||||
this.viewTracker.unregisterView(this);
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
protected async onMessage(msg: FromModelEditorMessage): Promise<void> {
|
||||
@@ -573,12 +569,9 @@ export class ModelEditorView extends AbstractWebview<
|
||||
return;
|
||||
}
|
||||
|
||||
let existingView = this.viewTracker.getView(
|
||||
addedDatabase.databaseUri.toString(),
|
||||
);
|
||||
if (existingView) {
|
||||
await existingView.focusView();
|
||||
|
||||
const addedDbUri = addedDatabase.databaseUri.toString();
|
||||
if (this.modelingStore.isDbOpen(addedDbUri)) {
|
||||
this.modelingEvents.fireFocusModelEditorEvent(addedDbUri);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -596,12 +589,8 @@ export class ModelEditorView extends AbstractWebview<
|
||||
|
||||
// Check again just before opening the editor to ensure no model editor has been opened between
|
||||
// our first check and now.
|
||||
existingView = this.viewTracker.getView(
|
||||
addedDatabase.databaseUri.toString(),
|
||||
);
|
||||
if (existingView) {
|
||||
await existingView.focusView();
|
||||
|
||||
if (this.modelingStore.isDbOpen(addedDbUri)) {
|
||||
this.modelingEvents.fireFocusModelEditorEvent(addedDbUri);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -609,7 +598,6 @@ export class ModelEditorView extends AbstractWebview<
|
||||
this.app,
|
||||
this.modelingStore,
|
||||
this.modelingEvents,
|
||||
this.viewTracker,
|
||||
this.modelConfig,
|
||||
this.databaseManager,
|
||||
this.cliServer,
|
||||
@@ -742,6 +730,22 @@ export class ModelEditorView extends AbstractWebview<
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
this.push(
|
||||
this.modelingEvents.onRevealInModelEditor(async (event) => {
|
||||
if (event.dbUri === this.databaseItem.databaseUri.toString()) {
|
||||
await this.revealMethod(event.method);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
this.push(
|
||||
this.modelingEvents.onFocusModelEditor(async (event) => {
|
||||
if (event.dbUri === this.databaseItem.databaseUri.toString()) {
|
||||
await this.focusView();
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private registerToModelConfigEvents() {
|
||||
|
||||
@@ -126,3 +126,38 @@ export function isModelAccepted(
|
||||
modeledMethod.provenance !== "ai-generated"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the new provenance for a modeled method based on the current provenance.
|
||||
* @param modeledMethod The modeled method if there is one.
|
||||
* @returns The new provenance.
|
||||
*/
|
||||
export function calculateNewProvenance(
|
||||
modeledMethod: ModeledMethod | undefined,
|
||||
) {
|
||||
if (!modeledMethod || !modeledMethodSupportsProvenance(modeledMethod)) {
|
||||
// If nothing has been modeled or the modeled method does not support
|
||||
// provenance, we assume that the user has entered it manually.
|
||||
return "manual";
|
||||
}
|
||||
|
||||
switch (modeledMethod.provenance) {
|
||||
case "df-generated":
|
||||
// If the method has been generated and there has been a change, we assume
|
||||
// that the user has manually edited it.
|
||||
return "df-manual";
|
||||
case "df-manual":
|
||||
// If the method has had manual edits, we want the provenance to stay the same.
|
||||
return "df-manual";
|
||||
case "ai-generated":
|
||||
// If the method has been generated and there has been a change, we assume
|
||||
// that the user has manually edited it.
|
||||
return "ai-manual";
|
||||
case "ai-manual":
|
||||
// If the method has had manual edits, we want the provenance to stay the same.
|
||||
return "ai-manual";
|
||||
default:
|
||||
// The method has been modeled manually.
|
||||
return "manual";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,15 @@ interface InProgressMethodsChangedEvent {
|
||||
readonly methods: ReadonlySet<string>;
|
||||
}
|
||||
|
||||
interface RevealInModelEditorEvent {
|
||||
dbUri: string;
|
||||
method: Method;
|
||||
}
|
||||
|
||||
interface FocusModelEditorEvent {
|
||||
dbUri: string;
|
||||
}
|
||||
|
||||
export class ModelingEvents extends DisposableObject {
|
||||
public readonly onActiveDbChanged: AppEvent<void>;
|
||||
public readonly onDbOpened: AppEvent<DatabaseItem>;
|
||||
@@ -59,6 +68,8 @@ export class ModelingEvents extends DisposableObject {
|
||||
public readonly onModifiedMethodsChanged: AppEvent<ModifiedMethodsChangedEvent>;
|
||||
public readonly onSelectedMethodChanged: AppEvent<SelectedMethodChangedEvent>;
|
||||
public readonly onInProgressMethodsChanged: AppEvent<InProgressMethodsChangedEvent>;
|
||||
public readonly onRevealInModelEditor: AppEvent<RevealInModelEditorEvent>;
|
||||
public readonly onFocusModelEditor: AppEvent<FocusModelEditorEvent>;
|
||||
|
||||
private readonly onActiveDbChangedEventEmitter: AppEventEmitter<void>;
|
||||
private readonly onDbOpenedEventEmitter: AppEventEmitter<DatabaseItem>;
|
||||
@@ -70,6 +81,8 @@ export class ModelingEvents extends DisposableObject {
|
||||
private readonly onModifiedMethodsChangedEventEmitter: AppEventEmitter<ModifiedMethodsChangedEvent>;
|
||||
private readonly onSelectedMethodChangedEventEmitter: AppEventEmitter<SelectedMethodChangedEvent>;
|
||||
private readonly onInProgressMethodsChangedEventEmitter: AppEventEmitter<InProgressMethodsChangedEvent>;
|
||||
private readonly onRevealInModelEditorEventEmitter: AppEventEmitter<RevealInModelEditorEvent>;
|
||||
private readonly onFocusModelEditorEventEmitter: AppEventEmitter<FocusModelEditorEvent>;
|
||||
|
||||
constructor(app: App) {
|
||||
super();
|
||||
@@ -126,6 +139,16 @@ export class ModelingEvents extends DisposableObject {
|
||||
);
|
||||
this.onInProgressMethodsChanged =
|
||||
this.onInProgressMethodsChangedEventEmitter.event;
|
||||
|
||||
this.onRevealInModelEditorEventEmitter = this.push(
|
||||
app.createEventEmitter<RevealInModelEditorEvent>(),
|
||||
);
|
||||
this.onRevealInModelEditor = this.onRevealInModelEditorEventEmitter.event;
|
||||
|
||||
this.onFocusModelEditorEventEmitter = this.push(
|
||||
app.createEventEmitter<FocusModelEditorEvent>(),
|
||||
);
|
||||
this.onFocusModelEditor = this.onFocusModelEditorEventEmitter.event;
|
||||
}
|
||||
|
||||
public fireActiveDbChangedEvent() {
|
||||
@@ -220,4 +243,17 @@ export class ModelingEvents extends DisposableObject {
|
||||
methods,
|
||||
});
|
||||
}
|
||||
|
||||
public fireRevealInModelEditorEvent(dbUri: string, method: Method) {
|
||||
this.onRevealInModelEditorEventEmitter.fire({
|
||||
dbUri,
|
||||
method,
|
||||
});
|
||||
}
|
||||
|
||||
public fireFocusModelEditorEvent(dbUri: string) {
|
||||
this.onFocusModelEditorEventEmitter.fire({
|
||||
dbUri,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +112,10 @@ export class ModelingStore extends DisposableObject {
|
||||
return this.state.size > 0;
|
||||
}
|
||||
|
||||
public isDbOpen(dbUri: string): boolean {
|
||||
return this.state.has(dbUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method for the given database item and method signature.
|
||||
* Returns undefined if no method exists with that signature.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { CodeQLCliServer } from "../codeql-cli/cli";
|
||||
import { extLogger } from "../common/logging/vscode";
|
||||
import { App } from "../common/app";
|
||||
import { isCanary, showQueriesPanel } from "../config";
|
||||
import { DisposableObject } from "../common/disposable-object";
|
||||
import { QueriesPanel } from "./queries-panel";
|
||||
import { QueryDiscovery } from "./query-discovery";
|
||||
@@ -41,11 +40,6 @@ export class QueriesModule extends DisposableObject {
|
||||
langauageContext: LanguageContextStore,
|
||||
cliServer: CodeQLCliServer,
|
||||
): void {
|
||||
// Currently, we only want to expose the new panel when we are in canary mode
|
||||
// and the user has enabled the "Show queries panel" flag.
|
||||
if (!isCanary() || !showQueriesPanel()) {
|
||||
return;
|
||||
}
|
||||
void extLogger.log("Initializing queries panel.");
|
||||
|
||||
const queryPackDiscovery = new QueryPackDiscovery(cliServer);
|
||||
|
||||
@@ -103,6 +103,7 @@ export class TestRunner extends DisposableObject {
|
||||
try {
|
||||
const reopenedDatabase = await this.databaseManager.openDatabase(
|
||||
uri,
|
||||
closedDatabase.origin,
|
||||
false,
|
||||
);
|
||||
await this.databaseManager.renameDatabaseItem(
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as React from "react";
|
||||
import { ChangeEvent, useCallback, useMemo } from "react";
|
||||
import {
|
||||
ModeledMethod,
|
||||
calculateNewProvenance,
|
||||
isModelAccepted,
|
||||
modeledMethodSupportsInput,
|
||||
} from "../../model-editor/modeled-method";
|
||||
@@ -53,6 +54,7 @@ export const ModelInputDropdown = ({
|
||||
|
||||
onChange({
|
||||
...modeledMethod,
|
||||
provenance: calculateNewProvenance(modeledMethod),
|
||||
input: target.value,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
ModeledMethodKind,
|
||||
modeledMethodSupportsKind,
|
||||
isModelAccepted,
|
||||
calculateNewProvenance,
|
||||
} from "../../model-editor/modeled-method";
|
||||
import { getModelsAsDataLanguage } from "../../model-editor/languages";
|
||||
import { QueryLanguage } from "../../common/query-language";
|
||||
@@ -52,6 +53,7 @@ export const ModelKindDropdown = ({
|
||||
|
||||
onChange({
|
||||
...modeledMethod,
|
||||
provenance: calculateNewProvenance(modeledMethod),
|
||||
kind,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as React from "react";
|
||||
import { ChangeEvent, useCallback, useMemo } from "react";
|
||||
import {
|
||||
ModeledMethod,
|
||||
calculateNewProvenance,
|
||||
isModelAccepted,
|
||||
modeledMethodSupportsOutput,
|
||||
} from "../../model-editor/modeled-method";
|
||||
@@ -54,6 +55,7 @@ export const ModelOutputDropdown = ({
|
||||
|
||||
onChange({
|
||||
...modeledMethod,
|
||||
provenance: calculateNewProvenance(modeledMethod),
|
||||
output: target.value,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import * as React from "react";
|
||||
import { ChangeEvent, useCallback } from "react";
|
||||
import {
|
||||
calculateNewProvenance,
|
||||
isModelAccepted,
|
||||
ModeledMethod,
|
||||
modeledMethodSupportsProvenance,
|
||||
ModeledMethodType,
|
||||
Provenance,
|
||||
} from "../../model-editor/modeled-method";
|
||||
import { Method } from "../../model-editor/method";
|
||||
import { createEmptyModeledMethod } from "../../model-editor/modeled-method-empty";
|
||||
@@ -43,15 +42,6 @@ export const ModelTypeDropdown = ({
|
||||
(e: ChangeEvent<HTMLSelectElement>) => {
|
||||
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
|
||||
|
||||
let newProvenance: Provenance = "manual";
|
||||
if (modeledMethod && modeledMethodSupportsProvenance(modeledMethod)) {
|
||||
if (modeledMethod.provenance === "df-generated") {
|
||||
newProvenance = "df-manual";
|
||||
} else if (modeledMethod.provenance === "ai-generated") {
|
||||
newProvenance = "ai-manual";
|
||||
}
|
||||
}
|
||||
|
||||
const emptyModeledMethod = createEmptyModeledMethod(
|
||||
e.target.value as ModeledMethodType,
|
||||
method,
|
||||
@@ -67,7 +57,7 @@ export const ModelTypeDropdown = ({
|
||||
updatedModeledMethod.output = "ReturnValue";
|
||||
}
|
||||
if ("provenance" in updatedModeledMethod) {
|
||||
updatedModeledMethod.provenance = newProvenance;
|
||||
updatedModeledMethod.provenance = calculateNewProvenance(modeledMethod);
|
||||
}
|
||||
if ("kind" in updatedModeledMethod) {
|
||||
updatedModeledMethod.kind = "value";
|
||||
|
||||
@@ -27,7 +27,7 @@ describe(MethodRow.name, () => {
|
||||
input: "Argument[0]",
|
||||
output: "ReturnValue",
|
||||
kind: "taint",
|
||||
provenance: "df-generated",
|
||||
provenance: "manual",
|
||||
};
|
||||
const onChange = jest.fn();
|
||||
|
||||
@@ -111,6 +111,32 @@ describe(MethodRow.name, () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("changes the provenance when the kind is changed", async () => {
|
||||
const modeledMethodWithGeneratedProvenance: ModeledMethod = {
|
||||
...modeledMethod,
|
||||
provenance: "df-generated",
|
||||
};
|
||||
render({ modeledMethods: [modeledMethodWithGeneratedProvenance] });
|
||||
|
||||
onChange.mockReset();
|
||||
|
||||
expect(screen.getByRole("combobox", { name: "Kind" })).toHaveValue("taint");
|
||||
|
||||
await userEvent.selectOptions(
|
||||
screen.getByRole("combobox", { name: "Kind" }),
|
||||
"value",
|
||||
);
|
||||
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
expect(onChange).toHaveBeenCalledWith(method.signature, [
|
||||
{
|
||||
...modeledMethod,
|
||||
kind: "value",
|
||||
provenance: "df-manual",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("has the correct input options", () => {
|
||||
render();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[
|
||||
"v2.15.1",
|
||||
"v2.15.2",
|
||||
"v2.14.6",
|
||||
"v2.13.5",
|
||||
"v2.12.7",
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { mockedObject } from "../../vscode-tests/utils/mocking.helpers";
|
||||
import { ModelEditorViewTracker } from "../../../src/model-editor/model-editor-view-tracker";
|
||||
import { ModelEditorView } from "../../../src/model-editor/model-editor-view";
|
||||
|
||||
export function createMockModelEditorViewTracker({
|
||||
registerView = jest.fn(),
|
||||
unregisterView = jest.fn(),
|
||||
getView = jest.fn(),
|
||||
}: {
|
||||
registerView?: ModelEditorViewTracker["registerView"];
|
||||
unregisterView?: ModelEditorViewTracker["unregisterView"];
|
||||
getView?: ModelEditorViewTracker["getView"];
|
||||
} = {}): ModelEditorViewTracker<ModelEditorView> {
|
||||
return mockedObject<ModelEditorViewTracker<ModelEditorView>>({
|
||||
registerView,
|
||||
unregisterView,
|
||||
getView,
|
||||
});
|
||||
}
|
||||
@@ -10,6 +10,8 @@ export function createMockModelingEvents({
|
||||
onModeledMethodsChanged = jest.fn(),
|
||||
onModifiedMethodsChanged = jest.fn(),
|
||||
onInProgressMethodsChanged = jest.fn(),
|
||||
onRevealInModelEditor = jest.fn(),
|
||||
onFocusModelEditor = jest.fn(),
|
||||
}: {
|
||||
onActiveDbChanged?: ModelingEvents["onActiveDbChanged"];
|
||||
onDbClosed?: ModelingEvents["onDbClosed"];
|
||||
@@ -19,6 +21,8 @@ export function createMockModelingEvents({
|
||||
onModeledMethodsChanged?: ModelingEvents["onModeledMethodsChanged"];
|
||||
onModifiedMethodsChanged?: ModelingEvents["onModifiedMethodsChanged"];
|
||||
onInProgressMethodsChanged?: ModelingEvents["onInProgressMethodsChanged"];
|
||||
onRevealInModelEditor?: ModelingEvents["onRevealInModelEditor"];
|
||||
onFocusModelEditor?: ModelingEvents["onFocusModelEditor"];
|
||||
} = {}): ModelingEvents {
|
||||
return mockedObject<ModelingEvents>({
|
||||
onActiveDbChanged,
|
||||
@@ -29,5 +33,7 @@ export function createMockModelingEvents({
|
||||
onModeledMethodsChanged,
|
||||
onModifiedMethodsChanged,
|
||||
onInProgressMethodsChanged,
|
||||
onRevealInModelEditor,
|
||||
onFocusModelEditor,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ export function mockDbOptions(): FullDatabaseOptions {
|
||||
return {
|
||||
dateAdded: 123,
|
||||
language: "",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
SelectedDbItem,
|
||||
DB_CONFIG_VERSION,
|
||||
} from "../../src/databases/config/db-config";
|
||||
import { DatabaseOrigin } from "../../src/databases/local-databases/database-origin";
|
||||
|
||||
export function createDbConfig({
|
||||
remoteLists = [],
|
||||
@@ -45,16 +46,21 @@ export function createLocalDbConfigItem({
|
||||
dateAdded = faker.date.past().getTime(),
|
||||
language = `language${faker.number.int()}`,
|
||||
storagePath = `storagePath${faker.number.int()}`,
|
||||
origin = {
|
||||
type: "folder",
|
||||
},
|
||||
}: {
|
||||
name?: string;
|
||||
dateAdded?: number;
|
||||
language?: string;
|
||||
storagePath?: string;
|
||||
origin?: DatabaseOrigin;
|
||||
} = {}): LocalDatabase {
|
||||
return {
|
||||
name,
|
||||
dateAdded,
|
||||
language,
|
||||
storagePath,
|
||||
origin,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
RootLocalDbItem,
|
||||
RootRemoteDbItem,
|
||||
} from "../../src/databases/db-item";
|
||||
import { DatabaseOrigin } from "../../src/databases/local-databases/database-origin";
|
||||
|
||||
// Root Remote Db Items
|
||||
export function createRootRemoteDbItem({
|
||||
@@ -124,12 +125,16 @@ export function createLocalDatabaseDbItem({
|
||||
language = `language${faker.number.int()}`,
|
||||
storagePath = `storagePath${faker.number.int()}`,
|
||||
selected = false,
|
||||
origin = {
|
||||
type: "folder",
|
||||
},
|
||||
}: {
|
||||
databaseName?: string;
|
||||
dateAdded?: number;
|
||||
language?: string;
|
||||
storagePath?: string;
|
||||
selected?: boolean;
|
||||
origin?: DatabaseOrigin;
|
||||
} = {}): LocalDatabaseDbItem {
|
||||
return {
|
||||
kind: DbItemKind.LocalDatabase,
|
||||
@@ -138,6 +143,7 @@ export function createLocalDatabaseDbItem({
|
||||
dateAdded,
|
||||
language,
|
||||
storagePath,
|
||||
origin,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ describe("db item selection", () => {
|
||||
dateAdded: 1234,
|
||||
language: "javascript",
|
||||
storagePath: "/foo/bar",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
selected: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -337,12 +337,18 @@ describe("db tree creator", () => {
|
||||
dateAdded: 1668428293677,
|
||||
language: QueryLanguage.Cpp,
|
||||
storagePath: "/path/to/db1/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "db2",
|
||||
dateAdded: 1668428472731,
|
||||
language: "cpp",
|
||||
storagePath: "/path/to/db2/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -354,6 +360,9 @@ describe("db tree creator", () => {
|
||||
dateAdded: 1668428472731,
|
||||
language: "ruby",
|
||||
storagePath: "/path/to/db3/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -380,6 +389,7 @@ describe("db tree creator", () => {
|
||||
databaseName: db.name,
|
||||
dateAdded: db.dateAdded,
|
||||
language: db.language,
|
||||
origin: db.origin,
|
||||
storagePath: db.storagePath,
|
||||
parentListName: dbConfig.databases.local.lists[0].name,
|
||||
})),
|
||||
@@ -395,6 +405,7 @@ describe("db tree creator", () => {
|
||||
databaseName: db.name,
|
||||
dateAdded: db.dateAdded,
|
||||
language: db.language,
|
||||
origin: db.origin,
|
||||
storagePath: db.storagePath,
|
||||
parentListName: dbConfig.databases.local.lists[1].name,
|
||||
})),
|
||||
@@ -409,12 +420,18 @@ describe("db tree creator", () => {
|
||||
dateAdded: 1668428293677,
|
||||
language: "csharp",
|
||||
storagePath: "/path/to/db1/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "db2",
|
||||
dateAdded: 1668428472731,
|
||||
language: "go",
|
||||
storagePath: "/path/to/db2/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -434,6 +451,7 @@ describe("db tree creator", () => {
|
||||
databaseName: dbConfig.databases.local.databases[0].name,
|
||||
dateAdded: dbConfig.databases.local.databases[0].dateAdded,
|
||||
language: dbConfig.databases.local.databases[0].language,
|
||||
origin: dbConfig.databases.local.databases[0].origin,
|
||||
storagePath: dbConfig.databases.local.databases[0].storagePath,
|
||||
});
|
||||
expect(localDatabaseNodes[1]).toEqual({
|
||||
@@ -442,6 +460,7 @@ describe("db tree creator", () => {
|
||||
databaseName: dbConfig.databases.local.databases[1].name,
|
||||
dateAdded: dbConfig.databases.local.databases[1].dateAdded,
|
||||
language: dbConfig.databases.local.databases[1].language,
|
||||
origin: dbConfig.databases.local.databases[1].origin,
|
||||
storagePath: dbConfig.databases.local.databases[1].storagePath,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -186,12 +186,18 @@ describe("db panel rendering nodes", () => {
|
||||
dateAdded: 1668428293677,
|
||||
language: QueryLanguage.Cpp,
|
||||
storagePath: "/path/to/db1/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "db2",
|
||||
dateAdded: 1668428472731,
|
||||
language: QueryLanguage.Cpp,
|
||||
storagePath: "/path/to/db2/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -203,6 +209,9 @@ describe("db panel rendering nodes", () => {
|
||||
dateAdded: 1668428472731,
|
||||
language: "ruby",
|
||||
storagePath: "/path/to/db3/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -238,6 +247,9 @@ describe("db panel rendering nodes", () => {
|
||||
language: QueryLanguage.Cpp,
|
||||
storagePath: "/path/to/db1/",
|
||||
selected: false,
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: DbItemKind.LocalDatabase,
|
||||
@@ -246,6 +258,9 @@ describe("db panel rendering nodes", () => {
|
||||
language: QueryLanguage.Cpp,
|
||||
storagePath: "/path/to/db2/",
|
||||
selected: false,
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
]);
|
||||
checkLocalListItem(localListItems[1], "my-list-2", [
|
||||
@@ -256,6 +271,9 @@ describe("db panel rendering nodes", () => {
|
||||
language: "ruby",
|
||||
storagePath: "/path/to/db3/",
|
||||
selected: false,
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -268,12 +286,18 @@ describe("db panel rendering nodes", () => {
|
||||
dateAdded: 1668428293677,
|
||||
language: "csharp",
|
||||
storagePath: "/path/to/db1/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "db2",
|
||||
dateAdded: 1668428472731,
|
||||
language: "go",
|
||||
storagePath: "/path/to/db2/",
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -306,6 +330,9 @@ describe("db panel rendering nodes", () => {
|
||||
language: "csharp",
|
||||
storagePath: "/path/to/db1/",
|
||||
selected: false,
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
});
|
||||
checkLocalDatabaseItem(localDatabaseItems[1], {
|
||||
kind: DbItemKind.LocalDatabase,
|
||||
@@ -314,6 +341,9 @@ describe("db panel rendering nodes", () => {
|
||||
language: "go",
|
||||
storagePath: "/path/to/db2/",
|
||||
selected: false,
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -597,6 +597,9 @@ describe("local databases", () => {
|
||||
const options: FullDatabaseOptions = {
|
||||
dateAdded: 123,
|
||||
language,
|
||||
origin: {
|
||||
type: "folder",
|
||||
},
|
||||
};
|
||||
mockDbItem = createMockDB(dir, options);
|
||||
|
||||
@@ -728,19 +731,41 @@ describe("local databases", () => {
|
||||
});
|
||||
|
||||
it("should resolve the database contents", async () => {
|
||||
await databaseManager.openDatabase(mockDbItem.databaseUri);
|
||||
await databaseManager.openDatabase(
|
||||
mockDbItem.databaseUri,
|
||||
mockDbItem.origin,
|
||||
);
|
||||
|
||||
expect(resolveDatabaseContentsSpy).toBeCalledTimes(2);
|
||||
});
|
||||
|
||||
it("should set the database as the currently selected one", async () => {
|
||||
await databaseManager.openDatabase(mockDbItem.databaseUri);
|
||||
await databaseManager.openDatabase(
|
||||
mockDbItem.databaseUri,
|
||||
mockDbItem.origin,
|
||||
);
|
||||
|
||||
expect(setCurrentDatabaseItemSpy).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should add database source archive folder", async () => {
|
||||
await databaseManager.openDatabase(mockDbItem.databaseUri);
|
||||
it("should not add database source archive folder when `codeQL.addingDatabases.addDatabaseSourceToWorkspace` is `false`", async () => {
|
||||
jest.spyOn(config, "addDatabaseSourceToWorkspace").mockReturnValue(false);
|
||||
|
||||
await databaseManager.openDatabase(
|
||||
mockDbItem.databaseUri,
|
||||
mockDbItem.origin,
|
||||
);
|
||||
|
||||
expect(addDatabaseSourceArchiveFolderSpy).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
it("should add database source archive folder when `codeQL.addingDatabases.addDatabaseSourceToWorkspace` is `true`", async () => {
|
||||
jest.spyOn(config, "addDatabaseSourceToWorkspace").mockReturnValue(true);
|
||||
|
||||
await databaseManager.openDatabase(
|
||||
mockDbItem.databaseUri,
|
||||
mockDbItem.origin,
|
||||
);
|
||||
|
||||
expect(addDatabaseSourceArchiveFolderSpy).toBeCalledTimes(1);
|
||||
});
|
||||
@@ -756,6 +781,7 @@ describe("local databases", () => {
|
||||
|
||||
await databaseManager.openDatabase(
|
||||
mockDbItem.databaseUri,
|
||||
mockDbItem.origin,
|
||||
makeSelected,
|
||||
nameOverride,
|
||||
{ isTutorialDatabase },
|
||||
@@ -769,7 +795,10 @@ describe("local databases", () => {
|
||||
it("should create a skeleton QL pack", async () => {
|
||||
jest.spyOn(config, "isCodespacesTemplate").mockReturnValue(true);
|
||||
|
||||
await databaseManager.openDatabase(mockDbItem.databaseUri);
|
||||
await databaseManager.openDatabase(
|
||||
mockDbItem.databaseUri,
|
||||
mockDbItem.origin,
|
||||
);
|
||||
|
||||
expect(createSkeletonPacksSpy).toBeCalledTimes(1);
|
||||
});
|
||||
@@ -780,7 +809,10 @@ describe("local databases", () => {
|
||||
it("should not create a skeleton QL pack", async () => {
|
||||
jest.spyOn(config, "isCodespacesTemplate").mockReturnValue(false);
|
||||
|
||||
await databaseManager.openDatabase(mockDbItem.databaseUri);
|
||||
await databaseManager.openDatabase(
|
||||
mockDbItem.databaseUri,
|
||||
mockDbItem.origin,
|
||||
);
|
||||
expect(createSkeletonPacksSpy).toBeCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,11 @@ import {
|
||||
findDirWithFile,
|
||||
} from "../../../../src/databases/database-fetcher";
|
||||
import * as Octokit from "@octokit/rest";
|
||||
import { mockedQuickPickItem } from "../../utils/mocking.helpers";
|
||||
import {
|
||||
mockedObject,
|
||||
mockedOctokitFunction,
|
||||
mockedQuickPickItem,
|
||||
} from "../../utils/mocking.helpers";
|
||||
|
||||
// These tests make API calls and may need extra time to complete.
|
||||
jest.setTimeout(10000);
|
||||
@@ -18,10 +22,17 @@ describe("database-fetcher", () => {
|
||||
let quickPickSpy: jest.SpiedFunction<typeof window.showQuickPick>;
|
||||
|
||||
const progressSpy = jest.fn();
|
||||
const mockRequest = jest.fn();
|
||||
const octokit: Octokit.Octokit = {
|
||||
request: mockRequest,
|
||||
} as unknown as Octokit.Octokit;
|
||||
const mockListCodeqlDatabases = mockedOctokitFunction<
|
||||
"codeScanning",
|
||||
"listCodeqlDatabases"
|
||||
>();
|
||||
const octokit = mockedObject<Octokit.Octokit>({
|
||||
rest: {
|
||||
codeScanning: {
|
||||
listCodeqlDatabases: mockListCodeqlDatabases,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// We can't make the real octokit request (since we need credentials), so we mock the response.
|
||||
const successfullMockApiResponse = {
|
||||
@@ -72,7 +83,7 @@ describe("database-fetcher", () => {
|
||||
});
|
||||
|
||||
it("should convert a GitHub nwo to a database url", async () => {
|
||||
mockRequest.mockResolvedValue(successfullMockApiResponse);
|
||||
mockListCodeqlDatabases.mockResolvedValue(successfullMockApiResponse);
|
||||
quickPickSpy.mockResolvedValue(
|
||||
mockedQuickPickItem({
|
||||
label: "JavaScript",
|
||||
@@ -93,7 +104,7 @@ describe("database-fetcher", () => {
|
||||
const { databaseUrl, name, owner } = result;
|
||||
|
||||
expect(databaseUrl).toBe(
|
||||
"https://api.github.com/repos/github/codeql/code-scanning/codeql/databases/javascript",
|
||||
"https://api.github.com/repositories/143040428/code-scanning/codeql/databases/javascript",
|
||||
);
|
||||
expect(name).toBe("codeql");
|
||||
expect(owner).toBe("github");
|
||||
@@ -128,7 +139,7 @@ describe("database-fetcher", () => {
|
||||
},
|
||||
status: 404,
|
||||
};
|
||||
mockRequest.mockResolvedValue(mockApiResponse);
|
||||
mockListCodeqlDatabases.mockResolvedValue(mockApiResponse);
|
||||
const githubRepo = "foo/bar-not-real";
|
||||
await expect(
|
||||
convertGithubNwoToDatabaseUrl(githubRepo, octokit, progressSpy),
|
||||
@@ -142,7 +153,7 @@ describe("database-fetcher", () => {
|
||||
data: [],
|
||||
};
|
||||
|
||||
mockRequest.mockResolvedValue(mockApiResponse);
|
||||
mockListCodeqlDatabases.mockResolvedValue(mockApiResponse);
|
||||
const githubRepo = "foo/bar-with-no-dbs";
|
||||
await expect(
|
||||
convertGithubNwoToDatabaseUrl(githubRepo, octokit, progressSpy),
|
||||
@@ -153,7 +164,7 @@ describe("database-fetcher", () => {
|
||||
describe("when language is already provided", () => {
|
||||
describe("when language is valid", () => {
|
||||
it("should not prompt the user", async () => {
|
||||
mockRequest.mockResolvedValue(successfullMockApiResponse);
|
||||
mockListCodeqlDatabases.mockResolvedValue(successfullMockApiResponse);
|
||||
const githubRepo = "github/codeql";
|
||||
await convertGithubNwoToDatabaseUrl(
|
||||
githubRepo,
|
||||
@@ -167,7 +178,7 @@ describe("database-fetcher", () => {
|
||||
|
||||
describe("when language is invalid", () => {
|
||||
it("should prompt for language", async () => {
|
||||
mockRequest.mockResolvedValue(successfullMockApiResponse);
|
||||
mockListCodeqlDatabases.mockResolvedValue(successfullMockApiResponse);
|
||||
const githubRepo = "github/codeql";
|
||||
await convertGithubNwoToDatabaseUrl(
|
||||
githubRepo,
|
||||
@@ -182,7 +193,7 @@ describe("database-fetcher", () => {
|
||||
|
||||
describe("when language is not provided", () => {
|
||||
it("should prompt for language", async () => {
|
||||
mockRequest.mockResolvedValue(successfullMockApiResponse);
|
||||
mockListCodeqlDatabases.mockResolvedValue(successfullMockApiResponse);
|
||||
const githubRepo = "github/codeql";
|
||||
await convertGithubNwoToDatabaseUrl(githubRepo, octokit, progressSpy);
|
||||
expect(quickPickSpy).toHaveBeenCalled();
|
||||
|
||||
@@ -9,7 +9,6 @@ import { mockEmptyDatabaseManager } from "../query-testing/test-runner-helpers";
|
||||
import { QueryRunner } from "../../../../src/query-server";
|
||||
import { ExtensionPack } from "../../../../src/model-editor/shared/extension-pack";
|
||||
import { createMockModelingStore } from "../../../__mocks__/model-editor/modelingStoreMock";
|
||||
import { createMockModelEditorViewTracker } from "../../../__mocks__/model-editor/modelEditorViewTrackerMock";
|
||||
import { ModelConfigListener } from "../../../../src/config";
|
||||
import { createMockModelingEvents } from "../../../__mocks__/model-editor/modelingEventsMock";
|
||||
import { QueryLanguage } from "../../../../src/common/query-language";
|
||||
@@ -18,7 +17,6 @@ describe("ModelEditorView", () => {
|
||||
const app = createMockApp({});
|
||||
const modelingStore = createMockModelingStore();
|
||||
const modelingEvents = createMockModelingEvents();
|
||||
const viewTracker = createMockModelEditorViewTracker();
|
||||
const modelConfig = mockedObject<ModelConfigListener>({
|
||||
onDidChangeConfiguration: jest.fn(),
|
||||
});
|
||||
@@ -48,7 +46,6 @@ describe("ModelEditorView", () => {
|
||||
app,
|
||||
modelingStore,
|
||||
modelingEvents,
|
||||
viewTracker,
|
||||
modelConfig,
|
||||
databaseManager,
|
||||
cliServer,
|
||||
|
||||
@@ -39,12 +39,18 @@ describe("test-runner", () => {
|
||||
const preTestDatabaseItem = new DatabaseItemImpl(
|
||||
Uri.file("/path/to/test/dir/dir.testproj"),
|
||||
undefined,
|
||||
mockedObject<FullDatabaseOptions>({ displayName: "custom display name" }),
|
||||
mockedObject<FullDatabaseOptions>({
|
||||
displayName: "custom display name",
|
||||
origin: { type: "folder" },
|
||||
}),
|
||||
);
|
||||
const postTestDatabaseItem = new DatabaseItemImpl(
|
||||
Uri.file("/path/to/test/dir/dir.testproj"),
|
||||
undefined,
|
||||
mockedObject<FullDatabaseOptions>({ displayName: "default name" }),
|
||||
mockedObject<FullDatabaseOptions>({
|
||||
displayName: "default name",
|
||||
origin: { type: "folder" },
|
||||
}),
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -160,6 +166,7 @@ describe("test-runner", () => {
|
||||
expect(openDatabaseSpy).toBeCalledTimes(1);
|
||||
expect(openDatabaseSpy).toBeCalledWith(
|
||||
preTestDatabaseItem.databaseUri,
|
||||
preTestDatabaseItem.origin,
|
||||
false,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { QuickPickItem, window, Uri } from "vscode";
|
||||
import { DatabaseItem } from "../../../src/databases/local-databases";
|
||||
import * as Octokit from "@octokit/rest";
|
||||
|
||||
export type DeepPartial<T> = T extends object
|
||||
? {
|
||||
@@ -57,6 +58,14 @@ export function mockedObject<T extends object>(
|
||||
});
|
||||
}
|
||||
|
||||
export function mockedOctokitFunction<
|
||||
Namespace extends keyof Octokit.Octokit["rest"],
|
||||
Name extends keyof Octokit.Octokit["rest"][Namespace],
|
||||
>(): Octokit.Octokit["rest"][Namespace][Name] & jest.Mock {
|
||||
const fn = jest.fn();
|
||||
return fn as unknown as Octokit.Octokit["rest"][Namespace][Name] & jest.Mock;
|
||||
}
|
||||
|
||||
export function mockDatabaseItem(
|
||||
props: DeepPartial<DatabaseItem> = {},
|
||||
): DatabaseItem {
|
||||
|
||||
Reference in New Issue
Block a user