Skip to content

Commit 54d4821

Browse files
committed
feat(query-options): Add query target options too
1 parent fb02817 commit 54d4821

3 files changed

Lines changed: 201 additions & 5 deletions

File tree

package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@
196196
"default": "...:*",
197197
"description": "A [query language expression](https://bazel.build/query/language) which determines the packages displayed in the workspace tree and quick picker. The default inspects the entire workspace, but you could narrow it. For example: `//part/you/want/...:*`"
198198
},
199-
"bazel.queryPackagesOptions": {
199+
"bazel.queryOptions.packages": {
200200
"type": "array",
201201
"items": {
202202
"type": "string"
@@ -205,6 +205,15 @@
205205
"default": [],
206206
"markdownDescription": "A list of additional command line options to pass to `bazel query` when querying packages. Useful for scenarios like git sparse-checkout where `--keep_going` can help handle missing packages. One option per entry, no shell escaping is needed."
207207
},
208+
"bazel.queryOptions.targets": {
209+
"type": "array",
210+
"items": {
211+
"type": "string"
212+
},
213+
"uniqueItems": true,
214+
"default": [],
215+
"markdownDescription": "A list of additional command line options to pass to `bazel query` when querying targets. Useful for scenarios like git sparse-checkout where `--keep_going` can help handle missing packages. One option per entry, no shell escaping is needed."
216+
},
208217
"bazel.lsp.command": {
209218
"type": "string",
210219
"default": "",

src/bazel/bazel_query.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import * as vscode from "vscode";
2020
import { blaze_query } from "../protos";
2121
import { BazelCommand } from "./bazel_command";
2222
import { getBazelWorkspaceFolder } from "./bazel_utils";
23-
import { logDebug, logError } from "../extension/logger";
23+
import { logDebug, logError, logWarn } from "../extension/logger";
2424

2525
const protoOutputOptions = [
2626
"--proto:output_rule_attrs=''",
@@ -58,8 +58,12 @@ export class BazelQuery extends BazelCommand {
5858
abortSignal?: AbortSignal;
5959
} = {},
6060
): Promise<blaze_query.QueryResult> {
61+
const bazelConfig = vscode.workspace.getConfiguration("bazel");
62+
const configOptions =
63+
bazelConfig.get<string[]>("queryOptions.targets") ?? [];
64+
const allOptions = [...configOptions, ...additionalOptions];
6165
const buffer = await this.run(
62-
[query, ...additionalOptions, "--output=proto", ...protoOutputOptions],
66+
[query, ...allOptions, "--output=proto", ...protoOutputOptions],
6367
{ ignoresErrors, abortSignal },
6468
);
6569
const result = blaze_query.QueryResult.decode(buffer);
@@ -104,7 +108,7 @@ export class BazelQuery extends BazelCommand {
104108
): Promise<string[]> {
105109
const bazelConfig = vscode.workspace.getConfiguration("bazel");
106110
const configOptions =
107-
bazelConfig.get<string[]>("queryPackagesOptions") ?? [];
111+
bazelConfig.get<string[]>("queryOptions.packages") ?? [];
108112
const allOptions = [...configOptions, ...additionalOptions];
109113
const buffer = await this.run([query, ...allOptions, "--output=package"], {
110114
abortSignal,
@@ -233,7 +237,10 @@ export class BazelQuery extends BazelCommand {
233237

234238
// Handle exit code 3 with --keep_going as a partial success
235239
if (code === 3 && hasKeepGoing) {
236-
vscode.window.showWarningMessage(
240+
logWarn(
241+
"Bazel query was partially successful (if you are using git " +
242+
"sparse-checkout, this may be expected).",
243+
true,
237244
"Partial success, but the query encountered 1 or more errors " +
238245
"in the input BUILD file set and therefore the results of " +
239246
"the operation are not 100% reliable. This is likely due " +

test/bazel_query.test.ts

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import * as assert from "assert";
2+
import * as path from "path";
3+
import * as vscode from "vscode";
4+
import { BazelQuery } from "../src/bazel/bazel_query";
5+
import { blaze_query } from "../src/protos";
6+
7+
describe("BazelQuery", () => {
8+
const workspacePath = path.join(
9+
__dirname,
10+
"..",
11+
"..",
12+
"test",
13+
"bazel_workspace",
14+
);
15+
16+
async function setQueryOptionsConfig(
17+
packages?: string[],
18+
targets?: string[],
19+
): Promise<void> {
20+
const config = vscode.workspace.getConfiguration("bazel");
21+
if (packages !== undefined) {
22+
await config.update("queryOptions.packages", packages);
23+
}
24+
if (targets !== undefined) {
25+
await config.update("queryOptions.targets", targets);
26+
}
27+
}
28+
29+
beforeEach(async () => {
30+
// Reset config before each test
31+
await setQueryOptionsConfig([], []);
32+
});
33+
34+
afterEach(async () => {
35+
// Reset config after each test
36+
await setQueryOptionsConfig([], []);
37+
});
38+
39+
describe("queryTargets", () => {
40+
it("should merge config options with additionalOptions", async function () {
41+
this.timeout(10000);
42+
await setQueryOptionsConfig(undefined, ["--keep_going"]);
43+
44+
const query = new BazelQuery("bazel", workspacePath);
45+
let capturedOptions: string[] = [];
46+
47+
// Mock the run method to capture options
48+
// @ts-expect-error - accessing protected method for testing
49+
const originalRun = query.run.bind(query);
50+
// @ts-expect-error - accessing protected method for testing
51+
query.run = async (options: string[]) => {
52+
capturedOptions = options;
53+
// Return a minimal valid QueryResult proto
54+
const result = blaze_query.QueryResult.create({
55+
target: [],
56+
});
57+
return Buffer.from(blaze_query.QueryResult.encode(result).finish());
58+
};
59+
60+
await query.queryTargets("//...", {
61+
additionalOptions: ["--output=json"],
62+
});
63+
64+
// Verify config options come before additionalOptions
65+
const queryIndex = capturedOptions.indexOf("//...");
66+
const keepGoingIndex = capturedOptions.indexOf("--keep_going");
67+
const outputJsonIndex = capturedOptions.indexOf("--output=json");
68+
69+
assert.ok(queryIndex >= 0, "Query should be in options");
70+
assert.ok(keepGoingIndex >= 0, "Config option should be in options");
71+
assert.ok(outputJsonIndex >= 0, "Additional option should be in options");
72+
assert.ok(
73+
keepGoingIndex < outputJsonIndex,
74+
"Config options should come before additionalOptions",
75+
);
76+
});
77+
78+
it("should use empty array when config is not set", async function () {
79+
this.timeout(10000);
80+
await setQueryOptionsConfig(undefined, []);
81+
82+
const query = new BazelQuery("bazel", workspacePath);
83+
let capturedOptions: string[] = [];
84+
85+
// @ts-expect-error - accessing protected method for testing
86+
const originalRun = query.run.bind(query);
87+
// @ts-expect-error - accessing protected method for testing
88+
query.run = async (options: string[]) => {
89+
capturedOptions = options;
90+
const result = blaze_query.QueryResult.create({
91+
target: [],
92+
});
93+
return Buffer.from(blaze_query.QueryResult.encode(result).finish());
94+
};
95+
96+
await query.queryTargets("//...", {
97+
additionalOptions: ["--output=json"],
98+
});
99+
100+
// Verify only additionalOptions are present (no config options)
101+
const keepGoingIndex = capturedOptions.indexOf("--keep_going");
102+
const outputJsonIndex = capturedOptions.indexOf("--output=json");
103+
104+
assert.strictEqual(
105+
keepGoingIndex,
106+
-1,
107+
"Config option should not be present",
108+
);
109+
assert.ok(outputJsonIndex >= 0, "Additional option should be present");
110+
});
111+
});
112+
113+
describe("queryPackages", () => {
114+
it("should merge config options with additionalOptions", async function () {
115+
this.timeout(10000);
116+
await setQueryOptionsConfig(["--keep_going"], undefined);
117+
118+
const query = new BazelQuery("bazel", workspacePath);
119+
let capturedOptions: string[] = [];
120+
121+
// Mock the run method to capture options
122+
// @ts-expect-error - accessing protected method for testing
123+
const originalRun = query.run.bind(query);
124+
// @ts-expect-error - accessing protected method for testing
125+
query.run = async (options: string[]) => {
126+
capturedOptions = options;
127+
// Return empty result
128+
return Buffer.from("");
129+
};
130+
131+
await query.queryPackages("//...", {
132+
additionalOptions: ["--output=json"],
133+
});
134+
135+
// Verify config options come before additionalOptions
136+
const queryIndex = capturedOptions.indexOf("//...");
137+
const keepGoingIndex = capturedOptions.indexOf("--keep_going");
138+
const outputJsonIndex = capturedOptions.indexOf("--output=json");
139+
140+
assert.ok(queryIndex >= 0, "Query should be in options");
141+
assert.ok(keepGoingIndex >= 0, "Config option should be in options");
142+
assert.ok(outputJsonIndex >= 0, "Additional option should be in options");
143+
assert.ok(
144+
keepGoingIndex < outputJsonIndex,
145+
"Config options should come before additionalOptions",
146+
);
147+
});
148+
149+
it("should use empty array when config is not set", async function () {
150+
this.timeout(10000);
151+
await setQueryOptionsConfig([], undefined);
152+
153+
const query = new BazelQuery("bazel", workspacePath);
154+
let capturedOptions: string[] = [];
155+
156+
// @ts-expect-error - accessing protected method for testing
157+
const originalRun = query.run.bind(query);
158+
// @ts-expect-error - accessing protected method for testing
159+
query.run = async (options: string[]) => {
160+
capturedOptions = options;
161+
return Buffer.from("");
162+
};
163+
164+
await query.queryPackages("//...", {
165+
additionalOptions: ["--output=json"],
166+
});
167+
168+
// Verify only additionalOptions are present (no config options)
169+
const keepGoingIndex = capturedOptions.indexOf("--keep_going");
170+
const outputJsonIndex = capturedOptions.indexOf("--output=json");
171+
172+
assert.strictEqual(
173+
keepGoingIndex,
174+
-1,
175+
"Config option should not be present",
176+
);
177+
assert.ok(outputJsonIndex >= 0, "Additional option should be present");
178+
});
179+
});
180+
});

0 commit comments

Comments
 (0)