Skip to content

Commit 09a0f62

Browse files
authored
Refactor resolveToolsInput: accept repository properties as parameter, simplify implementation and tests
1 parent 652e91d commit 09a0f62

6 files changed

Lines changed: 100 additions & 234 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
44

55
## [UNRELEASED]
66

7-
- Organizations can now create a custom repository property with the name `github-codeql-tools` to control the CodeQL CLI tools input at the repository level. When this property is set to a valid tools input value (such as `"toolcache"`, `"latest"`, or a specific version), it will override the default tools configuration for that repository. This allows organization administrators to standardize CodeQL CLI versions across repositories or enable toolcache usage on repositories where it would otherwise be restricted. For more information on creating custom repository properties, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization).
7+
- Organizations can now create a custom repository property with the name `github-codeql-tools` to set the default CodeQL CLI tools value for their repositories. For more information, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization) and [Customizing your advanced setup for code scanning](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning).
88

99
## 4.35.2 - 15 Apr 2026
1010

src/init-action.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ async function run(startedAt: Date) {
253253
repositoryNwo,
254254
logger,
255255
);
256+
const repositoryProperties = repositoryPropertiesResult.orElse({});
256257

257258
// Create a unique identifier for this run.
258259
const jobRunUuid = uuidV4();
@@ -303,7 +304,11 @@ async function run(startedAt: Date) {
303304
// Determine the effective tools input.
304305
// The explicit `tools` workflow input takes precedence. If none is provided,
305306
// fall back to the 'github-codeql-tools' repository property (if set).
306-
effectiveToolsInput = await resolveToolsInput(repositoryNwo, logger);
307+
effectiveToolsInput = resolveToolsInput(
308+
getOptionalInput("tools"),
309+
repositoryProperties,
310+
logger,
311+
);
307312

308313
const initCodeQLResult = await initCodeQL(
309314
effectiveToolsInput,
@@ -351,7 +356,6 @@ async function run(startedAt: Date) {
351356

352357
analysisKinds = await getAnalysisKinds(logger);
353358
const debugMode = getOptionalInput("debug") === "true" || core.isDebug();
354-
const repositoryProperties = repositoryPropertiesResult.orElse({});
355359
const fileCoverageResult = await getFileCoverageInformationEnabled(
356360
debugMode,
357361
codeql,

src/resolve-tools-input.test.ts

Lines changed: 58 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,32 @@
11
import test from "ava";
2-
import * as sinon from "sinon";
32

4-
import * as actionsUtil from "./actions-util";
5-
import * as properties from "./feature-flags/properties";
63
import { RepositoryPropertyName } from "./feature-flags/properties";
7-
import { RepositoryNwo } from "./repository";
4+
import type { RepositoryProperties } from "./feature-flags/properties";
85
import { resolveToolsInput } from "./resolve-tools-input";
96
import { getRecordingLogger, LoggedMessage, setupTests } from "./testing-utils";
10-
import { Success } from "./util";
117

128
setupTests(test);
139

14-
const repositoryNwo = { owner: "owner", repo: "repo" } as RepositoryNwo;
15-
16-
test.serial(
10+
test(
1711
"resolveToolsInput returns undefined when no tools input or repository property is set",
18-
async (t) => {
12+
(t) => {
1913
const loggedMessages: LoggedMessage[] = [];
2014
const logger = getRecordingLogger(loggedMessages);
2115

22-
sinon
23-
.stub(actionsUtil, "getOptionalInput")
24-
.withArgs("tools")
25-
.returns(undefined);
26-
27-
sinon
28-
.stub(properties, "loadRepositoryProperties")
29-
.withArgs(repositoryNwo, logger)
30-
.resolves(undefined);
31-
32-
const result = await resolveToolsInput(repositoryNwo, logger);
16+
const result = resolveToolsInput(undefined, {}, logger);
3317

3418
t.is(result, undefined);
35-
t.is(loggedMessages.length, 0); // No logging when no tools input is resolved
19+
t.is(loggedMessages.length, 0);
3620
},
3721
);
3822

39-
test.serial(
23+
test(
4024
"resolveToolsInput returns workflow input when only workflow input is provided",
41-
async (t) => {
25+
(t) => {
4226
const loggedMessages: LoggedMessage[] = [];
4327
const logger = getRecordingLogger(loggedMessages);
4428

45-
sinon
46-
.stub(actionsUtil, "getOptionalInput")
47-
.withArgs("tools")
48-
.returns("latest");
49-
sinon
50-
.stub(properties, "loadRepositoryProperties")
51-
.withArgs(repositoryNwo, logger)
52-
.resolves(undefined);
53-
const result = await resolveToolsInput(repositoryNwo, logger);
29+
const result = resolveToolsInput("latest", {}, logger);
5430

5531
t.is(result, "latest");
5632
t.is(loggedMessages.length, 1);
@@ -61,235 +37,135 @@ test.serial(
6137
},
6238
);
6339

64-
test.serial(
40+
test(
6541
"resolveToolsInput returns repository property when only repository property is provided",
66-
async (t) => {
42+
(t) => {
6743
const loggedMessages: LoggedMessage[] = [];
6844
const logger = getRecordingLogger(loggedMessages);
6945

70-
sinon
71-
.stub(actionsUtil, "getOptionalInput")
72-
.withArgs("tools")
73-
.returns(undefined);
74-
75-
const repositoryPropertiesResult = new Success({
46+
const repositoryProperties: RepositoryProperties = {
7647
[RepositoryPropertyName.TOOLS]: "toolcache",
77-
});
78-
sinon
79-
.stub(properties, "loadRepositoryProperties")
80-
.withArgs(repositoryNwo, logger)
81-
.resolves(repositoryPropertiesResult);
82-
const result = await resolveToolsInput(repositoryNwo, logger);
48+
};
49+
const result = resolveToolsInput(undefined, repositoryProperties, logger);
8350

8451
t.is(result, "toolcache");
85-
t.is(loggedMessages.length, 2);
52+
t.is(loggedMessages.length, 1);
8653
t.is(
87-
loggedMessages[1].message,
54+
loggedMessages[0].message,
8855
"Setting tools: toolcache based on the 'github-codeql-tools' repository property.",
8956
);
9057
},
9158
);
9259

93-
test.serial(
60+
test(
9461
"resolveToolsInput prioritizes workflow input over repository property",
95-
async (t) => {
62+
(t) => {
9663
const loggedMessages: LoggedMessage[] = [];
9764
const logger = getRecordingLogger(loggedMessages);
9865

99-
sinon
100-
.stub(actionsUtil, "getOptionalInput")
101-
.withArgs("tools")
102-
.returns("nightly");
103-
104-
const repositoryPropertiesResult = new Success({
66+
const repositoryProperties: RepositoryProperties = {
10567
[RepositoryPropertyName.TOOLS]: "toolcache",
106-
});
107-
sinon
108-
.stub(properties, "loadRepositoryProperties")
109-
.withArgs(repositoryNwo, logger)
110-
.resolves(repositoryPropertiesResult);
111-
const result = await resolveToolsInput(repositoryNwo, logger);
68+
};
69+
const result = resolveToolsInput("nightly", repositoryProperties, logger);
11270

11371
t.is(result, "nightly");
114-
t.is(loggedMessages.length, 2);
72+
t.is(loggedMessages.length, 1);
11573
t.is(
116-
loggedMessages[1].message,
74+
loggedMessages[0].message,
11775
"Setting tools: nightly based on workflow input.",
11876
);
11977
},
12078
);
12179

122-
test.serial(
123-
"resolveToolsInput handles empty string values correctly",
124-
async (t) => {
80+
test(
81+
"resolveToolsInput treats empty string workflow input as not set",
82+
(t) => {
12583
const loggedMessages: LoggedMessage[] = [];
12684
const logger = getRecordingLogger(loggedMessages);
12785

128-
sinon.stub(actionsUtil, "getOptionalInput").withArgs("tools").returns("");
129-
130-
const repositoryPropertiesResult = new Success({
86+
const repositoryProperties: RepositoryProperties = {
13187
[RepositoryPropertyName.TOOLS]: "toolcache",
132-
});
133-
sinon
134-
.stub(properties, "loadRepositoryProperties")
135-
.withArgs(repositoryNwo, logger)
136-
.resolves(repositoryPropertiesResult);
137-
138-
const result = await resolveToolsInput(repositoryNwo, logger);
88+
};
89+
const result = resolveToolsInput("", repositoryProperties, logger);
13990

140-
// Empty string is falsy, so should fall back to repository property
14191
t.is(result, "toolcache");
142-
t.is(loggedMessages.length, 2);
92+
t.is(loggedMessages.length, 1);
14393
t.is(
144-
loggedMessages[1].message,
94+
loggedMessages[0].message,
14595
"Setting tools: toolcache based on the 'github-codeql-tools' repository property.",
14696
);
14797
},
14898
);
14999

150-
test.serial(
151-
"resolveToolsInput handles various tools input values correctly",
152-
async (t) => {
100+
test(
101+
"resolveToolsInput returns workflow input with URL value",
102+
(t) => {
153103
const loggedMessages: LoggedMessage[] = [];
154104
const logger = getRecordingLogger(loggedMessages);
155105

156-
// Test with specific version
157-
sinon
158-
.stub(actionsUtil, "getOptionalInput")
159-
.withArgs("tools")
160-
.returns("2.15.0");
161-
162-
const repositoryPropertiesResult = new Success({
163-
[RepositoryPropertyName.TOOLS]: "2.20.0",
164-
});
165-
sinon
166-
.stub(properties, "loadRepositoryProperties")
167-
.withArgs(repositoryNwo, logger)
168-
.resolves(repositoryPropertiesResult);
169-
const result = await resolveToolsInput(repositoryNwo, logger);
170-
t.is(result, "2.15.0");
171-
t.is(
172-
loggedMessages[loggedMessages.length - 1].message,
173-
"Setting tools: 2.15.0 based on workflow input.",
174-
);
175-
},
176-
);
177-
178-
test.serial(
179-
"resolveToolsInput handles URL input values correctly",
180-
async (t) => {
181-
const loggedMessages: LoggedMessage[] = [];
182-
const logger = getRecordingLogger(loggedMessages);
106+
const url = "https://example.com/codeql-bundle.tar.gz";
107+
const result = resolveToolsInput(url, {}, logger);
183108

184-
// Test with URL
185-
sinon
186-
.stub(actionsUtil, "getOptionalInput")
187-
.withArgs("tools")
188-
.returns("https://example.com/codeql-bundle.tar.gz");
189-
const repositoryPropertiesResult = new Success({
190-
[RepositoryPropertyName.TOOLS]:
191-
"https://example.com/old-codeql-bundle.tar.gz",
192-
});
193-
sinon
194-
.stub(properties, "loadRepositoryProperties")
195-
.withArgs(repositoryNwo, logger)
196-
.resolves(repositoryPropertiesResult);
197-
const result = await resolveToolsInput(repositoryNwo, logger);
198-
t.is(result, "https://example.com/codeql-bundle.tar.gz");
109+
t.is(result, url);
110+
t.is(loggedMessages.length, 1);
199111
t.is(
200-
loggedMessages[loggedMessages.length - 1].message,
201-
"Setting tools: https://example.com/codeql-bundle.tar.gz based on workflow input.",
112+
loggedMessages[0].message,
113+
`Setting tools: ${url} based on workflow input.`,
202114
);
203115
},
204116
);
205117

206-
test.serial(
207-
"resolveToolsInput handles repository property with different values",
208-
async (t) => {
118+
test(
119+
"resolveToolsInput returns repository property with 'latest' value",
120+
(t) => {
209121
const loggedMessages: LoggedMessage[] = [];
210122
const logger = getRecordingLogger(loggedMessages);
211123

212-
sinon
213-
.stub(actionsUtil, "getOptionalInput")
214-
.withArgs("tools")
215-
.returns(undefined);
216-
217-
// Test with "latest"
218-
const repositoryProperties = {
124+
const repositoryProperties: RepositoryProperties = {
219125
[RepositoryPropertyName.TOOLS]: "latest",
220126
};
221-
const repositoryPropertiesResult = new Success(repositoryProperties);
222-
sinon
223-
.stub(properties, "loadRepositoryProperties")
224-
.withArgs(repositoryNwo, logger)
225-
.resolves(repositoryPropertiesResult);
127+
const result = resolveToolsInput(undefined, repositoryProperties, logger);
226128

227-
const result = await resolveToolsInput(repositoryNwo, logger);
228129
t.is(result, "latest");
229130
t.is(
230-
loggedMessages[loggedMessages.length - 1].message,
131+
loggedMessages[0].message,
231132
"Setting tools: latest based on the 'github-codeql-tools' repository property.",
232133
);
233134
},
234135
);
235136

236-
test.serial(
237-
"resolveToolsInput handles repository property with specific version",
238-
async (t) => {
137+
test(
138+
"resolveToolsInput returns repository property with specific version",
139+
(t) => {
239140
const loggedMessages: LoggedMessage[] = [];
240141
const logger = getRecordingLogger(loggedMessages);
241142

242-
sinon
243-
.stub(actionsUtil, "getOptionalInput")
244-
.withArgs("tools")
245-
.returns(undefined);
246-
247-
const repositoryProperties = {
143+
const repositoryProperties: RepositoryProperties = {
248144
[RepositoryPropertyName.TOOLS]: "2.16.1",
249145
};
250-
const repositoryPropertiesResult = new Success(repositoryProperties);
251-
sinon
252-
.stub(properties, "loadRepositoryProperties")
253-
.withArgs(repositoryNwo, logger)
254-
.resolves(repositoryPropertiesResult);
146+
const result = resolveToolsInput(undefined, repositoryProperties, logger);
255147

256-
const result = await resolveToolsInput(repositoryNwo, logger);
257148
t.is(result, "2.16.1");
258149
t.is(
259-
loggedMessages[loggedMessages.length - 1].message,
150+
loggedMessages[0].message,
260151
"Setting tools: 2.16.1 based on the 'github-codeql-tools' repository property.",
261152
);
262153
},
263154
);
264155

265-
test.serial(
266-
"resolveToolsInput handles undefined repository property correctly",
267-
async (t) => {
156+
test(
157+
"resolveToolsInput returns undefined when repository property is undefined",
158+
(t) => {
268159
const loggedMessages: LoggedMessage[] = [];
269160
const logger = getRecordingLogger(loggedMessages);
270161

271-
sinon
272-
.stub(actionsUtil, "getOptionalInput")
273-
.withArgs("tools")
274-
.returns(undefined);
275-
276-
const repositoryProperties = {
162+
const repositoryProperties: RepositoryProperties = {
277163
[RepositoryPropertyName.TOOLS]: undefined,
278164
};
279-
280-
const repositoryPropertiesResult = new Success(repositoryProperties);
281-
sinon
282-
.stub(properties, "loadRepositoryProperties")
283-
.withArgs(repositoryNwo, logger)
284-
.resolves(repositoryPropertiesResult);
285-
286-
const result = await resolveToolsInput(repositoryNwo, logger);
165+
const result = resolveToolsInput(undefined, repositoryProperties, logger);
287166

288167
t.is(result, undefined);
289-
t.is(loggedMessages.length, 1);
290-
t.is(
291-
loggedMessages[0].message,
292-
"Loaded repository properties: github-codeql-tools",
293-
);
168+
t.is(loggedMessages.length, 0);
294169
},
295170
);
171+

0 commit comments

Comments
 (0)