mirror of
https://github.com/golangci/golangci-lint-action.git
synced 2025-12-12 14:01:14 +00:00
feat: automatic module directories (#1315)
This commit is contained in:
parent
f3ae99f5f5
commit
e7fa5ac41e
18 changed files with 541 additions and 275 deletions
27
.github/workflows/test.yml
vendored
27
.github/workflows/test.yml
vendored
|
|
@ -146,3 +146,30 @@ jobs:
|
||||||
version: ${{ matrix.version }}
|
version: ${{ matrix.version }}
|
||||||
working-directory: sample-plugins
|
working-directory: sample-plugins
|
||||||
args: --timeout=5m --issues-exit-code=0 ./...
|
args: --timeout=5m --issues-exit-code=0 ./...
|
||||||
|
|
||||||
|
test-monorepo:
|
||||||
|
needs: [ build ]
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- ubuntu-22.04-arm
|
||||||
|
- macos-latest
|
||||||
|
- windows-latest
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: 24.x
|
||||||
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version: oldstable
|
||||||
|
- uses: ./
|
||||||
|
with:
|
||||||
|
working-directory: sample-monorepo
|
||||||
|
experimental: "automatic-module-directories"
|
||||||
|
args: --timeout=5m --issues-exit-code=0 ./...
|
||||||
|
|
|
||||||
42
README.md
42
README.md
|
|
@ -275,6 +275,7 @@ You will also likely need to add the following `.gitattributes` file to ensure t
|
||||||
| [`skip-save-cache`](#skip-save-cache) | Don't save cache. |
|
| [`skip-save-cache`](#skip-save-cache) | Don't save cache. |
|
||||||
| [`cache-invalidation-interval`](#cache-invalidation-interval) | Number of days before cache invalidation. |
|
| [`cache-invalidation-interval`](#cache-invalidation-interval) | Number of days before cache invalidation. |
|
||||||
| [`problem-matchers`](#problem-matchers) | Forces the usage of the embedded problem matchers. |
|
| [`problem-matchers`](#problem-matchers) | Forces the usage of the embedded problem matchers. |
|
||||||
|
| [Experimental](#experimental) | Experimental options |
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
|
|
@ -552,6 +553,47 @@ with:
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### Experimental
|
||||||
|
|
||||||
|
The following options are experimental: those may or may not be supported in the future, and so they will be either converted into a dedicated option or removed.
|
||||||
|
|
||||||
|
List of comma-separated options.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example</summary>
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
uses: golangci/golangci-lint-action@v9
|
||||||
|
with:
|
||||||
|
experimental: "foo,bar"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
#### `automatic-module-directories`
|
||||||
|
|
||||||
|
(optional)
|
||||||
|
|
||||||
|
This option will run golangci-lint in each module directory, useful for monorepos.
|
||||||
|
|
||||||
|
The automatic detection of modules uses the `working-directory` as the base directory if defined, otherwise the root directory.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> - The cache key will refer to the `working-directory` (if defined) because all the golangci-lint runs must use the same cache directory/key.
|
||||||
|
> - The version detection will only work if the project has a single module.
|
||||||
|
> - If the project has multiple modules, the custom build file must be located in the repository root ( or `working-directory`).
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example</summary>
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
uses: golangci/golangci-lint-action@v9
|
||||||
|
with:
|
||||||
|
experimental: "automatic-module-directories"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
## Annotations
|
## Annotations
|
||||||
|
|
||||||
Currently, GitHub parses the action's output and creates [annotations](https://github.blog/2018-12-14-introducing-check-runs-and-annotations/).
|
Currently, GitHub parses the action's output and creates [annotations](https://github.blog/2018-12-14-introducing-check-runs-and-annotations/).
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,12 @@ inputs:
|
||||||
example: "cache,clean"
|
example: "cache,clean"
|
||||||
default: ""
|
default: ""
|
||||||
required: false
|
required: false
|
||||||
|
experimental:
|
||||||
|
description: |
|
||||||
|
Experimental options for the action.
|
||||||
|
List of comma separated options.
|
||||||
|
default: ""
|
||||||
|
required: false
|
||||||
runs:
|
runs:
|
||||||
using: "node24"
|
using: "node24"
|
||||||
main: "dist/run/index.js"
|
main: "dist/run/index.js"
|
||||||
|
|
|
||||||
186
dist/post_run/index.js
generated
vendored
186
dist/post_run/index.js
generated
vendored
|
|
@ -96844,8 +96844,10 @@ async function buildCacheKeys() {
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
async function restoreCache() {
|
async function restoreCache() {
|
||||||
if (core.getBooleanInput(`skip-cache`, { required: true }))
|
if (core.getBooleanInput(`skip-cache`, { required: true })) {
|
||||||
|
core.info(`Skipping cache restoration`);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (!utils.isValidEvent()) {
|
if (!utils.isValidEvent()) {
|
||||||
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
||||||
return;
|
return;
|
||||||
|
|
@ -96881,10 +96883,14 @@ async function restoreCache() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function saveCache() {
|
async function saveCache() {
|
||||||
if (core.getBooleanInput(`skip-cache`, { required: true }))
|
if (core.getBooleanInput(`skip-cache`, { required: true })) {
|
||||||
|
core.info(`Skipping cache saving`);
|
||||||
return;
|
return;
|
||||||
if (core.getBooleanInput(`skip-save-cache`, { required: true }))
|
}
|
||||||
|
if (core.getBooleanInput(`skip-save-cache`, { required: true })) {
|
||||||
|
core.info(`Skipping cache saving`);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
// Validate inputs, this can cause task failure
|
// Validate inputs, this can cause task failure
|
||||||
if (!utils.isValidEvent()) {
|
if (!utils.isValidEvent()) {
|
||||||
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
||||||
|
|
@ -96999,12 +97005,13 @@ exports.installBinary = installBinary;
|
||||||
const core = __importStar(__nccwpck_require__(37484));
|
const core = __importStar(__nccwpck_require__(37484));
|
||||||
const tc = __importStar(__nccwpck_require__(33472));
|
const tc = __importStar(__nccwpck_require__(33472));
|
||||||
const child_process_1 = __nccwpck_require__(35317);
|
const child_process_1 = __nccwpck_require__(35317);
|
||||||
|
const fs_1 = __importDefault(__nccwpck_require__(79896));
|
||||||
const os_1 = __importDefault(__nccwpck_require__(70857));
|
const os_1 = __importDefault(__nccwpck_require__(70857));
|
||||||
const path_1 = __importDefault(__nccwpck_require__(16928));
|
const path_1 = __importDefault(__nccwpck_require__(16928));
|
||||||
const util_1 = __nccwpck_require__(39023);
|
const util_1 = __nccwpck_require__(39023);
|
||||||
const which_1 = __importDefault(__nccwpck_require__(11189));
|
const which_1 = __importDefault(__nccwpck_require__(11189));
|
||||||
const version_1 = __nccwpck_require__(311);
|
const version_1 = __nccwpck_require__(311);
|
||||||
const execShellCommand = (0, util_1.promisify)(child_process_1.exec);
|
const execCommand = (0, util_1.promisify)(child_process_1.exec);
|
||||||
var InstallMode;
|
var InstallMode;
|
||||||
(function (InstallMode) {
|
(function (InstallMode) {
|
||||||
InstallMode["Binary"] = "binary";
|
InstallMode["Binary"] = "binary";
|
||||||
|
|
@ -97018,6 +97025,7 @@ const printOutput = (res) => {
|
||||||
if (res.stderr) {
|
if (res.stderr) {
|
||||||
core.info(res.stderr);
|
core.info(res.stderr);
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Install golangci-lint.
|
* Install golangci-lint.
|
||||||
|
|
@ -97025,6 +97033,15 @@ const printOutput = (res) => {
|
||||||
* @returns path to installed binary of golangci-lint.
|
* @returns path to installed binary of golangci-lint.
|
||||||
*/
|
*/
|
||||||
async function install() {
|
async function install() {
|
||||||
|
const problemMatchers = core.getBooleanInput(`problem-matchers`);
|
||||||
|
if (problemMatchers) {
|
||||||
|
const matchersPath = path_1.default.join(__dirname, "../..", "problem-matchers.json");
|
||||||
|
if (fs_1.default.existsSync(matchersPath)) {
|
||||||
|
// Adds problem matchers.
|
||||||
|
// https://github.com/actions/setup-go/blob/cdcb36043654635271a94b9a6d1392de5bb323a7/src/main.ts#L81-L83
|
||||||
|
core.info(`##[add-matcher]${matchersPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
const mode = core.getInput("install-mode").toLowerCase();
|
const mode = core.getInput("install-mode").toLowerCase();
|
||||||
if (mode === InstallMode.None) {
|
if (mode === InstallMode.None) {
|
||||||
const binPath = await (0, which_1.default)("golangci-lint", { nothrow: true });
|
const binPath = await (0, which_1.default)("golangci-lint", { nothrow: true });
|
||||||
|
|
@ -97064,10 +97081,8 @@ async function goInstall(versionInfo) {
|
||||||
core.info(`Installing golangci-lint ${versionInfo.TargetVersion}...`);
|
core.info(`Installing golangci-lint ${versionInfo.TargetVersion}...`);
|
||||||
const startedAt = Date.now();
|
const startedAt = Date.now();
|
||||||
const options = { env: { ...process.env, CGO_ENABLED: "1" } };
|
const options = { env: { ...process.env, CGO_ENABLED: "1" } };
|
||||||
const exres = await execShellCommand(`go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`, options);
|
await execCommand(`go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`, options).then(printOutput);
|
||||||
printOutput(exres);
|
const res = await execCommand(`go install -n github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`, options).then(printOutput);
|
||||||
const res = await execShellCommand(`go install -n github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`, options);
|
|
||||||
printOutput(res);
|
|
||||||
// The output of `go install -n` when the binary is already installed is `touch <path_to_the_binary>`.
|
// The output of `go install -n` when the binary is already installed is `touch <path_to_the_binary>`.
|
||||||
const binPath = res.stderr
|
const binPath = res.stderr
|
||||||
.split(/\r?\n/)
|
.split(/\r?\n/)
|
||||||
|
|
@ -97196,9 +97211,6 @@ function isOnlyNewIssues() {
|
||||||
return core.getBooleanInput(`only-new-issues`, { required: true });
|
return core.getBooleanInput(`only-new-issues`, { required: true });
|
||||||
}
|
}
|
||||||
async function fetchPatch() {
|
async function fetchPatch() {
|
||||||
if (!isOnlyNewIssues()) {
|
|
||||||
return ``;
|
|
||||||
}
|
|
||||||
const ctx = github.context;
|
const ctx = github.context;
|
||||||
switch (ctx.eventName) {
|
switch (ctx.eventName) {
|
||||||
case `pull_request`:
|
case `pull_request`:
|
||||||
|
|
@ -97242,8 +97254,7 @@ async function fetchPullRequestPatch(ctx) {
|
||||||
return ``; // don't fail the action, but analyze without patch
|
return ``; // don't fail the action, but analyze without patch
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const tempDir = await createTempDir();
|
const patchPath = await createTempDir().then((tempDir) => path_1.default.join(tempDir, "pull.patch"));
|
||||||
const patchPath = path_1.default.join(tempDir, "pull.patch");
|
|
||||||
core.info(`Writing patch to ${patchPath}`);
|
core.info(`Writing patch to ${patchPath}`);
|
||||||
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
|
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
|
||||||
return patchPath;
|
return patchPath;
|
||||||
|
|
@ -97277,8 +97288,7 @@ async function fetchPushPatch(ctx) {
|
||||||
return ``; // don't fail the action, but analyze without patch
|
return ``; // don't fail the action, but analyze without patch
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const tempDir = await createTempDir();
|
const patchPath = await createTempDir().then((tempDir) => path_1.default.join(tempDir, "push.patch"));
|
||||||
const patchPath = path_1.default.join(tempDir, "push.patch");
|
|
||||||
core.info(`Writing patch to ${patchPath}`);
|
core.info(`Writing patch to ${patchPath}`);
|
||||||
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
|
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
|
||||||
return patchPath;
|
return patchPath;
|
||||||
|
|
@ -97341,7 +97351,7 @@ const fs = __importStar(__nccwpck_require__(79896));
|
||||||
const path = __importStar(__nccwpck_require__(16928));
|
const path = __importStar(__nccwpck_require__(16928));
|
||||||
const util_1 = __nccwpck_require__(39023);
|
const util_1 = __nccwpck_require__(39023);
|
||||||
const yaml_1 = __importDefault(__nccwpck_require__(38815));
|
const yaml_1 = __importDefault(__nccwpck_require__(38815));
|
||||||
const execShellCommand = (0, util_1.promisify)(child_process_1.exec);
|
const execCommand = (0, util_1.promisify)(child_process_1.exec);
|
||||||
const printOutput = (res) => {
|
const printOutput = (res) => {
|
||||||
if (res.stdout) {
|
if (res.stdout) {
|
||||||
core.info(res.stdout);
|
core.info(res.stdout);
|
||||||
|
|
@ -97366,7 +97376,7 @@ async function install(binPath) {
|
||||||
.map((filename) => path.join(rootDir, filename))
|
.map((filename) => path.join(rootDir, filename))
|
||||||
.find((filePath) => fs.existsSync(filePath));
|
.find((filePath) => fs.existsSync(filePath));
|
||||||
if (!configFile || configFile === "") {
|
if (!configFile || configFile === "") {
|
||||||
return "";
|
return binPath;
|
||||||
}
|
}
|
||||||
core.info(`Found configuration for the plugin module system : ${configFile}`);
|
core.info(`Found configuration for the plugin module system : ${configFile}`);
|
||||||
core.info(`Building and installing custom golangci-lint binary...`);
|
core.info(`Building and installing custom golangci-lint binary...`);
|
||||||
|
|
@ -97388,18 +97398,16 @@ async function install(binPath) {
|
||||||
}
|
}
|
||||||
const cmd = `${binPath} custom`;
|
const cmd = `${binPath} custom`;
|
||||||
core.info(`Running [${cmd}] in [${rootDir}] ...`);
|
core.info(`Running [${cmd}] in [${rootDir}] ...`);
|
||||||
try {
|
const options = {
|
||||||
const options = {
|
cwd: rootDir,
|
||||||
cwd: rootDir,
|
};
|
||||||
};
|
return execCommand(cmd, options)
|
||||||
const res = await execShellCommand(cmd, options);
|
.then(printOutput)
|
||||||
printOutput(res);
|
.then(() => core.info(`Built custom golangci-lint binary in ${Date.now() - startedAt}ms`))
|
||||||
core.info(`Built custom golangci-lint binary in ${Date.now() - startedAt}ms`);
|
.then(() => path.join(rootDir, config.destination, config.name))
|
||||||
return path.join(rootDir, config.destination, config.name);
|
.catch((exc) => {
|
||||||
}
|
|
||||||
catch (exc) {
|
|
||||||
throw new Error(`Failed to build custom golangci-lint binary: ${exc.message}`);
|
throw new Error(`Failed to build custom golangci-lint binary: ${exc.message}`);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -97456,24 +97464,7 @@ const cache_1 = __nccwpck_require__(97377);
|
||||||
const install_1 = __nccwpck_require__(90232);
|
const install_1 = __nccwpck_require__(90232);
|
||||||
const patch_1 = __nccwpck_require__(47161);
|
const patch_1 = __nccwpck_require__(47161);
|
||||||
const plugins = __importStar(__nccwpck_require__(96067));
|
const plugins = __importStar(__nccwpck_require__(96067));
|
||||||
const execShellCommand = (0, util_1.promisify)(child_process_1.exec);
|
const execCommand = (0, util_1.promisify)(child_process_1.exec);
|
||||||
async function prepareEnv(installOnly) {
|
|
||||||
const startedAt = Date.now();
|
|
||||||
// Prepare cache, lint and go in parallel.
|
|
||||||
await (0, cache_1.restoreCache)();
|
|
||||||
let binPath = await (0, install_1.install)();
|
|
||||||
// Build custom golangci-lint if needed.
|
|
||||||
const customBinPath = await plugins.install(binPath);
|
|
||||||
if (customBinPath !== "") {
|
|
||||||
binPath = customBinPath;
|
|
||||||
}
|
|
||||||
if (installOnly) {
|
|
||||||
return { binPath, patchPath: `` };
|
|
||||||
}
|
|
||||||
const patchPath = await (0, patch_1.fetchPatch)();
|
|
||||||
core.info(`Prepared env in ${Date.now() - startedAt}ms`);
|
|
||||||
return { binPath, patchPath };
|
|
||||||
}
|
|
||||||
const printOutput = (res) => {
|
const printOutput = (res) => {
|
||||||
if (res.stdout) {
|
if (res.stdout) {
|
||||||
core.info(res.stdout);
|
core.info(res.stdout);
|
||||||
|
|
@ -97482,12 +97473,7 @@ const printOutput = (res) => {
|
||||||
core.info(res.stderr);
|
core.info(res.stderr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
async function runLint(binPath, patchPath) {
|
async function runGolangciLint(binPath, rootDir) {
|
||||||
const debug = core.getInput(`debug`);
|
|
||||||
if (debug.split(`,`).includes(`cache`)) {
|
|
||||||
const res = await execShellCommand(`${binPath} cache status`);
|
|
||||||
printOutput(res);
|
|
||||||
}
|
|
||||||
const userArgs = core.getInput(`args`);
|
const userArgs = core.getInput(`args`);
|
||||||
const addedArgs = [];
|
const addedArgs = [];
|
||||||
const userArgsList = userArgs
|
const userArgsList = userArgs
|
||||||
|
|
@ -97499,15 +97485,6 @@ async function runLint(binPath, patchPath) {
|
||||||
.map(([key, value]) => [key.toLowerCase(), value ?? ""]);
|
.map(([key, value]) => [key.toLowerCase(), value ?? ""]);
|
||||||
const userArgsMap = new Map(userArgsList);
|
const userArgsMap = new Map(userArgsList);
|
||||||
const userArgNames = new Set(userArgsList.map(([key]) => key));
|
const userArgNames = new Set(userArgsList.map(([key]) => key));
|
||||||
const problemMatchers = core.getBooleanInput(`problem-matchers`);
|
|
||||||
if (problemMatchers) {
|
|
||||||
const matchersPath = path.join(__dirname, "../..", "problem-matchers.json");
|
|
||||||
if (fs.existsSync(matchersPath)) {
|
|
||||||
// Adds problem matchers.
|
|
||||||
// https://github.com/actions/setup-go/blob/cdcb36043654635271a94b9a6d1392de5bb323a7/src/main.ts#L81-L83
|
|
||||||
core.info(`##[add-matcher]${matchersPath}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((0, patch_1.isOnlyNewIssues)()) {
|
if ((0, patch_1.isOnlyNewIssues)()) {
|
||||||
if (userArgNames.has(`new`) ||
|
if (userArgNames.has(`new`) ||
|
||||||
userArgNames.has(`new-from-rev`) ||
|
userArgNames.has(`new-from-rev`) ||
|
||||||
|
|
@ -97516,6 +97493,7 @@ async function runLint(binPath, patchPath) {
|
||||||
throw new Error(`please, don't specify manually --new* args when requesting only new issues`);
|
throw new Error(`please, don't specify manually --new* args when requesting only new issues`);
|
||||||
}
|
}
|
||||||
const ctx = github.context;
|
const ctx = github.context;
|
||||||
|
const patchPath = await (0, patch_1.fetchPatch)();
|
||||||
core.info(`only new issues on ${ctx.eventName}: ${patchPath}`);
|
core.info(`only new issues on ${ctx.eventName}: ${patchPath}`);
|
||||||
switch (ctx.eventName) {
|
switch (ctx.eventName) {
|
||||||
case `pull_request`:
|
case `pull_request`:
|
||||||
|
|
@ -97541,27 +97519,21 @@ async function runLint(binPath, patchPath) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const cmdArgs = {};
|
const cmdArgs = {};
|
||||||
const workingDirectory = core.getInput(`working-directory`);
|
if (rootDir) {
|
||||||
if (workingDirectory) {
|
|
||||||
if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) {
|
|
||||||
throw new Error(`working-directory (${workingDirectory}) was not a path`);
|
|
||||||
}
|
|
||||||
if (!userArgNames.has(`path-prefix`) && !userArgNames.has(`path-mode`)) {
|
if (!userArgNames.has(`path-prefix`) && !userArgNames.has(`path-mode`)) {
|
||||||
addedArgs.push(`--path-mode=abs`);
|
addedArgs.push(`--path-mode=abs`);
|
||||||
}
|
}
|
||||||
cmdArgs.cwd = path.resolve(workingDirectory);
|
cmdArgs.cwd = path.resolve(rootDir);
|
||||||
}
|
}
|
||||||
await runVerify(binPath, userArgsMap, cmdArgs);
|
await runVerify(binPath, userArgsMap, cmdArgs);
|
||||||
const cmd = `${binPath} run ${addedArgs.join(` `)} ${userArgs}`.trimEnd();
|
const cmd = `${binPath} run ${addedArgs.join(` `)} ${userArgs}`.trimEnd();
|
||||||
core.info(`Running [${cmd}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
core.info(`Running [${cmd}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
||||||
const startedAt = Date.now();
|
const startedAt = Date.now();
|
||||||
try {
|
return execCommand(cmd, cmdArgs)
|
||||||
const res = await execShellCommand(cmd, cmdArgs);
|
.then(printOutput)
|
||||||
printOutput(res);
|
.then(() => core.info(`golangci-lint found no issues`))
|
||||||
core.info(`golangci-lint found no issues`);
|
.catch((exc) => {
|
||||||
}
|
// This logging passes issues to GitHub annotations.
|
||||||
catch (exc) {
|
|
||||||
// This logging passes issues to GitHub annotations but comments can be more convenient for some users.
|
|
||||||
printOutput(exc);
|
printOutput(exc);
|
||||||
if (exc.code === 1) {
|
if (exc.code === 1) {
|
||||||
core.setFailed(`issues found`);
|
core.setFailed(`issues found`);
|
||||||
|
|
@ -97569,8 +97541,8 @@ async function runLint(binPath, patchPath) {
|
||||||
else {
|
else {
|
||||||
core.setFailed(`golangci-lint exit with code ${exc.code}`);
|
core.setFailed(`golangci-lint exit with code ${exc.code}`);
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`);
|
.finally(() => core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`));
|
||||||
}
|
}
|
||||||
async function runVerify(binPath, userArgsMap, cmdArgs) {
|
async function runVerify(binPath, userArgsMap, cmdArgs) {
|
||||||
const verify = core.getBooleanInput(`verify`, { required: true });
|
const verify = core.getBooleanInput(`verify`, { required: true });
|
||||||
|
|
@ -97586,8 +97558,7 @@ async function runVerify(binPath, userArgsMap, cmdArgs) {
|
||||||
cmdVerify += ` --config=${userArgsMap.get("config")}`;
|
cmdVerify += ` --config=${userArgsMap.get("config")}`;
|
||||||
}
|
}
|
||||||
core.info(`Running [${cmdVerify}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
core.info(`Running [${cmdVerify}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
||||||
const res = await execShellCommand(cmdVerify, cmdArgs);
|
await execCommand(cmdVerify, cmdArgs).then(printOutput);
|
||||||
printOutput(res);
|
|
||||||
}
|
}
|
||||||
async function getConfigPath(binPath, userArgsMap, cmdArgs) {
|
async function getConfigPath(binPath, userArgsMap, cmdArgs) {
|
||||||
let cmdConfigPath = `${binPath} config path`;
|
let cmdConfigPath = `${binPath} config path`;
|
||||||
|
|
@ -97596,22 +97567,73 @@ async function getConfigPath(binPath, userArgsMap, cmdArgs) {
|
||||||
}
|
}
|
||||||
core.info(`Running [${cmdConfigPath}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
core.info(`Running [${cmdConfigPath}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
||||||
try {
|
try {
|
||||||
const resPath = await execShellCommand(cmdConfigPath, cmdArgs);
|
const resPath = await execCommand(cmdConfigPath, cmdArgs);
|
||||||
return resPath.stderr.trim();
|
return resPath.stderr.trim();
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
return ``;
|
return ``;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function debugAction(binPath) {
|
||||||
|
const flags = core.getInput(`debug`).split(`,`);
|
||||||
|
if (flags.includes(`clean`)) {
|
||||||
|
const cmd = `${binPath} cache clean`;
|
||||||
|
core.info(`Running [${cmd}] ...`);
|
||||||
|
await execCommand(cmd).then(printOutput);
|
||||||
|
}
|
||||||
|
if (flags.includes(`cache`)) {
|
||||||
|
const cmd = `${binPath} cache status`;
|
||||||
|
core.info(`Running [${cmd}] ...`);
|
||||||
|
await execCommand(cmd).then(printOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getWorkingDirectory() {
|
||||||
|
const workingDirectory = core.getInput(`working-directory`);
|
||||||
|
if (workingDirectory) {
|
||||||
|
if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) {
|
||||||
|
throw new Error(`working-directory (${workingDirectory}) was not a path`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return workingDirectory;
|
||||||
|
}
|
||||||
|
function modulesAutoDetection(rootDir) {
|
||||||
|
const o = {
|
||||||
|
cwd: rootDir,
|
||||||
|
exclude: ["**/vendor/**", "**/node_modules/**", "**/.git/**", "**/dist/**"],
|
||||||
|
};
|
||||||
|
const matches = fs.globSync("**/go.mod", o);
|
||||||
|
const dirs = matches
|
||||||
|
.filter((m) => typeof m === "string")
|
||||||
|
.map((m) => path.resolve(rootDir, path.dirname(m)))
|
||||||
|
.sort();
|
||||||
|
return [...new Set(dirs)];
|
||||||
|
}
|
||||||
|
async function runLint(binPath) {
|
||||||
|
const workingDirectory = getWorkingDirectory();
|
||||||
|
const experimental = core.getInput(`experimental`).split(`,`);
|
||||||
|
if (experimental.includes(`automatic-module-directories`)) {
|
||||||
|
const wds = modulesAutoDetection(workingDirectory);
|
||||||
|
const cwd = process.cwd();
|
||||||
|
for (const wd of wds) {
|
||||||
|
await core.group(`run golangci-lint in ${path.relative(cwd, wd)}`, () => runGolangciLint(binPath, wd));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await core.group(`run golangci-lint`, () => runGolangciLint(binPath, workingDirectory));
|
||||||
|
}
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
const installOnly = core.getBooleanInput(`install-only`, { required: true });
|
await core.group(`Restore cache`, cache_1.restoreCache);
|
||||||
const { binPath, patchPath } = await core.group(`prepare environment`, () => prepareEnv(installOnly));
|
const binPath = await core.group(`Install`, () => (0, install_1.install)().then(plugins.install));
|
||||||
core.addPath(path.dirname(binPath));
|
core.addPath(path.dirname(binPath));
|
||||||
|
if (core.getInput(`debug`)) {
|
||||||
|
await core.group(`Debug`, () => debugAction(binPath));
|
||||||
|
}
|
||||||
|
const installOnly = core.getBooleanInput(`install-only`, { required: true });
|
||||||
if (installOnly) {
|
if (installOnly) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await core.group(`run golangci-lint`, () => runLint(binPath, patchPath));
|
await runLint(binPath);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.error(`Failed to run: ${error}, ${error.stack}`);
|
core.error(`Failed to run: ${error}, ${error.stack}`);
|
||||||
|
|
|
||||||
186
dist/run/index.js
generated
vendored
186
dist/run/index.js
generated
vendored
|
|
@ -96844,8 +96844,10 @@ async function buildCacheKeys() {
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
async function restoreCache() {
|
async function restoreCache() {
|
||||||
if (core.getBooleanInput(`skip-cache`, { required: true }))
|
if (core.getBooleanInput(`skip-cache`, { required: true })) {
|
||||||
|
core.info(`Skipping cache restoration`);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (!utils.isValidEvent()) {
|
if (!utils.isValidEvent()) {
|
||||||
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
||||||
return;
|
return;
|
||||||
|
|
@ -96881,10 +96883,14 @@ async function restoreCache() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function saveCache() {
|
async function saveCache() {
|
||||||
if (core.getBooleanInput(`skip-cache`, { required: true }))
|
if (core.getBooleanInput(`skip-cache`, { required: true })) {
|
||||||
|
core.info(`Skipping cache saving`);
|
||||||
return;
|
return;
|
||||||
if (core.getBooleanInput(`skip-save-cache`, { required: true }))
|
}
|
||||||
|
if (core.getBooleanInput(`skip-save-cache`, { required: true })) {
|
||||||
|
core.info(`Skipping cache saving`);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
// Validate inputs, this can cause task failure
|
// Validate inputs, this can cause task failure
|
||||||
if (!utils.isValidEvent()) {
|
if (!utils.isValidEvent()) {
|
||||||
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`);
|
||||||
|
|
@ -96999,12 +97005,13 @@ exports.installBinary = installBinary;
|
||||||
const core = __importStar(__nccwpck_require__(37484));
|
const core = __importStar(__nccwpck_require__(37484));
|
||||||
const tc = __importStar(__nccwpck_require__(33472));
|
const tc = __importStar(__nccwpck_require__(33472));
|
||||||
const child_process_1 = __nccwpck_require__(35317);
|
const child_process_1 = __nccwpck_require__(35317);
|
||||||
|
const fs_1 = __importDefault(__nccwpck_require__(79896));
|
||||||
const os_1 = __importDefault(__nccwpck_require__(70857));
|
const os_1 = __importDefault(__nccwpck_require__(70857));
|
||||||
const path_1 = __importDefault(__nccwpck_require__(16928));
|
const path_1 = __importDefault(__nccwpck_require__(16928));
|
||||||
const util_1 = __nccwpck_require__(39023);
|
const util_1 = __nccwpck_require__(39023);
|
||||||
const which_1 = __importDefault(__nccwpck_require__(11189));
|
const which_1 = __importDefault(__nccwpck_require__(11189));
|
||||||
const version_1 = __nccwpck_require__(311);
|
const version_1 = __nccwpck_require__(311);
|
||||||
const execShellCommand = (0, util_1.promisify)(child_process_1.exec);
|
const execCommand = (0, util_1.promisify)(child_process_1.exec);
|
||||||
var InstallMode;
|
var InstallMode;
|
||||||
(function (InstallMode) {
|
(function (InstallMode) {
|
||||||
InstallMode["Binary"] = "binary";
|
InstallMode["Binary"] = "binary";
|
||||||
|
|
@ -97018,6 +97025,7 @@ const printOutput = (res) => {
|
||||||
if (res.stderr) {
|
if (res.stderr) {
|
||||||
core.info(res.stderr);
|
core.info(res.stderr);
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Install golangci-lint.
|
* Install golangci-lint.
|
||||||
|
|
@ -97025,6 +97033,15 @@ const printOutput = (res) => {
|
||||||
* @returns path to installed binary of golangci-lint.
|
* @returns path to installed binary of golangci-lint.
|
||||||
*/
|
*/
|
||||||
async function install() {
|
async function install() {
|
||||||
|
const problemMatchers = core.getBooleanInput(`problem-matchers`);
|
||||||
|
if (problemMatchers) {
|
||||||
|
const matchersPath = path_1.default.join(__dirname, "../..", "problem-matchers.json");
|
||||||
|
if (fs_1.default.existsSync(matchersPath)) {
|
||||||
|
// Adds problem matchers.
|
||||||
|
// https://github.com/actions/setup-go/blob/cdcb36043654635271a94b9a6d1392de5bb323a7/src/main.ts#L81-L83
|
||||||
|
core.info(`##[add-matcher]${matchersPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
const mode = core.getInput("install-mode").toLowerCase();
|
const mode = core.getInput("install-mode").toLowerCase();
|
||||||
if (mode === InstallMode.None) {
|
if (mode === InstallMode.None) {
|
||||||
const binPath = await (0, which_1.default)("golangci-lint", { nothrow: true });
|
const binPath = await (0, which_1.default)("golangci-lint", { nothrow: true });
|
||||||
|
|
@ -97064,10 +97081,8 @@ async function goInstall(versionInfo) {
|
||||||
core.info(`Installing golangci-lint ${versionInfo.TargetVersion}...`);
|
core.info(`Installing golangci-lint ${versionInfo.TargetVersion}...`);
|
||||||
const startedAt = Date.now();
|
const startedAt = Date.now();
|
||||||
const options = { env: { ...process.env, CGO_ENABLED: "1" } };
|
const options = { env: { ...process.env, CGO_ENABLED: "1" } };
|
||||||
const exres = await execShellCommand(`go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`, options);
|
await execCommand(`go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`, options).then(printOutput);
|
||||||
printOutput(exres);
|
const res = await execCommand(`go install -n github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`, options).then(printOutput);
|
||||||
const res = await execShellCommand(`go install -n github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`, options);
|
|
||||||
printOutput(res);
|
|
||||||
// The output of `go install -n` when the binary is already installed is `touch <path_to_the_binary>`.
|
// The output of `go install -n` when the binary is already installed is `touch <path_to_the_binary>`.
|
||||||
const binPath = res.stderr
|
const binPath = res.stderr
|
||||||
.split(/\r?\n/)
|
.split(/\r?\n/)
|
||||||
|
|
@ -97196,9 +97211,6 @@ function isOnlyNewIssues() {
|
||||||
return core.getBooleanInput(`only-new-issues`, { required: true });
|
return core.getBooleanInput(`only-new-issues`, { required: true });
|
||||||
}
|
}
|
||||||
async function fetchPatch() {
|
async function fetchPatch() {
|
||||||
if (!isOnlyNewIssues()) {
|
|
||||||
return ``;
|
|
||||||
}
|
|
||||||
const ctx = github.context;
|
const ctx = github.context;
|
||||||
switch (ctx.eventName) {
|
switch (ctx.eventName) {
|
||||||
case `pull_request`:
|
case `pull_request`:
|
||||||
|
|
@ -97242,8 +97254,7 @@ async function fetchPullRequestPatch(ctx) {
|
||||||
return ``; // don't fail the action, but analyze without patch
|
return ``; // don't fail the action, but analyze without patch
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const tempDir = await createTempDir();
|
const patchPath = await createTempDir().then((tempDir) => path_1.default.join(tempDir, "pull.patch"));
|
||||||
const patchPath = path_1.default.join(tempDir, "pull.patch");
|
|
||||||
core.info(`Writing patch to ${patchPath}`);
|
core.info(`Writing patch to ${patchPath}`);
|
||||||
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
|
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
|
||||||
return patchPath;
|
return patchPath;
|
||||||
|
|
@ -97277,8 +97288,7 @@ async function fetchPushPatch(ctx) {
|
||||||
return ``; // don't fail the action, but analyze without patch
|
return ``; // don't fail the action, but analyze without patch
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const tempDir = await createTempDir();
|
const patchPath = await createTempDir().then((tempDir) => path_1.default.join(tempDir, "push.patch"));
|
||||||
const patchPath = path_1.default.join(tempDir, "push.patch");
|
|
||||||
core.info(`Writing patch to ${patchPath}`);
|
core.info(`Writing patch to ${patchPath}`);
|
||||||
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
|
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
|
||||||
return patchPath;
|
return patchPath;
|
||||||
|
|
@ -97341,7 +97351,7 @@ const fs = __importStar(__nccwpck_require__(79896));
|
||||||
const path = __importStar(__nccwpck_require__(16928));
|
const path = __importStar(__nccwpck_require__(16928));
|
||||||
const util_1 = __nccwpck_require__(39023);
|
const util_1 = __nccwpck_require__(39023);
|
||||||
const yaml_1 = __importDefault(__nccwpck_require__(38815));
|
const yaml_1 = __importDefault(__nccwpck_require__(38815));
|
||||||
const execShellCommand = (0, util_1.promisify)(child_process_1.exec);
|
const execCommand = (0, util_1.promisify)(child_process_1.exec);
|
||||||
const printOutput = (res) => {
|
const printOutput = (res) => {
|
||||||
if (res.stdout) {
|
if (res.stdout) {
|
||||||
core.info(res.stdout);
|
core.info(res.stdout);
|
||||||
|
|
@ -97366,7 +97376,7 @@ async function install(binPath) {
|
||||||
.map((filename) => path.join(rootDir, filename))
|
.map((filename) => path.join(rootDir, filename))
|
||||||
.find((filePath) => fs.existsSync(filePath));
|
.find((filePath) => fs.existsSync(filePath));
|
||||||
if (!configFile || configFile === "") {
|
if (!configFile || configFile === "") {
|
||||||
return "";
|
return binPath;
|
||||||
}
|
}
|
||||||
core.info(`Found configuration for the plugin module system : ${configFile}`);
|
core.info(`Found configuration for the plugin module system : ${configFile}`);
|
||||||
core.info(`Building and installing custom golangci-lint binary...`);
|
core.info(`Building and installing custom golangci-lint binary...`);
|
||||||
|
|
@ -97388,18 +97398,16 @@ async function install(binPath) {
|
||||||
}
|
}
|
||||||
const cmd = `${binPath} custom`;
|
const cmd = `${binPath} custom`;
|
||||||
core.info(`Running [${cmd}] in [${rootDir}] ...`);
|
core.info(`Running [${cmd}] in [${rootDir}] ...`);
|
||||||
try {
|
const options = {
|
||||||
const options = {
|
cwd: rootDir,
|
||||||
cwd: rootDir,
|
};
|
||||||
};
|
return execCommand(cmd, options)
|
||||||
const res = await execShellCommand(cmd, options);
|
.then(printOutput)
|
||||||
printOutput(res);
|
.then(() => core.info(`Built custom golangci-lint binary in ${Date.now() - startedAt}ms`))
|
||||||
core.info(`Built custom golangci-lint binary in ${Date.now() - startedAt}ms`);
|
.then(() => path.join(rootDir, config.destination, config.name))
|
||||||
return path.join(rootDir, config.destination, config.name);
|
.catch((exc) => {
|
||||||
}
|
|
||||||
catch (exc) {
|
|
||||||
throw new Error(`Failed to build custom golangci-lint binary: ${exc.message}`);
|
throw new Error(`Failed to build custom golangci-lint binary: ${exc.message}`);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -97456,24 +97464,7 @@ const cache_1 = __nccwpck_require__(97377);
|
||||||
const install_1 = __nccwpck_require__(90232);
|
const install_1 = __nccwpck_require__(90232);
|
||||||
const patch_1 = __nccwpck_require__(47161);
|
const patch_1 = __nccwpck_require__(47161);
|
||||||
const plugins = __importStar(__nccwpck_require__(96067));
|
const plugins = __importStar(__nccwpck_require__(96067));
|
||||||
const execShellCommand = (0, util_1.promisify)(child_process_1.exec);
|
const execCommand = (0, util_1.promisify)(child_process_1.exec);
|
||||||
async function prepareEnv(installOnly) {
|
|
||||||
const startedAt = Date.now();
|
|
||||||
// Prepare cache, lint and go in parallel.
|
|
||||||
await (0, cache_1.restoreCache)();
|
|
||||||
let binPath = await (0, install_1.install)();
|
|
||||||
// Build custom golangci-lint if needed.
|
|
||||||
const customBinPath = await plugins.install(binPath);
|
|
||||||
if (customBinPath !== "") {
|
|
||||||
binPath = customBinPath;
|
|
||||||
}
|
|
||||||
if (installOnly) {
|
|
||||||
return { binPath, patchPath: `` };
|
|
||||||
}
|
|
||||||
const patchPath = await (0, patch_1.fetchPatch)();
|
|
||||||
core.info(`Prepared env in ${Date.now() - startedAt}ms`);
|
|
||||||
return { binPath, patchPath };
|
|
||||||
}
|
|
||||||
const printOutput = (res) => {
|
const printOutput = (res) => {
|
||||||
if (res.stdout) {
|
if (res.stdout) {
|
||||||
core.info(res.stdout);
|
core.info(res.stdout);
|
||||||
|
|
@ -97482,12 +97473,7 @@ const printOutput = (res) => {
|
||||||
core.info(res.stderr);
|
core.info(res.stderr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
async function runLint(binPath, patchPath) {
|
async function runGolangciLint(binPath, rootDir) {
|
||||||
const debug = core.getInput(`debug`);
|
|
||||||
if (debug.split(`,`).includes(`cache`)) {
|
|
||||||
const res = await execShellCommand(`${binPath} cache status`);
|
|
||||||
printOutput(res);
|
|
||||||
}
|
|
||||||
const userArgs = core.getInput(`args`);
|
const userArgs = core.getInput(`args`);
|
||||||
const addedArgs = [];
|
const addedArgs = [];
|
||||||
const userArgsList = userArgs
|
const userArgsList = userArgs
|
||||||
|
|
@ -97499,15 +97485,6 @@ async function runLint(binPath, patchPath) {
|
||||||
.map(([key, value]) => [key.toLowerCase(), value ?? ""]);
|
.map(([key, value]) => [key.toLowerCase(), value ?? ""]);
|
||||||
const userArgsMap = new Map(userArgsList);
|
const userArgsMap = new Map(userArgsList);
|
||||||
const userArgNames = new Set(userArgsList.map(([key]) => key));
|
const userArgNames = new Set(userArgsList.map(([key]) => key));
|
||||||
const problemMatchers = core.getBooleanInput(`problem-matchers`);
|
|
||||||
if (problemMatchers) {
|
|
||||||
const matchersPath = path.join(__dirname, "../..", "problem-matchers.json");
|
|
||||||
if (fs.existsSync(matchersPath)) {
|
|
||||||
// Adds problem matchers.
|
|
||||||
// https://github.com/actions/setup-go/blob/cdcb36043654635271a94b9a6d1392de5bb323a7/src/main.ts#L81-L83
|
|
||||||
core.info(`##[add-matcher]${matchersPath}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((0, patch_1.isOnlyNewIssues)()) {
|
if ((0, patch_1.isOnlyNewIssues)()) {
|
||||||
if (userArgNames.has(`new`) ||
|
if (userArgNames.has(`new`) ||
|
||||||
userArgNames.has(`new-from-rev`) ||
|
userArgNames.has(`new-from-rev`) ||
|
||||||
|
|
@ -97516,6 +97493,7 @@ async function runLint(binPath, patchPath) {
|
||||||
throw new Error(`please, don't specify manually --new* args when requesting only new issues`);
|
throw new Error(`please, don't specify manually --new* args when requesting only new issues`);
|
||||||
}
|
}
|
||||||
const ctx = github.context;
|
const ctx = github.context;
|
||||||
|
const patchPath = await (0, patch_1.fetchPatch)();
|
||||||
core.info(`only new issues on ${ctx.eventName}: ${patchPath}`);
|
core.info(`only new issues on ${ctx.eventName}: ${patchPath}`);
|
||||||
switch (ctx.eventName) {
|
switch (ctx.eventName) {
|
||||||
case `pull_request`:
|
case `pull_request`:
|
||||||
|
|
@ -97541,27 +97519,21 @@ async function runLint(binPath, patchPath) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const cmdArgs = {};
|
const cmdArgs = {};
|
||||||
const workingDirectory = core.getInput(`working-directory`);
|
if (rootDir) {
|
||||||
if (workingDirectory) {
|
|
||||||
if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) {
|
|
||||||
throw new Error(`working-directory (${workingDirectory}) was not a path`);
|
|
||||||
}
|
|
||||||
if (!userArgNames.has(`path-prefix`) && !userArgNames.has(`path-mode`)) {
|
if (!userArgNames.has(`path-prefix`) && !userArgNames.has(`path-mode`)) {
|
||||||
addedArgs.push(`--path-mode=abs`);
|
addedArgs.push(`--path-mode=abs`);
|
||||||
}
|
}
|
||||||
cmdArgs.cwd = path.resolve(workingDirectory);
|
cmdArgs.cwd = path.resolve(rootDir);
|
||||||
}
|
}
|
||||||
await runVerify(binPath, userArgsMap, cmdArgs);
|
await runVerify(binPath, userArgsMap, cmdArgs);
|
||||||
const cmd = `${binPath} run ${addedArgs.join(` `)} ${userArgs}`.trimEnd();
|
const cmd = `${binPath} run ${addedArgs.join(` `)} ${userArgs}`.trimEnd();
|
||||||
core.info(`Running [${cmd}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
core.info(`Running [${cmd}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
||||||
const startedAt = Date.now();
|
const startedAt = Date.now();
|
||||||
try {
|
return execCommand(cmd, cmdArgs)
|
||||||
const res = await execShellCommand(cmd, cmdArgs);
|
.then(printOutput)
|
||||||
printOutput(res);
|
.then(() => core.info(`golangci-lint found no issues`))
|
||||||
core.info(`golangci-lint found no issues`);
|
.catch((exc) => {
|
||||||
}
|
// This logging passes issues to GitHub annotations.
|
||||||
catch (exc) {
|
|
||||||
// This logging passes issues to GitHub annotations but comments can be more convenient for some users.
|
|
||||||
printOutput(exc);
|
printOutput(exc);
|
||||||
if (exc.code === 1) {
|
if (exc.code === 1) {
|
||||||
core.setFailed(`issues found`);
|
core.setFailed(`issues found`);
|
||||||
|
|
@ -97569,8 +97541,8 @@ async function runLint(binPath, patchPath) {
|
||||||
else {
|
else {
|
||||||
core.setFailed(`golangci-lint exit with code ${exc.code}`);
|
core.setFailed(`golangci-lint exit with code ${exc.code}`);
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`);
|
.finally(() => core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`));
|
||||||
}
|
}
|
||||||
async function runVerify(binPath, userArgsMap, cmdArgs) {
|
async function runVerify(binPath, userArgsMap, cmdArgs) {
|
||||||
const verify = core.getBooleanInput(`verify`, { required: true });
|
const verify = core.getBooleanInput(`verify`, { required: true });
|
||||||
|
|
@ -97586,8 +97558,7 @@ async function runVerify(binPath, userArgsMap, cmdArgs) {
|
||||||
cmdVerify += ` --config=${userArgsMap.get("config")}`;
|
cmdVerify += ` --config=${userArgsMap.get("config")}`;
|
||||||
}
|
}
|
||||||
core.info(`Running [${cmdVerify}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
core.info(`Running [${cmdVerify}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
||||||
const res = await execShellCommand(cmdVerify, cmdArgs);
|
await execCommand(cmdVerify, cmdArgs).then(printOutput);
|
||||||
printOutput(res);
|
|
||||||
}
|
}
|
||||||
async function getConfigPath(binPath, userArgsMap, cmdArgs) {
|
async function getConfigPath(binPath, userArgsMap, cmdArgs) {
|
||||||
let cmdConfigPath = `${binPath} config path`;
|
let cmdConfigPath = `${binPath} config path`;
|
||||||
|
|
@ -97596,22 +97567,73 @@ async function getConfigPath(binPath, userArgsMap, cmdArgs) {
|
||||||
}
|
}
|
||||||
core.info(`Running [${cmdConfigPath}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
core.info(`Running [${cmdConfigPath}] in [${cmdArgs.cwd || process.cwd()}] ...`);
|
||||||
try {
|
try {
|
||||||
const resPath = await execShellCommand(cmdConfigPath, cmdArgs);
|
const resPath = await execCommand(cmdConfigPath, cmdArgs);
|
||||||
return resPath.stderr.trim();
|
return resPath.stderr.trim();
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
return ``;
|
return ``;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function debugAction(binPath) {
|
||||||
|
const flags = core.getInput(`debug`).split(`,`);
|
||||||
|
if (flags.includes(`clean`)) {
|
||||||
|
const cmd = `${binPath} cache clean`;
|
||||||
|
core.info(`Running [${cmd}] ...`);
|
||||||
|
await execCommand(cmd).then(printOutput);
|
||||||
|
}
|
||||||
|
if (flags.includes(`cache`)) {
|
||||||
|
const cmd = `${binPath} cache status`;
|
||||||
|
core.info(`Running [${cmd}] ...`);
|
||||||
|
await execCommand(cmd).then(printOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getWorkingDirectory() {
|
||||||
|
const workingDirectory = core.getInput(`working-directory`);
|
||||||
|
if (workingDirectory) {
|
||||||
|
if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) {
|
||||||
|
throw new Error(`working-directory (${workingDirectory}) was not a path`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return workingDirectory;
|
||||||
|
}
|
||||||
|
function modulesAutoDetection(rootDir) {
|
||||||
|
const o = {
|
||||||
|
cwd: rootDir,
|
||||||
|
exclude: ["**/vendor/**", "**/node_modules/**", "**/.git/**", "**/dist/**"],
|
||||||
|
};
|
||||||
|
const matches = fs.globSync("**/go.mod", o);
|
||||||
|
const dirs = matches
|
||||||
|
.filter((m) => typeof m === "string")
|
||||||
|
.map((m) => path.resolve(rootDir, path.dirname(m)))
|
||||||
|
.sort();
|
||||||
|
return [...new Set(dirs)];
|
||||||
|
}
|
||||||
|
async function runLint(binPath) {
|
||||||
|
const workingDirectory = getWorkingDirectory();
|
||||||
|
const experimental = core.getInput(`experimental`).split(`,`);
|
||||||
|
if (experimental.includes(`automatic-module-directories`)) {
|
||||||
|
const wds = modulesAutoDetection(workingDirectory);
|
||||||
|
const cwd = process.cwd();
|
||||||
|
for (const wd of wds) {
|
||||||
|
await core.group(`run golangci-lint in ${path.relative(cwd, wd)}`, () => runGolangciLint(binPath, wd));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await core.group(`run golangci-lint`, () => runGolangciLint(binPath, workingDirectory));
|
||||||
|
}
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
const installOnly = core.getBooleanInput(`install-only`, { required: true });
|
await core.group(`Restore cache`, cache_1.restoreCache);
|
||||||
const { binPath, patchPath } = await core.group(`prepare environment`, () => prepareEnv(installOnly));
|
const binPath = await core.group(`Install`, () => (0, install_1.install)().then(plugins.install));
|
||||||
core.addPath(path.dirname(binPath));
|
core.addPath(path.dirname(binPath));
|
||||||
|
if (core.getInput(`debug`)) {
|
||||||
|
await core.group(`Debug`, () => debugAction(binPath));
|
||||||
|
}
|
||||||
|
const installOnly = core.getBooleanInput(`install-only`, { required: true });
|
||||||
if (installOnly) {
|
if (installOnly) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await core.group(`run golangci-lint`, () => runLint(binPath, patchPath));
|
await runLint(binPath);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.error(`Failed to run: ${error}, ${error.stack}`);
|
core.error(`Failed to run: ${error}, ${error.stack}`);
|
||||||
|
|
|
||||||
3
sample-monorepo/a/go.mod
Normal file
3
sample-monorepo/a/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/golangci/actiona
|
||||||
|
|
||||||
|
go 1.24.0
|
||||||
26
sample-monorepo/a/sample.go
Normal file
26
sample-monorepo/a/sample.go
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Package sample is used as test input for golangci action.
|
||||||
|
package sample
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash~
|
||||||
|
func Hash(data string) string {
|
||||||
|
retError()
|
||||||
|
retError2()
|
||||||
|
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(data))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func retError() error {
|
||||||
|
return errors.New("err")
|
||||||
|
}
|
||||||
|
|
||||||
|
func retError2() error {
|
||||||
|
return errors.New("err2")
|
||||||
|
}
|
||||||
3
sample-monorepo/a/suba/go.mod
Normal file
3
sample-monorepo/a/suba/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/golangci/actiona/suba
|
||||||
|
|
||||||
|
go 1.24.0
|
||||||
26
sample-monorepo/a/suba/sample.go
Normal file
26
sample-monorepo/a/suba/sample.go
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Package sample is used as test input for golangci action.
|
||||||
|
package sample
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash~
|
||||||
|
func Hash(data string) string {
|
||||||
|
retError()
|
||||||
|
retError2()
|
||||||
|
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(data))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func retError() error {
|
||||||
|
return errors.New("err")
|
||||||
|
}
|
||||||
|
|
||||||
|
func retError2() error {
|
||||||
|
return errors.New("err2")
|
||||||
|
}
|
||||||
3
sample-monorepo/b/go.mod
Normal file
3
sample-monorepo/b/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/golangci/actionb
|
||||||
|
|
||||||
|
go 1.24.0
|
||||||
26
sample-monorepo/b/sample.go
Normal file
26
sample-monorepo/b/sample.go
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Package sample is used as test input for golangci action.
|
||||||
|
package sample
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash~
|
||||||
|
func Hash(data string) string {
|
||||||
|
retError()
|
||||||
|
retError2()
|
||||||
|
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(data))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func retError() error {
|
||||||
|
return errors.New("err")
|
||||||
|
}
|
||||||
|
|
||||||
|
func retError2() error {
|
||||||
|
return errors.New("err2")
|
||||||
|
}
|
||||||
3
sample-monorepo/c/go.mod
Normal file
3
sample-monorepo/c/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/golangci/actionc
|
||||||
|
|
||||||
|
go 1.24.0
|
||||||
26
sample-monorepo/c/sample.go
Normal file
26
sample-monorepo/c/sample.go
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Package sample is used as test input for golangci action.
|
||||||
|
package sample
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash~
|
||||||
|
func Hash(data string) string {
|
||||||
|
retError()
|
||||||
|
retError2()
|
||||||
|
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(data))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func retError() error {
|
||||||
|
return errors.New("err")
|
||||||
|
}
|
||||||
|
|
||||||
|
func retError2() error {
|
||||||
|
return errors.New("err2")
|
||||||
|
}
|
||||||
16
src/cache.ts
16
src/cache.ts
|
|
@ -74,7 +74,10 @@ async function buildCacheKeys(): Promise<string[]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function restoreCache(): Promise<void> {
|
export async function restoreCache(): Promise<void> {
|
||||||
if (core.getBooleanInput(`skip-cache`, { required: true })) return
|
if (core.getBooleanInput(`skip-cache`, { required: true })) {
|
||||||
|
core.info(`Skipping cache restoration`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!utils.isValidEvent()) {
|
if (!utils.isValidEvent()) {
|
||||||
utils.logWarning(
|
utils.logWarning(
|
||||||
|
|
@ -116,8 +119,15 @@ export async function restoreCache(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveCache(): Promise<void> {
|
export async function saveCache(): Promise<void> {
|
||||||
if (core.getBooleanInput(`skip-cache`, { required: true })) return
|
if (core.getBooleanInput(`skip-cache`, { required: true })) {
|
||||||
if (core.getBooleanInput(`skip-save-cache`, { required: true })) return
|
core.info(`Skipping cache saving`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (core.getBooleanInput(`skip-save-cache`, { required: true })) {
|
||||||
|
core.info(`Skipping cache saving`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Validate inputs, this can cause task failure
|
// Validate inputs, this can cause task failure
|
||||||
if (!utils.isValidEvent()) {
|
if (!utils.isValidEvent()) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import * as core from "@actions/core"
|
import * as core from "@actions/core"
|
||||||
import * as tc from "@actions/tool-cache"
|
import * as tc from "@actions/tool-cache"
|
||||||
import { exec, ExecOptionsWithStringEncoding } from "child_process"
|
import { exec, ExecOptionsWithStringEncoding } from "child_process"
|
||||||
|
import fs from "fs"
|
||||||
import os from "os"
|
import os from "os"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { promisify } from "util"
|
import { promisify } from "util"
|
||||||
|
|
@ -8,7 +9,7 @@ import which from "which"
|
||||||
|
|
||||||
import { getVersion, VersionInfo } from "./version"
|
import { getVersion, VersionInfo } from "./version"
|
||||||
|
|
||||||
const execShellCommand = promisify(exec)
|
const execCommand = promisify(exec)
|
||||||
|
|
||||||
export enum InstallMode {
|
export enum InstallMode {
|
||||||
Binary = "binary",
|
Binary = "binary",
|
||||||
|
|
@ -21,13 +22,15 @@ type ExecRes = {
|
||||||
stderr: string
|
stderr: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const printOutput = (res: ExecRes): void => {
|
const printOutput = (res: ExecRes): ExecRes => {
|
||||||
if (res.stdout) {
|
if (res.stdout) {
|
||||||
core.info(res.stdout)
|
core.info(res.stdout)
|
||||||
}
|
}
|
||||||
if (res.stderr) {
|
if (res.stderr) {
|
||||||
core.info(res.stderr)
|
core.info(res.stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -36,6 +39,17 @@ const printOutput = (res: ExecRes): void => {
|
||||||
* @returns path to installed binary of golangci-lint.
|
* @returns path to installed binary of golangci-lint.
|
||||||
*/
|
*/
|
||||||
export async function install(): Promise<string> {
|
export async function install(): Promise<string> {
|
||||||
|
const problemMatchers = core.getBooleanInput(`problem-matchers`)
|
||||||
|
|
||||||
|
if (problemMatchers) {
|
||||||
|
const matchersPath = path.join(__dirname, "../..", "problem-matchers.json")
|
||||||
|
if (fs.existsSync(matchersPath)) {
|
||||||
|
// Adds problem matchers.
|
||||||
|
// https://github.com/actions/setup-go/blob/cdcb36043654635271a94b9a6d1392de5bb323a7/src/main.ts#L81-L83
|
||||||
|
core.info(`##[add-matcher]${matchersPath}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const mode = core.getInput("install-mode").toLowerCase()
|
const mode = core.getInput("install-mode").toLowerCase()
|
||||||
|
|
||||||
if (mode === InstallMode.None) {
|
if (mode === InstallMode.None) {
|
||||||
|
|
@ -84,17 +98,14 @@ async function goInstall(versionInfo: VersionInfo): Promise<string> {
|
||||||
|
|
||||||
const options: ExecOptionsWithStringEncoding = { env: { ...process.env, CGO_ENABLED: "1" } }
|
const options: ExecOptionsWithStringEncoding = { env: { ...process.env, CGO_ENABLED: "1" } }
|
||||||
|
|
||||||
const exres = await execShellCommand(
|
await execCommand(`go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`, options).then(
|
||||||
`go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`,
|
printOutput
|
||||||
options
|
|
||||||
)
|
)
|
||||||
printOutput(exres)
|
|
||||||
|
|
||||||
const res = await execShellCommand(
|
const res = await execCommand(
|
||||||
`go install -n github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`,
|
`go install -n github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${versionInfo.TargetVersion}`,
|
||||||
options
|
options
|
||||||
)
|
).then(printOutput)
|
||||||
printOutput(res)
|
|
||||||
|
|
||||||
// The output of `go install -n` when the binary is already installed is `touch <path_to_the_binary>`.
|
// The output of `go install -n` when the binary is already installed is `touch <path_to_the_binary>`.
|
||||||
const binPath = res.stderr
|
const binPath = res.stderr
|
||||||
|
|
|
||||||
10
src/patch.ts
10
src/patch.ts
|
|
@ -17,10 +17,6 @@ export function isOnlyNewIssues(): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchPatch(): Promise<string> {
|
export async function fetchPatch(): Promise<string> {
|
||||||
if (!isOnlyNewIssues()) {
|
|
||||||
return ``
|
|
||||||
}
|
|
||||||
|
|
||||||
const ctx = github.context
|
const ctx = github.context
|
||||||
|
|
||||||
switch (ctx.eventName) {
|
switch (ctx.eventName) {
|
||||||
|
|
@ -70,8 +66,7 @@ async function fetchPullRequestPatch(ctx: Context): Promise<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tempDir = await createTempDir()
|
const patchPath = await createTempDir().then((tempDir) => path.join(tempDir, "pull.patch"))
|
||||||
const patchPath = path.join(tempDir, "pull.patch")
|
|
||||||
core.info(`Writing patch to ${patchPath}`)
|
core.info(`Writing patch to ${patchPath}`)
|
||||||
await writeFile(patchPath, alterDiffPatch(patch))
|
await writeFile(patchPath, alterDiffPatch(patch))
|
||||||
return patchPath
|
return patchPath
|
||||||
|
|
@ -108,8 +103,7 @@ async function fetchPushPatch(ctx: Context): Promise<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tempDir = await createTempDir()
|
const patchPath = await createTempDir().then((tempDir) => path.join(tempDir, "push.patch"))
|
||||||
const patchPath = path.join(tempDir, "push.patch")
|
|
||||||
core.info(`Writing patch to ${patchPath}`)
|
core.info(`Writing patch to ${patchPath}`)
|
||||||
await writeFile(patchPath, alterDiffPatch(patch))
|
await writeFile(patchPath, alterDiffPatch(patch))
|
||||||
return patchPath
|
return patchPath
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import * as path from "path"
|
||||||
import { promisify } from "util"
|
import { promisify } from "util"
|
||||||
import YAML from "yaml"
|
import YAML from "yaml"
|
||||||
|
|
||||||
const execShellCommand = promisify(exec)
|
const execCommand = promisify(exec)
|
||||||
|
|
||||||
type ExecRes = {
|
type ExecRes = {
|
||||||
stdout: string
|
stdout: string
|
||||||
|
|
@ -40,7 +40,7 @@ export async function install(binPath: string): Promise<string> {
|
||||||
.find((filePath) => fs.existsSync(filePath))
|
.find((filePath) => fs.existsSync(filePath))
|
||||||
|
|
||||||
if (!configFile || configFile === "") {
|
if (!configFile || configFile === "") {
|
||||||
return ""
|
return binPath
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info(`Found configuration for the plugin module system : ${configFile}`)
|
core.info(`Found configuration for the plugin module system : ${configFile}`)
|
||||||
|
|
@ -74,18 +74,15 @@ export async function install(binPath: string): Promise<string> {
|
||||||
|
|
||||||
core.info(`Running [${cmd}] in [${rootDir}] ...`)
|
core.info(`Running [${cmd}] in [${rootDir}] ...`)
|
||||||
|
|
||||||
try {
|
const options: ExecOptionsWithStringEncoding = {
|
||||||
const options: ExecOptionsWithStringEncoding = {
|
cwd: rootDir,
|
||||||
cwd: rootDir,
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await execShellCommand(cmd, options)
|
|
||||||
printOutput(res)
|
|
||||||
|
|
||||||
core.info(`Built custom golangci-lint binary in ${Date.now() - startedAt}ms`)
|
|
||||||
|
|
||||||
return path.join(rootDir, config.destination, config.name)
|
|
||||||
} catch (exc) {
|
|
||||||
throw new Error(`Failed to build custom golangci-lint binary: ${exc.message}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return execCommand(cmd, options)
|
||||||
|
.then(printOutput)
|
||||||
|
.then(() => core.info(`Built custom golangci-lint binary in ${Date.now() - startedAt}ms`))
|
||||||
|
.then(() => path.join(rootDir, config.destination, config.name))
|
||||||
|
.catch((exc) => {
|
||||||
|
throw new Error(`Failed to build custom golangci-lint binary: ${exc.message}`)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
171
src/run.ts
171
src/run.ts
|
|
@ -10,37 +10,7 @@ import { install } from "./install"
|
||||||
import { fetchPatch, isOnlyNewIssues } from "./patch"
|
import { fetchPatch, isOnlyNewIssues } from "./patch"
|
||||||
import * as plugins from "./plugins"
|
import * as plugins from "./plugins"
|
||||||
|
|
||||||
const execShellCommand = promisify(exec)
|
const execCommand = promisify(exec)
|
||||||
|
|
||||||
type Env = {
|
|
||||||
binPath: string
|
|
||||||
patchPath: string
|
|
||||||
}
|
|
||||||
|
|
||||||
async function prepareEnv(installOnly: boolean): Promise<Env> {
|
|
||||||
const startedAt = Date.now()
|
|
||||||
|
|
||||||
// Prepare cache, lint and go in parallel.
|
|
||||||
await restoreCache()
|
|
||||||
|
|
||||||
let binPath = await install()
|
|
||||||
|
|
||||||
// Build custom golangci-lint if needed.
|
|
||||||
const customBinPath = await plugins.install(binPath)
|
|
||||||
if (customBinPath !== "") {
|
|
||||||
binPath = customBinPath
|
|
||||||
}
|
|
||||||
|
|
||||||
if (installOnly) {
|
|
||||||
return { binPath, patchPath: `` }
|
|
||||||
}
|
|
||||||
|
|
||||||
const patchPath = await fetchPatch()
|
|
||||||
|
|
||||||
core.info(`Prepared env in ${Date.now() - startedAt}ms`)
|
|
||||||
|
|
||||||
return { binPath, patchPath }
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExecRes = {
|
type ExecRes = {
|
||||||
stdout: string
|
stdout: string
|
||||||
|
|
@ -56,13 +26,7 @@ const printOutput = (res: ExecRes): void => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runLint(binPath: string, patchPath: string): Promise<void> {
|
async function runGolangciLint(binPath: string, rootDir: string): Promise<void> {
|
||||||
const debug = core.getInput(`debug`)
|
|
||||||
if (debug.split(`,`).includes(`cache`)) {
|
|
||||||
const res = await execShellCommand(`${binPath} cache status`)
|
|
||||||
printOutput(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
const userArgs = core.getInput(`args`)
|
const userArgs = core.getInput(`args`)
|
||||||
const addedArgs: string[] = []
|
const addedArgs: string[] = []
|
||||||
|
|
||||||
|
|
@ -77,17 +41,6 @@ async function runLint(binPath: string, patchPath: string): Promise<void> {
|
||||||
const userArgsMap = new Map<string, string>(userArgsList)
|
const userArgsMap = new Map<string, string>(userArgsList)
|
||||||
const userArgNames = new Set<string>(userArgsList.map(([key]) => key))
|
const userArgNames = new Set<string>(userArgsList.map(([key]) => key))
|
||||||
|
|
||||||
const problemMatchers = core.getBooleanInput(`problem-matchers`)
|
|
||||||
|
|
||||||
if (problemMatchers) {
|
|
||||||
const matchersPath = path.join(__dirname, "../..", "problem-matchers.json")
|
|
||||||
if (fs.existsSync(matchersPath)) {
|
|
||||||
// Adds problem matchers.
|
|
||||||
// https://github.com/actions/setup-go/blob/cdcb36043654635271a94b9a6d1392de5bb323a7/src/main.ts#L81-L83
|
|
||||||
core.info(`##[add-matcher]${matchersPath}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOnlyNewIssues()) {
|
if (isOnlyNewIssues()) {
|
||||||
if (
|
if (
|
||||||
userArgNames.has(`new`) ||
|
userArgNames.has(`new`) ||
|
||||||
|
|
@ -99,6 +52,7 @@ async function runLint(binPath: string, patchPath: string): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctx = github.context
|
const ctx = github.context
|
||||||
|
const patchPath = await fetchPatch()
|
||||||
|
|
||||||
core.info(`only new issues on ${ctx.eventName}: ${patchPath}`)
|
core.info(`only new issues on ${ctx.eventName}: ${patchPath}`)
|
||||||
|
|
||||||
|
|
@ -130,17 +84,12 @@ async function runLint(binPath: string, patchPath: string): Promise<void> {
|
||||||
|
|
||||||
const cmdArgs: ExecOptionsWithStringEncoding = {}
|
const cmdArgs: ExecOptionsWithStringEncoding = {}
|
||||||
|
|
||||||
const workingDirectory = core.getInput(`working-directory`)
|
if (rootDir) {
|
||||||
if (workingDirectory) {
|
|
||||||
if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) {
|
|
||||||
throw new Error(`working-directory (${workingDirectory}) was not a path`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!userArgNames.has(`path-prefix`) && !userArgNames.has(`path-mode`)) {
|
if (!userArgNames.has(`path-prefix`) && !userArgNames.has(`path-mode`)) {
|
||||||
addedArgs.push(`--path-mode=abs`)
|
addedArgs.push(`--path-mode=abs`)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdArgs.cwd = path.resolve(workingDirectory)
|
cmdArgs.cwd = path.resolve(rootDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
await runVerify(binPath, userArgsMap, cmdArgs)
|
await runVerify(binPath, userArgsMap, cmdArgs)
|
||||||
|
|
@ -150,22 +99,21 @@ async function runLint(binPath: string, patchPath: string): Promise<void> {
|
||||||
core.info(`Running [${cmd}] in [${cmdArgs.cwd || process.cwd()}] ...`)
|
core.info(`Running [${cmd}] in [${cmdArgs.cwd || process.cwd()}] ...`)
|
||||||
|
|
||||||
const startedAt = Date.now()
|
const startedAt = Date.now()
|
||||||
try {
|
|
||||||
const res = await execShellCommand(cmd, cmdArgs)
|
|
||||||
printOutput(res)
|
|
||||||
core.info(`golangci-lint found no issues`)
|
|
||||||
} catch (exc) {
|
|
||||||
// This logging passes issues to GitHub annotations but comments can be more convenient for some users.
|
|
||||||
printOutput(exc)
|
|
||||||
|
|
||||||
if (exc.code === 1) {
|
return execCommand(cmd, cmdArgs)
|
||||||
core.setFailed(`issues found`)
|
.then(printOutput)
|
||||||
} else {
|
.then(() => core.info(`golangci-lint found no issues`))
|
||||||
core.setFailed(`golangci-lint exit with code ${exc.code}`)
|
.catch((exc) => {
|
||||||
}
|
// This logging passes issues to GitHub annotations.
|
||||||
}
|
printOutput(exc)
|
||||||
|
|
||||||
core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`)
|
if (exc.code === 1) {
|
||||||
|
core.setFailed(`issues found`)
|
||||||
|
} else {
|
||||||
|
core.setFailed(`golangci-lint exit with code ${exc.code}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => core.info(`Ran golangci-lint in ${Date.now() - startedAt}ms`))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runVerify(binPath: string, userArgsMap: Map<string, string>, cmdArgs: ExecOptionsWithStringEncoding): Promise<void> {
|
async function runVerify(binPath: string, userArgsMap: Map<string, string>, cmdArgs: ExecOptionsWithStringEncoding): Promise<void> {
|
||||||
|
|
@ -186,8 +134,7 @@ async function runVerify(binPath: string, userArgsMap: Map<string, string>, cmdA
|
||||||
|
|
||||||
core.info(`Running [${cmdVerify}] in [${cmdArgs.cwd || process.cwd()}] ...`)
|
core.info(`Running [${cmdVerify}] in [${cmdArgs.cwd || process.cwd()}] ...`)
|
||||||
|
|
||||||
const res = await execShellCommand(cmdVerify, cmdArgs)
|
await execCommand(cmdVerify, cmdArgs).then(printOutput)
|
||||||
printOutput(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getConfigPath(binPath: string, userArgsMap: Map<string, string>, cmdArgs: ExecOptionsWithStringEncoding): Promise<string> {
|
async function getConfigPath(binPath: string, userArgsMap: Map<string, string>, cmdArgs: ExecOptionsWithStringEncoding): Promise<string> {
|
||||||
|
|
@ -199,26 +146,98 @@ async function getConfigPath(binPath: string, userArgsMap: Map<string, string>,
|
||||||
core.info(`Running [${cmdConfigPath}] in [${cmdArgs.cwd || process.cwd()}] ...`)
|
core.info(`Running [${cmdConfigPath}] in [${cmdArgs.cwd || process.cwd()}] ...`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resPath = await execShellCommand(cmdConfigPath, cmdArgs)
|
const resPath = await execCommand(cmdConfigPath, cmdArgs)
|
||||||
return resPath.stderr.trim()
|
return resPath.stderr.trim()
|
||||||
} catch {
|
} catch {
|
||||||
return ``
|
return ``
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function debugAction(binPath: string) {
|
||||||
|
const flags = core.getInput(`debug`).split(`,`)
|
||||||
|
|
||||||
|
if (flags.includes(`clean`)) {
|
||||||
|
const cmd = `${binPath} cache clean`
|
||||||
|
|
||||||
|
core.info(`Running [${cmd}] ...`)
|
||||||
|
|
||||||
|
await execCommand(cmd).then(printOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.includes(`cache`)) {
|
||||||
|
const cmd = `${binPath} cache status`
|
||||||
|
|
||||||
|
core.info(`Running [${cmd}] ...`)
|
||||||
|
|
||||||
|
await execCommand(cmd).then(printOutput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWorkingDirectory(): string {
|
||||||
|
const workingDirectory = core.getInput(`working-directory`)
|
||||||
|
if (workingDirectory) {
|
||||||
|
if (!fs.existsSync(workingDirectory) || !fs.lstatSync(workingDirectory).isDirectory()) {
|
||||||
|
throw new Error(`working-directory (${workingDirectory}) was not a path`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return workingDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
function modulesAutoDetection(rootDir: string): string[] {
|
||||||
|
const o: fs.GlobOptions = {
|
||||||
|
cwd: rootDir,
|
||||||
|
exclude: ["**/vendor/**", "**/node_modules/**", "**/.git/**", "**/dist/**"],
|
||||||
|
}
|
||||||
|
|
||||||
|
const matches = fs.globSync("**/go.mod", o)
|
||||||
|
|
||||||
|
const dirs = matches
|
||||||
|
.filter((m) => typeof m === "string")
|
||||||
|
.map((m) => path.resolve(rootDir, path.dirname(m)))
|
||||||
|
.sort()
|
||||||
|
|
||||||
|
return [...new Set(dirs)]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runLint(binPath: string): Promise<void> {
|
||||||
|
const workingDirectory = getWorkingDirectory()
|
||||||
|
|
||||||
|
const experimental = core.getInput(`experimental`).split(`,`)
|
||||||
|
|
||||||
|
if (experimental.includes(`automatic-module-directories`)) {
|
||||||
|
const wds = modulesAutoDetection(workingDirectory)
|
||||||
|
|
||||||
|
const cwd = process.cwd()
|
||||||
|
|
||||||
|
for (const wd of wds) {
|
||||||
|
await core.group(`run golangci-lint in ${path.relative(cwd, wd)}`, () => runGolangciLint(binPath, wd))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await core.group(`run golangci-lint`, () => runGolangciLint(binPath, workingDirectory))
|
||||||
|
}
|
||||||
|
|
||||||
export async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const installOnly = core.getBooleanInput(`install-only`, { required: true })
|
await core.group(`Restore cache`, restoreCache)
|
||||||
|
|
||||||
const { binPath, patchPath } = await core.group(`prepare environment`, () => prepareEnv(installOnly))
|
const binPath = await core.group(`Install`, () => install().then(plugins.install))
|
||||||
|
|
||||||
core.addPath(path.dirname(binPath))
|
core.addPath(path.dirname(binPath))
|
||||||
|
|
||||||
|
if (core.getInput(`debug`)) {
|
||||||
|
await core.group(`Debug`, () => debugAction(binPath))
|
||||||
|
}
|
||||||
|
|
||||||
|
const installOnly = core.getBooleanInput(`install-only`, { required: true })
|
||||||
if (installOnly) {
|
if (installOnly) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await core.group(`run golangci-lint`, () => runLint(binPath, patchPath))
|
await runLint(binPath)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.error(`Failed to run: ${error}, ${error.stack}`)
|
core.error(`Failed to run: ${error}, ${error.stack}`)
|
||||||
core.setFailed(error.message)
|
core.setFailed(error.message)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue