Merge branch 'main' into aeisenberg/multi-token

This commit is contained in:
Andrew Eisenberg
2023-10-04 07:09:21 -07:00
committed by GitHub
25 changed files with 475 additions and 270 deletions

View File

@@ -62,7 +62,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: '18.15.0'
node-version-file: extensions/ql-vscode/.nvmrc
cache: 'npm'
cache-dependency-path: extensions/ql-vscode/package-lock.json

View File

@@ -22,7 +22,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: '18.15.0'
node-version-file: extensions/ql-vscode/.nvmrc
cache: 'npm'
cache-dependency-path: extensions/ql-vscode/package-lock.json
@@ -64,7 +64,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: '18.15.0'
node-version-file: extensions/ql-vscode/.nvmrc
cache: 'npm'
cache-dependency-path: extensions/ql-vscode/package-lock.json
@@ -81,6 +81,8 @@ jobs:
- name: Lint
working-directory: extensions/ql-vscode
env:
NODE_OPTIONS: '--max-old-space-size=4096'
run: |
npm run lint
@@ -110,7 +112,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: '18.15.0'
node-version-file: extensions/ql-vscode/.nvmrc
cache: 'npm'
cache-dependency-path: extensions/ql-vscode/package-lock.json
@@ -149,7 +151,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: '18.15.0'
node-version-file: extensions/ql-vscode/.nvmrc
cache: 'npm'
cache-dependency-path: extensions/ql-vscode/package-lock.json
@@ -183,7 +185,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: '18.15.0'
node-version-file: extensions/ql-vscode/.nvmrc
cache: 'npm'
cache-dependency-path: extensions/ql-vscode/package-lock.json
@@ -251,7 +253,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: '18.15.0'
node-version-file: extensions/ql-vscode/.nvmrc
cache: 'npm'
cache-dependency-path: extensions/ql-vscode/package-lock.json

View File

@@ -22,7 +22,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: '18.15.0'
node-version-file: extensions/ql-vscode/.nvmrc
- name: Install dependencies
run: |

View File

@@ -15,14 +15,14 @@ You can find this info by seleting "About Visual Studio Code" from the top menu.
The following files will need to be updated:
- `.github/workflows/cli-test.yml` - the "node-version: '[VERSION]'" setting
- `.github/workflows/main.yml` - all the "node-version: '[VERSION]'" settings
- `.github/workflows/release.yml` - the "node-version: '[VERSION]'" setting
- `extensions/ql-vscode/.nvmrc` - this will enable nvm to automatically switch to the correct node version when you're in the project folder
- `extensions/ql-vscode/package-lock.json` - the "engines.node: '[VERSION]'" setting
- `extensions/ql-vscode/.nvmrc` - this will enable nvm to automatically switch to the correct Node
version when you're in the project folder. It will also change the Node version the GitHub Actions
workflows use.
- `extensions/ql-vscode/package.json` - the "engines.node: '[VERSION]'" setting
- `extensions/ql-vscode/package.json` - the "@types/node: '[VERSION]'" dependency
Then run `npm install` to update the `extensions/ql-vscode/package-lock.json` file.
## Node.js version used in tests
Unit tests will use whatever version of Node.js is installed locally. In CI this will be the version specified in the workflow.

View File

@@ -709,6 +709,7 @@ const MODEL_SETTING = new Setting("model", ROOT_SETTING);
const FLOW_GENERATION = new Setting("flowGeneration", MODEL_SETTING);
const LLM_GENERATION = new Setting("llmGeneration", MODEL_SETTING);
const EXTENSIONS_DIRECTORY = new Setting("extensionsDirectory", MODEL_SETTING);
const SHOW_MULTIPLE_MODELS = new Setting("showMultipleModels", MODEL_SETTING);
export function showFlowGeneration(): boolean {
return !!FLOW_GENERATION.getValue<boolean>();
@@ -723,3 +724,7 @@ export function getExtensionsDirectory(languageId: string): string | undefined {
languageId,
});
}
export function showMultipleModels(): boolean {
return !!SHOW_MULTIPLE_MODELS.getValue<boolean>();
}

View File

