Filter set of possible Action inputs to those from a particular job

This better handles cases where customers have a monorepo and have
separate jobs for different components.
This commit is contained in:
Henry Mercer 2022-11-25 17:40:27 +00:00
parent 9f2aa7ec75
commit 8f05fcd048
6 changed files with 90 additions and 25 deletions

14
lib/workflow.js generated
View file

@ -262,13 +262,15 @@ exports.getStepsCallingAction = getStepsCallingAction;
* @throws an error if the value of the input could not be determined, or we could not
* determine that no such input is passed to the Action.
*/
function getInputOrThrow(workflow, actionName, inputName, matrixVars) {
function getInputOrThrow(workflow, jobName, actionName, inputName, matrixVars) {
if (!workflow.jobs) {
throw new Error(`Could not get ${inputName} input to ${actionName} since the workflow has no jobs.`);
}
const inputs = Object.values(workflow.jobs)
.map((job) => getStepsCallingAction(job, actionName).map((step) => { var _a; return (_a = step.with) === null || _a === void 0 ? void 0 : _a[inputName]; }))
.flat()
if (!workflow.jobs[jobName]) {
throw new Error(`Could not get ${inputName} input to ${actionName} since the workflow has no job named ${jobName}.`);
}
const inputs = getStepsCallingAction(workflow.jobs[jobName], actionName)
.map((step) => { var _a; return (_a = step.with) === null || _a === void 0 ? void 0 : _a[inputName]; })
.filter((input) => input !== undefined)
.map((input) => input);
if (inputs.length === 0) {
@ -296,8 +298,8 @@ function getInputOrThrow(workflow, actionName, inputName, matrixVars) {
* @returns the category input, or undefined if the category input is not defined
* @throws an error if the category input could not be determined
*/
function getCategoryInputOrThrow(workflow, matrixVars) {
return getInputOrThrow(workflow, "github/codeql-action/analyze", "category", matrixVars);
function getCategoryInputOrThrow(workflow, jobName, matrixVars) {
return getInputOrThrow(workflow, jobName, "github/codeql-action/analyze", "category", matrixVars);
}
exports.getCategoryInputOrThrow = getCategoryInputOrThrow;
//# sourceMappingURL=workflow.js.map

File diff suppressed because one or more lines are too long

33
lib/workflow.test.js generated
View file

@ -366,7 +366,7 @@ function errorCodes(actual, expected) {
- uses: github/codeql-action/analyze@v2
with:
category: some-category
`), {}), "some-category");
`), "analysis", {}), "some-category");
});
(0, ava_1.default)("getCategoryInputOrThrow returns undefined for simple workflow without category", (t) => {
t.is((0, workflow_1.getCategoryInputOrThrow)(yaml.load(`
@ -377,7 +377,30 @@ function errorCodes(actual, expected) {
- uses: actions/checkout@v2
- uses: github/codeql-action/init@v2
- uses: github/codeql-action/analyze@v2
`), {}), undefined);
`), "analysis", {}), undefined);
});
(0, ava_1.default)("getCategoryInputOrThrow returns category for workflow with multiple jobs", (t) => {
t.is((0, workflow_1.getCategoryInputOrThrow)(yaml.load(`
jobs:
foo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: github/codeql-action/init@v2
- runs: ./build foo
- uses: github/codeql-action/analyze@v2
with:
category: foo-category
bar:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: github/codeql-action/init@v2
- runs: ./build bar
- uses: github/codeql-action/analyze@v2
with:
category: bar-category
`), "bar", {}), "bar-category");
});
(0, ava_1.default)("getCategoryInputOrThrow finds category for workflow with language matrix", (t) => {
t.is((0, workflow_1.getCategoryInputOrThrow)(yaml.load(`
@ -395,7 +418,7 @@ function errorCodes(actual, expected) {
- uses: github/codeql-action/analyze@v2
with:
category: "/language:\${{ matrix.language }}"
`), { language: "javascript" }), "/language:javascript");
`), "analysis", { language: "javascript" }), "/language:javascript");
});
(0, ava_1.default)("getCategoryInputOrThrow throws error for workflow with dynamic category", (t) => {
t.throws(() => (0, workflow_1.getCategoryInputOrThrow)(yaml.load(`
@ -407,7 +430,7 @@ function errorCodes(actual, expected) {
- uses: github/codeql-action/analyze@v2
with:
category: "\${{ github.workflow }}"
`), {}), {
`), "analysis", {}), {
message: "Could not get category input to github/codeql-action/analyze since it contained " +
"an unrecognized dynamic value.",
});
@ -426,7 +449,7 @@ function errorCodes(actual, expected) {
- uses: github/codeql-action/analyze@v2
with:
category: another-category
`), {}), {
`), "analysis", {}), {
message: "Could not get category input to github/codeql-action/analyze since there were multiple steps " +
"calling github/codeql-action/analyze with different values for category.",
});

File diff suppressed because one or more lines are too long

View file

@ -537,7 +537,8 @@ test("getCategoryInputOrThrow returns category for simple workflow with category
- uses: github/codeql-action/analyze@v2
with:
category: some-category
`) as Workflow,
`) as Workflow,
"analysis",
{}
),
"some-category"
@ -555,13 +556,45 @@ test("getCategoryInputOrThrow returns undefined for simple workflow without cate
- uses: actions/checkout@v2
- uses: github/codeql-action/init@v2
- uses: github/codeql-action/analyze@v2
`) as Workflow,
`) as Workflow,
"analysis",
{}
),
undefined
);
});
test("getCategoryInputOrThrow returns category for workflow with multiple jobs", (t) => {
t.is(
getCategoryInputOrThrow(
yaml.load(`
jobs:
foo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: github/codeql-action/init@v2
- runs: ./build foo
- uses: github/codeql-action/analyze@v2
with:
category: foo-category
bar:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: github/codeql-action/init@v2
- runs: ./build bar
- uses: github/codeql-action/analyze@v2
with:
category: bar-category
`) as Workflow,
"bar",
{}
),
"bar-category"
);
});
test("getCategoryInputOrThrow finds category for workflow with language matrix", (t) => {
t.is(
getCategoryInputOrThrow(
@ -580,7 +613,8 @@ test("getCategoryInputOrThrow finds category for workflow with language matrix",
- uses: github/codeql-action/analyze@v2
with:
category: "/language:\${{ matrix.language }}"
`) as Workflow,
`) as Workflow,
"analysis",
{ language: "javascript" }
),
"/language:javascript"
@ -600,7 +634,8 @@ test("getCategoryInputOrThrow throws error for workflow with dynamic category",
- uses: github/codeql-action/analyze@v2
with:
category: "\${{ github.workflow }}"
`) as Workflow,
`) as Workflow,
"analysis",
{}
),
{
@ -628,7 +663,8 @@ test("getCategoryInputOrThrow throws error for workflow with multiple categories
- uses: github/codeql-action/analyze@v2
with:
category: another-category
`) as Workflow,
`) as Workflow,
"analysis",
{}
),
{

View file

@ -316,6 +316,7 @@ export function getStepsCallingAction(
*/
function getInputOrThrow(
workflow: Workflow,
jobName: string,
actionName: string,
inputName: string,
matrixVars: { [key: string]: string }
@ -325,13 +326,14 @@ function getInputOrThrow(
`Could not get ${inputName} input to ${actionName} since the workflow has no jobs.`
);
}
const inputs: string[] = Object.values(workflow.jobs)
.map((job) =>
getStepsCallingAction(job, actionName).map(
(step) => step.with?.[inputName]
)
)
.flat()
if (!workflow.jobs[jobName]) {
throw new Error(
`Could not get ${inputName} input to ${actionName} since the workflow has no job named ${jobName}.`
);
}
const inputs = getStepsCallingAction(workflow.jobs[jobName], actionName)
.map((step) => step.with?.[inputName])
.filter((input) => input !== undefined)
.map((input) => input!);
@ -369,10 +371,12 @@ function getInputOrThrow(
*/
export function getCategoryInputOrThrow(
workflow: Workflow,
jobName: string,
matrixVars: { [key: string]: string }
): string | undefined {
return getInputOrThrow(
workflow,
jobName,
"github/codeql-action/analyze",
"category",
matrixVars