Compare commits

..

12 Commits
v4 ... v5.1.0

8 changed files with 429 additions and 254 deletions

View File

@ -3,13 +3,15 @@
[![Build Status](https://github.com/golangci/golangci-lint-action/workflows/build-and-test/badge.svg)](https://github.com/golangci/golangci-lint-action/actions) [![Build Status](https://github.com/golangci/golangci-lint-action/workflows/build-and-test/badge.svg)](https://github.com/golangci/golangci-lint-action/actions)
It's the official GitHub action for [golangci-lint](https://github.com/golangci/golangci-lint) from its authors. It's the official GitHub action for [golangci-lint](https://github.com/golangci/golangci-lint) from its authors.
The action runs [golangci-lint](https://github.com/golangci/golangci-lint) and reports issues from linters. The action runs [golangci-lint](https://github.com/golangci/golangci-lint) and reports issues from linters.
![GitHub Annotations](./static/annotations.png) ![GitHub Annotations](./static/annotations.png)
## Compatibility ## Compatibility
* `v4.0.0+` requires an explicit setup-go installation step before using this action: `uses: actions/setup-go@v5`. * `v5.0.0+` removes `skip-pkg-cache` and `skip-build-cache` because the cache related to Go itself is already handled by `actions/setup-go`.
* `v4.0.0+` requires an explicit `actions/setup-go` installation step before using this action: `uses: actions/setup-go@v5`.
The `skip-go-installation` option has been removed. The `skip-go-installation` option has been removed.
* `v2.0.0+` works with `golangci-lint` version >= `v1.28.3` * `v2.0.0+` works with `golangci-lint` version >= `v1.28.3`
* `v1.2.2` is deprecated due to we forgot to change the minimum version of `golangci-lint` to `v1.28.3` ([issue](https://github.com/golangci/golangci-lint-action/issues/39)) * `v1.2.2` is deprecated due to we forgot to change the minimum version of `golangci-lint` to `v1.28.3` ([issue](https://github.com/golangci/golangci-lint-action/issues/39))
@ -24,8 +26,8 @@ name: golangci-lint
on: on:
push: push:
branches: branches:
- master
- main - main
- master
pull_request: pull_request:
permissions: permissions:
@ -42,14 +44,13 @@ jobs:
- uses: actions/setup-go@v5 - uses: actions/setup-go@v5
with: with:
go-version: '1.21' go-version: '1.21'
cache: false
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v4 uses: golangci/golangci-lint-action@v5
with: with:
# Require: The version of golangci-lint to use. # Require: The version of golangci-lint to use.
# When `install-mode` is `binary` (default) the value can be v1.2 or v1.2.3 or `latest` to use the latest version. # When `install-mode` is `binary` (default) the value can be v1.2 or v1.2.3 or `latest` to use the latest version.
# When `install-mode` is `goinstall` the value can be v1.2.3, `latest`, or the hash of a commit. # When `install-mode` is `goinstall` the value can be v1.2.3, `latest`, or the hash of a commit.
version: v1.54 version: v1.57
# Optional: working directory, useful for monorepos # Optional: working directory, useful for monorepos
# working-directory: somedir # working-directory: somedir
@ -60,37 +61,39 @@ jobs:
# The location of the configuration file can be changed by using `--config=` # The location of the configuration file can be changed by using `--config=`
# args: --timeout=30m --config=/my/path/.golangci.yml --issues-exit-code=0 # args: --timeout=30m --config=/my/path/.golangci.yml --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`. # Optional: Show only new issues.
# If you are using `merge_group` event (merge queue) you should add the option `fetch-depth: 0` to `actions/checkout` step.
# The default value is `false`.
# only-new-issues: true # only-new-issues: true
# Optional: if set to true, then all caching functionality will be completely disabled, # Optional: if set to true, then all caching functionality will be completely disabled,
# takes precedence over all other caching options. # takes precedence over all other caching options.
# skip-cache: true # skip-cache: true
# Optional: if set to true, then the action won't cache or restore ~/go/pkg. # Optional: if set to true, caches will not be saved, but they may still be restored,
# skip-pkg-cache: true # subject to other options
# skip-save-cache: true
# Optional: if set to true, then the action won't cache or restore ~/.cache/go-build.
# skip-build-cache: true
# Optional: The mode to install golangci-lint. It can be 'binary' or 'goinstall'. # Optional: The mode to install golangci-lint. It can be 'binary' or 'goinstall'.
# install-mode: "goinstall" # install-mode: "goinstall"
``` ```
We recommend running this action in a job separate from other jobs (`go test`, etc) We recommend running this action in a job separate from other jobs (`go test`, etc.)
because different jobs [run in parallel](https://help.github.com/en/actions/getting-started-with-github-actions/core-concepts-for-github-actions#job). because different jobs [run in parallel](https://help.github.com/en/actions/getting-started-with-github-actions/core-concepts-for-github-actions#job).
### Multiple OS Support ### Multiple OS Support
If you need to run linters for specific operating systems, you will need to use the action `>=v2`. Here is a sample configuration file: If you need to run linters for specific operating systems, you will need to use the action `>=v2`.
Here is a sample configuration file:
```yaml ```yaml
name: golangci-lint name: golangci-lint
on: on:
push: push:
branches: branches:
- master
- main - main
- master
pull_request: pull_request:
permissions: permissions:
@ -103,7 +106,7 @@ jobs:
strategy: strategy:
matrix: matrix:
go: ['1.21'] go: ['1.21']
os: [macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
name: lint name: lint
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
@ -111,28 +114,37 @@ jobs:
- uses: actions/setup-go@v5 - uses: actions/setup-go@v5
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}
cache: false
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v4 uses: golangci/golangci-lint-action@v5
with: with:
# Require: The version of golangci-lint to use. # Require: The version of golangci-lint to use.
# When `install-mode` is `binary` (default) the value can be v1.2 or v1.2.3 or `latest` to use the latest version. # When `install-mode` is `binary` (default) the value can be v1.2 or v1.2.3 or `latest` to use the latest version.
# When `install-mode` is `goinstall` the value can be v1.2.3, `latest`, or the hash of a commit. # When `install-mode` is `goinstall` the value can be v1.2.3, `latest`, or the hash of a commit.
version: v1.54 version: v1.57
# Optional: working directory, useful for monorepos # Optional: working directory, useful for monorepos
# working-directory: somedir # working-directory: somedir
# Optional: golangci-lint command line arguments. # Optional: golangci-lint command line arguments.
# #
# Note: by default the `.golangci.yml` file should be at the root of the repository. # Note: By default, the `.golangci.yml` file should be at the root of the repository.
# The location of the configuration file can be changed by using `--config=` # The location of the configuration file can be changed by using `--config=`
# args: --timeout=30m --config=/my/path/.golangci.yml --issues-exit-code=0 # args: --timeout=30m --config=/my/path/.golangci.yml --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`. # Optional: Show only new issues.
# If you are using `merge_group` event (merge queue) you should add the option `fetch-depth: 0` to `actions/checkout` step.
# The default value is `false`.
# only-new-issues: true # only-new-issues: true
# Optional:The mode to install golangci-lint. It can be 'binary' or 'goinstall'. # Optional: if set to true, then all caching functionality will be completely disabled,
# takes precedence over all other caching options.
# skip-cache: true
# Optional: if set to true, caches will not be saved, but they may still be restored,
# subject to other options
# skip-save-cache: true
# Optional: The mode to install golangci-lint. It can be 'binary' or 'goinstall'.
# install-mode: "goinstall" # install-mode: "goinstall"
``` ```
@ -148,8 +160,9 @@ Currently, GitHub parses the action's output and creates [annotations](https://g
The restrictions of annotations are the following: The restrictions of annotations are the following:
1. Currently, they don't support markdown formatting (see the [feature request](https://github.community/t5/GitHub-API-Development-and/Checks-Ability-to-include-Markdown-in-line-annotations/m-p/56704)) 1. Currently, they don't support Markdown formatting (see the [feature request](https://github.community/t5/GitHub-API-Development-and/Checks-Ability-to-include-Markdown-in-line-annotations/m-p/56704))
2. They aren't shown in the list of comments like it was with [golangci.com](https://golangci.com). If you would like to have comments - please, up-vote [the issue](https://github.com/golangci/golangci-lint-action/issues/5). 2. They aren't shown in the list of comments.
If you would like to have comments - please, up-vote [the issue](https://github.com/golangci/golangci-lint-action/issues/5).
To enable annotations, you need to add the `checks' permission to your action. To enable annotations, you need to add the `checks' permission to your action.
@ -167,9 +180,9 @@ permissions:
The action was implemented with performance in mind: The action was implemented with performance in mind:
1. We cache data by [@actions/cache](https://github.com/actions/toolkit/tree/master/packages/cache) between builds: Go build cache, Go modules cache, golangci-lint analysis cache. 1. We cache data from golangci-lint analysis between builds by using [@actions/cache](https://github.com/actions/toolkit/tree/master/packages/cache).
2. We don't use Docker because image pulling is slow. 2. We don't use Docker because image pulling is slow.
3. We do as much as we can in parallel, e.g. we download cache, go, and golangci-lint binary in parallel. 3. We do as much as we can in parallel, e.g. we download cache, and golangci-lint binary in parallel.
For example, in a repository of [golangci-lint](https://github.com/golangci/golangci-lint) running this action without the cache takes 50s, but with cache takes 14s: For example, in a repository of [golangci-lint](https://github.com/golangci/golangci-lint) running this action without the cache takes 50s, but with cache takes 14s:
* in parallel: * in parallel:
@ -179,9 +192,10 @@ For example, in a repository of [golangci-lint](https://github.com/golangci/gola
## Internals ## Internals
We use JavaScript-based action. We don't use Docker-based action because: We use JavaScript-based action.
We don't use Docker-based action because:
1. docker pulling is slow currently 1. Docker pulling is slow currently
2. it's easier to use caching from [@actions/cache](https://github.com/actions/toolkit/tree/master/packages/cache) 2. it's easier to use caching from [@actions/cache](https://github.com/actions/toolkit/tree/master/packages/cache)
We support different platforms, such as `ubuntu`, `macos`, and `windows` with `x32` and `x64` archs. We support different platforms, such as `ubuntu`, `macos`, and `windows` with `x32` and `x64` archs.
@ -190,17 +204,20 @@ Inside our action, we perform 3 steps:
1. Setup environment running in parallel: 1. Setup environment running in parallel:
* restore [cache](https://github.com/actions/cache) of previous analyses * restore [cache](https://github.com/actions/cache) of previous analyses
* fetch [action config](https://github.com/golangci/golangci-lint/blob/master/assets/github-action-config.json) and find the latest `golangci-lint` patch version * fetch [action config](https://github.com/golangci/golangci-lint/blob/master/assets/github-action-config.json) and find the latest `golangci-lint` patch version for needed version
for needed version (users of this action can specify only minor version of `golangci-lint`). After that install [golangci-lint](https://github.com/golangci/golangci-lint) using [@actions/tool-cache](https://github.com/actions/toolkit/tree/master/packages/tool-cache) (users of this action can specify only minor version of `golangci-lint`).
After that install [golangci-lint](https://github.com/golangci/golangci-lint) using [@actions/tool-cache](https://github.com/actions/toolkit/tree/master/packages/tool-cache)
2. Run `golangci-lint` with specified by user `args` 2. Run `golangci-lint` with specified by user `args`
3. Save cache for later builds 3. Save cache for later builds
### Caching internals ### Caching internals
1. We save and restore the following directories: `~/.cache/golangci-lint`, `~/.cache/go-build`, `~/go/pkg`. 1. We save and restore the following directory: `~/.cache/golangci-lint`.
2. The primary caching key looks like `golangci-lint.cache-{interval_number}-{go.mod_hash}`. Interval number ensures that we periodically invalidate 2. The primary caching key looks like `golangci-lint.cache-{interval_number}-{go.mod_hash}`.
our cache (every 7 days). `go.mod` hash ensures that we invalidate the cache early - as soon as dependencies have changed. Interval number ensures that we periodically invalidate our cache (every 7 days).
3. We use [restore keys](https://help.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key): `golangci-lint.cache-{interval_number}-`. GitHub matches keys by prefix if we have no exact match for the primary cache. `go.mod` hash ensures that we invalidate the cache early - as soon as dependencies have changed.
3. We use [restore keys](https://help.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key): `golangci-lint.cache-{interval_number}-`.
GitHub matches keys by prefix if we have no exact match for the primary cache.
This scheme is basic and needs improvements. Pull requests and ideas are welcome. This scheme is basic and needs improvements. Pull requests and ideas are welcome.

View File

@ -29,12 +29,10 @@ inputs:
takes precedence over all other caching options. takes precedence over all other caching options.
default: 'false' default: 'false'
required: false required: false
skip-pkg-cache: skip-save-cache:
description: "if set to true then the action doesn't cache or restore ~/go/pkg." description: |
default: 'false' if set to true then the action will not save any caches, but it may still
required: false restore existing caches, subject to other options.
skip-build-cache:
description: "if set to true then the action doesn't cache or restore ~/.cache/go-build."
default: 'false' default: 'false'
required: false required: false
install-mode: install-mode:

119
dist/post_run/index.js generated vendored
View File

@ -88813,25 +88813,6 @@ const pathExists = async (path) => !!(await fs.promises.stat(path).catch(() => f
const getLintCacheDir = () => { const getLintCacheDir = () => {
return path_1.default.resolve(`${process.env.HOME}/.cache/golangci-lint`); return path_1.default.resolve(`${process.env.HOME}/.cache/golangci-lint`);
}; };
const getCacheDirs = () => {
// Not existing dirs are ok here: it works.
const skipPkgCache = core.getInput(`skip-pkg-cache`, { required: true }).trim();
const skipBuildCache = core.getInput(`skip-build-cache`, { required: true }).trim();
const dirs = [getLintCacheDir()];
if (skipBuildCache.toLowerCase() == "true") {
core.info(`Omitting ~/.cache/go-build from cache directories`);
}
else {
dirs.push(path_1.default.resolve(`${process.env.HOME}/.cache/go-build`));
}
if (skipPkgCache.toLowerCase() == "true") {
core.info(`Omitting ~/go/pkg from cache directories`);
}
else {
dirs.push(path_1.default.resolve(`${process.env.HOME}/go/pkg`));
}
return dirs;
};
const getIntervalKey = (invalidationIntervalDays) => { const getIntervalKey = (invalidationIntervalDays) => {
const now = new Date(); const now = new Date();
const secondsSinceEpoch = now.getTime() / 1000; const secondsSinceEpoch = now.getTime() / 1000;
@ -88878,7 +88859,7 @@ async function restoreCache() {
} }
core.saveState(constants_1.State.CachePrimaryKey, primaryKey); core.saveState(constants_1.State.CachePrimaryKey, primaryKey);
try { try {
const cacheKey = await cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys); const cacheKey = await cache.restoreCache([getLintCacheDir()], primaryKey, restoreKeys);
if (!cacheKey) { if (!cacheKey) {
core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`); core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`);
return; return;
@ -88900,13 +88881,15 @@ exports.restoreCache = restoreCache;
async function saveCache() { async function saveCache() {
if (core.getInput(`skip-cache`, { required: true }).trim() == "true") if (core.getInput(`skip-cache`, { required: true }).trim() == "true")
return; return;
if (core.getInput(`skip-save-cache`, { required: true }).trim() == "true")
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.`);
return; return;
} }
const startedAt = Date.now(); const startedAt = Date.now();
const cacheDirs = getCacheDirs(); const cacheDirs = [getLintCacheDir()];
const primaryKey = core.getState(constants_1.State.CachePrimaryKey); const primaryKey = core.getState(constants_1.State.CachePrimaryKey);
if (!primaryKey) { if (!primaryKey) {
utils.logWarning(`Error retrieving key from state.`); utils.logWarning(`Error retrieving key from state.`);
@ -89163,26 +89146,40 @@ const version_1 = __nccwpck_require__(1946);
const execShellCommand = (0, util_1.promisify)(child_process_1.exec); const execShellCommand = (0, util_1.promisify)(child_process_1.exec);
const writeFile = (0, util_1.promisify)(fs.writeFile); const writeFile = (0, util_1.promisify)(fs.writeFile);
const createTempDir = (0, util_1.promisify)(tmp_1.dir); const createTempDir = (0, util_1.promisify)(tmp_1.dir);
function isOnlyNewIssues() {
const onlyNewIssues = core.getInput(`only-new-issues`, { required: true }).trim();
if (onlyNewIssues !== `false` && onlyNewIssues !== `true`) {
throw new Error(`invalid value of "only-new-issues": "${onlyNewIssues}", expected "true" or "false"`);
}
return onlyNewIssues === `true`;
}
async function prepareLint() { async function prepareLint() {
const mode = core.getInput("install-mode").toLowerCase(); const mode = core.getInput("install-mode").toLowerCase();
const versionConfig = await (0, version_1.findLintVersion)(mode); const versionConfig = await (0, version_1.findLintVersion)(mode);
return await (0, install_1.installLint)(versionConfig, mode); return await (0, install_1.installLint)(versionConfig, mode);
} }
async function fetchPatch() { async function fetchPatch() {
const onlyNewIssues = core.getInput(`only-new-issues`, { required: true }).trim(); if (!isOnlyNewIssues()) {
if (onlyNewIssues !== `false` && onlyNewIssues !== `true`) {
throw new Error(`invalid value of "only-new-issues": "${onlyNewIssues}", expected "true" or "false"`);
}
if (onlyNewIssues === `false`) {
return ``; return ``;
} }
const ctx = github.context; const ctx = github.context;
if (ctx.eventName !== `pull_request`) { switch (ctx.eventName) {
case `pull_request`:
case `pull_request_target`:
return await fetchPullRequestPatch(ctx);
case `push`:
return await fetchPushPatch(ctx);
case `merge_group`:
core.info(JSON.stringify(ctx.payload));
return ``;
default:
core.info(`Not fetching patch for showing only new issues because it's not a pull request context: event name is ${ctx.eventName}`); core.info(`Not fetching patch for showing only new issues because it's not a pull request context: event name is ${ctx.eventName}`);
return ``; return ``;
} }
const pull = ctx.payload.pull_request; }
if (!pull) { async function fetchPullRequestPatch(ctx) {
const pr = ctx.payload.pull_request;
if (!pr) {
core.warning(`No pull request in context`); core.warning(`No pull request in context`);
return ``; return ``;
} }
@ -89192,7 +89189,7 @@ async function fetchPatch() {
const patchResp = await octokit.rest.pulls.get({ const patchResp = await octokit.rest.pulls.get({
owner: ctx.repo.owner, owner: ctx.repo.owner,
repo: ctx.repo.repo, repo: ctx.repo.repo,
[`pull_number`]: pull.number, [`pull_number`]: pr.number,
mediaType: { mediaType: {
format: `diff`, format: `diff`,
}, },
@ -89220,14 +89217,48 @@ async function fetchPatch() {
return ``; // don't fail the action, but analyze without patch return ``; // don't fail the action, but analyze without patch
} }
} }
async function fetchPushPatch(ctx) {
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }));
let patch;
try {
const patchResp = await octokit.rest.repos.compareCommits({
owner: ctx.repo.owner,
repo: ctx.repo.repo,
base: ctx.payload.before,
head: ctx.payload.after,
mediaType: {
format: `diff`,
},
});
if (patchResp.status !== 200) {
core.warning(`failed to fetch push patch: response status is ${patchResp.status}`);
return ``; // don't fail the action, but analyze without patch
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
patch = patchResp.data;
}
catch (err) {
console.warn(`failed to fetch push patch:`, err);
return ``; // don't fail the action, but analyze without patch
}
try {
const tempDir = await createTempDir();
const patchPath = path.join(tempDir, "push.patch");
core.info(`Writing patch to ${patchPath}`);
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
return patchPath;
}
catch (err) {
console.warn(`failed to save pull request patch:`, err);
return ``; // don't fail the action, but analyze without patch
}
}
async function prepareEnv() { async function prepareEnv() {
const startedAt = Date.now(); const startedAt = Date.now();
// Prepare cache, lint and go in parallel. // Prepare cache, lint and go in parallel.
await (0, cache_1.restoreCache)(); await (0, cache_1.restoreCache)();
const prepareLintPromise = prepareLint(); const lintPath = await prepareLint();
const patchPromise = fetchPatch(); const patchPath = await fetchPatch();
const lintPath = await prepareLintPromise;
const patchPath = await patchPromise;
core.info(`Prepared env in ${Date.now() - startedAt}ms`); core.info(`Prepared env in ${Date.now() - startedAt}ms`);
return { lintPath, patchPath }; return { lintPath, patchPath };
} }
@ -89265,15 +89296,33 @@ async function runLint(lintPath, patchPath) {
.join(","); .join(",");
addedArgs.push(`--out-format=${formats}`); addedArgs.push(`--out-format=${formats}`);
userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim(); userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim();
if (patchPath) { if (isOnlyNewIssues()) {
if (userArgNames.has(`new`) || userArgNames.has(`new-from-rev`) || userArgNames.has(`new-from-patch`)) { if (userArgNames.has(`new`) || userArgNames.has(`new-from-rev`) || userArgNames.has(`new-from-patch`)) {
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;
core.info(`only new issues on ${ctx.eventName}: ${patchPath}`);
switch (ctx.eventName) {
case `pull_request`:
case `pull_request_target`:
case `push`:
if (patchPath) {
addedArgs.push(`--new-from-patch=${patchPath}`); addedArgs.push(`--new-from-patch=${patchPath}`);
// Override config values. // Override config values.
addedArgs.push(`--new=false`); addedArgs.push(`--new=false`);
addedArgs.push(`--new-from-rev=`); addedArgs.push(`--new-from-rev=`);
} }
break;
case `merge_group`:
addedArgs.push(`--new-from-rev=${ctx.payload.merge_group.base_sha}`);
// Override config values.
addedArgs.push(`--new=false`);
addedArgs.push(`--new-from-patch=`);
break;
default:
break;
}
}
const workingDirectory = core.getInput(`working-directory`); const workingDirectory = core.getInput(`working-directory`);
const cmdArgs = {}; const cmdArgs = {};
if (workingDirectory) { if (workingDirectory) {

119
dist/run/index.js generated vendored
View File

@ -88813,25 +88813,6 @@ const pathExists = async (path) => !!(await fs.promises.stat(path).catch(() => f
const getLintCacheDir = () => { const getLintCacheDir = () => {
return path_1.default.resolve(`${process.env.HOME}/.cache/golangci-lint`); return path_1.default.resolve(`${process.env.HOME}/.cache/golangci-lint`);
}; };
const getCacheDirs = () => {
// Not existing dirs are ok here: it works.
const skipPkgCache = core.getInput(`skip-pkg-cache`, { required: true }).trim();
const skipBuildCache = core.getInput(`skip-build-cache`, { required: true }).trim();
const dirs = [getLintCacheDir()];
if (skipBuildCache.toLowerCase() == "true") {
core.info(`Omitting ~/.cache/go-build from cache directories`);
}
else {
dirs.push(path_1.default.resolve(`${process.env.HOME}/.cache/go-build`));
}
if (skipPkgCache.toLowerCase() == "true") {
core.info(`Omitting ~/go/pkg from cache directories`);
}
else {
dirs.push(path_1.default.resolve(`${process.env.HOME}/go/pkg`));
}
return dirs;
};
const getIntervalKey = (invalidationIntervalDays) => { const getIntervalKey = (invalidationIntervalDays) => {
const now = new Date(); const now = new Date();
const secondsSinceEpoch = now.getTime() / 1000; const secondsSinceEpoch = now.getTime() / 1000;
@ -88878,7 +88859,7 @@ async function restoreCache() {
} }
core.saveState(constants_1.State.CachePrimaryKey, primaryKey); core.saveState(constants_1.State.CachePrimaryKey, primaryKey);
try { try {
const cacheKey = await cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys); const cacheKey = await cache.restoreCache([getLintCacheDir()], primaryKey, restoreKeys);
if (!cacheKey) { if (!cacheKey) {
core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`); core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`);
return; return;
@ -88900,13 +88881,15 @@ exports.restoreCache = restoreCache;
async function saveCache() { async function saveCache() {
if (core.getInput(`skip-cache`, { required: true }).trim() == "true") if (core.getInput(`skip-cache`, { required: true }).trim() == "true")
return; return;
if (core.getInput(`skip-save-cache`, { required: true }).trim() == "true")
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.`);
return; return;
} }
const startedAt = Date.now(); const startedAt = Date.now();
const cacheDirs = getCacheDirs(); const cacheDirs = [getLintCacheDir()];
const primaryKey = core.getState(constants_1.State.CachePrimaryKey); const primaryKey = core.getState(constants_1.State.CachePrimaryKey);
if (!primaryKey) { if (!primaryKey) {
utils.logWarning(`Error retrieving key from state.`); utils.logWarning(`Error retrieving key from state.`);
@ -89163,26 +89146,40 @@ const version_1 = __nccwpck_require__(1946);
const execShellCommand = (0, util_1.promisify)(child_process_1.exec); const execShellCommand = (0, util_1.promisify)(child_process_1.exec);
const writeFile = (0, util_1.promisify)(fs.writeFile); const writeFile = (0, util_1.promisify)(fs.writeFile);
const createTempDir = (0, util_1.promisify)(tmp_1.dir); const createTempDir = (0, util_1.promisify)(tmp_1.dir);
function isOnlyNewIssues() {
const onlyNewIssues = core.getInput(`only-new-issues`, { required: true }).trim();
if (onlyNewIssues !== `false` && onlyNewIssues !== `true`) {
throw new Error(`invalid value of "only-new-issues": "${onlyNewIssues}", expected "true" or "false"`);
}
return onlyNewIssues === `true`;
}
async function prepareLint() { async function prepareLint() {
const mode = core.getInput("install-mode").toLowerCase(); const mode = core.getInput("install-mode").toLowerCase();
const versionConfig = await (0, version_1.findLintVersion)(mode); const versionConfig = await (0, version_1.findLintVersion)(mode);
return await (0, install_1.installLint)(versionConfig, mode); return await (0, install_1.installLint)(versionConfig, mode);
} }
async function fetchPatch() { async function fetchPatch() {
const onlyNewIssues = core.getInput(`only-new-issues`, { required: true }).trim(); if (!isOnlyNewIssues()) {
if (onlyNewIssues !== `false` && onlyNewIssues !== `true`) {
throw new Error(`invalid value of "only-new-issues": "${onlyNewIssues}", expected "true" or "false"`);
}
if (onlyNewIssues === `false`) {
return ``; return ``;
} }
const ctx = github.context; const ctx = github.context;
if (ctx.eventName !== `pull_request`) { switch (ctx.eventName) {
case `pull_request`:
case `pull_request_target`:
return await fetchPullRequestPatch(ctx);
case `push`:
return await fetchPushPatch(ctx);
case `merge_group`:
core.info(JSON.stringify(ctx.payload));
return ``;
default:
core.info(`Not fetching patch for showing only new issues because it's not a pull request context: event name is ${ctx.eventName}`); core.info(`Not fetching patch for showing only new issues because it's not a pull request context: event name is ${ctx.eventName}`);
return ``; return ``;
} }
const pull = ctx.payload.pull_request; }
if (!pull) { async function fetchPullRequestPatch(ctx) {
const pr = ctx.payload.pull_request;
if (!pr) {
core.warning(`No pull request in context`); core.warning(`No pull request in context`);
return ``; return ``;
} }
@ -89192,7 +89189,7 @@ async function fetchPatch() {
const patchResp = await octokit.rest.pulls.get({ const patchResp = await octokit.rest.pulls.get({
owner: ctx.repo.owner, owner: ctx.repo.owner,
repo: ctx.repo.repo, repo: ctx.repo.repo,
[`pull_number`]: pull.number, [`pull_number`]: pr.number,
mediaType: { mediaType: {
format: `diff`, format: `diff`,
}, },
@ -89220,14 +89217,48 @@ async function fetchPatch() {
return ``; // don't fail the action, but analyze without patch return ``; // don't fail the action, but analyze without patch
} }
} }
async function fetchPushPatch(ctx) {
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }));
let patch;
try {
const patchResp = await octokit.rest.repos.compareCommits({
owner: ctx.repo.owner,
repo: ctx.repo.repo,
base: ctx.payload.before,
head: ctx.payload.after,
mediaType: {
format: `diff`,
},
});
if (patchResp.status !== 200) {
core.warning(`failed to fetch push patch: response status is ${patchResp.status}`);
return ``; // don't fail the action, but analyze without patch
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
patch = patchResp.data;
}
catch (err) {
console.warn(`failed to fetch push patch:`, err);
return ``; // don't fail the action, but analyze without patch
}
try {
const tempDir = await createTempDir();
const patchPath = path.join(tempDir, "push.patch");
core.info(`Writing patch to ${patchPath}`);
await writeFile(patchPath, (0, diffUtils_1.alterDiffPatch)(patch));
return patchPath;
}
catch (err) {
console.warn(`failed to save pull request patch:`, err);
return ``; // don't fail the action, but analyze without patch
}
}
async function prepareEnv() { async function prepareEnv() {
const startedAt = Date.now(); const startedAt = Date.now();
// Prepare cache, lint and go in parallel. // Prepare cache, lint and go in parallel.
await (0, cache_1.restoreCache)(); await (0, cache_1.restoreCache)();
const prepareLintPromise = prepareLint(); const lintPath = await prepareLint();
const patchPromise = fetchPatch(); const patchPath = await fetchPatch();
const lintPath = await prepareLintPromise;
const patchPath = await patchPromise;
core.info(`Prepared env in ${Date.now() - startedAt}ms`); core.info(`Prepared env in ${Date.now() - startedAt}ms`);
return { lintPath, patchPath }; return { lintPath, patchPath };
} }
@ -89265,15 +89296,33 @@ async function runLint(lintPath, patchPath) {
.join(","); .join(",");
addedArgs.push(`--out-format=${formats}`); addedArgs.push(`--out-format=${formats}`);
userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim(); userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim();
if (patchPath) { if (isOnlyNewIssues()) {
if (userArgNames.has(`new`) || userArgNames.has(`new-from-rev`) || userArgNames.has(`new-from-patch`)) { if (userArgNames.has(`new`) || userArgNames.has(`new-from-rev`) || userArgNames.has(`new-from-patch`)) {
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;
core.info(`only new issues on ${ctx.eventName}: ${patchPath}`);
switch (ctx.eventName) {
case `pull_request`:
case `pull_request_target`:
case `push`:
if (patchPath) {
addedArgs.push(`--new-from-patch=${patchPath}`); addedArgs.push(`--new-from-patch=${patchPath}`);
// Override config values. // Override config values.
addedArgs.push(`--new=false`); addedArgs.push(`--new=false`);
addedArgs.push(`--new-from-rev=`); addedArgs.push(`--new-from-rev=`);
} }
break;
case `merge_group`:
addedArgs.push(`--new-from-rev=${ctx.payload.merge_group.base_sha}`);
// Override config values.
addedArgs.push(`--new=false`);
addedArgs.push(`--new-from-patch=`);
break;
default:
break;
}
}
const workingDirectory = core.getInput(`working-directory`); const workingDirectory = core.getInput(`working-directory`);
const cmdArgs = {}; const cmdArgs = {};
if (workingDirectory) { if (workingDirectory) {

172
package-lock.json generated
View File

@ -21,8 +21,8 @@
"tmp": "^0.2.3" "tmp": "^0.2.3"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^7.7.0", "@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^7.7.0", "@typescript-eslint/parser": "^7.7.1",
"@vercel/ncc": "^0.38.1", "@vercel/ncc": "^0.38.1",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
@ -691,16 +691,16 @@
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz",
"integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==", "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "7.7.0", "@typescript-eslint/scope-manager": "7.7.1",
"@typescript-eslint/type-utils": "7.7.0", "@typescript-eslint/type-utils": "7.7.1",
"@typescript-eslint/utils": "7.7.0", "@typescript-eslint/utils": "7.7.1",
"@typescript-eslint/visitor-keys": "7.7.0", "@typescript-eslint/visitor-keys": "7.7.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^5.3.1", "ignore": "^5.3.1",
@ -741,15 +741,15 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz",
"integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==", "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "7.7.0", "@typescript-eslint/scope-manager": "7.7.1",
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/typescript-estree": "7.7.0", "@typescript-eslint/typescript-estree": "7.7.1",
"@typescript-eslint/visitor-keys": "7.7.0", "@typescript-eslint/visitor-keys": "7.7.1",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@ -769,13 +769,13 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz",
"integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==", "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/visitor-keys": "7.7.0" "@typescript-eslint/visitor-keys": "7.7.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || >=20.0.0" "node": "^18.18.0 || >=20.0.0"
@ -786,13 +786,13 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz",
"integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==", "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "7.7.0", "@typescript-eslint/typescript-estree": "7.7.1",
"@typescript-eslint/utils": "7.7.0", "@typescript-eslint/utils": "7.7.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
}, },
@ -813,9 +813,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz",
"integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==", "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^18.18.0 || >=20.0.0" "node": "^18.18.0 || >=20.0.0"
@ -826,13 +826,13 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz",
"integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==", "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/visitor-keys": "7.7.0", "@typescript-eslint/visitor-keys": "7.7.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"globby": "^11.1.0", "globby": "^11.1.0",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@ -893,17 +893,17 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz",
"integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==", "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.15", "@types/json-schema": "^7.0.15",
"@types/semver": "^7.5.8", "@types/semver": "^7.5.8",
"@typescript-eslint/scope-manager": "7.7.0", "@typescript-eslint/scope-manager": "7.7.1",
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/typescript-estree": "7.7.0", "@typescript-eslint/typescript-estree": "7.7.1",
"semver": "^7.6.0" "semver": "^7.6.0"
}, },
"engines": { "engines": {
@ -933,12 +933,12 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz",
"integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==", "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"eslint-visitor-keys": "^3.4.3" "eslint-visitor-keys": "^3.4.3"
}, },
"engines": { "engines": {
@ -4610,16 +4610,16 @@
} }
}, },
"@typescript-eslint/eslint-plugin": { "@typescript-eslint/eslint-plugin": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz",
"integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==", "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==",
"dev": true, "dev": true,
"requires": { "requires": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "7.7.0", "@typescript-eslint/scope-manager": "7.7.1",
"@typescript-eslint/type-utils": "7.7.0", "@typescript-eslint/type-utils": "7.7.1",
"@typescript-eslint/utils": "7.7.0", "@typescript-eslint/utils": "7.7.1",
"@typescript-eslint/visitor-keys": "7.7.0", "@typescript-eslint/visitor-keys": "7.7.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^5.3.1", "ignore": "^5.3.1",
@ -4640,54 +4640,54 @@
} }
}, },
"@typescript-eslint/parser": { "@typescript-eslint/parser": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz",
"integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==", "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/scope-manager": "7.7.0", "@typescript-eslint/scope-manager": "7.7.1",
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/typescript-estree": "7.7.0", "@typescript-eslint/typescript-estree": "7.7.1",
"@typescript-eslint/visitor-keys": "7.7.0", "@typescript-eslint/visitor-keys": "7.7.1",
"debug": "^4.3.4" "debug": "^4.3.4"
} }
}, },
"@typescript-eslint/scope-manager": { "@typescript-eslint/scope-manager": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz",
"integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==", "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/visitor-keys": "7.7.0" "@typescript-eslint/visitor-keys": "7.7.1"
} }
}, },
"@typescript-eslint/type-utils": { "@typescript-eslint/type-utils": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz",
"integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==", "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/typescript-estree": "7.7.0", "@typescript-eslint/typescript-estree": "7.7.1",
"@typescript-eslint/utils": "7.7.0", "@typescript-eslint/utils": "7.7.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
} }
}, },
"@typescript-eslint/types": { "@typescript-eslint/types": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz",
"integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==", "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==",
"dev": true "dev": true
}, },
"@typescript-eslint/typescript-estree": { "@typescript-eslint/typescript-estree": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz",
"integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==", "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/visitor-keys": "7.7.0", "@typescript-eslint/visitor-keys": "7.7.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"globby": "^11.1.0", "globby": "^11.1.0",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@ -4726,17 +4726,17 @@
} }
}, },
"@typescript-eslint/utils": { "@typescript-eslint/utils": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz",
"integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==", "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.15", "@types/json-schema": "^7.0.15",
"@types/semver": "^7.5.8", "@types/semver": "^7.5.8",
"@typescript-eslint/scope-manager": "7.7.0", "@typescript-eslint/scope-manager": "7.7.1",
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"@typescript-eslint/typescript-estree": "7.7.0", "@typescript-eslint/typescript-estree": "7.7.1",
"semver": "^7.6.0" "semver": "^7.6.0"
}, },
"dependencies": { "dependencies": {
@ -4752,12 +4752,12 @@
} }
}, },
"@typescript-eslint/visitor-keys": { "@typescript-eslint/visitor-keys": {
"version": "7.7.0", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz",
"integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==", "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/types": "7.7.0", "@typescript-eslint/types": "7.7.1",
"eslint-visitor-keys": "^3.4.3" "eslint-visitor-keys": "^3.4.3"
} }
}, },

View File

@ -36,8 +36,8 @@
"tmp": "^0.2.3" "tmp": "^0.2.3"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^7.7.0", "@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^7.7.0", "@typescript-eslint/parser": "^7.7.1",
"@vercel/ncc": "^0.38.1", "@vercel/ncc": "^0.38.1",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",

View File

@ -23,26 +23,6 @@ const getLintCacheDir = (): string => {
return path.resolve(`${process.env.HOME}/.cache/golangci-lint`) return path.resolve(`${process.env.HOME}/.cache/golangci-lint`)
} }
const getCacheDirs = (): string[] => {
// Not existing dirs are ok here: it works.
const skipPkgCache = core.getInput(`skip-pkg-cache`, { required: true }).trim()
const skipBuildCache = core.getInput(`skip-build-cache`, { required: true }).trim()
const dirs = [getLintCacheDir()]
if (skipBuildCache.toLowerCase() == "true") {
core.info(`Omitting ~/.cache/go-build from cache directories`)
} else {
dirs.push(path.resolve(`${process.env.HOME}/.cache/go-build`))
}
if (skipPkgCache.toLowerCase() == "true") {
core.info(`Omitting ~/go/pkg from cache directories`)
} else {
dirs.push(path.resolve(`${process.env.HOME}/go/pkg`))
}
return dirs
}
const getIntervalKey = (invalidationIntervalDays: number): string => { const getIntervalKey = (invalidationIntervalDays: number): string => {
const now = new Date() const now = new Date()
const secondsSinceEpoch = now.getTime() / 1000 const secondsSinceEpoch = now.getTime() / 1000
@ -97,7 +77,7 @@ export async function restoreCache(): Promise<void> {
} }
core.saveState(State.CachePrimaryKey, primaryKey) core.saveState(State.CachePrimaryKey, primaryKey)
try { try {
const cacheKey = await cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys) const cacheKey = await cache.restoreCache([getLintCacheDir()], primaryKey, restoreKeys)
if (!cacheKey) { if (!cacheKey) {
core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`) core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`)
return return
@ -116,6 +96,7 @@ export async function restoreCache(): Promise<void> {
export async function saveCache(): Promise<void> { export async function saveCache(): Promise<void> {
if (core.getInput(`skip-cache`, { required: true }).trim() == "true") return if (core.getInput(`skip-cache`, { required: true }).trim() == "true") return
if (core.getInput(`skip-save-cache`, { required: true }).trim() == "true") return
// Validate inputs, this can cause task failure // Validate inputs, this can cause task failure
if (!utils.isValidEvent()) { if (!utils.isValidEvent()) {
@ -127,7 +108,7 @@ export async function saveCache(): Promise<void> {
const startedAt = Date.now() const startedAt = Date.now()
const cacheDirs = getCacheDirs() const cacheDirs = [getLintCacheDir()]
const primaryKey = core.getState(State.CachePrimaryKey) const primaryKey = core.getState(State.CachePrimaryKey)
if (!primaryKey) { if (!primaryKey) {
utils.logWarning(`Error retrieving key from state.`) utils.logWarning(`Error retrieving key from state.`)

View File

@ -1,5 +1,6 @@
import * as core from "@actions/core" import * as core from "@actions/core"
import * as github from "@actions/github" import * as github from "@actions/github"
import { Context } from "@actions/github/lib/context"
import { exec, ExecOptions } from "child_process" import { exec, ExecOptions } from "child_process"
import * as fs from "fs" import * as fs from "fs"
import * as path from "path" import * as path from "path"
@ -15,6 +16,16 @@ const execShellCommand = promisify(exec)
const writeFile = promisify(fs.writeFile) const writeFile = promisify(fs.writeFile)
const createTempDir = promisify(dir) const createTempDir = promisify(dir)
function isOnlyNewIssues(): boolean {
const onlyNewIssues = core.getInput(`only-new-issues`, { required: true }).trim()
if (onlyNewIssues !== `false` && onlyNewIssues !== `true`) {
throw new Error(`invalid value of "only-new-issues": "${onlyNewIssues}", expected "true" or "false"`)
}
return onlyNewIssues === `true`
}
async function prepareLint(): Promise<string> { async function prepareLint(): Promise<string> {
const mode = core.getInput("install-mode").toLowerCase() const mode = core.getInput("install-mode").toLowerCase()
const versionConfig = await findLintVersion(<InstallMode>mode) const versionConfig = await findLintVersion(<InstallMode>mode)
@ -23,31 +34,42 @@ async function prepareLint(): Promise<string> {
} }
async function fetchPatch(): Promise<string> { async function fetchPatch(): Promise<string> {
const onlyNewIssues = core.getInput(`only-new-issues`, { required: true }).trim() if (!isOnlyNewIssues()) {
if (onlyNewIssues !== `false` && onlyNewIssues !== `true`) {
throw new Error(`invalid value of "only-new-issues": "${onlyNewIssues}", expected "true" or "false"`)
}
if (onlyNewIssues === `false`) {
return `` return ``
} }
const ctx = github.context const ctx = github.context
if (ctx.eventName !== `pull_request`) {
switch (ctx.eventName) {
case `pull_request`:
case `pull_request_target`:
return await fetchPullRequestPatch(ctx)
case `push`:
return await fetchPushPatch(ctx)
case `merge_group`:
core.info(JSON.stringify(ctx.payload))
return ``
default:
core.info(`Not fetching patch for showing only new issues because it's not a pull request context: event name is ${ctx.eventName}`) core.info(`Not fetching patch for showing only new issues because it's not a pull request context: event name is ${ctx.eventName}`)
return `` return ``
} }
const pull = ctx.payload.pull_request }
if (!pull) {
async function fetchPullRequestPatch(ctx: Context): Promise<string> {
const pr = ctx.payload.pull_request
if (!pr) {
core.warning(`No pull request in context`) core.warning(`No pull request in context`)
return `` return ``
} }
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true })) const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }))
let patch: string let patch: string
try { try {
const patchResp = await octokit.rest.pulls.get({ const patchResp = await octokit.rest.pulls.get({
owner: ctx.repo.owner, owner: ctx.repo.owner,
repo: ctx.repo.repo, repo: ctx.repo.repo,
[`pull_number`]: pull.number, [`pull_number`]: pr.number,
mediaType: { mediaType: {
format: `diff`, format: `diff`,
}, },
@ -77,6 +99,45 @@ async function fetchPatch(): Promise<string> {
} }
} }
async function fetchPushPatch(ctx: Context): Promise<string> {
const octokit = github.getOctokit(core.getInput(`github-token`, { required: true }))
let patch: string
try {
const patchResp = await octokit.rest.repos.compareCommits({
owner: ctx.repo.owner,
repo: ctx.repo.repo,
base: ctx.payload.before,
head: ctx.payload.after,
mediaType: {
format: `diff`,
},
})
if (patchResp.status !== 200) {
core.warning(`failed to fetch push patch: response status is ${patchResp.status}`)
return `` // don't fail the action, but analyze without patch
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
patch = patchResp.data as any
} catch (err) {
console.warn(`failed to fetch push patch:`, err)
return `` // don't fail the action, but analyze without patch
}
try {
const tempDir = await createTempDir()
const patchPath = path.join(tempDir, "push.patch")
core.info(`Writing patch to ${patchPath}`)
await writeFile(patchPath, alterDiffPatch(patch))
return patchPath
} catch (err) {
console.warn(`failed to save pull request patch:`, err)
return `` // don't fail the action, but analyze without patch
}
}
type Env = { type Env = {
lintPath: string lintPath: string
patchPath: string patchPath: string
@ -87,11 +148,9 @@ async function prepareEnv(): Promise<Env> {
// Prepare cache, lint and go in parallel. // Prepare cache, lint and go in parallel.
await restoreCache() await restoreCache()
const prepareLintPromise = prepareLint()
const patchPromise = fetchPatch()
const lintPath = await prepareLintPromise const lintPath = await prepareLint()
const patchPath = await patchPromise const patchPath = await fetchPatch()
core.info(`Prepared env in ${Date.now() - startedAt}ms`) core.info(`Prepared env in ${Date.now() - startedAt}ms`)
@ -144,16 +203,38 @@ async function runLint(lintPath: string, patchPath: string): Promise<void> {
addedArgs.push(`--out-format=${formats}`) addedArgs.push(`--out-format=${formats}`)
userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim() userArgs = userArgs.replace(/--out-format=\S*/gi, "").trim()
if (patchPath) { if (isOnlyNewIssues()) {
if (userArgNames.has(`new`) || userArgNames.has(`new-from-rev`) || userArgNames.has(`new-from-patch`)) { if (userArgNames.has(`new`) || userArgNames.has(`new-from-rev`) || userArgNames.has(`new-from-patch`)) {
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
core.info(`only new issues on ${ctx.eventName}: ${patchPath}`)
switch (ctx.eventName) {
case `pull_request`:
case `pull_request_target`:
case `push`:
if (patchPath) {
addedArgs.push(`--new-from-patch=${patchPath}`) addedArgs.push(`--new-from-patch=${patchPath}`)
// Override config values. // Override config values.
addedArgs.push(`--new=false`) addedArgs.push(`--new=false`)
addedArgs.push(`--new-from-rev=`) addedArgs.push(`--new-from-rev=`)
} }
break
case `merge_group`:
addedArgs.push(`--new-from-rev=${ctx.payload.merge_group.base_sha}`)
// Override config values.
addedArgs.push(`--new=false`)
addedArgs.push(`--new-from-patch=`)
break
default:
break
}
}
const workingDirectory = core.getInput(`working-directory`) const workingDirectory = core.getInput(`working-directory`)
const cmdArgs: ExecOptions = {} const cmdArgs: ExecOptions = {}