@@ -871,6 +871,7 @@ async function activateWithInstalledDistribution(
ctx,
queryHistoryConfigurationListener,
labelProvider,
languageContext,
async (
from: CompletedLocalQueryInfo,
to: CompletedLocalQueryInfo,

View File

@@ -16,6 +16,7 @@ import { QueryRunner } from "../query-server";
import { DatabaseItem } from "../databases/local-databases";
import { Mode } from "./shared/mode";
import { CancellationTokenSource } from "vscode";
import { convertToLegacyModeledMethods } from "./modeled-methods-legacy";
// Limit the number of candidates we send to the model in each request
// to avoid long requests.
@@ -192,11 +193,13 @@ export class AutoModeler {
filename: "auto-model.yml",
});
const loadedMethods = loadDataExtensionYaml(models);
if (!loadedMethods) {
const rawLoadedMethods = loadDataExtensionYaml(models);
if (!rawLoadedMethods) {
return;
}
const loadedMethods = convertToLegacyModeledMethods(rawLoadedMethods);
// Any candidate that was part of the response is a negative result
// meaning that the canidate is not a sink for the kinds that the LLM is checking for.
// For now we model this as a sink neutral method, however this is subject

View File

@@ -34,7 +34,11 @@ import {
import { Method, Usage } from "./method";
import { ModeledMethod } from "./modeled-method";
import { ExtensionPack } from "./shared/extension-pack";
import { showFlowGeneration, showLlmGeneration } from "../config";
import {
showFlowGeneration,
showLlmGeneration,
showMultipleModels,
} from "../config";
import { Mode } from "./shared/mode";
import { loadModeledMethods, saveModeledMethods } from "./modeled-method-fs";
import { pickExtensionPack } from "./extension-pack-picker";
@@ -365,6 +369,7 @@ export class ModelEditorView extends AbstractWebview<
extensionPack: this.extensionPack,
showFlowGeneration: showFlowGeneration(),
showLlmButton,
showMultipleModels: showMultipleModels(),
mode: this.mode,
},
});

View File

@@ -10,6 +10,11 @@ import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { load as loadYaml } from "js-yaml";
import { CodeQLCliServer } from "../codeql-cli/cli";
import { pathsEqual } from "../common/files";
import {
convertFromLegacyModeledMethods,
convertFromLegacyModeledMethodsFiles,
convertToLegacyModeledMethods,
} from "./modeled-methods-legacy";
export async function saveModeledMethods(
extensionPack: ExtensionPack,
@@ -29,8 +34,8 @@ export async function saveModeledMethods(
const yamls = createDataExtensionYamls(
language,
methods,
modeledMethods,
existingModeledMethods,
convertFromLegacyModeledMethods(modeledMethods),
convertFromLegacyModeledMethodsFiles(existingModeledMethods),
mode,
);
@@ -68,7 +73,8 @@ async function loadModeledMethodFiles(
);
continue;
}
modeledMethodsByFile[modelFile] = modeledMethods;
modeledMethodsByFile[modelFile] =
convertToLegacyModeledMethods(modeledMethods);
}
return modeledMethodsByFile;

View File

@@ -0,0 +1,33 @@
import { ModeledMethod } from "./modeled-method";
export function convertFromLegacyModeledMethods(
modeledMethods: Record<string, ModeledMethod>,
): Record<string, ModeledMethod[]> {
// Convert a single ModeledMethod to an array of ModeledMethods
return Object.fromEntries(
Object.entries(modeledMethods).map(([signature, modeledMethod]) => {
return [signature, [modeledMethod]];
}),
);
}
export function convertToLegacyModeledMethods(
modeledMethods: Record<string, ModeledMethod[]>,
): Record<string, ModeledMethod> {
// Always take the first modeled method in the array
return Object.fromEntries(
Object.entries(modeledMethods).map(([signature, modeledMethods]) => {
return [signature, modeledMethods[0]];
}),
);
}
export function convertFromLegacyModeledMethodsFiles(
modeledMethods: Record<string, Record<string, ModeledMethod>>,
): Record<string, Record<string, ModeledMethod[]>> {
return Object.fromEntries(
Object.entries(modeledMethods).map(([filename, modeledMethods]) => {
return [filename, convertFromLegacyModeledMethods(modeledMethods)];
}),
);
}

View File

@@ -5,5 +5,6 @@ export interface ModelEditorViewState {
extensionPack: ExtensionPack;
showFlowGeneration: boolean;
showLlmButton: boolean;
showMultipleModels: boolean;
mode: Mode;
}

View File

