Skip to content

Commit 49f2e37

Browse files
committed
Add and use getToolsInput
1 parent 3479f3f commit 49f2e37

5 files changed

Lines changed: 271 additions & 18 deletions

File tree

lib/entry-points.js

Lines changed: 63 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/config/inputs.test.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import test from "ava";
2+
import sinon from "sinon";
3+
4+
import { getActionsEnv } from "../actions-util";
5+
import { Feature } from "../feature-flags";
6+
import { RepositoryPropertyName } from "../feature-flags/properties";
7+
import { callee } from "../testing-utils";
8+
9+
import {
10+
EffectiveInput,
11+
getToolsInput,
12+
InputName,
13+
InputSource,
14+
} from "./inputs";
15+
16+
test("getToolsInput - undefined if there's no input", async (t) => {
17+
await callee(getToolsInput).withArgs({}).passes(t.is, undefined);
18+
});
19+
20+
const expectedWorkflowResult: EffectiveInput = {
21+
name: InputName.Tools,
22+
source: InputSource.Workflow,
23+
value: "workflow-input-value",
24+
};
25+
26+
const expectedRepositoryPropertyResult: EffectiveInput = {
27+
name: InputName.Tools,
28+
source: InputSource.RepositoryProperty,
29+
value: "repo-property-input-value",
30+
};
31+
32+
function stubGetToolsInput() {
33+
const actions = getActionsEnv();
34+
sinon
35+
.stub(actions, "getOptionalInput")
36+
.withArgs(InputName.Tools)
37+
.returns(expectedWorkflowResult.value);
38+
return actions;
39+
}
40+
41+
test("getToolsInput - returns workflow input if available", async (t) => {
42+
const actions = stubGetToolsInput();
43+
44+
await callee(getToolsInput)
45+
.withActions(actions)
46+
.withArgs({})
47+
.passes(t.deepEqual, expectedWorkflowResult);
48+
});
49+
50+
test("getToolsInput - returns repository property value if enforced", async (t) => {
51+
const actions = stubGetToolsInput();
52+
53+
const target = callee(getToolsInput)
54+
.withActions(actions)
55+
.withArgs({
56+
[RepositoryPropertyName.TOOLS]: `!${expectedRepositoryPropertyResult.value}`,
57+
});
58+
59+
// We expect the repository value if provided and the FF is enabled.
60+
await target
61+
.withFeatures([Feature.ToolsRepositoryProperty])
62+
.passes(t.deepEqual, expectedRepositoryPropertyResult);
63+
await target.passes(t.deepEqual, expectedWorkflowResult);
64+
});
65+
66+
test("getToolsInput - prefers workflow input", async (t) => {
67+
const actions = stubGetToolsInput();
68+
69+
const target = callee(getToolsInput)
70+
.withActions(actions)
71+
.withArgs({
72+
[RepositoryPropertyName.TOOLS]: expectedRepositoryPropertyResult.value,
73+
});
74+
75+
// We expect the workflow input regardless of the FF state.
76+
await target
77+
.withFeatures([Feature.ToolsRepositoryProperty])
78+
.passes(t.deepEqual, expectedWorkflowResult);
79+
await target.passes(t.deepEqual, expectedWorkflowResult);
80+
});
81+
82+
test("getToolsInput - returns repository property", async (t) => {
83+
const target = callee(getToolsInput).withArgs({
84+
[RepositoryPropertyName.TOOLS]: expectedRepositoryPropertyResult.value,
85+
});
86+
87+
// We expect the repository property if the FF is enabled or undefined otherwise.
88+
await target
89+
.withFeatures([Feature.ToolsRepositoryProperty])
90+
.passes(t.deepEqual, expectedRepositoryPropertyResult);
91+
await target.passes(t.is, undefined);
92+
});

src/config/inputs.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { ActionState } from "../action-common";
2+
import { Feature } from "../feature-flags";
3+
import {
4+
RepositoryProperties,
5+
RepositoryPropertyName,
6+
} from "../feature-flags/properties";
7+
8+
/** Enumerates input names. */
9+
export enum InputName {
10+
Tools = "tools",
11+
}
12+
13+
/** Enumerates input sources. */
14+
export enum InputSource {
15+
Workflow = "workflow",
16+
RepositoryProperty = "repository-property",
17+
}
18+
19+
/**
20+
* Represents an effective input to the CodeQL Action. That is,
21+
* the input value that was computed or selected from multiple sources.
22+
*/
23+
export type EffectiveInput = {
24+
/** The name of the property. */
25+
name: InputName;
26+
/** The value of the property. */
27+
value: string;
28+
/** The source of the property. */
29+
source: InputSource;
30+
};
31+
32+
/**
33+
* Gets the effective `tools` input. This comes from either the workflow or
34+
* the repository property.
35+
*
36+
* @param action The Action state.
37+
* @param repositoryProperties The values of known repository properties.
38+
* @returns The effective input or `undefined` if there is no input.
39+
*/
40+
export async function getToolsInput(
41+
action: ActionState<["Logger", "Actions", "FeatureFlags"]>,
42+
repositoryProperties: Partial<RepositoryProperties>,
43+
): Promise<EffectiveInput | undefined> {
44+
const name = InputName.Tools;
45+
const input = action.actions.getOptionalInput(name);
46+
const propertyValue = repositoryProperties[RepositoryPropertyName.TOOLS];
47+
const allowRepositoryProperty = await action.features.getValue(
48+
Feature.ToolsRepositoryProperty,
49+
);
50+
51+
// The repository property takes precedence if it starts with an '!'.
52+
if (allowRepositoryProperty && propertyValue?.startsWith("!")) {
53+
action.logger.info(
54+
`Using ${name} input from repository property (enforced): ${propertyValue}`,
55+
);
56+
return {
57+
name,
58+
// Drop the '!' from the value.
59+
value: propertyValue.substring(1),
60+
source: InputSource.RepositoryProperty,
61+
};
62+
}
63+
64+
// Otherwise, the input from the workflow takes precedence.
65+
if (input !== undefined) {
66+
action.logger.info(`Using ${name} input from workflow: ${input}`);
67+
return { name, value: input, source: InputSource.Workflow };
68+
}
69+
70+
// Use the repository property if there's no workflow input.
71+
if (allowRepositoryProperty && propertyValue !== undefined) {
72+
action.logger.info(
73+
`Using ${name} input from repository property: ${propertyValue}`,
74+
);
75+
return {
76+
name,
77+
value: propertyValue,
78+
source: InputSource.RepositoryProperty,
79+
};
80+
}
81+
82+
// There's no input.
83+
return undefined;
84+
}

0 commit comments

Comments
 (0)