Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions extensions/ql-vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [UNRELEASED]

- Add settings `codeQL.variantAnalysis.defaultResultsFilter` and `codeQL.variantAnalysis.defaultResultsSort` for configuring how variant analysis results are filtered and sorted in the results view. The default is to show all repositories, and to sort by the number of results. [#2392](https://github.com/github/vscode-codeql/pull/2392)

## 1.8.4 - 3 May 2023

- Avoid repeated error messages when unable to monitor a variant analysis. [#2396](https://github.com/github/vscode-codeql/pull/2396)
Expand Down
30 changes: 30 additions & 0 deletions extensions/ql-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,36 @@
"patternErrorMessage": "Please enter a valid GitHub repository",
"markdownDescription": "[For internal use only] The name of the GitHub repository in which the GitHub Actions workflow is run when using the \"Run Variant Analysis\" command. The repository should be of the form `<owner>/<repo>`)."
},
"codeQL.variantAnalysis.defaultResultsFilter": {
"type": "string",
"default": "all",
"enum": [
"all",
"withResults"
],
"enumDescriptions": [
"Show all repositories in the results view.",
"Show only repositories with results in the results view."
],
"description": "The default filter to apply to the variant analysis results view."
},
"codeQL.variantAnalysis.defaultResultsSort": {
"type": "string",
"default": "numberOfResults",
"enum": [
"alphabetically",
"popularity",
"mostRecentCommit",
"numberOfResults"
],
"enumDescriptions": [
"Sort repositories alphabetically in the results view.",
"Sort repositories by popularity in the results view.",
"Sort repositories by most recent commit in the results view.",
"Sort repositories by number of results in the results view."
],
"description": "The default sorting order for repositories in the variant analysis results view."
},
"codeQL.logInsights.joinOrderWarningThreshold": {
"type": "number",
"default": 50,
Expand Down
33 changes: 33 additions & 0 deletions extensions/ql-vscode/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import {
import { DistributionManager } from "./codeql-cli/distribution";
import { extLogger } from "./common";
import { ONE_DAY_IN_MS } from "./pure/time";
import {
FilterKey,
SortKey,
defaultFilterSortState,
} from "./pure/variant-analysis-filter-sort";

export const ALL_SETTINGS: Setting[] = [];

Expand Down Expand Up @@ -541,6 +546,34 @@ export class VariantAnalysisConfigListener
}
}

const VARIANT_ANALYSIS_FILTER_RESULTS = new Setting(
"defaultResultsFilter",
VARIANT_ANALYSIS_SETTING,
);

export function getVariantAnalysisDefaultResultsFilter(): FilterKey {
const value = VARIANT_ANALYSIS_FILTER_RESULTS.getValue<string>();
if (Object.values(FilterKey).includes(value as FilterKey)) {
return value as FilterKey;
} else {
return defaultFilterSortState.filterKey;
}
}

const VARIANT_ANALYSIS_SORT_RESULTS = new Setting(
"defaultResultsSort",
VARIANT_ANALYSIS_SETTING,
);

export function getVariantAnalysisDefaultResultsSort(): SortKey {
const value = VARIANT_ANALYSIS_SORT_RESULTS.getValue<string>();
if (Object.values(SortKey).includes(value as SortKey)) {
return value as SortKey;
} else {
return defaultFilterSortState.sortKey;
}
}

/**
* The branch of "github/codeql-variant-analysis-action" to use with the "Run Variant Analysis" command.
* Default value is "main".
Expand Down
11 changes: 10 additions & 1 deletion extensions/ql-vscode/src/pure/interface-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {
VariantAnalysisScannedRepositoryResult,
VariantAnalysisScannedRepositoryState,
} from "../variant-analysis/shared/variant-analysis";
import { RepositoriesFilterSortStateWithIds } from "./variant-analysis-filter-sort";
import {
RepositoriesFilterSortState,
RepositoriesFilterSortStateWithIds,
} from "./variant-analysis-filter-sort";
import { ErrorLike } from "./errors";
import { DataFlowPaths } from "../variant-analysis/shared/data-flow-paths";
import { ExternalApiUsage } from "../data-extensions-editor/external-api-usage";
Expand Down Expand Up @@ -407,6 +410,11 @@ export interface SetVariantAnalysisMessage {
variantAnalysis: VariantAnalysis;
}

export interface SetFilterSortStateMessage {
t: "setFilterSortState";
filterSortState: RepositoriesFilterSortState;
}

export type VariantAnalysisState = {
variantAnalysisId: number;
};
Expand Down Expand Up @@ -459,6 +467,7 @@ export interface ShowDataFlowPathsMessage {

export type ToVariantAnalysisMessage =
| SetVariantAnalysisMessage
| SetFilterSortStateMessage
| SetRepoResultsMessage
| SetRepoStatesMessage;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type RepositoriesFilterSortStateWithIds = RepositoriesFilterSortState & {
export const defaultFilterSortState: RepositoriesFilterSortState = {
searchValue: "",
filterKey: FilterKey.All,
sortKey: SortKey.Alphabetically,
sortKey: SortKey.NumberOfResults,
};

export function matchesFilter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ import { redactableError } from "../pure/errors";
import { DataFlowPathsView } from "./data-flow-paths-view";
import { DataFlowPaths } from "./shared/data-flow-paths";
import { App } from "../common/app";
import {
getVariantAnalysisDefaultResultsFilter,
getVariantAnalysisDefaultResultsSort,
} from "../config";

export class VariantAnalysisView
extends AbstractWebview<ToVariantAnalysisMessage, FromVariantAnalysisMessage>
Expand Down Expand Up @@ -186,11 +190,22 @@ export class VariantAnalysisView
return;
}

const filterSortState = {
searchValue: "",
filterKey: getVariantAnalysisDefaultResultsFilter(),
sortKey: getVariantAnalysisDefaultResultsSort(),
};

await this.postMessage({
t: "setVariantAnalysis",
variantAnalysis,
});

await this.postMessage({
t: "setFilterSortState",
filterSortState,
});

const repoStates = await this.manager.getRepoStates(this.variantAnalysisId);
if (repoStates.length === 0) {
return;
Expand Down
19 changes: 19 additions & 0 deletions extensions/ql-vscode/src/view/common/post-message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { act } from "@testing-library/react";

/** Helper function used in tests */
export async function postMessage<T>(msg: T): Promise<void> {
await act(async () => {
// window.postMessage doesn't set the origin correctly, see
// https://github.com/jsdom/jsdom/issues/2745
window.dispatchEvent(
new MessageEvent("message", {
source: window,
origin: window.location.origin,
data: msg,
}),
);

// The event is dispatched asynchronously, so we need to wait for it to be handled.
await new Promise((resolve) => setTimeout(resolve, 0));
});
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { act, render as reactRender, screen } from "@testing-library/react";
import { render as reactRender, screen } from "@testing-library/react";
import { ResultsApp } from "../results";
import {
Interpretation,
Expand All @@ -9,6 +9,7 @@ import {
import * as fs from "fs-extra";
import { resolve } from "path";
import { ColumnKindCode } from "../../../pure/bqrs-cli-types";
import { postMessage } from "../../common/post-message";

const exampleSarif = fs.readJSONSync(
resolve(
Expand All @@ -19,22 +20,6 @@ const exampleSarif = fs.readJSONSync(

describe(ResultsApp.name, () => {
const render = () => reactRender(<ResultsApp />);
const postMessage = async (msg: IntoResultsViewMsg) => {
await act(async () => {
// window.postMessage doesn't set the origin correctly, see
// https://github.com/jsdom/jsdom/issues/2745
window.dispatchEvent(
new MessageEvent("message", {
source: window,
origin: window.location.origin,
data: msg,
}),
);

// The event is dispatched asynchronously, so we need to wait for it to be handled.
await new Promise((resolve) => setTimeout(resolve, 0));
});
};

it("renders results", async () => {
render();
Expand Down Expand Up @@ -98,13 +83,13 @@ describe(ResultsApp.name, () => {
},
};

await postMessage(message);
await postMessage<IntoResultsViewMsg>(message);

expect(
screen.getByText("'x' is assigned a value but never used."),
).toBeInTheDocument();

await postMessage({
await postMessage<IntoResultsViewMsg>({
...message,
t: "showInterpretedPage",
pageNumber: 1,
Expand All @@ -124,7 +109,7 @@ describe(ResultsApp.name, () => {
it("renders results when switching between queries with different result set names", async () => {
render();

await postMessage({
await postMessage<IntoResultsViewMsg>({
t: "setState",
interpretation: undefined,
origResultsPaths: {
Expand Down Expand Up @@ -162,7 +147,7 @@ describe(ResultsApp.name, () => {

expect(screen.getByText("foobar1")).toBeInTheDocument();

await postMessage({
await postMessage<IntoResultsViewMsg>({
t: "setState",
interpretation: undefined,
origResultsPaths: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export function VariantAnalysis({
vscode.setState({
variantAnalysisId: msg.variantAnalysis.id,
});
} else if (msg.t === "setFilterSortState") {
setFilterSortState(msg.filterSortState);
} else if (msg.t === "setRepoResults") {
setRepoResults((oldRepoResults) => {
const newRepoIds = msg.repoResults.map((r) => r.repositoryId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import * as React from "react";
import { render as reactRender, screen } from "@testing-library/react";
import { render as reactRender, screen, waitFor } from "@testing-library/react";
import {
VariantAnalysisFailureReason,
VariantAnalysisStatus,
} from "../../../variant-analysis/shared/variant-analysis";
import { VariantAnalysis, VariantAnalysisProps } from "../VariantAnalysis";
import { createMockVariantAnalysis } from "../../../../test/factories/variant-analysis/shared/variant-analysis";
import { ToVariantAnalysisMessage } from "../../../pure/interface-types";
import { FilterKey, SortKey } from "../../../pure/variant-analysis-filter-sort";
import { postMessage } from "../../common/post-message";

describe(VariantAnalysis.name, () => {
const render = (props: Partial<VariantAnalysisProps> = {}) =>
Expand Down Expand Up @@ -46,4 +49,29 @@ describe(VariantAnalysis.name, () => {
),
).toBeInTheDocument();
});

it("renders results view with correct filter and sort state", async () => {
const variantAnalysis = createMockVariantAnalysis({});
render({ variantAnalysis });

await waitFor(() => screen.getByDisplayValue("All"));
await waitFor(() => screen.getByDisplayValue("Number of results"));

await postMessage<ToVariantAnalysisMessage>({
t: "setFilterSortState",
filterSortState: {
searchValue: "",
filterKey: FilterKey.WithResults,
sortKey: SortKey.Alphabetically,
},
});

expect(screen.getByDisplayValue("With results")).toBeInTheDocument();
expect(screen.getByDisplayValue("Alphabetically")).toBeInTheDocument();

expect(screen.queryByDisplayValue("All")).not.toBeInTheDocument();
expect(
screen.queryByDisplayValue("Number of results"),
).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ import {
import { createMockVariantAnalysis } from "../../../../test/factories/variant-analysis/shared/variant-analysis";
import { createMockRepositoryWithMetadata } from "../../../../test/factories/variant-analysis/shared/repository";
import { createMockScannedRepo } from "../../../../test/factories/variant-analysis/shared/scanned-repositories";
import {
defaultFilterSortState,
SortKey,
} from "../../../pure/variant-analysis-filter-sort";
import { SortKey } from "../../../pure/variant-analysis-filter-sort";
import { permissiveFilterSortState } from "../../../../test/unit-tests/variant-analysis-filter-sort.test";

describe(VariantAnalysisAnalyzedRepos.name, () => {
const defaultVariantAnalysis = createMockVariantAnalysis({
Expand Down Expand Up @@ -170,7 +168,7 @@ describe(VariantAnalysisAnalyzedRepos.name, () => {
it("uses the search value", () => {
render({
filterSortState: {
...defaultFilterSortState,
...permissiveFilterSortState,
searchValue: "world-2",
},
});
Expand All @@ -190,7 +188,7 @@ describe(VariantAnalysisAnalyzedRepos.name, () => {
it("uses the sort key", async () => {
render({
filterSortState: {
...defaultFilterSortState,
...permissiveFilterSortState,
sortKey: SortKey.Popularity,
},
});
Expand All @@ -209,7 +207,7 @@ describe(VariantAnalysisAnalyzedRepos.name, () => {
it("uses the 'Number of results' sort key", async () => {
render({
filterSortState: {
...defaultFilterSortState,
...permissiveFilterSortState,
sortKey: SortKey.NumberOfResults,
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import {
VariantAnalysisSkippedRepositoriesTab,
VariantAnalysisSkippedRepositoriesTabProps,
} from "../VariantAnalysisSkippedRepositoriesTab";
import {
defaultFilterSortState,
SortKey,
} from "../../../pure/variant-analysis-filter-sort";
import { SortKey } from "../../../pure/variant-analysis-filter-sort";
import { permissiveFilterSortState } from "../../../../test/unit-tests/variant-analysis-filter-sort.test";

describe(VariantAnalysisSkippedRepositoriesTab.name, () => {
const render = (props: VariantAnalysisSkippedRepositoriesTabProps) =>
Expand Down Expand Up @@ -142,7 +140,7 @@ describe(VariantAnalysisSkippedRepositoriesTab.name, () => {
],
},
filterSortState: {
...defaultFilterSortState,
...permissiveFilterSortState,
searchValue: "world",
},
});
Expand Down Expand Up @@ -177,7 +175,7 @@ describe(VariantAnalysisSkippedRepositoriesTab.name, () => {
],
},
filterSortState: {
...defaultFilterSortState,
...permissiveFilterSortState,
sortKey: SortKey.Popularity,
},
});
Expand Down Expand Up @@ -210,7 +208,7 @@ describe(VariantAnalysisSkippedRepositoriesTab.name, () => {
],
},
filterSortState: {
...defaultFilterSortState,
...permissiveFilterSortState,
sortKey: SortKey.NumberOfResults,
},
});
Expand Down
Loading