@@ -71,8 +71,8 @@ ${extensions.join("\n")}`;
export function createDataExtensionYamls(
language: string,
methods: Method[],
newModeledMethods: Record<string, ModeledMethod>,
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
newModeledMethods: Record<string, ModeledMethod[]>,
existingModeledMethods: Record<string, Record<string, ModeledMethod[]>>,
mode: Mode,
) {
switch (mode) {
@@ -98,11 +98,11 @@ export function createDataExtensionYamls(
function createDataExtensionYamlsByGrouping(
language: string,
methods: Method[],
newModeledMethods: Record<string, ModeledMethod>,
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
newModeledMethods: Record<string, ModeledMethod[]>,
existingModeledMethods: Record<string, Record<string, ModeledMethod[]>>,
createFilename: (method: Method) => string,
): Record<string, string> {
const methodsByFilename: Record<string, Record<string, ModeledMethod>> = {};
const methodsByFilename: Record<string, Record<string, ModeledMethod[]>> = {};
// We only want to generate a yaml file when it's a known external API usage
// and there are new modeled methods for it. This avoids us overwriting other
@@ -114,10 +114,12 @@ function createDataExtensionYamlsByGrouping(
}
// First populate methodsByFilename with any existing modeled methods.
for (const [filename, methods] of Object.entries(existingModeledMethods)) {
for (const [filename, methodsBySignature] of Object.entries(
existingModeledMethods,
)) {
if (filename in methodsByFilename) {
for (const [signature, method] of Object.entries(methods)) {
methodsByFilename[filename][signature] = method;
for (const [signature, methods] of Object.entries(methodsBySignature)) {
methodsByFilename[filename][signature] = methods;
}
}
}
@@ -125,10 +127,12 @@ function createDataExtensionYamlsByGrouping(
// Add the new modeled methods, potentially overwriting existing modeled methods
// but not removing existing modeled methods that are not in the new set.
for (const method of methods) {
const newMethod = newModeledMethods[method.signature];
if (newMethod) {
const newMethods = newModeledMethods[method.signature];
if (newMethods) {
const filename = createFilename(method);
methodsByFilename[filename][newMethod.signature] = newMethod;
// Override any existing modeled methods with the new ones.
methodsByFilename[filename][method.signature] = newMethods;
}
}
@@ -137,7 +141,7 @@ function createDataExtensionYamlsByGrouping(
for (const [filename, methods] of Object.entries(methodsByFilename)) {
result[filename] = createDataExtensionYaml(
language,
Object.values(methods),
Object.values(methods).flatMap((methods) => methods),
);
}
@@ -147,8 +151,8 @@ function createDataExtensionYamlsByGrouping(
export function createDataExtensionYamlsForApplicationMode(
language: string,
methods: Method[],
newModeledMethods: Record<string, ModeledMethod>,
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
newModeledMethods: Record<string, ModeledMethod[]>,
existingModeledMethods: Record<string, Record<string, ModeledMethod[]>>,
): Record<string, string> {
return createDataExtensionYamlsByGrouping(
language,
@@ -162,8 +166,8 @@ export function createDataExtensionYamlsForApplicationMode(
export function createDataExtensionYamlsForFrameworkMode(
language: string,
methods: Method[],
newModeledMethods: Record<string, ModeledMethod>,
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
newModeledMethods: Record<string, ModeledMethod[]>,
existingModeledMethods: Record<string, Record<string, ModeledMethod[]>>,
): Record<string, string> {
return createDataExtensionYamlsByGrouping(
language,
@@ -228,14 +232,14 @@ function validateModelExtensionFile(data: unknown): data is ModelExtensionFile {
export function loadDataExtensionYaml(
data: unknown,
): Record<string, ModeledMethod> | undefined {
): Record<string, ModeledMethod[]> | undefined {
if (!validateModelExtensionFile(data)) {
return undefined;
}
const extensions = data.extensions;
const modeledMethods: Record<string, ModeledMethod> = {};
const modeledMethods: Record<string, ModeledMethod[]> = {};
for (const extension of extensions) {
const addsTo = extension.addsTo;
@@ -250,11 +254,16 @@ export function loadDataExtensionYaml(
}
for (const row of data) {
const modeledMethod = definition.readModeledMethod(row);
const modeledMethod: ModeledMethod = definition.readModeledMethod(row);
if (!modeledMethod) {
continue;
}
modeledMethods[modeledMethod.signature] = modeledMethod;
if (!(modeledMethod.signature in modeledMethods)) {
modeledMethods[modeledMethod.signature] = [];
}
modeledMethods[modeledMethod.signature].push(modeledMethod);
}
}

View File

@@ -10,9 +10,10 @@ import {
} from "vscode";
import { DisposableObject } from "../common/disposable-object";
import { assertNever } from "../common/helpers-pure";
import { QueryHistoryInfo } from "./query-history-info";
import { getLanguage, QueryHistoryInfo } from "./query-history-info";
import { QueryStatus } from "./query-status";
import { HistoryItemLabelProvider } from "./history-item-label-provider";
import { LanguageContextStore } from "../language-context-store";
export enum SortOrder {
NameAsc = "NameAsc",
@@ -50,7 +51,10 @@ export class HistoryTreeDataProvider
private current: QueryHistoryInfo | undefined;
constructor(private readonly labelProvider: HistoryItemLabelProvider) {
constructor(
private readonly labelProvider: HistoryItemLabelProvider,
private readonly languageContext: LanguageContextStore,
) {
super();
}
@@ -127,51 +131,55 @@ export class HistoryTreeDataProvider
getChildren(element?: QueryHistoryInfo): ProviderResult<QueryHistoryInfo[]> {
return element
? []
: this.history.sort((h1, h2) => {
const h1Label = this.labelProvider.getLabel(h1).toLowerCase();
const h2Label = this.labelProvider.getLabel(h2).toLowerCase();
: this.history
.filter((h) => {
return this.languageContext.shouldInclude(getLanguage(h));
})
.sort((h1, h2) => {
const h1Label = this.labelProvider.getLabel(h1).toLowerCase();
const h2Label = this.labelProvider.getLabel(h2).toLowerCase();
const h1Date = this.getItemDate(h1);
const h1Date = this.getItemDate(h1);
const h2Date = this.getItemDate(h2);
const h2Date = this.getItemDate(h2);
const resultCount1 =
h1.t === "local"
? h1.completedQuery?.resultCount ?? -1
: h1.resultCount ?? -1;
const resultCount2 =
h2.t === "local"
? h2.completedQuery?.resultCount ?? -1
: h2.resultCount ?? -1;
const resultCount1 =
h1.t === "local"
? h1.completedQuery?.resultCount ?? -1
: h1.resultCount ?? -1;
const resultCount2 =
h2.t === "local"
? h2.completedQuery?.resultCount ?? -1
: h2.resultCount ?? -1;
switch (this.sortOrder) {
case SortOrder.NameAsc:
return h1Label.localeCompare(h2Label, env.language);
switch (this.sortOrder) {
case SortOrder.NameAsc:
return h1Label.localeCompare(h2Label, env.language);
case SortOrder.NameDesc:
return h2Label.localeCompare(h1Label, env.language);
case SortOrder.NameDesc:
return h2Label.localeCompare(h1Label, env.language);
case SortOrder.DateAsc:
return h1Date - h2Date;
case SortOrder.DateAsc:
return h1Date - h2Date;
case SortOrder.DateDesc:
return h2Date - h1Date;
case SortOrder.DateDesc:
return h2Date - h1Date;
case SortOrder.CountAsc:
// If the result counts are equal, sort by name.
return resultCount1 - resultCount2 === 0
? h1Label.localeCompare(h2Label, env.language)
: resultCount1 - resultCount2;
case SortOrder.CountAsc:
// If the result counts are equal, sort by name.
return resultCount1 - resultCount2 === 0
? h1Label.localeCompare(h2Label, env.language)
: resultCount1 - resultCount2;
case SortOrder.CountDesc:
// If the result counts are equal, sort by name.
return resultCount2 - resultCount1 === 0
? h2Label.localeCompare(h1Label, env.language)
: resultCount2 - resultCount1;
default:
assertNever(this.sortOrder);
}
});
case SortOrder.CountDesc:
// If the result counts are equal, sort by name.
return resultCount2 - resultCount1 === 0
? h2Label.localeCompare(h1Label, env.language)
: resultCount2 - resultCount1;
default:
assertNever(this.sortOrder);
}
});
}
getParent(_element: QueryHistoryInfo): ProviderResult<QueryHistoryInfo> {

View File

@@ -62,6 +62,7 @@ import {
showAndLogInformationMessage,
showAndLogWarningMessage,
} from "../common/logging";
import { LanguageContextStore } from "../language-context-store";
/**
* query-history-manager.ts
@@ -141,6 +142,7 @@ export class QueryHistoryManager extends DisposableObject {
ctx: ExtensionContext,
private readonly queryHistoryConfigListener: QueryHistoryConfig,
private readonly labelProvider: HistoryItemLabelProvider,
private readonly languageContext: LanguageContextStore,
private readonly doCompareCallback: (
from: CompletedLocalQueryInfo,
to: CompletedLocalQueryInfo,
@@ -158,7 +160,7 @@ export class QueryHistoryManager extends DisposableObject {
);
this.treeDataProvider = this.push(
new HistoryTreeDataProvider(this.labelProvider),
new HistoryTreeDataProvider(this.labelProvider, this.languageContext),
);
this.treeView = this.push(
window.createTreeView("codeQLQueryHistory", {
@@ -230,6 +232,12 @@ export class QueryHistoryManager extends DisposableObject {
this.registerQueryHistoryScrubber(queryHistoryConfigListener, this, ctx);
this.registerToVariantAnalysisEvents();
this.push(
this.languageContext.onLanguageContextChanged(async () => {
this.treeDataProvider.refresh();
}),
);
}
public getCommands(): QueryHistoryCommands {

View File

@@ -214,6 +214,7 @@ LibraryRow.args = {
extensionPack: createMockExtensionPack(),
showFlowGeneration: true,
showLlmButton: true,
showMultipleModels: true,
mode: Mode.Application,
},
hideModeledMethods: false,

View File

@@ -30,6 +30,7 @@ ModelEditor.args = {
},
showFlowGeneration: true,
showLlmButton: true,
showMultipleModels: true,
mode: Mode.Application,
},
initialMethods: [

View File

@@ -20,6 +20,7 @@ describe(LibraryRow.name, () => {
mode: Mode.Application,
showFlowGeneration: false,
showLlmButton: false,
showMultipleModels: false,
extensionPack: createMockExtensionPack(),
};

View File

@@ -48,6 +48,7 @@ describe(ModeledMethodsList.name, () => {
mode: Mode.Application,
showFlowGeneration: false,
showLlmButton: false,
showMultipleModels: false,
extensionPack: createMockExtensionPack(),
};

View File

@@ -7,6 +7,7 @@ import {
import { CancellationTokenSource } from "vscode";
import { QueryResultType } from "../../../src/query-server/legacy-messages";
import { QueryMetadata } from "../../../src/common/interface-types";
import { QueryLanguage } from "../../../src/common/query-language";
export function createMockLocalQueryInfo({
startTime = new Date(),
@@ -16,6 +17,7 @@ export function createMockLocalQueryInfo({
dbName = "db-name",
hasMetadata = false,
queryWithResults = undefined,
language = undefined,
}: {
startTime?: Date;
resultCount?: number;
@@ -24,6 +26,7 @@ export function createMockLocalQueryInfo({
dbName?: string;
hasMetadata?: boolean;
queryWithResults?: QueryWithResults | undefined;
language?: QueryLanguage;
}): LocalQueryInfo {
const cancellationToken = {
dispose: () => {
@@ -40,6 +43,7 @@ export function createMockLocalQueryInfo({
databaseInfo: {
databaseUri: "databaseUri",
name: dbName,
language,
},
start: startTime,
id: faker.number.int().toString(),

View File

@@ -5,6 +5,7 @@ import {
VariantAnalysisStatus,
} from "../../../src/variant-analysis/shared/variant-analysis";
import { createMockVariantAnalysis } from "../variant-analysis/shared/variant-analysis";
import { QueryLanguage } from "../../../src/common/query-language";
export function createMockVariantAnalysisHistoryItem({
historyItemStatus = QueryStatus.InProgress,
@@ -14,6 +15,7 @@ export function createMockVariantAnalysisHistoryItem({
userSpecifiedLabel = undefined,
executionStartTime = undefined,
variantAnalysis = undefined,
language = QueryLanguage.Javascript,
}: {
historyItemStatus?: QueryStatus;
variantAnalysisStatus?: VariantAnalysisStatus;
@@ -22,6 +24,7 @@ export function createMockVariantAnalysisHistoryItem({
userSpecifiedLabel?: string;
executionStartTime?: number;
variantAnalysis?: VariantAnalysis;
language?: QueryLanguage;
}): VariantAnalysisHistoryItem {
return {
t: "variant-analysis",
@@ -34,6 +37,7 @@ export function createMockVariantAnalysisHistoryItem({
createMockVariantAnalysis({
status: variantAnalysisStatus,
executionStartTime,
language,
}),
userSpecifiedLabel,
};

View File

@@ -15,11 +15,13 @@ export function createMockVariantAnalysis({
scannedRepos = createMockScannedRepos(),
skippedRepos = createMockSkippedRepos(),
executionStartTime = faker.number.int(),
language = QueryLanguage.Javascript,
}: {
status?: VariantAnalysisStatus;
scannedRepos?: VariantAnalysisScannedRepository[];
skippedRepos?: VariantAnalysisSkippedRepositories;
executionStartTime?: number | undefined;
language?: QueryLanguage;
}): VariantAnalysis {
return {
id: faker.number.int(),
@@ -32,7 +34,7 @@ export function createMockVariantAnalysis({
query: {
name: "a-query-name",
filePath: "a-query-file-path",
language: QueryLanguage.Javascript,
language,
text: "a-query-text",
},
databases: {

View File

@@ -225,43 +225,49 @@ describe("createDataExtensionYamlsForApplicationMode", () => {
},
],
{
"org.sql2o.Connection#createQuery(String)": {
type: "sink",
input: "Argument[0]",
output: "",
kind: "sql",
provenance: "df-generated",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
"org.springframework.boot.SpringApplication#run(Class,String[])": {
type: "neutral",
input: "",
output: "",
kind: "summary",
provenance: "manual",
signature:
"org.springframework.boot.SpringApplication#run(Class,String[])",
packageName: "org.springframework.boot",
typeName: "SpringApplication",
methodName: "run",
methodParameters: "(Class,String[])",
},
"org.sql2o.Sql2o#Sql2o(String,String,String)": {
type: "sink",
input: "Argument[0]",
output: "",
kind: "jndi",
provenance: "manual",
signature: "org.sql2o.Sql2o#Sql2o(String,String,String)",
packageName: "org.sql2o",
typeName: "Sql2o",
methodName: "Sql2o",
methodParameters: "(String,String,String)",
},
"org.sql2o.Connection#createQuery(String)": [
{
type: "sink",
input: "Argument[0]",
output: "",
kind: "sql",
provenance: "df-generated",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
],
"org.springframework.boot.SpringApplication#run(Class,String[])": [
{
type: "neutral",
input: "",
output: "",
kind: "summary",
provenance: "manual",
signature:
"org.springframework.boot.SpringApplication#run(Class,String[])",
packageName: "org.springframework.boot",
typeName: "SpringApplication",
methodName: "run",
methodParameters: "(Class,String[])",
},
],
"org.sql2o.Sql2o#Sql2o(String,String,String)": [
{
type: "sink",
input: "Argument[0]",
output: "",
kind: "jndi",
provenance: "manual",
signature: "org.sql2o.Sql2o#Sql2o(String,String,String)",
packageName: "org.sql2o",
typeName: "Sql2o",
methodName: "Sql2o",
methodParameters: "(String,String,String)",
},
],
},
{},
);
@@ -463,84 +469,97 @@ describe("createDataExtensionYamlsForApplicationMode", () => {
},
],
{
"org.sql2o.Connection#createQuery(String)": {
type: "sink",
input: "Argument[0]",
output: "",
kind: "sql",
provenance: "df-generated",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
"org.springframework.boot.SpringApplication#run(Class,String[])": {
type: "neutral",
input: "",
output: "",
kind: "summary",
provenance: "manual",
signature:
"org.springframework.boot.SpringApplication#run(Class,String[])",
packageName: "org.springframework.boot",
typeName: "SpringApplication",
methodName: "run",
methodParameters: "(Class,String[])",
},
"org.sql2o.Sql2o#Sql2o(String,String,String)": {
type: "sink",
input: "Argument[0]",
output: "",
kind: "jndi",
provenance: "manual",
signature: "org.sql2o.Sql2o#Sql2o(String,String,String)",
packageName: "org.sql2o",
typeName: "Sql2o",
methodName: "Sql2o",
methodParameters: "(String,String,String)",
},
},
{
"models/sql2o.model.yml": {
"org.sql2o.Connection#createQuery(String)": {
type: "neutral",
input: "",
"org.sql2o.Connection#createQuery(String)": [
{
type: "sink",
input: "Argument[0]",
output: "",
kind: "summary",
provenance: "manual",
kind: "sql",
provenance: "df-generated",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
"org.sql2o.Query#executeScalar(Class)": {
],
"org.springframework.boot.SpringApplication#run(Class,String[])": [
{
type: "neutral",
input: "",
output: "",
kind: "summary",
provenance: "manual",
signature: "org.sql2o.Query#executeScalar(Class)",
packageName: "org.sql2o",
typeName: "Query",
methodName: "executeScalar",
methodParameters: "(Class)",
signature:
"org.springframework.boot.SpringApplication#run(Class,String[])",
packageName: "org.springframework.boot",
typeName: "SpringApplication",
methodName: "run",
methodParameters: "(Class,String[])",
},
],
"org.sql2o.Sql2o#Sql2o(String,String,String)": [
{
type: "sink",
input: "Argument[0]",
output: "",
kind: "jndi",
provenance: "manual",
signature: "org.sql2o.Sql2o#Sql2o(String,String,String)",
packageName: "org.sql2o",
typeName: "Sql2o",
methodName: "Sql2o",
methodParameters: "(String,String,String)",
},
],
},
{
"models/sql2o.model.yml": {
"org.sql2o.Connection#createQuery(String)": [
{
type: "neutral",
input: "",
output: "",
kind: "summary",
provenance: "manual",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
],
"org.sql2o.Query#executeScalar(Class)": [
{
type: "neutral",
input: "",
output: "",
kind: "summary",
provenance: "manual",
signature: "org.sql2o.Query#executeScalar(Class)",
packageName: "org.sql2o",
typeName: "Query",
methodName: "executeScalar",
methodParameters: "(Class)",
},
],
},
"models/gson.model.yml": {
"com.google.gson.TypeAdapter#fromJsonTree(JsonElement)": {
type: "summary",
input: "Argument[this]",
output: "ReturnValue",
kind: "taint",
provenance: "df-generated",
signature: "com.google.gson.TypeAdapter#fromJsonTree(JsonElement)",
packageName: "com.google.gson",
typeName: "TypeAdapter",
methodName: "fromJsonTree",
methodParameters: "(JsonElement)",
},
"com.google.gson.TypeAdapter#fromJsonTree(JsonElement)": [
{
type: "summary",
input: "Argument[this]",
output: "ReturnValue",
kind: "taint",
provenance: "df-generated",
signature:
"com.google.gson.TypeAdapter#fromJsonTree(JsonElement)",
packageName: "com.google.gson",
typeName: "TypeAdapter",
methodName: "fromJsonTree",
methodParameters: "(JsonElement)",
},
],
},
},
);
@@ -694,30 +713,34 @@ describe("createDataExtensionYamlsForFrameworkMode", () => {
},
],
{
"org.sql2o.Connection#createQuery(String)": {
type: "sink",
input: "Argument[0]",
output: "",
kind: "sql",
provenance: "df-generated",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
"org.sql2o.Sql2o#Sql2o(String,String,String)": {
type: "sink",
input: "Argument[0]",
output: "",
kind: "jndi",
provenance: "manual",
signature: "org.sql2o.Sql2o#Sql2o(String,String,String)",
packageName: "org.sql2o",
typeName: "Sql2o",
methodName: "Sql2o",
methodParameters: "(String,String,String)",
},
"org.sql2o.Connection#createQuery(String)": [
{
type: "sink",
input: "Argument[0]",
output: "",
kind: "sql",
provenance: "df-generated",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
],
"org.sql2o.Sql2o#Sql2o(String,String,String)": [
{
type: "sink",
input: "Argument[0]",
output: "",
kind: "jndi",
provenance: "manual",
signature: "org.sql2o.Sql2o#Sql2o(String,String,String)",
packageName: "org.sql2o",
typeName: "Sql2o",
methodName: "Sql2o",
methodParameters: "(String,String,String)",
},
],
},
{},
);
@@ -846,71 +869,82 @@ describe("createDataExtensionYamlsForFrameworkMode", () => {
},
],
{
"org.sql2o.Connection#createQuery(String)": {
type: "sink",
input: "Argument[0]",
output: "",
kind: "sql",
provenance: "df-generated",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
"org.sql2o.Sql2o#Sql2o(String,String,String)": {
type: "sink",
input: "Argument[0]",
output: "",
kind: "jndi",
provenance: "manual",
signature: "org.sql2o.Sql2o#Sql2o(String,String,String)",
packageName: "org.sql2o",
typeName: "Sql2o",
methodName: "Sql2o",
methodParameters: "(String,String,String)",
},
},
{
"models/org.sql2o.model.yml": {
"org.sql2o.Connection#createQuery(String)": {
type: "neutral",
input: "",
"org.sql2o.Connection#createQuery(String)": [
{
type: "sink",
input: "Argument[0]",
output: "",
kind: "summary",
provenance: "manual",
kind: "sql",
provenance: "df-generated",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
"org.sql2o.Query#executeScalar(Class)": {
type: "neutral",
input: "",
],
"org.sql2o.Sql2o#Sql2o(String,String,String)": [
{
type: "sink",
input: "Argument[0]",
output: "",
kind: "summary",
kind: "jndi",
provenance: "manual",
signature: "org.sql2o.Query#executeScalar(Class)",
signature: "org.sql2o.Sql2o#Sql2o(String,String,String)",
packageName: "org.sql2o",
typeName: "Query",
methodName: "executeScalar",
methodParameters: "(Class)",
typeName: "Sql2o",
methodName: "Sql2o",
methodParameters: "(String,String,String)",
},
],
},
{
"models/org.sql2o.model.yml": {
"org.sql2o.Connection#createQuery(String)": [
{
type: "neutral",
input: "",
output: "",
kind: "summary",
provenance: "manual",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
],
"org.sql2o.Query#executeScalar(Class)": [
{
type: "neutral",
input: "",
output: "",
kind: "summary",
provenance: "manual",
signature: "org.sql2o.Query#executeScalar(Class)",
packageName: "org.sql2o",
typeName: "Query",
methodName: "executeScalar",
methodParameters: "(Class)",
},
],
},
"models/gson.model.yml": {
"com.google.gson.TypeAdapter#fromJsonTree(JsonElement)": {
type: "summary",
input: "Argument[this]",
output: "ReturnValue",
kind: "taint",
provenance: "df-generated",
signature: "com.google.gson.TypeAdapter#fromJsonTree(JsonElement)",
packageName: "com.google.gson",
typeName: "TypeAdapter",
methodName: "fromJsonTree",
methodParameters: "(JsonElement)",
},
"com.google.gson.TypeAdapter#fromJsonTree(JsonElement)": [
{
type: "summary",
input: "Argument[this]",
output: "ReturnValue",
kind: "taint",
provenance: "df-generated",
signature:
"com.google.gson.TypeAdapter#fromJsonTree(JsonElement)",
packageName: "com.google.gson",
typeName: "TypeAdapter",
methodName: "fromJsonTree",
methodParameters: "(JsonElement)",
},
],
},
},
);
@@ -980,18 +1014,20 @@ describe("loadDataExtensionYaml", () => {
});
expect(data).toEqual({
"org.sql2o.Connection#createQuery(String)": {
input: "Argument[0]",
kind: "sql",
output: "",
type: "sink",
provenance: "manual",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
"org.sql2o.Connection#createQuery(String)": [
{
input: "Argument[0]",
kind: "sql",
output: "",
type: "sink",
provenance: "manual",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
},
],
});
});

View File

@@ -28,9 +28,13 @@ import {
import { QueryHistoryManager } from "../../../../src/query-history/query-history-manager";
import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs";
import { createMockApp } from "../../../__mocks__/appMock";
import { LanguageContextStore } from "../../../../src/language-context-store";
import { App } from "../../../../src/common/app";
import { QueryLanguage } from "../../../../src/common/query-language";
describe("HistoryTreeDataProvider", () => {
const mockExtensionLocation = join(tmpDir.name, "mock-extension-location");
let app: App;
let configListener: QueryHistoryConfigListener;
const doCompareCallback = jest.fn();
@@ -45,10 +49,12 @@ describe("HistoryTreeDataProvider", () => {
let historyTreeDataProvider: HistoryTreeDataProvider;
let labelProvider: HistoryItemLabelProvider;
let languageContext: LanguageContextStore;
beforeEach(() => {
jest.spyOn(extLogger, "log").mockResolvedValue(undefined);
app = createMockApp({});
configListener = new QueryHistoryConfigListener();
localQueriesResultsViewStub = {
showResults: jest.fn(),
@@ -124,7 +130,11 @@ describe("HistoryTreeDataProvider", () => {
ttlInMillis: 0,
onDidChangeConfiguration: jest.fn(),
});
historyTreeDataProvider = new HistoryTreeDataProvider(labelProvider);
languageContext = new LanguageContextStore(app);
historyTreeDataProvider = new HistoryTreeDataProvider(
labelProvider,
languageContext,
);
});
afterEach(async () => {
@@ -418,11 +428,68 @@ describe("HistoryTreeDataProvider", () => {
expect(children).toEqual(expected);
});
});
describe("filtering", () => {
const history = [
createMockLocalQueryInfo({
userSpecifiedLabel: "a",
// No language at all => unknown
}),
createMockVariantAnalysisHistoryItem({
userSpecifiedLabel: "b",
// No specified language => javascript
}),
createMockLocalQueryInfo({
userSpecifiedLabel: "c",
language: QueryLanguage.Python,
}),
createMockVariantAnalysisHistoryItem({
userSpecifiedLabel: "d",
language: QueryLanguage.Java,
}),
];
let treeDataProvider: HistoryTreeDataProvider;
beforeEach(async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
(queryHistoryManager.treeDataProvider as any).history = [...history];
treeDataProvider = queryHistoryManager.treeDataProvider;
});
it("should get all if no filter is provided", async () => {
const expected = [history[0], history[1], history[2], history[3]];
treeDataProvider.sortOrder = SortOrder.NameAsc;
const children = await treeDataProvider.getChildren();
expect(children).toEqual(expected);
});
it("should filter local runs by language", async () => {
const expected = [history[3]];
treeDataProvider.sortOrder = SortOrder.NameAsc;
await languageContext.setLanguageContext(QueryLanguage.Java);
const children = await treeDataProvider.getChildren();
expect(children).toEqual(expected);
});
it("should filter variant analysis runs by language", async () => {
const expected = [history[2]];
treeDataProvider.sortOrder = SortOrder.NameAsc;
await languageContext.setLanguageContext(QueryLanguage.Python);
const children = await treeDataProvider.getChildren();
expect(children).toEqual(expected);
});
});
});
async function createMockQueryHistory(allHistory: QueryHistoryInfo[]) {
const qhm = new QueryHistoryManager(
createMockApp({}),
app,
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,
@@ -439,6 +506,7 @@ describe("HistoryTreeDataProvider", () => {
ttlInMillis: 0,
onDidChangeConfiguration: jest.fn(),
}),
languageContext,
doCompareCallback,
);
(qhm.treeDataProvider as any).history = [...allHistory];

View File

@@ -28,6 +28,7 @@ import { createMockQueryHistoryDirs } from "../../../factories/query-history/que
import { createMockApp } from "../../../__mocks__/appMock";
import { App } from "../../../../src/common/app";
import { createMockCommandManager } from "../../../__mocks__/commandsMock";
import { LanguageContextStore } from "../../../../src/language-context-store";
describe("QueryHistoryManager", () => {
const mockExtensionLocation = join(tmpDir.name, "mock-extension-location");
@@ -937,6 +938,7 @@ describe("QueryHistoryManager", () => {
ttlInMillis: 0,
onDidChangeConfiguration: jest.fn(),
}),
new LanguageContextStore(mockApp),
doCompareCallback,
);
(qhm.treeDataProvider as any).history = [...allHistory];

View File

@@ -23,6 +23,7 @@ import { QueryHistoryManager } from "../../../../src/query-history/query-history
import { mockedObject } from "../../utils/mocking.helpers";
import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs";
import { createMockApp } from "../../../__mocks__/appMock";
import { LanguageContextStore } from "../../../../src/language-context-store";
// set a higher timeout since recursive delete may take a while, expecially on Windows.
jest.setTimeout(120000);
@@ -74,8 +75,10 @@ describe("Variant Analyses and QueryHistoryManager", () => {
join(STORAGE_DIR, "workspace-query-history.json"),
).queries;
const app = createMockApp({});
qhm = new QueryHistoryManager(
createMockApp({}),
app,
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,
@@ -97,6 +100,7 @@ describe("Variant Analyses and QueryHistoryManager", () => {
ttlInMillis: 0,
onDidChangeConfiguration: jest.fn(),
}),
new LanguageContextStore(app),
asyncNoop,
);
disposables.push(qhm);