mirror of
https://github.com/golangci/golangci-lint-action.git
synced 2025-12-16 15:38:28 +00:00
Memory management and let runLint handle resolving exit code
This commit is contained in:
parent
dd63ff3880
commit
61a0ce84ec
3 changed files with 360 additions and 386 deletions
242
dist/post_run/index.js
vendored
242
dist/post_run/index.js
vendored
|
|
@ -6798,8 +6798,9 @@ const parseOutput = (json) => {
|
||||||
}
|
}
|
||||||
if (lintOutput.Issues.length) {
|
if (lintOutput.Issues.length) {
|
||||||
lintOutput.Issues = lintOutput.Issues.filter((issue) => issue.Severity !== `ignore`).map((issue) => {
|
lintOutput.Issues = lintOutput.Issues.filter((issue) => issue.Severity !== `ignore`).map((issue) => {
|
||||||
const Severity = issue.Severity.toLowerCase();
|
issue.Severity = ((Severity) => {
|
||||||
issue.Severity = severityMap[`${Severity}`] ? severityMap[`${Severity}`] : `failure`;
|
return severityMap[`${Severity}`] ? severityMap[`${Severity}`] : `failure`;
|
||||||
|
})(issue.Severity.toLowerCase());
|
||||||
return issue;
|
return issue;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -6807,21 +6808,30 @@ const parseOutput = (json) => {
|
||||||
};
|
};
|
||||||
const logLintIssues = (issues) => {
|
const logLintIssues = (issues) => {
|
||||||
issues.forEach((issue) => {
|
issues.forEach((issue) => {
|
||||||
let header = `${ansi_styles_1.default.red.open}${ansi_styles_1.default.bold.open}Lint Error:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.red.close}`;
|
core.info(((issue) => {
|
||||||
if (issue.Severity === `warning`) {
|
switch (issue.Severity) {
|
||||||
header = `${ansi_styles_1.default.yellow.open}${ansi_styles_1.default.bold.open}Lint Warning:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.yellow.close}`;
|
case `warning`:
|
||||||
}
|
return `${ansi_styles_1.default.yellow.open}${ansi_styles_1.default.bold.open}Lint Warning:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.yellow.close}`;
|
||||||
else if (issue.Severity === `notice`) {
|
case `notice`:
|
||||||
header = `${ansi_styles_1.default.cyan.open}${ansi_styles_1.default.bold.open}Lint Notice:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.cyan.close}`;
|
return `${ansi_styles_1.default.cyan.open}${ansi_styles_1.default.bold.open}Lint Notice:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.cyan.close}`;
|
||||||
}
|
default:
|
||||||
let pos = `${issue.Pos.Filename}:${issue.Pos.Line}`;
|
return `${ansi_styles_1.default.red.open}${ansi_styles_1.default.bold.open}Lint Error:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.red.close}`;
|
||||||
if (issue.LineRange !== undefined) {
|
}
|
||||||
pos += `-${issue.LineRange.To}`;
|
})(issue) +
|
||||||
}
|
` ` +
|
||||||
else if (issue.Pos.Column) {
|
`${issue.Pos.Filename}:${issue.Pos.Line}` +
|
||||||
pos += `:${issue.Pos.Column}`;
|
((issue) => {
|
||||||
}
|
if (issue.LineRange !== undefined) {
|
||||||
core.info(`${header} ${pos} - ${issue.Text} (${issue.FromLinter})`);
|
return `-${issue.LineRange.To}`;
|
||||||
|
}
|
||||||
|
else if (issue.Pos.Column) {
|
||||||
|
return `:${issue.Pos.Column}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ``;
|
||||||
|
}
|
||||||
|
})(issue) +
|
||||||
|
` - ${issue.Text} (${issue.FromLinter})`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
function resolveCheckRunId() {
|
function resolveCheckRunId() {
|
||||||
|
|
@ -6894,77 +6904,52 @@ function annotateLintIssues(issues, checkRunId) {
|
||||||
};
|
};
|
||||||
const ctx = github.context;
|
const ctx = github.context;
|
||||||
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }));
|
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }));
|
||||||
const githubAnnotations = issues.map((issue) => {
|
|
||||||
// If/when we transition to comments, we would build the request structure here
|
|
||||||
const annotation = {
|
|
||||||
path: issue.Pos.Filename,
|
|
||||||
start_line: issue.Pos.Line,
|
|
||||||
end_line: issue.Pos.Line,
|
|
||||||
title: issue.FromLinter,
|
|
||||||
message: issue.Text,
|
|
||||||
annotation_level: issue.Severity,
|
|
||||||
};
|
|
||||||
issueCounts[issue.Severity]++;
|
|
||||||
if (issue.LineRange !== undefined) {
|
|
||||||
annotation.end_line = issue.LineRange.To;
|
|
||||||
}
|
|
||||||
else if (issue.Pos.Column) {
|
|
||||||
annotation.start_column = issue.Pos.Column;
|
|
||||||
annotation.end_column = issue.Pos.Column;
|
|
||||||
}
|
|
||||||
if (issue.Replacement !== null) {
|
|
||||||
let replacement = ``;
|
|
||||||
if (issue.Replacement.Inline) {
|
|
||||||
replacement =
|
|
||||||
issue.SourceLines[0].slice(0, issue.Replacement.Inline.StartCol) +
|
|
||||||
issue.Replacement.Inline.NewString +
|
|
||||||
issue.SourceLines[0].slice(issue.Replacement.Inline.StartCol + issue.Replacement.Inline.Length);
|
|
||||||
}
|
|
||||||
else if (issue.Replacement.NewLines) {
|
|
||||||
replacement = issue.Replacement.NewLines.join("\n");
|
|
||||||
}
|
|
||||||
annotation.raw_details = "```suggestion\n" + replacement + "\n```";
|
|
||||||
}
|
|
||||||
return annotation;
|
|
||||||
});
|
|
||||||
const title = `GolangCI-Lint`;
|
const title = `GolangCI-Lint`;
|
||||||
const summary = `There are {issueCounts.failure} failures, {issueCounts.wairning} warnings, and {issueCounts.notice} notices.`;
|
for (let i = 0; i < Math.ceil(issues.length / chunkSize); i++) {
|
||||||
Array.from({ length: Math.ceil(githubAnnotations.length / chunkSize) }, (v, i) => githubAnnotations.slice(i * chunkSize, i * chunkSize + chunkSize)).forEach((annotations) => {
|
|
||||||
octokit.checks
|
octokit.checks
|
||||||
.update(Object.assign(Object.assign({}, ctx.repo), { check_run_id: checkRunId, output: {
|
.update(Object.assign(Object.assign({}, ctx.repo), { check_run_id: checkRunId, output: {
|
||||||
title,
|
title: title,
|
||||||
summary,
|
annotations: issues.slice(i * chunkSize, i * chunkSize + chunkSize).map((issue) => {
|
||||||
annotations,
|
// If/when we transition to comments, we would build the request structure here
|
||||||
|
const annotation = {
|
||||||
|
path: issue.Pos.Filename,
|
||||||
|
start_line: issue.Pos.Line,
|
||||||
|
end_line: issue.Pos.Line,
|
||||||
|
title: issue.FromLinter,
|
||||||
|
message: issue.Text,
|
||||||
|
annotation_level: issue.Severity,
|
||||||
|
};
|
||||||
|
issueCounts[issue.Severity]++;
|
||||||
|
if (issue.LineRange !== undefined) {
|
||||||
|
annotation.end_line = issue.LineRange.To;
|
||||||
|
}
|
||||||
|
else if (issue.Pos.Column) {
|
||||||
|
annotation.start_column = issue.Pos.Column;
|
||||||
|
annotation.end_column = issue.Pos.Column;
|
||||||
|
}
|
||||||
|
if (issue.Replacement !== null) {
|
||||||
|
let replacement = ``;
|
||||||
|
if (issue.Replacement.Inline) {
|
||||||
|
replacement =
|
||||||
|
issue.SourceLines[0].slice(0, issue.Replacement.Inline.StartCol) +
|
||||||
|
issue.Replacement.Inline.NewString +
|
||||||
|
issue.SourceLines[0].slice(issue.Replacement.Inline.StartCol + issue.Replacement.Inline.Length);
|
||||||
|
}
|
||||||
|
else if (issue.Replacement.NewLines) {
|
||||||
|
replacement = issue.Replacement.NewLines.join("\n");
|
||||||
|
}
|
||||||
|
annotation.raw_details = "```suggestion\n" + replacement + "\n```";
|
||||||
|
}
|
||||||
|
return annotation;
|
||||||
|
}),
|
||||||
|
summary: `There are {issueCounts.failure} failures, {issueCounts.wairning} warnings, and {issueCounts.notice} notices.`,
|
||||||
} }))
|
} }))
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
throw `Error patching Check Run Data (annotations): ${e}`;
|
throw `Error patching Check Run Data (annotations): ${e}`;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const hasFailingIssues = (issues) => {
|
|
||||||
// If the user input is not a valid Severity Level, this will be -1, and any issue will fail
|
|
||||||
const userFailureSeverity = core.getInput(`failure-severity`).toLowerCase();
|
|
||||||
let failureSeverity = DefaultFailureSeverity;
|
|
||||||
if (userFailureSeverity) {
|
|
||||||
failureSeverity = Object.values(LintSeverity).indexOf(userFailureSeverity);
|
|
||||||
}
|
|
||||||
if (failureSeverity < 0) {
|
|
||||||
core.info(`::warning::failure-severity must be one of (${Object.keys(LintSeverity).join(" | ")}). "${userFailureSeverity}" not supported, using default (${LintSeverity[DefaultFailureSeverity]})`);
|
|
||||||
failureSeverity = DefaultFailureSeverity;
|
|
||||||
}
|
|
||||||
if (issues.length) {
|
|
||||||
if (failureSeverity <= 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (const issue of issues) {
|
|
||||||
if (failureSeverity <= LintSeverity[issue.Severity]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
const printOutput = (res) => {
|
const printOutput = (res) => {
|
||||||
if (res.stdout) {
|
if (res.stdout) {
|
||||||
core.info(res.stdout);
|
core.info(res.stdout);
|
||||||
|
|
@ -6973,56 +6958,39 @@ const printOutput = (res) => {
|
||||||
core.info(res.stderr);
|
core.info(res.stderr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
function printLintOutput(res, checkRunId) {
|
function processLintOutput(res, checkRunId) {
|
||||||
var _a;
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let lintOutput;
|
let lintIssues = [];
|
||||||
const exit_code = (_a = res.code) !== null && _a !== void 0 ? _a : 0;
|
if (res.stdout) {
|
||||||
try {
|
try {
|
||||||
if (res.stdout) {
|
// This object contains other information, such as errors and the active linters
|
||||||
try {
|
// TODO: Should we do something with that data?
|
||||||
// This object contains other information, such as errors and the active linters
|
;
|
||||||
// TODO: Should we do something with that data?
|
({ Issues: lintIssues } = parseOutput(res.stdout));
|
||||||
lintOutput = parseOutput(res.stdout);
|
if (lintIssues.length) {
|
||||||
if (lintOutput.Issues.length) {
|
logLintIssues(lintIssues);
|
||||||
logLintIssues(lintOutput.Issues);
|
// We can only Annotate (or Comment) on Push or Pull Request
|
||||||
// We can only Annotate (or Comment) on Push or Pull Request
|
switch (github.context.eventName) {
|
||||||
switch (github.context.eventName) {
|
case `pull_request`:
|
||||||
case `pull_request`:
|
// TODO: When we are ready to handle these as Comments, instead of Annotations, we would place that logic here
|
||||||
// TODO: When we are ready to handle these as Comments, instead of Annotations, we would place that logic here
|
/* falls through */
|
||||||
/* falls through */
|
case `push`:
|
||||||
case `push`:
|
yield annotateLintIssues(lintIssues, checkRunId);
|
||||||
yield annotateLintIssues(lintOutput.Issues, checkRunId);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
// At this time, other events are not supported
|
||||||
// At this time, other events are not supported
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
|
||||||
throw `there was an error processing golangci-lint output: ${e}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (res.stderr) {
|
catch (e) {
|
||||||
core.info(res.stderr);
|
core.setFailed(`Error processing golangci-lint output: ${e}`);
|
||||||
}
|
|
||||||
if (exit_code === 1) {
|
|
||||||
if (!lintOutput) {
|
|
||||||
throw `unexpected state, golangci-lint exited with 1, but provided no lint output`;
|
|
||||||
}
|
|
||||||
if (hasFailingIssues(lintOutput.Issues)) {
|
|
||||||
throw `issues found`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (exit_code > 1) {
|
|
||||||
throw `golangci-lint exit with code ${exit_code}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
if (res.stderr) {
|
||||||
return core.setFailed(`${e}`);
|
core.info(res.stderr);
|
||||||
}
|
}
|
||||||
return core.info(`golangci-lint found no blocking issues`);
|
return lintIssues;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function runLint(lintPath, patchPath, checkRunId) {
|
function runLint(lintPath, patchPath, checkRunId) {
|
||||||
|
|
@ -7032,6 +7000,17 @@ function runLint(lintPath, patchPath, checkRunId) {
|
||||||
const res = yield execShellCommand(`${lintPath} cache status`);
|
const res = yield execShellCommand(`${lintPath} cache status`);
|
||||||
printOutput(res);
|
printOutput(res);
|
||||||
}
|
}
|
||||||
|
const failureSeverity = ((userFailureSeverity) => {
|
||||||
|
if (userFailureSeverity) {
|
||||||
|
if (Object.values(LintSeverity).indexOf(userFailureSeverity) != -1) {
|
||||||
|
return Object.values(LintSeverity).indexOf(userFailureSeverity);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.info(`::warning::failure-severity must be one of (${Object.keys(LintSeverity).join(" | ")}). "${userFailureSeverity}" not supported, using default (${LintSeverity[DefaultFailureSeverity]})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DefaultFailureSeverity;
|
||||||
|
})(core.getInput(`failure-severity`).toLowerCase());
|
||||||
const userArgs = core.getInput(`args`);
|
const userArgs = core.getInput(`args`);
|
||||||
const addedArgs = [];
|
const addedArgs = [];
|
||||||
const userArgNames = new Set();
|
const userArgNames = new Set();
|
||||||
|
|
@ -7073,14 +7052,29 @@ function runLint(lintPath, patchPath, checkRunId) {
|
||||||
const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimRight();
|
const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimRight();
|
||||||
core.info(`Running [${cmd}] in [${cmdArgs.cwd || ``}] ...`);
|
core.info(`Running [${cmd}] in [${cmdArgs.cwd || ``}] ...`);
|
||||||
const startedAt = Date.now();
|
const startedAt = Date.now();
|
||||||
|
let exit_code = 0;
|
||||||
try {
|
try {
|
||||||
const res = yield execShellCommand(cmd, cmdArgs);
|
const res = yield execShellCommand(cmd, cmdArgs);
|
||||||
yield printLintOutput(res, checkRunId);
|
processLintOutput(res, checkRunId);
|
||||||
}
|
}
|
||||||
catch (exc) {
|
catch (exc) {
|
||||||
// This logging passes issues to GitHub annotations but comments can be more convenient for some users.
|
// This logging passes issues to GitHub annotations but comments can be more convenient for some users.
|
||||||
// TODO: support reviewdog or leaving comments by GitHub API.
|
// TODO: support reviewdog or leaving comments by GitHub API.
|
||||||
yield printLintOutput(exc, checkRunId);
|
const issuesPromise = processLintOutput(exc, checkRunId);
|
||||||
|
if (exc.code !== 1 || (yield issuesPromise).findIndex((issue) => LintSeverity[issue.Severity] >= failureSeverity) != -1) {
|
||||||
|
exit_code = exc.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (exit_code === 0) {
|
||||||
|
core.info(`golangci-lint found no blocking issues`);
|
||||||
|
}
|
||||||
|
else if (exit_code === 1) {
|
||||||
|
core.setFailed(`issues found`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.setFailed(`golangci-lint exit with code ${exit_code}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`);
|
core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
242
dist/run/index.js
vendored
242
dist/run/index.js
vendored
|
|
@ -6808,8 +6808,9 @@ const parseOutput = (json) => {
|
||||||
}
|
}
|
||||||
if (lintOutput.Issues.length) {
|
if (lintOutput.Issues.length) {
|
||||||
lintOutput.Issues = lintOutput.Issues.filter((issue) => issue.Severity !== `ignore`).map((issue) => {
|
lintOutput.Issues = lintOutput.Issues.filter((issue) => issue.Severity !== `ignore`).map((issue) => {
|
||||||
const Severity = issue.Severity.toLowerCase();
|
issue.Severity = ((Severity) => {
|
||||||
issue.Severity = severityMap[`${Severity}`] ? severityMap[`${Severity}`] : `failure`;
|
return severityMap[`${Severity}`] ? severityMap[`${Severity}`] : `failure`;
|
||||||
|
})(issue.Severity.toLowerCase());
|
||||||
return issue;
|
return issue;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -6817,21 +6818,30 @@ const parseOutput = (json) => {
|
||||||
};
|
};
|
||||||
const logLintIssues = (issues) => {
|
const logLintIssues = (issues) => {
|
||||||
issues.forEach((issue) => {
|
issues.forEach((issue) => {
|
||||||
let header = `${ansi_styles_1.default.red.open}${ansi_styles_1.default.bold.open}Lint Error:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.red.close}`;
|
core.info(((issue) => {
|
||||||
if (issue.Severity === `warning`) {
|
switch (issue.Severity) {
|
||||||
header = `${ansi_styles_1.default.yellow.open}${ansi_styles_1.default.bold.open}Lint Warning:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.yellow.close}`;
|
case `warning`:
|
||||||
}
|
return `${ansi_styles_1.default.yellow.open}${ansi_styles_1.default.bold.open}Lint Warning:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.yellow.close}`;
|
||||||
else if (issue.Severity === `notice`) {
|
case `notice`:
|
||||||
header = `${ansi_styles_1.default.cyan.open}${ansi_styles_1.default.bold.open}Lint Notice:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.cyan.close}`;
|
return `${ansi_styles_1.default.cyan.open}${ansi_styles_1.default.bold.open}Lint Notice:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.cyan.close}`;
|
||||||
}
|
default:
|
||||||
let pos = `${issue.Pos.Filename}:${issue.Pos.Line}`;
|
return `${ansi_styles_1.default.red.open}${ansi_styles_1.default.bold.open}Lint Error:${ansi_styles_1.default.bold.close}${ansi_styles_1.default.red.close}`;
|
||||||
if (issue.LineRange !== undefined) {
|
}
|
||||||
pos += `-${issue.LineRange.To}`;
|
})(issue) +
|
||||||
}
|
` ` +
|
||||||
else if (issue.Pos.Column) {
|
`${issue.Pos.Filename}:${issue.Pos.Line}` +
|
||||||
pos += `:${issue.Pos.Column}`;
|
((issue) => {
|
||||||
}
|
if (issue.LineRange !== undefined) {
|
||||||
core.info(`${header} ${pos} - ${issue.Text} (${issue.FromLinter})`);
|
return `-${issue.LineRange.To}`;
|
||||||
|
}
|
||||||
|
else if (issue.Pos.Column) {
|
||||||
|
return `:${issue.Pos.Column}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ``;
|
||||||
|
}
|
||||||
|
})(issue) +
|
||||||
|
` - ${issue.Text} (${issue.FromLinter})`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
function resolveCheckRunId() {
|
function resolveCheckRunId() {
|
||||||
|
|
@ -6904,77 +6914,52 @@ function annotateLintIssues(issues, checkRunId) {
|
||||||
};
|
};
|
||||||
const ctx = github.context;
|
const ctx = github.context;
|
||||||
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }));
|
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }));
|
||||||
const githubAnnotations = issues.map((issue) => {
|
|
||||||
// If/when we transition to comments, we would build the request structure here
|
|
||||||
const annotation = {
|
|
||||||
path: issue.Pos.Filename,
|
|
||||||
start_line: issue.Pos.Line,
|
|
||||||
end_line: issue.Pos.Line,
|
|
||||||
title: issue.FromLinter,
|
|
||||||
message: issue.Text,
|
|
||||||
annotation_level: issue.Severity,
|
|
||||||
};
|
|
||||||
issueCounts[issue.Severity]++;
|
|
||||||
if (issue.LineRange !== undefined) {
|
|
||||||
annotation.end_line = issue.LineRange.To;
|
|
||||||
}
|
|
||||||
else if (issue.Pos.Column) {
|
|
||||||
annotation.start_column = issue.Pos.Column;
|
|
||||||
annotation.end_column = issue.Pos.Column;
|
|
||||||
}
|
|
||||||
if (issue.Replacement !== null) {
|
|
||||||
let replacement = ``;
|
|
||||||
if (issue.Replacement.Inline) {
|
|
||||||
replacement =
|
|
||||||
issue.SourceLines[0].slice(0, issue.Replacement.Inline.StartCol) +
|
|
||||||
issue.Replacement.Inline.NewString +
|
|
||||||
issue.SourceLines[0].slice(issue.Replacement.Inline.StartCol + issue.Replacement.Inline.Length);
|
|
||||||
}
|
|
||||||
else if (issue.Replacement.NewLines) {
|
|
||||||
replacement = issue.Replacement.NewLines.join("\n");
|
|
||||||
}
|
|
||||||
annotation.raw_details = "```suggestion\n" + replacement + "\n```";
|
|
||||||
}
|
|
||||||
return annotation;
|
|
||||||
});
|
|
||||||
const title = `GolangCI-Lint`;
|
const title = `GolangCI-Lint`;
|
||||||
const summary = `There are {issueCounts.failure} failures, {issueCounts.wairning} warnings, and {issueCounts.notice} notices.`;
|
for (let i = 0; i < Math.ceil(issues.length / chunkSize); i++) {
|
||||||
Array.from({ length: Math.ceil(githubAnnotations.length / chunkSize) }, (v, i) => githubAnnotations.slice(i * chunkSize, i * chunkSize + chunkSize)).forEach((annotations) => {
|
|
||||||
octokit.checks
|
octokit.checks
|
||||||
.update(Object.assign(Object.assign({}, ctx.repo), { check_run_id: checkRunId, output: {
|
.update(Object.assign(Object.assign({}, ctx.repo), { check_run_id: checkRunId, output: {
|
||||||
title,
|
title: title,
|
||||||
summary,
|
annotations: issues.slice(i * chunkSize, i * chunkSize + chunkSize).map((issue) => {
|
||||||
annotations,
|
// If/when we transition to comments, we would build the request structure here
|
||||||
|
const annotation = {
|
||||||
|
path: issue.Pos.Filename,
|
||||||
|
start_line: issue.Pos.Line,
|
||||||
|
end_line: issue.Pos.Line,
|
||||||
|
title: issue.FromLinter,
|
||||||
|
message: issue.Text,
|
||||||
|
annotation_level: issue.Severity,
|
||||||
|
};
|
||||||
|
issueCounts[issue.Severity]++;
|
||||||
|
if (issue.LineRange !== undefined) {
|
||||||
|
annotation.end_line = issue.LineRange.To;
|
||||||
|
}
|
||||||
|
else if (issue.Pos.Column) {
|
||||||
|
annotation.start_column = issue.Pos.Column;
|
||||||
|
annotation.end_column = issue.Pos.Column;
|
||||||
|
}
|
||||||
|
if (issue.Replacement !== null) {
|
||||||
|
let replacement = ``;
|
||||||
|
if (issue.Replacement.Inline) {
|
||||||
|
replacement =
|
||||||
|
issue.SourceLines[0].slice(0, issue.Replacement.Inline.StartCol) +
|
||||||
|
issue.Replacement.Inline.NewString +
|
||||||
|
issue.SourceLines[0].slice(issue.Replacement.Inline.StartCol + issue.Replacement.Inline.Length);
|
||||||
|
}
|
||||||
|
else if (issue.Replacement.NewLines) {
|
||||||
|
replacement = issue.Replacement.NewLines.join("\n");
|
||||||
|
}
|
||||||
|
annotation.raw_details = "```suggestion\n" + replacement + "\n```";
|
||||||
|
}
|
||||||
|
return annotation;
|
||||||
|
}),
|
||||||
|
summary: `There are {issueCounts.failure} failures, {issueCounts.wairning} warnings, and {issueCounts.notice} notices.`,
|
||||||
} }))
|
} }))
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
throw `Error patching Check Run Data (annotations): ${e}`;
|
throw `Error patching Check Run Data (annotations): ${e}`;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const hasFailingIssues = (issues) => {
|
|
||||||
// If the user input is not a valid Severity Level, this will be -1, and any issue will fail
|
|
||||||
const userFailureSeverity = core.getInput(`failure-severity`).toLowerCase();
|
|
||||||
let failureSeverity = DefaultFailureSeverity;
|
|
||||||
if (userFailureSeverity) {
|
|
||||||
failureSeverity = Object.values(LintSeverity).indexOf(userFailureSeverity);
|
|
||||||
}
|
|
||||||
if (failureSeverity < 0) {
|
|
||||||
core.info(`::warning::failure-severity must be one of (${Object.keys(LintSeverity).join(" | ")}). "${userFailureSeverity}" not supported, using default (${LintSeverity[DefaultFailureSeverity]})`);
|
|
||||||
failureSeverity = DefaultFailureSeverity;
|
|
||||||
}
|
|
||||||
if (issues.length) {
|
|
||||||
if (failureSeverity <= 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (const issue of issues) {
|
|
||||||
if (failureSeverity <= LintSeverity[issue.Severity]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
const printOutput = (res) => {
|
const printOutput = (res) => {
|
||||||
if (res.stdout) {
|
if (res.stdout) {
|
||||||
core.info(res.stdout);
|
core.info(res.stdout);
|
||||||
|
|
@ -6983,56 +6968,39 @@ const printOutput = (res) => {
|
||||||
core.info(res.stderr);
|
core.info(res.stderr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
function printLintOutput(res, checkRunId) {
|
function processLintOutput(res, checkRunId) {
|
||||||
var _a;
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let lintOutput;
|
let lintIssues = [];
|
||||||
const exit_code = (_a = res.code) !== null && _a !== void 0 ? _a : 0;
|
if (res.stdout) {
|
||||||
try {
|
try {
|
||||||
if (res.stdout) {
|
// This object contains other information, such as errors and the active linters
|
||||||
try {
|
// TODO: Should we do something with that data?
|
||||||
// This object contains other information, such as errors and the active linters
|
;
|
||||||
// TODO: Should we do something with that data?
|
({ Issues: lintIssues } = parseOutput(res.stdout));
|
||||||
lintOutput = parseOutput(res.stdout);
|
if (lintIssues.length) {
|
||||||
if (lintOutput.Issues.length) {
|
logLintIssues(lintIssues);
|
||||||
logLintIssues(lintOutput.Issues);
|
// We can only Annotate (or Comment) on Push or Pull Request
|
||||||
// We can only Annotate (or Comment) on Push or Pull Request
|
switch (github.context.eventName) {
|
||||||
switch (github.context.eventName) {
|
case `pull_request`:
|
||||||
case `pull_request`:
|
// TODO: When we are ready to handle these as Comments, instead of Annotations, we would place that logic here
|
||||||
// TODO: When we are ready to handle these as Comments, instead of Annotations, we would place that logic here
|
/* falls through */
|
||||||
/* falls through */
|
case `push`:
|
||||||
case `push`:
|
yield annotateLintIssues(lintIssues, checkRunId);
|
||||||
yield annotateLintIssues(lintOutput.Issues, checkRunId);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
// At this time, other events are not supported
|
||||||
// At this time, other events are not supported
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
|
||||||
throw `there was an error processing golangci-lint output: ${e}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (res.stderr) {
|
catch (e) {
|
||||||
core.info(res.stderr);
|
core.setFailed(`Error processing golangci-lint output: ${e}`);
|
||||||
}
|
|
||||||
if (exit_code === 1) {
|
|
||||||
if (!lintOutput) {
|
|
||||||
throw `unexpected state, golangci-lint exited with 1, but provided no lint output`;
|
|
||||||
}
|
|
||||||
if (hasFailingIssues(lintOutput.Issues)) {
|
|
||||||
throw `issues found`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (exit_code > 1) {
|
|
||||||
throw `golangci-lint exit with code ${exit_code}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
if (res.stderr) {
|
||||||
return core.setFailed(`${e}`);
|
core.info(res.stderr);
|
||||||
}
|
}
|
||||||
return core.info(`golangci-lint found no blocking issues`);
|
return lintIssues;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function runLint(lintPath, patchPath, checkRunId) {
|
function runLint(lintPath, patchPath, checkRunId) {
|
||||||
|
|
@ -7042,6 +7010,17 @@ function runLint(lintPath, patchPath, checkRunId) {
|
||||||
const res = yield execShellCommand(`${lintPath} cache status`);
|
const res = yield execShellCommand(`${lintPath} cache status`);
|
||||||
printOutput(res);
|
printOutput(res);
|
||||||
}
|
}
|
||||||
|
const failureSeverity = ((userFailureSeverity) => {
|
||||||
|
if (userFailureSeverity) {
|
||||||
|
if (Object.values(LintSeverity).indexOf(userFailureSeverity) != -1) {
|
||||||
|
return Object.values(LintSeverity).indexOf(userFailureSeverity);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.info(`::warning::failure-severity must be one of (${Object.keys(LintSeverity).join(" | ")}). "${userFailureSeverity}" not supported, using default (${LintSeverity[DefaultFailureSeverity]})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DefaultFailureSeverity;
|
||||||
|
})(core.getInput(`failure-severity`).toLowerCase());
|
||||||
const userArgs = core.getInput(`args`);
|
const userArgs = core.getInput(`args`);
|
||||||
const addedArgs = [];
|
const addedArgs = [];
|
||||||
const userArgNames = new Set();
|
const userArgNames = new Set();
|
||||||
|
|
@ -7083,14 +7062,29 @@ function runLint(lintPath, patchPath, checkRunId) {
|
||||||
const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimRight();
|
const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimRight();
|
||||||
core.info(`Running [${cmd}] in [${cmdArgs.cwd || ``}] ...`);
|
core.info(`Running [${cmd}] in [${cmdArgs.cwd || ``}] ...`);
|
||||||
const startedAt = Date.now();
|
const startedAt = Date.now();
|
||||||
|
let exit_code = 0;
|
||||||
try {
|
try {
|
||||||
const res = yield execShellCommand(cmd, cmdArgs);
|
const res = yield execShellCommand(cmd, cmdArgs);
|
||||||
yield printLintOutput(res, checkRunId);
|
processLintOutput(res, checkRunId);
|
||||||
}
|
}
|
||||||
catch (exc) {
|
catch (exc) {
|
||||||
// This logging passes issues to GitHub annotations but comments can be more convenient for some users.
|
// This logging passes issues to GitHub annotations but comments can be more convenient for some users.
|
||||||
// TODO: support reviewdog or leaving comments by GitHub API.
|
// TODO: support reviewdog or leaving comments by GitHub API.
|
||||||
yield printLintOutput(exc, checkRunId);
|
const issuesPromise = processLintOutput(exc, checkRunId);
|
||||||
|
if (exc.code !== 1 || (yield issuesPromise).findIndex((issue) => LintSeverity[issue.Severity] >= failureSeverity) != -1) {
|
||||||
|
exit_code = exc.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (exit_code === 0) {
|
||||||
|
core.info(`golangci-lint found no blocking issues`);
|
||||||
|
}
|
||||||
|
else if (exit_code === 1) {
|
||||||
|
core.setFailed(`issues found`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.setFailed(`golangci-lint exit with code ${exit_code}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`);
|
core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
262
src/run.ts
262
src/run.ts
|
|
@ -107,7 +107,6 @@ async function prepareEnv(): Promise<Env> {
|
||||||
type ExecRes = {
|
type ExecRes = {
|
||||||
stdout: string
|
stdout: string
|
||||||
stderr: string
|
stderr: string
|
||||||
code?: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LintSeverity {
|
enum LintSeverity {
|
||||||
|
|
@ -226,8 +225,9 @@ const parseOutput = (json: string): LintOutput => {
|
||||||
if (lintOutput.Issues.length) {
|
if (lintOutput.Issues.length) {
|
||||||
lintOutput.Issues = lintOutput.Issues.filter((issue: UnfilteredLintIssue) => issue.Severity !== `ignore`).map(
|
lintOutput.Issues = lintOutput.Issues.filter((issue: UnfilteredLintIssue) => issue.Severity !== `ignore`).map(
|
||||||
(issue: UnfilteredLintIssue): LintIssue => {
|
(issue: UnfilteredLintIssue): LintIssue => {
|
||||||
const Severity = issue.Severity.toLowerCase()
|
issue.Severity = ((Severity: string): LintSeverityStrings => {
|
||||||
issue.Severity = severityMap[`${Severity}`] ? severityMap[`${Severity}`] : `failure`
|
return severityMap[`${Severity}`] ? severityMap[`${Severity}`] : `failure`
|
||||||
|
})(issue.Severity.toLowerCase())
|
||||||
return issue as LintIssue
|
return issue as LintIssue
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -237,21 +237,30 @@ const parseOutput = (json: string): LintOutput => {
|
||||||
|
|
||||||
const logLintIssues = (issues: LintIssue[]): void => {
|
const logLintIssues = (issues: LintIssue[]): void => {
|
||||||
issues.forEach((issue: LintIssue): void => {
|
issues.forEach((issue: LintIssue): void => {
|
||||||
let header = `${style.red.open}${style.bold.open}Lint Error:${style.bold.close}${style.red.close}`
|
core.info(
|
||||||
if (issue.Severity === `warning`) {
|
((issue: LintIssue): string => {
|
||||||
header = `${style.yellow.open}${style.bold.open}Lint Warning:${style.bold.close}${style.yellow.close}`
|
switch (issue.Severity) {
|
||||||
} else if (issue.Severity === `notice`) {
|
case `warning`:
|
||||||
header = `${style.cyan.open}${style.bold.open}Lint Notice:${style.bold.close}${style.cyan.close}`
|
return `${style.yellow.open}${style.bold.open}Lint Warning:${style.bold.close}${style.yellow.close}`
|
||||||
}
|
case `notice`:
|
||||||
|
return `${style.cyan.open}${style.bold.open}Lint Notice:${style.bold.close}${style.cyan.close}`
|
||||||
let pos = `${issue.Pos.Filename}:${issue.Pos.Line}`
|
default:
|
||||||
if (issue.LineRange !== undefined) {
|
return `${style.red.open}${style.bold.open}Lint Error:${style.bold.close}${style.red.close}`
|
||||||
pos += `-${issue.LineRange.To}`
|
}
|
||||||
} else if (issue.Pos.Column) {
|
})(issue) +
|
||||||
pos += `:${issue.Pos.Column}`
|
` ` +
|
||||||
}
|
`${issue.Pos.Filename}:${issue.Pos.Line}` +
|
||||||
|
((issue: LintIssue): string => {
|
||||||
core.info(`${header} ${pos} - ${issue.Text} (${issue.FromLinter})`)
|
if (issue.LineRange !== undefined) {
|
||||||
|
return `-${issue.LineRange.To}`
|
||||||
|
} else if (issue.Pos.Column) {
|
||||||
|
return `:${issue.Pos.Column}`
|
||||||
|
} else {
|
||||||
|
return ``
|
||||||
|
}
|
||||||
|
})(issue) +
|
||||||
|
` - ${issue.Text} (${issue.FromLinter})`
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -324,101 +333,66 @@ async function annotateLintIssues(issues: LintIssue[], checkRunId: number): Prom
|
||||||
if (checkRunId === -1 || !issues.length) {
|
if (checkRunId === -1 || !issues.length) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const chunkSize = 50
|
const chunkSize = 50
|
||||||
const issueCounts = {
|
const issueCounts = {
|
||||||
notice: 0,
|
notice: 0,
|
||||||
warning: 0,
|
warning: 0,
|
||||||
failure: 0,
|
failure: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctx = github.context
|
const ctx = github.context
|
||||||
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }))
|
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }))
|
||||||
|
|
||||||
const githubAnnotations: GithubAnnotation[] = issues.map(
|
|
||||||
(issue: LintIssue): GithubAnnotation => {
|
|
||||||
// If/when we transition to comments, we would build the request structure here
|
|
||||||
const annotation: GithubAnnotation = {
|
|
||||||
path: issue.Pos.Filename,
|
|
||||||
start_line: issue.Pos.Line,
|
|
||||||
end_line: issue.Pos.Line,
|
|
||||||
title: issue.FromLinter,
|
|
||||||
message: issue.Text,
|
|
||||||
annotation_level: issue.Severity,
|
|
||||||
}
|
|
||||||
|
|
||||||
issueCounts[issue.Severity]++
|
|
||||||
|
|
||||||
if (issue.LineRange !== undefined) {
|
|
||||||
annotation.end_line = issue.LineRange.To
|
|
||||||
} else if (issue.Pos.Column) {
|
|
||||||
annotation.start_column = issue.Pos.Column
|
|
||||||
annotation.end_column = issue.Pos.Column
|
|
||||||
}
|
|
||||||
|
|
||||||
if (issue.Replacement !== null) {
|
|
||||||
let replacement = ``
|
|
||||||
if (issue.Replacement.Inline) {
|
|
||||||
replacement =
|
|
||||||
issue.SourceLines[0].slice(0, issue.Replacement.Inline.StartCol) +
|
|
||||||
issue.Replacement.Inline.NewString +
|
|
||||||
issue.SourceLines[0].slice(issue.Replacement.Inline.StartCol + issue.Replacement.Inline.Length)
|
|
||||||
} else if (issue.Replacement.NewLines) {
|
|
||||||
replacement = issue.Replacement.NewLines.join("\n")
|
|
||||||
}
|
|
||||||
annotation.raw_details = "```suggestion\n" + replacement + "\n```"
|
|
||||||
}
|
|
||||||
|
|
||||||
return annotation as GithubAnnotation
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const title = `GolangCI-Lint`
|
const title = `GolangCI-Lint`
|
||||||
const summary = `There are {issueCounts.failure} failures, {issueCounts.wairning} warnings, and {issueCounts.notice} notices.`
|
for (let i = 0; i < Math.ceil(issues.length / chunkSize); i++) {
|
||||||
Array.from({ length: Math.ceil(githubAnnotations.length / chunkSize) }, (v, i) =>
|
|
||||||
githubAnnotations.slice(i * chunkSize, i * chunkSize + chunkSize)
|
|
||||||
).forEach((annotations: GithubAnnotation[]): void => {
|
|
||||||
octokit.checks
|
octokit.checks
|
||||||
.update({
|
.update({
|
||||||
...ctx.repo,
|
...ctx.repo,
|
||||||
check_run_id: checkRunId,
|
check_run_id: checkRunId,
|
||||||
output: {
|
output: {
|
||||||
title,
|
title: title,
|
||||||
summary,
|
annotations: issues.slice(i * chunkSize, i * chunkSize + chunkSize).map(
|
||||||
annotations,
|
(issue: LintIssue): GithubAnnotation => {
|
||||||
|
// If/when we transition to comments, we would build the request structure here
|
||||||
|
const annotation: GithubAnnotation = {
|
||||||
|
path: issue.Pos.Filename,
|
||||||
|
start_line: issue.Pos.Line,
|
||||||
|
end_line: issue.Pos.Line,
|
||||||
|
title: issue.FromLinter,
|
||||||
|
message: issue.Text,
|
||||||
|
annotation_level: issue.Severity,
|
||||||
|
}
|
||||||
|
|
||||||
|
issueCounts[issue.Severity]++
|
||||||
|
|
||||||
|
if (issue.LineRange !== undefined) {
|
||||||
|
annotation.end_line = issue.LineRange.To
|
||||||
|
} else if (issue.Pos.Column) {
|
||||||
|
annotation.start_column = issue.Pos.Column
|
||||||
|
annotation.end_column = issue.Pos.Column
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issue.Replacement !== null) {
|
||||||
|
let replacement = ``
|
||||||
|
if (issue.Replacement.Inline) {
|
||||||
|
replacement =
|
||||||
|
issue.SourceLines[0].slice(0, issue.Replacement.Inline.StartCol) +
|
||||||
|
issue.Replacement.Inline.NewString +
|
||||||
|
issue.SourceLines[0].slice(issue.Replacement.Inline.StartCol + issue.Replacement.Inline.Length)
|
||||||
|
} else if (issue.Replacement.NewLines) {
|
||||||
|
replacement = issue.Replacement.NewLines.join("\n")
|
||||||
|
}
|
||||||
|
annotation.raw_details = "```suggestion\n" + replacement + "\n```"
|
||||||
|
}
|
||||||
|
|
||||||
|
return annotation as GithubAnnotation
|
||||||
|
}
|
||||||
|
),
|
||||||
|
summary: `There are {issueCounts.failure} failures, {issueCounts.wairning} warnings, and {issueCounts.notice} notices.`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
throw `Error patching Check Run Data (annotations): ${e}`
|
throw `Error patching Check Run Data (annotations): ${e}`
|
||||||
})
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasFailingIssues = (issues: LintIssue[]): boolean => {
|
|
||||||
// If the user input is not a valid Severity Level, this will be -1, and any issue will fail
|
|
||||||
const userFailureSeverity = core.getInput(`failure-severity`).toLowerCase()
|
|
||||||
let failureSeverity = DefaultFailureSeverity
|
|
||||||
if (userFailureSeverity) {
|
|
||||||
failureSeverity = Object.values(LintSeverity).indexOf(userFailureSeverity)
|
|
||||||
}
|
}
|
||||||
if (failureSeverity < 0) {
|
|
||||||
core.info(
|
|
||||||
`::warning::failure-severity must be one of (${Object.keys(LintSeverity).join(
|
|
||||||
" | "
|
|
||||||
)}). "${userFailureSeverity}" not supported, using default (${LintSeverity[DefaultFailureSeverity]})`
|
|
||||||
)
|
|
||||||
failureSeverity = DefaultFailureSeverity
|
|
||||||
}
|
|
||||||
if (issues.length) {
|
|
||||||
if (failureSeverity <= 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for (const issue of issues) {
|
|
||||||
if (failureSeverity <= LintSeverity[issue.Severity]) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const printOutput = (res: ExecRes): void => {
|
const printOutput = (res: ExecRes): void => {
|
||||||
|
|
@ -430,55 +404,40 @@ const printOutput = (res: ExecRes): void => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function printLintOutput(res: ExecRes, checkRunId: number): Promise<void> {
|
async function processLintOutput(res: ExecRes, checkRunId: number): Promise<LintIssue[]> {
|
||||||
let lintOutput: LintOutput | undefined
|
let lintIssues: LintIssue[] = []
|
||||||
const exit_code = res.code ?? 0
|
if (res.stdout) {
|
||||||
try {
|
try {
|
||||||
if (res.stdout) {
|
// This object contains other information, such as errors and the active linters
|
||||||
try {
|
// TODO: Should we do something with that data?
|
||||||
// This object contains other information, such as errors and the active linters
|
;({ Issues: lintIssues } = parseOutput(res.stdout))
|
||||||
// TODO: Should we do something with that data?
|
|
||||||
lintOutput = parseOutput(res.stdout)
|
|
||||||
|
|
||||||
if (lintOutput.Issues.length) {
|
if (lintIssues.length) {
|
||||||
logLintIssues(lintOutput.Issues)
|
logLintIssues(lintIssues)
|
||||||
|
|
||||||
// We can only Annotate (or Comment) on Push or Pull Request
|
// We can only Annotate (or Comment) on Push or Pull Request
|
||||||
switch (github.context.eventName) {
|
switch (github.context.eventName) {
|
||||||
case `pull_request`:
|
case `pull_request`:
|
||||||
// TODO: When we are ready to handle these as Comments, instead of Annotations, we would place that logic here
|
// TODO: When we are ready to handle these as Comments, instead of Annotations, we would place that logic here
|
||||||
/* falls through */
|
/* falls through */
|
||||||
case `push`:
|
case `push`:
|
||||||
await annotateLintIssues(lintOutput.Issues, checkRunId)
|
await annotateLintIssues(lintIssues, checkRunId)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
// At this time, other events are not supported
|
// At this time, other events are not supported
|
||||||
break
|
break
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
throw `there was an error processing golangci-lint output: ${e}`
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
core.setFailed(`Error processing golangci-lint output: ${e}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.stderr) {
|
|
||||||
core.info(res.stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exit_code === 1) {
|
|
||||||
if (!lintOutput) {
|
|
||||||
throw `unexpected state, golangci-lint exited with 1, but provided no lint output`
|
|
||||||
}
|
|
||||||
if (hasFailingIssues(lintOutput.Issues)) {
|
|
||||||
throw `issues found`
|
|
||||||
}
|
|
||||||
} else if (exit_code > 1) {
|
|
||||||
throw `golangci-lint exit with code ${exit_code}`
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return <void>core.setFailed(`${e}`)
|
|
||||||
}
|
}
|
||||||
return <void>core.info(`golangci-lint found no blocking issues`)
|
|
||||||
|
if (res.stderr) {
|
||||||
|
core.info(res.stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lintIssues
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runLint(lintPath: string, patchPath: string, checkRunId: number): Promise<void> {
|
async function runLint(lintPath: string, patchPath: string, checkRunId: number): Promise<void> {
|
||||||
|
|
@ -488,6 +447,21 @@ async function runLint(lintPath: string, patchPath: string, checkRunId: number):
|
||||||
printOutput(res)
|
printOutput(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const failureSeverity = ((userFailureSeverity: string): LintSeverity => {
|
||||||
|
if (userFailureSeverity) {
|
||||||
|
if (Object.values(LintSeverity).indexOf(userFailureSeverity) != -1) {
|
||||||
|
return Object.values(LintSeverity).indexOf(userFailureSeverity)
|
||||||
|
} else {
|
||||||
|
core.info(
|
||||||
|
`::warning::failure-severity must be one of (${Object.keys(LintSeverity).join(
|
||||||
|
" | "
|
||||||
|
)}). "${userFailureSeverity}" not supported, using default (${LintSeverity[DefaultFailureSeverity]})`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DefaultFailureSeverity
|
||||||
|
})(core.getInput(`failure-severity`).toLowerCase())
|
||||||
|
|
||||||
const userArgs = core.getInput(`args`)
|
const userArgs = core.getInput(`args`)
|
||||||
const addedArgs: string[] = []
|
const addedArgs: string[] = []
|
||||||
|
|
||||||
|
|
@ -535,13 +509,25 @@ async function runLint(lintPath: string, patchPath: string, checkRunId: number):
|
||||||
const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimRight()
|
const cmd = `${lintPath} run ${addedArgs.join(` `)} ${userArgs}`.trimRight()
|
||||||
core.info(`Running [${cmd}] in [${cmdArgs.cwd || ``}] ...`)
|
core.info(`Running [${cmd}] in [${cmdArgs.cwd || ``}] ...`)
|
||||||
const startedAt = Date.now()
|
const startedAt = Date.now()
|
||||||
|
let exit_code = 0
|
||||||
try {
|
try {
|
||||||
const res = await execShellCommand(cmd, cmdArgs)
|
const res = await execShellCommand(cmd, cmdArgs)
|
||||||
await printLintOutput(res, checkRunId)
|
processLintOutput(res, checkRunId)
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
// This logging passes issues to GitHub annotations but comments can be more convenient for some users.
|
// This logging passes issues to GitHub annotations but comments can be more convenient for some users.
|
||||||
// TODO: support reviewdog or leaving comments by GitHub API.
|
// TODO: support reviewdog or leaving comments by GitHub API.
|
||||||
await printLintOutput(exc, checkRunId)
|
const issuesPromise = processLintOutput(exc, checkRunId)
|
||||||
|
if (exc.code !== 1 || (await issuesPromise).findIndex((issue: LintIssue) => LintSeverity[issue.Severity] >= failureSeverity) != -1) {
|
||||||
|
exit_code = exc.code
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (exit_code === 0) {
|
||||||
|
core.info(`golangci-lint found no blocking issues`)
|
||||||
|
} else if (exit_code === 1) {
|
||||||
|
core.setFailed(`issues found`)
|
||||||
|
} else {
|
||||||
|
core.setFailed(`golangci-lint exit with code ${exit_code}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`)
|
core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue