Merge pull request #370 from github/simon-engledew/hide-workflow-not-found

Do not warn users if a workflow cannot be read
This commit is contained in:
Simon Engledew 2021-01-25 09:21:11 +00:00 committed by GitHub
commit 7a340d32a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 192 additions and 193 deletions

46
lib/actions-util.js generated
View file

@ -153,6 +153,8 @@ function toCodedErrors(errors) {
return acc;
}, {});
}
// code to send back via status report
// message to add as a warning annotation to the run
exports.WorkflowErrors = toCodedErrors({
MismatchedBranches: `Please make sure that every branch in on.pull_request is also in on.push so that Code Scanning can compare pull requests against the state of the base branch.`,
MissingHooks: `Please specify on.push and on.pull_request hooks so that Code Scanning can compare pull requests against the state of the base branch.`,
@ -161,9 +163,8 @@ exports.WorkflowErrors = toCodedErrors({
PathsSpecified: `Using on.push.paths can prevent Code Scanning annotating new alerts in your pull requests.`,
PathsIgnoreSpecified: `Using on.push.paths-ignore can prevent Code Scanning annotating new alerts in your pull requests.`,
CheckoutWrongHead: `git checkout HEAD^2 is no longer necessary. Please remove this step as Code Scanning recommends analyzing the merge commit for best results.`,
LintFailed: `Unable to lint workflow for CodeQL.`,
});
function validateWorkflow(doc) {
function getWorkflowErrors(doc) {
var _a, _b, _c, _d, _e, _f, _g, _h;
const errors = [];
const jobName = process.env.GITHUB_JOB;
@ -260,20 +261,35 @@ function validateWorkflow(doc) {
}
return errors;
}
exports.validateWorkflow = validateWorkflow;
async function getWorkflowErrors() {
exports.getWorkflowErrors = getWorkflowErrors;
async function validateWorkflow() {
let workflow;
try {
const workflow = await getWorkflow();
if (workflow === undefined) {
return [];
}
return validateWorkflow(workflow);
workflow = await getWorkflow();
}
catch (e) {
return [exports.WorkflowErrors.LintFailed];
return `error: getWorkflow() failed: ${e.toString()}`;
}
let workflowErrors;
try {
workflowErrors = getWorkflowErrors(workflow);
}
catch (e) {
return `error: getWorkflowErrors() failed: ${e.toString()}`;
}
if (workflowErrors.length > 0) {
let message;
try {
message = formatWorkflowErrors(workflowErrors);
}
catch (e) {
return `error: formatWorkflowErrors() failed: ${e.toString()}`;
}
core.warning(message);
}
return `warning: ${formatWorkflowCause(workflowErrors)}`;
}
exports.getWorkflowErrors = getWorkflowErrors;
exports.validateWorkflow = validateWorkflow;
function formatWorkflowErrors(errors) {
const issuesWere = errors.length === 1 ? "issue was" : "issues were";
const errorsList = errors.map((e) => e.message).join(" ");
@ -290,13 +306,7 @@ exports.formatWorkflowCause = formatWorkflowCause;
async function getWorkflow() {
const relativePath = await getWorkflowPath();
const absolutePath = path.join(getRequiredEnvParam("GITHUB_WORKSPACE"), relativePath);
try {
return yaml.safeLoad(fs.readFileSync(absolutePath, "utf-8"));
}
catch (e) {
core.warning(`Could not read workflow: ${e.toString()}`);
return undefined;
}
return yaml.safeLoad(fs.readFileSync(absolutePath, "utf-8"));
}
exports.getWorkflow = getWorkflow;
/**

File diff suppressed because one or more lines are too long

128
lib/actions-util.test.js generated
View file

@ -72,32 +72,32 @@ ava_1.default("prepareEnvironment() when a local run", (t) => {
t.deepEqual(process.env.GITHUB_JOB, "UNKNOWN-JOB");
t.deepEqual(process.env.CODEQL_ACTION_ANALYSIS_KEY, "LOCAL-RUN:UNKNOWN-JOB");
});
ava_1.default("validateWorkflow() when on is empty", (t) => {
const errors = actionsutil.validateWorkflow({ on: {} });
ava_1.default("getWorkflowErrors() when on is empty", (t) => {
const errors = actionsutil.getWorkflowErrors({ on: {} });
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.push is an array missing pull_request", (t) => {
const errors = actionsutil.validateWorkflow({ on: ["push"] });
ava_1.default("getWorkflowErrors() when on.push is an array missing pull_request", (t) => {
const errors = actionsutil.getWorkflowErrors({ on: ["push"] });
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.push is an array missing push", (t) => {
const errors = actionsutil.validateWorkflow({ on: ["pull_request"] });
ava_1.default("getWorkflowErrors() when on.push is an array missing push", (t) => {
const errors = actionsutil.getWorkflowErrors({ on: ["pull_request"] });
t.deepEqual(...errorCodes(errors, [actionsutil.WorkflowErrors.MissingPushHook]));
});
ava_1.default("validateWorkflow() when on.push is valid", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.push is valid", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: ["push", "pull_request"],
});
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.push is a valid superset", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.push is a valid superset", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: ["push", "pull_request", "schedule"],
});
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.push should not have a path", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.push should not have a path", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["main"], paths: ["test/*"] },
pull_request: { branches: ["main"] },
@ -105,34 +105,34 @@ ava_1.default("validateWorkflow() when on.push should not have a path", (t) => {
});
t.deepEqual(...errorCodes(errors, [actionsutil.WorkflowErrors.PathsSpecified]));
});
ava_1.default("validateWorkflow() when on.push is a correct object", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.push is a correct object", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: { push: { branches: ["main"] }, pull_request: { branches: ["main"] } },
});
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.pull_requests is a string", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.pull_requests is a string", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: { push: { branches: ["main"] }, pull_request: { branches: "*" } },
});
t.deepEqual(...errorCodes(errors, [actionsutil.WorkflowErrors.MismatchedBranches]));
});
ava_1.default("validateWorkflow() when on.pull_requests is a string and correct", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.pull_requests is a string and correct", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: { push: { branches: "*" }, pull_request: { branches: "*" } },
});
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.push is correct with empty objects", (t) => {
const errors = actionsutil.validateWorkflow(yaml.safeLoad(`
ava_1.default("getWorkflowErrors() when on.push is correct with empty objects", (t) => {
const errors = actionsutil.getWorkflowErrors(yaml.safeLoad(`
on:
push:
pull_request:
`));
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.push is mismatched", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.push is mismatched", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["main"] },
pull_request: { branches: ["feature"] },
@ -140,8 +140,8 @@ ava_1.default("validateWorkflow() when on.push is mismatched", (t) => {
});
t.deepEqual(...errorCodes(errors, [actionsutil.WorkflowErrors.MismatchedBranches]));
});
ava_1.default("validateWorkflow() when on.push is not mismatched", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.push is not mismatched", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["main", "feature"] },
pull_request: { branches: ["main"] },
@ -149,8 +149,8 @@ ava_1.default("validateWorkflow() when on.push is not mismatched", (t) => {
});
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.push is mismatched for pull_request", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.push is mismatched for pull_request", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["main"] },
pull_request: { branches: ["main", "feature"] },
@ -158,50 +158,50 @@ ava_1.default("validateWorkflow() when on.push is mismatched for pull_request",
});
t.deepEqual(...errorCodes(errors, [actionsutil.WorkflowErrors.MismatchedBranches]));
});
ava_1.default("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() for a range of malformed workflows", (t) => {
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: {
push: 1,
pull_request: 1,
},
}), []));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: 1,
}), [actionsutil.WorkflowErrors.MissingHooks]));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: 1,
jobs: 1,
}), [actionsutil.WorkflowErrors.MissingHooks]));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: 1,
jobs: [1],
}), [actionsutil.WorkflowErrors.MissingHooks]));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: 1,
jobs: { 1: 1 },
}), [actionsutil.WorkflowErrors.MissingHooks]));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: 1 },
}), [actionsutil.WorkflowErrors.MissingHooks]));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: [1] },
}), [actionsutil.WorkflowErrors.MissingHooks]));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: { steps: 1 } },
}), [actionsutil.WorkflowErrors.MissingHooks]));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: { steps: [{ notrun: "git checkout HEAD^2" }] } },
}), [actionsutil.WorkflowErrors.MissingHooks]));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: [undefined] },
}), [actionsutil.WorkflowErrors.MissingHooks]));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow(1), []));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow({
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors(1), []));
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors({
on: {
push: {
branches: 1,
@ -212,8 +212,8 @@ ava_1.default("validateWorkflow() for a range of malformed workflows", (t) => {
},
}), []));
});
ava_1.default("validateWorkflow() when on.pull_request for every branch but push specifies branches", (t) => {
const errors = actionsutil.validateWorkflow(yaml.safeLoad(`
ava_1.default("getWorkflowErrors() when on.pull_request for every branch but push specifies branches", (t) => {
const errors = actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
on:
push:
@ -222,8 +222,8 @@ on:
`));
t.deepEqual(...errorCodes(errors, [actionsutil.WorkflowErrors.MismatchedBranches]));
});
ava_1.default("validateWorkflow() when on.pull_request for wildcard branches", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.pull_request for wildcard branches", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["feature/*"] },
pull_request: { branches: "feature/moose" },
@ -231,8 +231,8 @@ ava_1.default("validateWorkflow() when on.pull_request for wildcard branches", (
});
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.pull_request for mismatched wildcard branches", (t) => {
const errors = actionsutil.validateWorkflow({
ava_1.default("getWorkflowErrors() when on.pull_request for mismatched wildcard branches", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["feature/moose"] },
pull_request: { branches: "feature/*" },
@ -240,9 +240,9 @@ ava_1.default("validateWorkflow() when on.pull_request for mismatched wildcard b
});
t.deepEqual(...errorCodes(errors, [actionsutil.WorkflowErrors.MismatchedBranches]));
});
ava_1.default("validateWorkflow() when HEAD^2 is checked out", (t) => {
ava_1.default("getWorkflowErrors() when HEAD^2 is checked out", (t) => {
process.env.GITHUB_JOB = "test";
const errors = actionsutil.validateWorkflow({
const errors = actionsutil.getWorkflowErrors({
on: ["push", "pull_request"],
jobs: { test: { steps: [{ run: "git checkout HEAD^2" }] } },
});
@ -291,8 +291,8 @@ ava_1.default("patternIsSuperset()", (t) => {
t.true(actionsutil.patternIsSuperset("/robin/*/release/*", "/robin/moose/release/goose"));
t.false(actionsutil.patternIsSuperset("/robin/moose/release/goose", "/robin/*/release/*"));
});
ava_1.default("validateWorkflow() when branches contain dots", (t) => {
const errors = actionsutil.validateWorkflow(yaml.safeLoad(`
ava_1.default("getWorkflowErrors() when branches contain dots", (t) => {
const errors = actionsutil.getWorkflowErrors(yaml.safeLoad(`
on:
push:
branches: [4.1, master]
@ -302,8 +302,8 @@ ava_1.default("validateWorkflow() when branches contain dots", (t) => {
`));
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on.push has a trailing comma", (t) => {
const errors = actionsutil.validateWorkflow(yaml.safeLoad(`
ava_1.default("getWorkflowErrors() when on.push has a trailing comma", (t) => {
const errors = actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
on:
push:
@ -314,9 +314,9 @@ on:
`));
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() should only report the current job's CheckoutWrongHead", (t) => {
ava_1.default("getWorkflowErrors() should only report the current job's CheckoutWrongHead", (t) => {
process.env.GITHUB_JOB = "test";
const errors = actionsutil.validateWorkflow(yaml.safeLoad(`
const errors = actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
on:
push:
@ -338,9 +338,9 @@ jobs:
`));
t.deepEqual(...errorCodes(errors, [actionsutil.WorkflowErrors.CheckoutWrongHead]));
});
ava_1.default("validateWorkflow() should not report a different job's CheckoutWrongHead", (t) => {
ava_1.default("getWorkflowErrors() should not report a different job's CheckoutWrongHead", (t) => {
process.env.GITHUB_JOB = "test3";
const errors = actionsutil.validateWorkflow(yaml.safeLoad(`
const errors = actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
on:
push:
@ -362,35 +362,35 @@ jobs:
`));
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() when on is missing", (t) => {
const errors = actionsutil.validateWorkflow(yaml.safeLoad(`
ava_1.default("getWorkflowErrors() when on is missing", (t) => {
const errors = actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
`));
t.deepEqual(...errorCodes(errors, []));
});
ava_1.default("validateWorkflow() with a different on setup", (t) => {
t.deepEqual(...errorCodes(actionsutil.validateWorkflow(yaml.safeLoad(`
ava_1.default("getWorkflowErrors() with a different on setup", (t) => {
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
on: "workflow_dispatch"
`)), []));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow(yaml.safeLoad(`
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
on: [workflow_dispatch]
`)), []));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow(yaml.safeLoad(`
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
on:
workflow_dispatch: {}
`)), []));
});
ava_1.default("validateWorkflow() should not report an error if PRs are totally unconfigured", (t) => {
t.deepEqual(...errorCodes(actionsutil.validateWorkflow(yaml.safeLoad(`
ava_1.default("getWorkflowErrors() should not report an error if PRs are totally unconfigured", (t) => {
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
on:
push:
branches: [master]
`)), []));
t.deepEqual(...errorCodes(actionsutil.validateWorkflow(yaml.safeLoad(`
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors(yaml.safeLoad(`
name: "CodeQL"
on: ["push"]
`)), []));

File diff suppressed because one or more lines are too long

11
lib/init-action.js generated
View file

@ -65,15 +65,8 @@ async function run() {
}
try {
actionsUtil.prepareLocalRunEnvironment();
const workflowErrors = await actionsUtil.getWorkflowErrors();
// we do not want to worry users if linting is failing
// but we do want to send a status report containing this error code
// below
const userWorkflowErrors = workflowErrors.filter((o) => o.code !== "LintFailed");
if (userWorkflowErrors.length > 0) {
core.warning(actionsUtil.formatWorkflowErrors(userWorkflowErrors));
}
if (!(await actionsUtil.sendStatusReport(await actionsUtil.createStatusReportBase("init", "starting", startedAt, actionsUtil.formatWorkflowCause(workflowErrors))))) {
const workflowErrors = await actionsUtil.validateWorkflow();
if (!(await actionsUtil.sendStatusReport(await actionsUtil.createStatusReportBase("init", "starting", startedAt, workflowErrors)))) {
return;
}
const initCodeQLResult = await init_1.initCodeQL(actionsUtil.getOptionalInput("tools"), apiDetails, actionsUtil.getRequiredEnvParam("RUNNER_TEMP"), actionsUtil.getRequiredEnvParam("RUNNER_TOOL_CACHE"), "actions", logger);

File diff suppressed because one or more lines are too long

View file

@ -90,44 +90,44 @@ test("prepareEnvironment() when a local run", (t) => {
t.deepEqual(process.env.CODEQL_ACTION_ANALYSIS_KEY, "LOCAL-RUN:UNKNOWN-JOB");
});
test("validateWorkflow() when on is empty", (t) => {
const errors = actionsutil.validateWorkflow({ on: {} });
test("getWorkflowErrors() when on is empty", (t) => {
const errors = actionsutil.getWorkflowErrors({ on: {} });
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.push is an array missing pull_request", (t) => {
const errors = actionsutil.validateWorkflow({ on: ["push"] });
test("getWorkflowErrors() when on.push is an array missing pull_request", (t) => {
const errors = actionsutil.getWorkflowErrors({ on: ["push"] });
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.push is an array missing push", (t) => {
const errors = actionsutil.validateWorkflow({ on: ["pull_request"] });
test("getWorkflowErrors() when on.push is an array missing push", (t) => {
const errors = actionsutil.getWorkflowErrors({ on: ["pull_request"] });
t.deepEqual(
...errorCodes(errors, [actionsutil.WorkflowErrors.MissingPushHook])
);
});
test("validateWorkflow() when on.push is valid", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.push is valid", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: ["push", "pull_request"],
});
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.push is a valid superset", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.push is a valid superset", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: ["push", "pull_request", "schedule"],
});
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.push should not have a path", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.push should not have a path", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["main"], paths: ["test/*"] },
pull_request: { branches: ["main"] },
@ -139,16 +139,16 @@ test("validateWorkflow() when on.push should not have a path", (t) => {
);
});
test("validateWorkflow() when on.push is a correct object", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.push is a correct object", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: { push: { branches: ["main"] }, pull_request: { branches: ["main"] } },
});
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.pull_requests is a string", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.pull_requests is a string", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: { push: { branches: ["main"] }, pull_request: { branches: "*" } },
});
@ -157,16 +157,16 @@ test("validateWorkflow() when on.pull_requests is a string", (t) => {
);
});
test("validateWorkflow() when on.pull_requests is a string and correct", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.pull_requests is a string and correct", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: { push: { branches: "*" }, pull_request: { branches: "*" } },
});
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.push is correct with empty objects", (t) => {
const errors = actionsutil.validateWorkflow(
test("getWorkflowErrors() when on.push is correct with empty objects", (t) => {
const errors = actionsutil.getWorkflowErrors(
yaml.safeLoad(`
on:
push:
@ -177,8 +177,8 @@ on:
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.push is mismatched", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.push is mismatched", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["main"] },
pull_request: { branches: ["feature"] },
@ -190,8 +190,8 @@ test("validateWorkflow() when on.push is mismatched", (t) => {
);
});
test("validateWorkflow() when on.push is not mismatched", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.push is not mismatched", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["main", "feature"] },
pull_request: { branches: ["main"] },
@ -201,8 +201,8 @@ test("validateWorkflow() when on.push is not mismatched", (t) => {
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.push is mismatched for pull_request", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.push is mismatched for pull_request", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["main"] },
pull_request: { branches: ["main", "feature"] },
@ -214,10 +214,10 @@ test("validateWorkflow() when on.push is mismatched for pull_request", (t) => {
);
});
test("validateWorkflow() for a range of malformed workflows", (t) => {
test("getWorkflowErrors() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: {
push: 1,
pull_request: 1,
@ -229,7 +229,7 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: 1,
} as any),
[actionsutil.WorkflowErrors.MissingHooks]
@ -238,7 +238,7 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: 1,
jobs: 1,
} as any),
@ -248,7 +248,7 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: 1,
jobs: [1],
} as any),
@ -258,7 +258,7 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: 1,
jobs: { 1: 1 },
} as any),
@ -268,7 +268,7 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: 1 },
} as any),
@ -278,7 +278,7 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: [1] },
} as any),
@ -288,7 +288,7 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: { steps: 1 } },
} as any),
@ -298,7 +298,7 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: { steps: [{ notrun: "git checkout HEAD^2" }] } },
} as any),
@ -308,7 +308,7 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: 1,
jobs: { test: [undefined] },
} as any),
@ -316,11 +316,11 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
)
);
t.deepEqual(...errorCodes(actionsutil.validateWorkflow(1 as any), []));
t.deepEqual(...errorCodes(actionsutil.getWorkflowErrors(1 as any), []));
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow({
actionsutil.getWorkflowErrors({
on: {
push: {
branches: 1,
@ -335,8 +335,8 @@ test("validateWorkflow() for a range of malformed workflows", (t) => {
);
});
test("validateWorkflow() when on.pull_request for every branch but push specifies branches", (t) => {
const errors = actionsutil.validateWorkflow(
test("getWorkflowErrors() when on.pull_request for every branch but push specifies branches", (t) => {
const errors = actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
on:
@ -351,8 +351,8 @@ on:
);
});
test("validateWorkflow() when on.pull_request for wildcard branches", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.pull_request for wildcard branches", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["feature/*"] },
pull_request: { branches: "feature/moose" },
@ -362,8 +362,8 @@ test("validateWorkflow() when on.pull_request for wildcard branches", (t) => {
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.pull_request for mismatched wildcard branches", (t) => {
const errors = actionsutil.validateWorkflow({
test("getWorkflowErrors() when on.pull_request for mismatched wildcard branches", (t) => {
const errors = actionsutil.getWorkflowErrors({
on: {
push: { branches: ["feature/moose"] },
pull_request: { branches: "feature/*" },
@ -375,10 +375,10 @@ test("validateWorkflow() when on.pull_request for mismatched wildcard branches",
);
});
test("validateWorkflow() when HEAD^2 is checked out", (t) => {
test("getWorkflowErrors() when HEAD^2 is checked out", (t) => {
process.env.GITHUB_JOB = "test";
const errors = actionsutil.validateWorkflow({
const errors = actionsutil.getWorkflowErrors({
on: ["push", "pull_request"],
jobs: { test: { steps: [{ run: "git checkout HEAD^2" }] } },
});
@ -446,8 +446,8 @@ test("patternIsSuperset()", (t) => {
);
});
test("validateWorkflow() when branches contain dots", (t) => {
const errors = actionsutil.validateWorkflow(
test("getWorkflowErrors() when branches contain dots", (t) => {
const errors = actionsutil.getWorkflowErrors(
yaml.safeLoad(`
on:
push:
@ -461,8 +461,8 @@ test("validateWorkflow() when branches contain dots", (t) => {
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on.push has a trailing comma", (t) => {
const errors = actionsutil.validateWorkflow(
test("getWorkflowErrors() when on.push has a trailing comma", (t) => {
const errors = actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
on:
@ -477,10 +477,10 @@ on:
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() should only report the current job's CheckoutWrongHead", (t) => {
test("getWorkflowErrors() should only report the current job's CheckoutWrongHead", (t) => {
process.env.GITHUB_JOB = "test";
const errors = actionsutil.validateWorkflow(
const errors = actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
on:
@ -508,10 +508,10 @@ jobs:
);
});
test("validateWorkflow() should not report a different job's CheckoutWrongHead", (t) => {
test("getWorkflowErrors() should not report a different job's CheckoutWrongHead", (t) => {
process.env.GITHUB_JOB = "test3";
const errors = actionsutil.validateWorkflow(
const errors = actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
on:
@ -537,8 +537,8 @@ jobs:
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() when on is missing", (t) => {
const errors = actionsutil.validateWorkflow(
test("getWorkflowErrors() when on is missing", (t) => {
const errors = actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
`)
@ -547,10 +547,10 @@ name: "CodeQL"
t.deepEqual(...errorCodes(errors, []));
});
test("validateWorkflow() with a different on setup", (t) => {
test("getWorkflowErrors() with a different on setup", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow(
actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
on: "workflow_dispatch"
@ -562,7 +562,7 @@ on: "workflow_dispatch"
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow(
actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
on: [workflow_dispatch]
@ -574,7 +574,7 @@ on: [workflow_dispatch]
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow(
actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
on:
@ -586,10 +586,10 @@ on:
);
});
test("validateWorkflow() should not report an error if PRs are totally unconfigured", (t) => {
test("getWorkflowErrors() should not report an error if PRs are totally unconfigured", (t) => {
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow(
actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
on:
@ -603,7 +603,7 @@ on:
t.deepEqual(
...errorCodes(
actionsutil.validateWorkflow(
actionsutil.getWorkflowErrors(
yaml.safeLoad(`
name: "CodeQL"
on: ["push"]

View file

@ -188,15 +188,15 @@ export interface CodedError {
message: string;
code: string;
}
function toCodedErrors(errors: {
[key: string]: string;
}): { [key: string]: CodedError } {
function toCodedErrors<T>(errors: T): Record<keyof T, CodedError> {
return Object.entries(errors).reduce((acc, [key, value]) => {
acc[key] = { message: value, code: key };
return acc;
}, {} as ReturnType<typeof toCodedErrors>);
}, {} as Record<keyof T, CodedError>);
}
// code to send back via status report
// message to add as a warning annotation to the run
export const WorkflowErrors = toCodedErrors({
MismatchedBranches: `Please make sure that every branch in on.pull_request is also in on.push so that Code Scanning can compare pull requests against the state of the base branch.`,
MissingHooks: `Please specify on.push and on.pull_request hooks so that Code Scanning can compare pull requests against the state of the base branch.`,
@ -205,10 +205,9 @@ export const WorkflowErrors = toCodedErrors({
PathsSpecified: `Using on.push.paths can prevent Code Scanning annotating new alerts in your pull requests.`,
PathsIgnoreSpecified: `Using on.push.paths-ignore can prevent Code Scanning annotating new alerts in your pull requests.`,
CheckoutWrongHead: `git checkout HEAD^2 is no longer necessary. Please remove this step as Code Scanning recommends analyzing the merge commit for best results.`,
LintFailed: `Unable to lint workflow for CodeQL.`,
});
export function validateWorkflow(doc: Workflow): CodedError[] {
export function getWorkflowErrors(doc: Workflow): CodedError[] {
const errors: CodedError[] = [];
const jobName = process.env.GITHUB_JOB;
@ -317,18 +316,31 @@ export function validateWorkflow(doc: Workflow): CodedError[] {
return errors;
}
export async function getWorkflowErrors(): Promise<CodedError[]> {
export async function validateWorkflow(): Promise<undefined | string> {
let workflow: Workflow;
try {
const workflow = await getWorkflow();
if (workflow === undefined) {
return [];
}
return validateWorkflow(workflow);
workflow = await getWorkflow();
} catch (e) {
return [WorkflowErrors.LintFailed];
return `error: getWorkflow() failed: ${e.toString()}`;
}
let workflowErrors: CodedError[];
try {
workflowErrors = getWorkflowErrors(workflow);
} catch (e) {
return `error: getWorkflowErrors() failed: ${e.toString()}`;
}
if (workflowErrors.length > 0) {
let message: string;
try {
message = formatWorkflowErrors(workflowErrors);
} catch (e) {
return `error: formatWorkflowErrors() failed: ${e.toString()}`;
}
core.warning(message);
}
return `warning: ${formatWorkflowCause(workflowErrors)}`;
}
export function formatWorkflowErrors(errors: CodedError[]): string {
@ -346,19 +358,14 @@ export function formatWorkflowCause(errors: CodedError[]): undefined | string {
return errors.map((e) => e.code).join(",");
}
export async function getWorkflow(): Promise<Workflow | undefined> {
export async function getWorkflow(): Promise<Workflow> {
const relativePath = await getWorkflowPath();
const absolutePath = path.join(
getRequiredEnvParam("GITHUB_WORKSPACE"),
relativePath
);
try {
return yaml.safeLoad(fs.readFileSync(absolutePath, "utf-8"));
} catch (e) {
core.warning(`Could not read workflow: ${e.toString()}`);
return undefined;
}
return yaml.safeLoad(fs.readFileSync(absolutePath, "utf-8"));
}
/**

View file

@ -108,18 +108,7 @@ async function run() {
try {
actionsUtil.prepareLocalRunEnvironment();
const workflowErrors = await actionsUtil.getWorkflowErrors();
// we do not want to worry users if linting is failing
// but we do want to send a status report containing this error code
// below
const userWorkflowErrors = workflowErrors.filter(
(o) => o.code !== "LintFailed"
);
if (userWorkflowErrors.length > 0) {
core.warning(actionsUtil.formatWorkflowErrors(userWorkflowErrors));
}
const workflowErrors = await actionsUtil.validateWorkflow();
if (
!(await actionsUtil.sendStatusReport(
@ -127,7 +116,7 @@ async function run() {
"init",
"starting",
startedAt,
actionsUtil.formatWorkflowCause(workflowErrors)
workflowErrors
)
))
) {