Compare commits

...

19 commits
v9.0.0 ... main

Author SHA1 Message Date
dependabot[bot]
ca80beefdd
build(deps-dev): bump the dev-dependencies group with 3 updates (#1325)
Some checks failed
build-and-test / test (macos-latest, v2.7.2) (push) Has been cancelled
build-and-test / test (ubuntu-22.04-arm, ) (push) Has been cancelled
build-and-test / test (ubuntu-22.04-arm, latest) (push) Has been cancelled
build-and-test / test (ubuntu-22.04-arm, v2.7) (push) Has been cancelled
build-and-test / test (ubuntu-22.04-arm, v2.7.2) (push) Has been cancelled
build-and-test / test (ubuntu-latest, ) (push) Has been cancelled
build-and-test / test (ubuntu-latest, latest) (push) Has been cancelled
build-and-test / test (ubuntu-latest, v2.7) (push) Has been cancelled
build-and-test / test (ubuntu-latest, v2.7.2) (push) Has been cancelled
build-and-test / test (windows-latest, ) (push) Has been cancelled
build-and-test / test (windows-latest, latest) (push) Has been cancelled
build-and-test / test (windows-latest, v2.7) (push) Has been cancelled
build-and-test / test (windows-latest, v2.7.2) (push) Has been cancelled
build-and-test / test-go-install (macos-latest, ) (push) Has been cancelled
build-and-test / test-go-install (macos-latest, 655e8ede5178280b2a640e185bc4a343aed0f54e) (push) Has been cancelled
build-and-test / test-go-install (macos-latest, latest) (push) Has been cancelled
build-and-test / test-go-install (macos-latest, v2.7.2) (push) Has been cancelled
build-and-test / test-go-install (ubuntu-22.04-arm, ) (push) Has been cancelled
build-and-test / test-go-install (ubuntu-22.04-arm, 655e8ede5178280b2a640e185bc4a343aed0f54e) (push) Has been cancelled
build-and-test / test-go-install (ubuntu-22.04-arm, latest) (push) Has been cancelled
build-and-test / test-go-install (ubuntu-22.04-arm, v2.7.2) (push) Has been cancelled
build-and-test / test-go-install (ubuntu-latest, ) (push) Has been cancelled
build-and-test / test-go-install (ubuntu-latest, 655e8ede5178280b2a640e185bc4a343aed0f54e) (push) Has been cancelled
build-and-test / test-go-install (ubuntu-latest, latest) (push) Has been cancelled
build-and-test / test-go-install (ubuntu-latest, v2.7.2) (push) Has been cancelled
build-and-test / test-go-install (windows-latest, ) (push) Has been cancelled
build-and-test / test-go-install (windows-latest, 655e8ede5178280b2a640e185bc4a343aed0f54e) (push) Has been cancelled
build-and-test / test-go-install (windows-latest, latest) (push) Has been cancelled
build-and-test / test-go-install (windows-latest, v2.7.2) (push) Has been cancelled
build-and-test / test-go-mod (macos-latest, fixtures/go-mod) (push) Has been cancelled
2025-12-08 13:32:43 +01:00
Fernandez Ludovic
87a373f691
chore: update workflow 2025-12-08 13:12:37 +01:00
Fernandez Ludovic
7fa6da85a5
chore: update workflow
Some checks are pending
build-and-test / test-go-install (windows-latest, 655e8ede5178280b2a640e185bc4a343aed0f54e) (push) Blocked by required conditions
build-and-test / test-go-install (windows-latest, latest) (push) Blocked by required conditions
build-and-test / test-go-install (windows-latest, v2.7.0) (push) Blocked by required conditions
build-and-test / test-go-mod (macos-latest, fixtures/go-mod) (push) Blocked by required conditions
build-and-test / test-go-mod (macos-latest, fixtures/go-tool) (push) Blocked by required conditions
build-and-test / test-go-mod (ubuntu-22.04-arm, fixtures/go-tool) (push) Blocked by required conditions
build-and-test / test-go-mod (ubuntu-latest, fixtures/go-mod) (push) Blocked by required conditions
build-and-test / test-go-mod (ubuntu-latest, fixtures/go-tool) (push) Blocked by required conditions
build-and-test / test-go-mod (windows-latest, fixtures/go-mod) (push) Blocked by required conditions
build-and-test / test-go-mod (windows-latest, fixtures/go-tool) (push) Blocked by required conditions
build-and-test / test-plugins (macos-latest, ) (push) Blocked by required conditions
build-and-test / test-plugins (macos-latest, latest) (push) Blocked by required conditions
build-and-test / test-plugins (macos-latest, v2.7) (push) Blocked by required conditions
build-and-test / test-plugins (macos-latest, v2.7.1) (push) Blocked by required conditions
build-and-test / test-plugins (ubuntu-22.04-arm, ) (push) Blocked by required conditions
build-and-test / test-plugins (ubuntu-22.04-arm, latest) (push) Blocked by required conditions
build-and-test / test-plugins (ubuntu-22.04-arm, v2.7) (push) Blocked by required conditions
build-and-test / test-plugins (ubuntu-22.04-arm, v2.7.1) (push) Blocked by required conditions
build-and-test / test-plugins (ubuntu-latest, ) (push) Blocked by required conditions
build-and-test / test-plugins (ubuntu-latest, latest) (push) Blocked by required conditions
build-and-test / test-plugins (ubuntu-latest, v2.7) (push) Blocked by required conditions
build-and-test / test-plugins (ubuntu-latest, v2.7.1) (push) Blocked by required conditions
build-and-test / test-plugins (windows-latest, ) (push) Blocked by required conditions
build-and-test / test-plugins (windows-latest, latest) (push) Blocked by required conditions
build-and-test / test-plugins (windows-latest, v2.7) (push) Blocked by required conditions
build-and-test / test-plugins (windows-latest, v2.7.1) (push) Blocked by required conditions
build-and-test / test-monorepo (macos-latest) (push) Blocked by required conditions
build-and-test / test-monorepo (ubuntu-22.04-arm) (push) Blocked by required conditions
build-and-test / test-monorepo (ubuntu-latest) (push) Blocked by required conditions
build-and-test / test-monorepo (windows-latest) (push) Blocked by required conditions
2025-12-08 12:54:19 +01:00
dependabot[bot]
1e7e51e771
build(deps): bump yaml from 2.8.1 to 2.8.2 in the dependencies group (#1324)
Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
2025-12-01 13:01:48 +01:00
dependabot[bot]
5256ff0c0a
build(deps-dev): bump the dev-dependencies group with 3 updates (#1323) 2025-12-01 12:32:33 +01:00
Fernandez Ludovic
13fed6f911 chore: update workflows 2025-11-28 17:39:49 +01:00
Fernandez Ludovic
7afe8ff863 chore: update workflows 2025-11-28 17:28:27 +01:00
Ludovic Fernandez
5a9289952f
chore: move samples into fixtures (#1321) 2025-11-28 17:21:09 +01:00
Ludovic Fernandez
aa6fad0ea0
feat: add version-file option (#1320) 2025-11-28 16:54:48 +01:00
dependabot[bot]
a6071aaacb
build(deps): bump actions/checkout from 5 to 6 (#1318) 2025-11-24 12:36:51 +01:00
dependabot[bot]
6e36c8460f
build(deps-dev): bump the dev-dependencies group with 2 updates (#1317) 2025-11-24 12:36:23 +01:00
Ludovic Fernandez
e7fa5ac41e
feat: automatic module directories (#1315) 2025-11-21 16:03:27 +01:00
Ludovic Fernandez
f3ae99f5f5
docs: organize options (#1314) 2025-11-21 15:52:17 +01:00
Fernandez Ludovic
1dfda283ac
docs: update readme 2025-11-18 18:51:26 +01:00
dependabot[bot]
8b0f9424d0
build(deps): bump the dependencies group with 2 updates (#1311) 2025-11-17 13:18:39 +01:00
dependabot[bot]
a77756c838
build(deps-dev): bump the dev-dependencies group with 2 updates (#1310) 2025-11-17 13:18:04 +01:00
dependabot[bot]
37a9fafcae
build(deps-dev): bump js-yaml from 4.1.0 to 4.1.1 (#1309) 2025-11-15 13:23:43 +01:00
dependabot[bot]
199a9c2889
build(deps-dev): bump the dev-dependencies group with 2 updates (#1307) 2025-11-10 11:00:55 +01:00
Fernandez Ludovic
c7c1219093
chore: simplify 2025-11-09 10:04:50 +01:00
38 changed files with 970 additions and 610 deletions

View file

@ -11,6 +11,11 @@ on:
schedule: schedule:
- cron: '0 17 * * 5' - cron: '0 17 * * 5'
permissions:
actions: read
contents: read
security-events: write
jobs: jobs:
codeQL: codeQL:
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
@ -18,7 +23,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
with: with:
# Must fetch at least the immediate parents so that if this is # Must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head of the pull request. # a pull request then we can checkout the head of the pull request.
@ -36,7 +41,7 @@ jobs:
uses: github/codeql-action/init@v4 uses: github/codeql-action/init@v4
# Override language selection by uncommenting this and choosing your languages # Override language selection by uncommenting this and choosing your languages
with: with:
language: 'javascript' languages: 'javascript-typescript'
- run: | - run: |
npm install npm install

View file

@ -1,5 +1,6 @@
name: "build-and-test" name: "build-and-test"
on: # rebuild any PRs and main branch changes
on:
pull_request: pull_request:
branches: branches:
- main - main
@ -7,22 +8,27 @@ on: # rebuild any PRs and main branch changes
branches: branches:
- main - main
permissions:
contents: read
jobs: jobs:
build: # make sure build/ci work properly # make sure build/ci work properly
build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/setup-node@v6 - uses: actions/setup-node@v6
with: with:
node-version: 24.x node-version: 24.x
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- run: | - run: |
npm install npm install
npm run all npm run all
# Fail the build if there is dirty change # Fail the build if there are changes.
- run: git diff --exit-code -- dist - run: git diff --exit-code -- dist
test: # make sure the action works on a clean machine without building # make sure the action works on a clean machine without building
test:
needs: [ build ] needs: [ build ]
strategy: strategy:
matrix: matrix:
@ -34,14 +40,14 @@ jobs:
version: version:
- "" - ""
- "latest" - "latest"
- "v2.5" - "v2.7"
- "v2.5.0" - "v2.7.2"
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
permissions: permissions:
contents: read contents: read
pull-requests: read pull-requests: read
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions/setup-node@v6 - uses: actions/setup-node@v6
with: with:
node-version: 24.x node-version: 24.x
@ -51,10 +57,11 @@ jobs:
- uses: ./ - uses: ./
with: with:
version: ${{ matrix.version }} version: ${{ matrix.version }}
args: --timeout=5m --issues-exit-code=0 ./sample/... args: --timeout=5m --issues-exit-code=0 ./fixtures/simple/...
only-new-issues: true only-new-issues: true
test-go-install: # make sure the action works on a clean machine without building (go-install mode) # make sure the action works on a clean machine without building (go-install mode)
test-go-install:
needs: [ build ] needs: [ build ]
strategy: strategy:
matrix: matrix:
@ -66,14 +73,14 @@ jobs:
version: version:
- "" - ""
- "latest" - "latest"
- "v2.5.0" - "v2.7.2"
- "655e8ede5178280b2a640e185bc4a343aed0f54e" - "655e8ede5178280b2a640e185bc4a343aed0f54e"
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
permissions: permissions:
contents: read contents: read
pull-requests: read pull-requests: read
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions/setup-node@v6 - uses: actions/setup-node@v6
with: with:
node-version: 24.x node-version: 24.x
@ -83,7 +90,7 @@ jobs:
- uses: ./ - uses: ./
with: with:
version: ${{ matrix.version }} version: ${{ matrix.version }}
args: --timeout=5m --issues-exit-code=0 ./sample/... args: --timeout=5m --issues-exit-code=0 ./fixtures/simple/...
only-new-issues: true only-new-issues: true
install-mode: goinstall install-mode: goinstall
@ -97,13 +104,13 @@ jobs:
- macos-latest - macos-latest
- windows-latest - windows-latest
wd: wd:
- sample-go-mod - fixtures/go-mod
- sample-go-tool - fixtures/go-tool
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions/setup-node@v6 - uses: actions/setup-node@v6
with: with:
node-version: 24.x node-version: 24.x
@ -115,7 +122,8 @@ jobs:
working-directory: ${{ matrix.wd }} working-directory: ${{ matrix.wd }}
args: --timeout=5m --issues-exit-code=0 ./... args: --timeout=5m --issues-exit-code=0 ./...
test-plugins: # make sure the action works on a clean machine with plugins # make sure the action works on a clean machine with plugins
test-plugins:
needs: [ build ] needs: [ build ]
strategy: strategy:
matrix: matrix:
@ -127,14 +135,14 @@ jobs:
version: version:
- "" - ""
- "latest" - "latest"
- "v2.5" - "v2.7"
- "v2.5.0" - "v2.7.2"
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
permissions: permissions:
contents: read contents: read
pull-requests: read pull-requests: read
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions/setup-node@v6 - uses: actions/setup-node@v6
with: with:
node-version: 24.x node-version: 24.x
@ -144,5 +152,32 @@ jobs:
- uses: ./ - uses: ./
with: with:
version: ${{ matrix.version }} version: ${{ matrix.version }}
working-directory: sample-plugins working-directory: fixtures/plugins
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@v6
- uses: actions/setup-node@v6
with:
node-version: 24.x
- uses: actions/setup-go@v6
with:
go-version: oldstable
- uses: ./
with:
working-directory: fixtures/monorepo
experimental: "automatic-module-directories"
args: --timeout=5m --issues-exit-code=0 ./... args: --timeout=5m --issues-exit-code=0 ./...

258
README.md
View file

@ -54,9 +54,9 @@ jobs:
with: with:
go-version: stable go-version: stable
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
version: v2.1 version: v2.6
``` ```
</details> </details>
@ -92,9 +92,9 @@ jobs:
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
version: v2.1 version: v2.6
``` ```
You will also likely need to add the following `.gitattributes` file to ensure that line endings for Windows builds are properly formatted: You will also likely need to add the following `.gitattributes` file to ensure that line endings for Windows builds are properly formatted:
@ -120,7 +120,7 @@ on:
env: env:
GO_VERSION: stable GO_VERSION: stable
GOLANGCI_LINT_VERSION: v2.1 GOLANGCI_LINT_VERSION: v2.6
jobs: jobs:
detect-modules: detect-modules:
@ -147,7 +147,7 @@ jobs:
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
- name: golangci-lint ${{ matrix.modules }} - name: golangci-lint ${{ matrix.modules }}
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
version: ${{ env.GOLANGCI_LINT_VERSION }} version: ${{ env.GOLANGCI_LINT_VERSION }}
working-directory: ${{ matrix.modules }} working-directory: ${{ matrix.modules }}
@ -179,7 +179,7 @@ jobs:
with: with:
os: ${{ matrix.os }} os: ${{ matrix.os }}
go-version: ${{ matrix.go-version }} go-version: ${{ matrix.go-version }}
golangci-lint-version: v2.1 golangci-lint-version: v2.6
``` ```
```yaml ```yaml
@ -201,7 +201,7 @@ on:
golangci-lint-version: golangci-lint-version:
description: 'Golangci-lint version' description: 'Golangci-lint version'
type: string type: string
default: 'v2.1' default: 'v2.6'
jobs: jobs:
detect-modules: detect-modules:
@ -229,7 +229,7 @@ jobs:
with: with:
go-version: ${{ inputs.go-version }} go-version: ${{ inputs.go-version }}
- name: golangci-lint ${{ matrix.modules }} - name: golangci-lint ${{ matrix.modules }}
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
version: ${{ inputs.golangci-lint-version }} version: ${{ inputs.golangci-lint-version }}
working-directory: ${{ matrix.modules }} working-directory: ${{ matrix.modules }}
@ -259,7 +259,28 @@ You will also likely need to add the following `.gitattributes` file to ensure t
## Options ## Options
### `version` ### Overview
| Option | Description |
|---------------------------------------------------------------|-------------------------------------------------------|
| [`version`](#version) | The version of golangci-lint to use. |
| [`version-file`](#version-file) | Gets the version of golangci-lint to use from a file. |
| [`install-mode`](#install-mode) | The mode to install golangci-lint. |
| [`install-only`](#install-only) | Only install golangci-lint. |
| [`verify`](#verify) | Validates golangci-lint configuration file. |
| [`github-token`](#github-token) | Used by the `only-new-issues` option. |
| [`only-new-issues`](#only-new-issues) | Show only new issues. |
| [`working-directory`](#working-directory) | The golangci-lint working directory. |
| [`args`](#args) | Golangci-lint command line arguments. |
| [`skip-cache`](#skip-cache) | Disable cache support. |
| [`skip-save-cache`](#skip-save-cache) | Don't save cache. |
| [`cache-invalidation-interval`](#cache-invalidation-interval) | Number of days before cache invalidation. |
| [`problem-matchers`](#problem-matchers) | Forces the usage of the embedded problem matchers. |
| [Experimental](#experimental) | Experimental options |
### Installation
#### `version`
(optional) (optional)
@ -274,15 +295,37 @@ When `install-mode` is:
<summary>Example</summary> <summary>Example</summary>
```yml ```yml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
version: v2.1 version: v2.6
# ... # ...
``` ```
</details> </details>
### `install-mode` #### `version-file`
Gets the version of golangci-lint to use from a file.
The path must be relative to the root of the project, or the `working-directory` if defined.
This parameter supports `.golangci-lint-version`, and `.tool-versions` files.
Only works with `install-mode: binary` (the default).
<details>
<summary>Example</summary>
```yml
uses: golangci/golangci-lint-action@v9
with:
version-file: .tool-versions
# ...
```
</details>
#### `install-mode`
(optional) (optional)
@ -296,7 +339,7 @@ The default value is `binary`.
<summary>Example</summary> <summary>Example</summary>
```yml ```yml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
install-mode: "none" install-mode: "none"
# ... # ...
@ -304,7 +347,7 @@ with:
</details> </details>
### `install-only` #### `install-only`
(optional) (optional)
@ -317,7 +360,7 @@ The default value is `false`.
<summary>Example</summary> <summary>Example</summary>
```yml ```yml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
install-only: true install-only: true
# ... # ...
@ -325,27 +368,9 @@ with:
</details> </details>
### `github-token` ### Run
(optional) #### `verify`
When using the `only-new-issues` option, the GitHub API is used, so a token is required.
By default, it uses the `github.token` from the action.
<details>
<summary>Example</summary>
```yml
uses: golangci/golangci-lint-action@v8
with:
github-token: xxx
# ...
```
</details>
### `verify`
(optional) (optional)
@ -360,7 +385,7 @@ The JSON Schema used to validate the configuration depends on the version of gol
<summary>Example</summary> <summary>Example</summary>
```yml ```yml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
verify: false verify: false
# ... # ...
@ -368,7 +393,27 @@ with:
</details> </details>
### `only-new-issues` #### `github-token`
(optional)
When using the `only-new-issues` option, the GitHub API is used, so a token is required.
By default, it uses the `github.token` from the action.
<details>
<summary>Example</summary>
```yml
uses: golangci/golangci-lint-action@v9
with:
github-token: xxx
# ...
```
</details>
#### `only-new-issues`
(optional) (optional)
@ -385,7 +430,7 @@ The default value is `false`.
<summary>Example</summary> <summary>Example</summary>
```yml ```yml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
only-new-issues: true only-new-issues: true
# ... # ...
@ -393,7 +438,7 @@ with:
</details> </details>
### `working-directory` #### `working-directory`
(optional) (optional)
@ -403,7 +448,7 @@ The golangci-lint working directory, useful for monorepos. The default is the pr
<summary>Example</summary> <summary>Example</summary>
```yml ```yml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
working-directory: somedir working-directory: somedir
# ... # ...
@ -411,7 +456,7 @@ with:
</details> </details>
### `args` #### `args`
(optional) (optional)
@ -428,7 +473,7 @@ golangci-lint command line arguments.
<summary>Example</summary> <summary>Example</summary>
```yml ```yml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
# In some rare cases, # In some rare cases,
# you may need to use `${{ github.workspace }}` as the base directory to reference your configuration file. # you may need to use `${{ github.workspace }}` as the base directory to reference your configuration file.
@ -438,7 +483,74 @@ with:
</details> </details>
### `problem-matchers` ### Cache
#### `skip-cache`
(optional)
If set to `true`, all caching functionality will be completely disabled.
This takes precedence over all other caching options.
The default value is `false`.
<details>
<summary>Example</summary>
```yml
uses: golangci/golangci-lint-action@v9
with:
skip-cache: true
# ...
```
</details>
#### `skip-save-cache`
(optional)
If set to `true`, caches will not be saved, but they may still be restored, requiring `skip-cache: false`.
The default value is `false`.
<details>
<summary>Example</summary>
```yml
uses: golangci/golangci-lint-action@v9
with:
skip-save-cache: true
# ...
```
</details>
#### `cache-invalidation-interval`
(optional)
Periodically invalidate a cache every `cache-invalidation-interval` days to ensure that outdated data is removed and fresh data is loaded.
The default value is `7`.
If the number is `<= 0`, the cache will always be invalidated (not recommended).
<details>
<summary>Example</summary>
```yml
uses: golangci/golangci-lint-action@v9
with:
cache-invalidation-interval: 15
# ...
```
</details>
### Extra
#### `problem-matchers`
(optional) (optional)
@ -456,7 +568,7 @@ The default value is `false`.
<summary>Example</summary> <summary>Example</summary>
```yml ```yml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
problem-matchers: true problem-matchers: true
# ... # ...
@ -464,65 +576,43 @@ with:
</details> </details>
### `skip-cache` ### Experimental
(optional) 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.
If set to `true`, all caching functionality will be completely disabled. List of comma-separated options.
This takes precedence over all other caching options.
The default value is `false`.
<details> <details>
<summary>Example</summary> <summary>Example</summary>
```yml ```yaml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
skip-cache: true experimental: "foo,bar"
# ...
``` ```
</details> </details>
### `skip-save-cache` #### `automatic-module-directories`
(optional) (optional)
If set to `true`, caches will not be saved, but they may still be restored, requiring `skip-cache: false`. This option will run golangci-lint in each module directory, useful for monorepos.
The default value is `false`. 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> <details>
<summary>Example</summary> <summary>Example</summary>
```yml ```yaml
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: with:
skip-save-cache: true experimental: "automatic-module-directories"
# ...
```
</details>
### `cache-invalidation-interval`
(optional)
Periodically invalidate a cache every `cache-invalidation-interval` days to ensure that outdated data is removed and fresh data is loaded.
The default value is `7`.
If the number is `<= 0`, the cache will always be invalidated (not recommended).
<details>
<summary>Example</summary>
```yml
uses: golangci/golangci-lint-action@v8
with:
cache-invalidation-interval: 15
# ...
``` ```
</details> </details>

View file

@ -11,6 +11,13 @@ inputs:
- `goinstall`: the value can be v2.3.4, `latest`, or the hash of a commit. - `goinstall`: the value can be v2.3.4, `latest`, or the hash of a commit.
- `none`: the value is ignored. - `none`: the value is ignored.
required: false required: false
version-file:
description: |
Gets the version of golangci-lint to use from a file.
The path must be relative to the root of the project, or the `working-directory` if defined.
This parameter supports `.golangci-lint-version`, and `.tool-versions` files.
Only works with `install-mode: binary` (the default).
required: false
install-mode: install-mode:
description: "The mode to install golangci-lint. It can be 'binary', 'goinstall', or 'none'." description: "The mode to install golangci-lint. It can be 'binary', 'goinstall', or 'none'."
default: "binary" default: "binary"
@ -34,6 +41,10 @@ inputs:
description: "If set to true and the action runs on a pull request, the action outputs only newly found issues." description: "If set to true and the action runs on a pull request, the action outputs only newly found issues."
default: 'false' default: 'false'
required: false required: false
args:
description: "golangci-lint command line arguments."
default: ""
required: false
skip-cache: skip-cache:
description: | description: |
If set to true, all caching functionality will be completely disabled. If set to true, all caching functionality will be completely disabled.
@ -42,21 +53,30 @@ inputs:
required: false required: false
skip-save-cache: skip-save-cache:
description: | description: |
If set to true, the action will not save any caches, but it may still If set to true, the action will not save any caches,
restore existing caches, subject to other options. but it may still restore existing caches, subject to other options.
default: 'false' default: 'false'
required: false required: false
cache-invalidation-interval:
description: "Periodically invalidate a cache when new code is added (number of days)."
default: '7'
required: false
problem-matchers: problem-matchers:
description: "Force the usage of the embedded problem matchers." description: "Force the usage of the embedded problem matchers."
default: 'false' default: 'false'
required: false required: false
args: debug:
description: "golangci-lint command line arguments." description: |
Debug options for the action.
List of comma separated options, the values are `cache`, `clean`.
example: "cache,clean"
default: "" default: ""
required: false required: false
cache-invalidation-interval: experimental:
description: "Periodically invalidate a cache when new code is added (number of days)." description: |
default: '7' Experimental options for the action.
List of comma separated options.
default: ""
required: false required: false
runs: runs:
using: "node24" using: "node24"

235
dist/post_run/index.js generated vendored
View file

@ -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);
@ -97361,11 +97371,12 @@ async function install(binPath) {
else { else {
rootDir = process.cwd(); rootDir = process.cwd();
} }
const configFile = [".custom-gcl.yml", ".custom-gcl.yaml", ".custom-gcl.json"] const configFile = ["yml", "yaml", "json"]
.map((v) => path.join(rootDir, v)) .map((ext) => `.custom-gcl.${ext}`)
.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...`);
@ -97373,7 +97384,7 @@ async function install(binPath) {
const config = yaml_1.default.parse(fs.readFileSync(configFile, "utf-8")); const config = yaml_1.default.parse(fs.readFileSync(configFile, "utf-8"));
const v = core.getInput(`version`); const v = core.getInput(`version`);
if (v !== "" && config.version !== v) { if (v !== "" && config.version !== v) {
core.warning(`The golangci-lint version (${config.version}) defined inside in ${configFile} does not match the version defined in the action (${v})`); core.warning(`The golangci-lint version (${config.version}) defined inside ${configFile} does not match the version defined in the action (${v})`);
} }
if (!config.destination) { if (!config.destination) {
config.destination = "."; config.destination = ".";
@ -97387,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}`);
} });
} }
@ -97455,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);
@ -97481,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
@ -97498,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`) ||
@ -97515,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`:
@ -97540,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`);
@ -97568,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 });
@ -97585,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`;
@ -97595,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}`);
@ -97889,6 +97912,10 @@ const isLessVersion = (a, b) => {
}; };
const getRequestedVersion = () => { const getRequestedVersion = () => {
let requestedVersion = core.getInput(`version`); let requestedVersion = core.getInput(`version`);
let versionFilePath = core.getInput(`version-file`);
if (requestedVersion && versionFilePath) {
core.warning(`Both version (${requestedVersion}) and version-file (${versionFilePath}) inputs are specified, only version will be used`);
}
const workingDirectory = core.getInput(`working-directory`); const workingDirectory = core.getInput(`working-directory`);
let goMod = "go.mod"; let goMod = "go.mod";
if (workingDirectory) { if (workingDirectory) {
@ -97902,6 +97929,24 @@ const getRequestedVersion = () => {
core.info(`Found golangci-lint version '${requestedVersion}' in '${goMod}' file`); core.info(`Found golangci-lint version '${requestedVersion}' in '${goMod}' file`);
} }
} }
if (requestedVersion == "" && versionFilePath) {
if (workingDirectory) {
versionFilePath = path_1.default.join(workingDirectory, versionFilePath);
}
if (!fs.existsSync(versionFilePath)) {
throw new Error(`The specified golangci-lint version file at: ${versionFilePath} does not exist`);
}
const content = fs.readFileSync(versionFilePath, "utf-8");
if (path_1.default.basename(versionFilePath) === ".tool-versions") {
// asdf/mise file.
const match = content.match(/^golangci-lint\s+([^\n#]+)/m);
requestedVersion = match ? "v" + match[1].trim().replace(/^v/gi, "") : "";
}
else {
// .golangci-lint-version file.
requestedVersion = "v" + content.trim().replace(/^v/gi, "");
}
}
const parsedRequestedVersion = parseVersion(requestedVersion); const parsedRequestedVersion = parseVersion(requestedVersion);
if (parsedRequestedVersion == null) { if (parsedRequestedVersion == null) {
return null; return null;
@ -102683,7 +102728,7 @@ function composeCollection(CN, ctx, token, props, onError) {
let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType); let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType);
if (!tag) { if (!tag) {
const kt = ctx.schema.knownTags[tagName]; const kt = ctx.schema.knownTags[tagName];
if (kt && kt.collection === expType) { if (kt?.collection === expType) {
ctx.schema.tags.push(Object.assign({}, kt, { default: false })); ctx.schema.tags.push(Object.assign({}, kt, { default: false }));
tag = kt; tag = kt;
} }
@ -103569,7 +103614,7 @@ function resolveBlockSeq({ composeNode, composeEmptyNode }, ctx, bs, onError, ta
}); });
if (!props.found) { if (!props.found) {
if (props.anchor || props.tag || value) { if (props.anchor || props.tag || value) {
if (value && value.type === 'block-seq') if (value?.type === 'block-seq')
onError(props.end, 'BAD_INDENT', 'All sequence items must start at the same column'); onError(props.end, 'BAD_INDENT', 'All sequence items must start at the same column');
else else
onError(offset, 'MISSING_CHAR', 'Sequence item without - indicator'); onError(offset, 'MISSING_CHAR', 'Sequence item without - indicator');
@ -103786,7 +103831,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
} }
} }
else if (value) { else if (value) {
if ('source' in value && value.source && value.source[0] === ':') if ('source' in value && value.source?.[0] === ':')
onError(value, 'MISSING_CHAR', `Missing space after : in ${fcName}`); onError(value, 'MISSING_CHAR', `Missing space after : in ${fcName}`);
else else
onError(valueProps.start, 'MISSING_CHAR', `Missing , or : between ${fcName} items`); onError(valueProps.start, 'MISSING_CHAR', `Missing , or : between ${fcName} items`);
@ -103830,7 +103875,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
const expectedEnd = isMap ? '}' : ']'; const expectedEnd = isMap ? '}' : ']';
const [ce, ...ee] = fc.end; const [ce, ...ee] = fc.end;
let cePos = offset; let cePos = offset;
if (ce && ce.source === expectedEnd) if (ce?.source === expectedEnd)
cePos = ce.offset + ce.source.length; cePos = ce.offset + ce.source.length;
else { else {
const name = fcName[0].toUpperCase() + fcName.substring(1); const name = fcName[0].toUpperCase() + fcName.substring(1);
@ -105211,7 +105256,7 @@ const prettifyError = (src, lc) => (error) => {
if (/[^ ]/.test(lineStr)) { if (/[^ ]/.test(lineStr)) {
let count = 1; let count = 1;
const end = error.linePos[1]; const end = error.linePos[1];
if (end && end.line === line && end.col > col) { if (end?.line === line && end.col > col) {
count = Math.max(1, Math.min(end.col - col, 80 - ci)); count = Math.max(1, Math.min(end.col - col, 80 - ci));
} }
const pointer = ' '.repeat(ci) + '^'.repeat(count); const pointer = ' '.repeat(ci) + '^'.repeat(count);
@ -105379,7 +105424,7 @@ class Alias extends Node.NodeBase {
data = anchors.get(source); data = anchors.get(source);
} }
/* istanbul ignore if */ /* istanbul ignore if */
if (!data || data.res === undefined) { if (data?.res === undefined) {
const msg = 'This should not happen: Alias anchor was not resolved?'; const msg = 'This should not happen: Alias anchor was not resolved?';
throw new ReferenceError(msg); throw new ReferenceError(msg);
} }
@ -107721,7 +107766,7 @@ class Parser {
} }
*step() { *step() {
const top = this.peek(1); const top = this.peek(1);
if (this.type === 'doc-end' && (!top || top.type !== 'doc-end')) { if (this.type === 'doc-end' && top?.type !== 'doc-end') {
while (this.stack.length > 0) while (this.stack.length > 0)
yield* this.pop(); yield* this.pop();
this.stack.push({ this.stack.push({
@ -108253,7 +108298,7 @@ class Parser {
do { do {
yield* this.pop(); yield* this.pop();
top = this.peek(1); top = this.peek(1);
} while (top && top.type === 'flow-collection'); } while (top?.type === 'flow-collection');
} }
else if (fc.end.length === 0) { else if (fc.end.length === 0) {
switch (this.type) { switch (this.type) {
@ -110439,7 +110484,7 @@ function stringifyNumber({ format, minFractionDigits, tag, value }) {
const num = typeof value === 'number' ? value : Number(value); const num = typeof value === 'number' ? value : Number(value);
if (!isFinite(num)) if (!isFinite(num))
return isNaN(num) ? '.nan' : num < 0 ? '-.inf' : '.inf'; return isNaN(num) ? '.nan' : num < 0 ? '-.inf' : '.inf';
let n = JSON.stringify(value); let n = Object.is(value, -0) ? '-0' : JSON.stringify(value);
if (!format && if (!format &&
minFractionDigits && minFractionDigits &&
(!tag || tag === 'tag:yaml.org,2002:float') && (!tag || tag === 'tag:yaml.org,2002:float') &&
@ -110570,7 +110615,7 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
ws += `\n${stringifyComment.indentComment(cs, ctx.indent)}`; ws += `\n${stringifyComment.indentComment(cs, ctx.indent)}`;
} }
if (valueStr === '' && !ctx.inFlow) { if (valueStr === '' && !ctx.inFlow) {
if (ws === '\n') if (ws === '\n' && valueComment)
ws = '\n\n'; ws = '\n\n';
} }
else { else {

235
dist/run/index.js generated vendored
View file

@ -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);
@ -97361,11 +97371,12 @@ async function install(binPath) {
else { else {
rootDir = process.cwd(); rootDir = process.cwd();
} }
const configFile = [".custom-gcl.yml", ".custom-gcl.yaml", ".custom-gcl.json"] const configFile = ["yml", "yaml", "json"]
.map((v) => path.join(rootDir, v)) .map((ext) => `.custom-gcl.${ext}`)
.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...`);
@ -97373,7 +97384,7 @@ async function install(binPath) {
const config = yaml_1.default.parse(fs.readFileSync(configFile, "utf-8")); const config = yaml_1.default.parse(fs.readFileSync(configFile, "utf-8"));
const v = core.getInput(`version`); const v = core.getInput(`version`);
if (v !== "" && config.version !== v) { if (v !== "" && config.version !== v) {
core.warning(`The golangci-lint version (${config.version}) defined inside in ${configFile} does not match the version defined in the action (${v})`); core.warning(`The golangci-lint version (${config.version}) defined inside ${configFile} does not match the version defined in the action (${v})`);
} }
if (!config.destination) { if (!config.destination) {
config.destination = "."; config.destination = ".";
@ -97387,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}`);
} });
} }
@ -97455,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);
@ -97481,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
@ -97498,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`) ||
@ -97515,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`:
@ -97540,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`);
@ -97568,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 });
@ -97585,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`;
@ -97595,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}`);
@ -97889,6 +97912,10 @@ const isLessVersion = (a, b) => {
}; };
const getRequestedVersion = () => { const getRequestedVersion = () => {
let requestedVersion = core.getInput(`version`); let requestedVersion = core.getInput(`version`);
let versionFilePath = core.getInput(`version-file`);
if (requestedVersion && versionFilePath) {
core.warning(`Both version (${requestedVersion}) and version-file (${versionFilePath}) inputs are specified, only version will be used`);
}
const workingDirectory = core.getInput(`working-directory`); const workingDirectory = core.getInput(`working-directory`);
let goMod = "go.mod"; let goMod = "go.mod";
if (workingDirectory) { if (workingDirectory) {
@ -97902,6 +97929,24 @@ const getRequestedVersion = () => {
core.info(`Found golangci-lint version '${requestedVersion}' in '${goMod}' file`); core.info(`Found golangci-lint version '${requestedVersion}' in '${goMod}' file`);
} }
} }
if (requestedVersion == "" && versionFilePath) {
if (workingDirectory) {
versionFilePath = path_1.default.join(workingDirectory, versionFilePath);
}
if (!fs.existsSync(versionFilePath)) {
throw new Error(`The specified golangci-lint version file at: ${versionFilePath} does not exist`);
}
const content = fs.readFileSync(versionFilePath, "utf-8");
if (path_1.default.basename(versionFilePath) === ".tool-versions") {
// asdf/mise file.
const match = content.match(/^golangci-lint\s+([^\n#]+)/m);
requestedVersion = match ? "v" + match[1].trim().replace(/^v/gi, "") : "";
}
else {
// .golangci-lint-version file.
requestedVersion = "v" + content.trim().replace(/^v/gi, "");
}
}
const parsedRequestedVersion = parseVersion(requestedVersion); const parsedRequestedVersion = parseVersion(requestedVersion);
if (parsedRequestedVersion == null) { if (parsedRequestedVersion == null) {
return null; return null;
@ -102683,7 +102728,7 @@ function composeCollection(CN, ctx, token, props, onError) {
let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType); let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType);
if (!tag) { if (!tag) {
const kt = ctx.schema.knownTags[tagName]; const kt = ctx.schema.knownTags[tagName];
if (kt && kt.collection === expType) { if (kt?.collection === expType) {
ctx.schema.tags.push(Object.assign({}, kt, { default: false })); ctx.schema.tags.push(Object.assign({}, kt, { default: false }));
tag = kt; tag = kt;
} }
@ -103569,7 +103614,7 @@ function resolveBlockSeq({ composeNode, composeEmptyNode }, ctx, bs, onError, ta
}); });
if (!props.found) { if (!props.found) {
if (props.anchor || props.tag || value) { if (props.anchor || props.tag || value) {
if (value && value.type === 'block-seq') if (value?.type === 'block-seq')
onError(props.end, 'BAD_INDENT', 'All sequence items must start at the same column'); onError(props.end, 'BAD_INDENT', 'All sequence items must start at the same column');
else else
onError(offset, 'MISSING_CHAR', 'Sequence item without - indicator'); onError(offset, 'MISSING_CHAR', 'Sequence item without - indicator');
@ -103786,7 +103831,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
} }
} }
else if (value) { else if (value) {
if ('source' in value && value.source && value.source[0] === ':') if ('source' in value && value.source?.[0] === ':')
onError(value, 'MISSING_CHAR', `Missing space after : in ${fcName}`); onError(value, 'MISSING_CHAR', `Missing space after : in ${fcName}`);
else else
onError(valueProps.start, 'MISSING_CHAR', `Missing , or : between ${fcName} items`); onError(valueProps.start, 'MISSING_CHAR', `Missing , or : between ${fcName} items`);
@ -103830,7 +103875,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
const expectedEnd = isMap ? '}' : ']'; const expectedEnd = isMap ? '}' : ']';
const [ce, ...ee] = fc.end; const [ce, ...ee] = fc.end;
let cePos = offset; let cePos = offset;
if (ce && ce.source === expectedEnd) if (ce?.source === expectedEnd)
cePos = ce.offset + ce.source.length; cePos = ce.offset + ce.source.length;
else { else {
const name = fcName[0].toUpperCase() + fcName.substring(1); const name = fcName[0].toUpperCase() + fcName.substring(1);
@ -105211,7 +105256,7 @@ const prettifyError = (src, lc) => (error) => {
if (/[^ ]/.test(lineStr)) { if (/[^ ]/.test(lineStr)) {
let count = 1; let count = 1;
const end = error.linePos[1]; const end = error.linePos[1];
if (end && end.line === line && end.col > col) { if (end?.line === line && end.col > col) {
count = Math.max(1, Math.min(end.col - col, 80 - ci)); count = Math.max(1, Math.min(end.col - col, 80 - ci));
} }
const pointer = ' '.repeat(ci) + '^'.repeat(count); const pointer = ' '.repeat(ci) + '^'.repeat(count);
@ -105379,7 +105424,7 @@ class Alias extends Node.NodeBase {
data = anchors.get(source); data = anchors.get(source);
} }
/* istanbul ignore if */ /* istanbul ignore if */
if (!data || data.res === undefined) { if (data?.res === undefined) {
const msg = 'This should not happen: Alias anchor was not resolved?'; const msg = 'This should not happen: Alias anchor was not resolved?';
throw new ReferenceError(msg); throw new ReferenceError(msg);
} }
@ -107721,7 +107766,7 @@ class Parser {
} }
*step() { *step() {
const top = this.peek(1); const top = this.peek(1);
if (this.type === 'doc-end' && (!top || top.type !== 'doc-end')) { if (this.type === 'doc-end' && top?.type !== 'doc-end') {
while (this.stack.length > 0) while (this.stack.length > 0)
yield* this.pop(); yield* this.pop();
this.stack.push({ this.stack.push({
@ -108253,7 +108298,7 @@ class Parser {
do { do {
yield* this.pop(); yield* this.pop();
top = this.peek(1); top = this.peek(1);
} while (top && top.type === 'flow-collection'); } while (top?.type === 'flow-collection');
} }
else if (fc.end.length === 0) { else if (fc.end.length === 0) {
switch (this.type) { switch (this.type) {
@ -110439,7 +110484,7 @@ function stringifyNumber({ format, minFractionDigits, tag, value }) {
const num = typeof value === 'number' ? value : Number(value); const num = typeof value === 'number' ? value : Number(value);
if (!isFinite(num)) if (!isFinite(num))
return isNaN(num) ? '.nan' : num < 0 ? '-.inf' : '.inf'; return isNaN(num) ? '.nan' : num < 0 ? '-.inf' : '.inf';
let n = JSON.stringify(value); let n = Object.is(value, -0) ? '-0' : JSON.stringify(value);
if (!format && if (!format &&
minFractionDigits && minFractionDigits &&
(!tag || tag === 'tag:yaml.org,2002:float') && (!tag || tag === 'tag:yaml.org,2002:float') &&
@ -110570,7 +110615,7 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
ws += `\n${stringifyComment.indentComment(cs, ctx.indent)}`; ws += `\n${stringifyComment.indentComment(cs, ctx.indent)}`;
} }
if (valueStr === '' && !ctx.inFlow) { if (valueStr === '' && !ctx.inFlow) {
if (ws === '\n') if (ws === '\n' && valueComment)
ws = '\n\n'; ws = '\n\n';
} }
else { else {

View file

@ -1,4 +1,4 @@
module sample module github.com/golangci/sample
go 1.24.0 go 1.24.0

View file

@ -1,4 +1,4 @@
module sample module github.com/golangci/sample
go 1.24.0 go 1.24.0

View file

@ -0,0 +1,3 @@
module github.com/golangci/actiona
go 1.24.0

View file

@ -0,0 +1,3 @@
module github.com/golangci/actiona/suba
go 1.24.0

View 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")
}

View file

@ -0,0 +1,3 @@
module github.com/golangci/actionb
go 1.24.0

View 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")
}

View file

@ -0,0 +1,3 @@
module github.com/golangci/actionc
go 1.24.0

View 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")
}

26
fixtures/simple/sample.go Normal file
View 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")
}

2
go.mod
View file

@ -1,3 +1,3 @@
module github.com/golangci/golangci-lint-action module github.com/golangci/golangci-lint-action
go 1.23 go 1.24.0

313
package-lock.json generated
View file

@ -16,16 +16,16 @@
"@actions/http-client": "^3.0.0", "@actions/http-client": "^3.0.0",
"@actions/tool-cache": "^2.0.2", "@actions/tool-cache": "^2.0.2",
"@octokit/plugin-retry": "^6.1.0", "@octokit/plugin-retry": "^6.1.0",
"@types/node": "^24.10.0", "@types/node": "^24.10.1",
"@types/semver": "^7.7.1", "@types/semver": "^7.7.1",
"@types/tmp": "^0.2.6", "@types/tmp": "^0.2.6",
"@types/which": "^3.0.4", "@types/which": "^3.0.4",
"tmp": "^0.2.5", "tmp": "^0.2.5",
"which": "^5.0.0", "which": "^6.0.0",
"yaml": "^2.8.1" "yaml": "^2.8.2"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.46.2", "@typescript-eslint/eslint-plugin": "^8.48.1",
"@typescript-eslint/parser": "^8.32.1", "@typescript-eslint/parser": "^8.32.1",
"@vercel/ncc": "^0.38.4", "@vercel/ncc": "^0.38.4",
"eslint": "^8.57.1", "eslint": "^8.57.1",
@ -33,7 +33,7 @@
"eslint-plugin-import": "^2.32.0", "eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.4", "eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-simple-import-sort": "^12.1.1",
"prettier": "^3.6.2", "prettier": "^3.7.4",
"typescript": "^5.9.3" "typescript": "^5.9.3"
}, },
"engines": { "engines": {
@ -528,6 +528,7 @@
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz",
"integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==",
"peer": true,
"dependencies": { "dependencies": {
"@octokit/auth-token": "^4.0.0", "@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0", "@octokit/graphql": "^7.1.0",
@ -730,9 +731,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "24.10.0", "version": "24.10.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
"integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~7.16.0" "undici-types": "~7.16.0"
@ -788,17 +789,17 @@
"integrity": "sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w==" "integrity": "sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w=="
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz",
"integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==", "integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/scope-manager": "8.48.1",
"@typescript-eslint/type-utils": "8.46.2", "@typescript-eslint/type-utils": "8.48.1",
"@typescript-eslint/utils": "8.46.2", "@typescript-eslint/utils": "8.48.1",
"@typescript-eslint/visitor-keys": "8.46.2", "@typescript-eslint/visitor-keys": "8.48.1",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^7.0.0", "ignore": "^7.0.0",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
@ -812,7 +813,7 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.46.2", "@typescript-eslint/parser": "^8.48.1",
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
@ -828,16 +829,17 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz",
"integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/scope-manager": "8.48.1",
"@typescript-eslint/types": "8.46.2", "@typescript-eslint/types": "8.48.1",
"@typescript-eslint/typescript-estree": "8.46.2", "@typescript-eslint/typescript-estree": "8.48.1",
"@typescript-eslint/visitor-keys": "8.46.2", "@typescript-eslint/visitor-keys": "8.48.1",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@ -853,14 +855,14 @@
} }
}, },
"node_modules/@typescript-eslint/project-service": { "node_modules/@typescript-eslint/project-service": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz",
"integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.46.2", "@typescript-eslint/tsconfig-utils": "^8.48.1",
"@typescript-eslint/types": "^8.46.2", "@typescript-eslint/types": "^8.48.1",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@ -875,14 +877,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz",
"integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.46.2", "@typescript-eslint/types": "8.48.1",
"@typescript-eslint/visitor-keys": "8.46.2" "@typescript-eslint/visitor-keys": "8.48.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -893,9 +895,9 @@
} }
}, },
"node_modules/@typescript-eslint/tsconfig-utils": { "node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz",
"integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -910,15 +912,15 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz",
"integrity": "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==", "integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.46.2", "@typescript-eslint/types": "8.48.1",
"@typescript-eslint/typescript-estree": "8.46.2", "@typescript-eslint/typescript-estree": "8.48.1",
"@typescript-eslint/utils": "8.46.2", "@typescript-eslint/utils": "8.48.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^2.1.0" "ts-api-utils": "^2.1.0"
}, },
@ -935,9 +937,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz",
"integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -949,21 +951,20 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz",
"integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/project-service": "8.46.2", "@typescript-eslint/project-service": "8.48.1",
"@typescript-eslint/tsconfig-utils": "8.46.2", "@typescript-eslint/tsconfig-utils": "8.48.1",
"@typescript-eslint/types": "8.46.2", "@typescript-eslint/types": "8.48.1",
"@typescript-eslint/visitor-keys": "8.46.2", "@typescript-eslint/visitor-keys": "8.48.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
"minimatch": "^9.0.4", "minimatch": "^9.0.4",
"semver": "^7.6.0", "semver": "^7.6.0",
"tinyglobby": "^0.2.15",
"ts-api-utils": "^2.1.0" "ts-api-utils": "^2.1.0"
}, },
"engines": { "engines": {
@ -1017,16 +1018,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz",
"integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", "integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.7.0", "@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/scope-manager": "8.48.1",
"@typescript-eslint/types": "8.46.2", "@typescript-eslint/types": "8.48.1",
"@typescript-eslint/typescript-estree": "8.46.2" "@typescript-eslint/typescript-estree": "8.48.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -1041,13 +1042,13 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.46.2", "version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz",
"integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.46.2", "@typescript-eslint/types": "8.48.1",
"eslint-visitor-keys": "^4.2.1" "eslint-visitor-keys": "^4.2.1"
}, },
"engines": { "engines": {
@ -1103,6 +1104,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@ -1344,19 +1346,6 @@
"concat-map": "0.0.1" "concat-map": "0.0.1"
} }
}, },
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/call-bind": { "node_modules/call-bind": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
@ -1811,6 +1800,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
@ -1867,6 +1857,7 @@
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"eslint-config-prettier": "bin/cli.js" "eslint-config-prettier": "bin/cli.js"
}, },
@ -2135,36 +2126,6 @@
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
"dev": true "dev": true
}, },
"node_modules/fast-glob": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.2",
"merge2": "^1.3.0",
"micromatch": "^4.0.8"
},
"engines": {
"node": ">=8.6.0"
}
},
"node_modules/fast-glob/node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fast-json-stable-stringify": { "node_modules/fast-json-stable-stringify": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@ -2186,6 +2147,24 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/file-entry-cache": { "node_modules/file-entry-cache": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@ -2198,19 +2177,6 @@
"node": "^10.12.0 || >=12.0.0" "node": "^10.12.0 || >=12.0.0"
} }
}, },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/find-up": { "node_modules/find-up": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@ -2831,16 +2797,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/is-number-object": { "node_modules/is-number-object": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
@ -3028,10 +2984,11 @@
} }
}, },
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "4.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^2.0.1" "argparse": "^2.0.1"
}, },
@ -3121,30 +3078,6 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=8.6"
}
},
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@ -3428,13 +3361,14 @@
"dev": true "dev": true
}, },
"node_modules/picomatch": { "node_modules/picomatch": {
"version": "2.3.1", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=8.6" "node": ">=12"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
@ -3460,10 +3394,12 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.6.2", "version": "3.7.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true, "dev": true,
"license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
@ -4025,6 +3961,23 @@
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true "dev": true
}, },
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/tmp": { "node_modules/tmp": {
"version": "0.2.5", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
@ -4034,19 +3987,6 @@
"node": ">=14.14" "node": ">=14.14"
} }
}, },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/tr46": { "node_modules/tr46": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@ -4199,6 +4139,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -4273,9 +4214,10 @@
} }
}, },
"node_modules/which": { "node_modules/which": {
"version": "5.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz",
"integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==",
"license": "ISC",
"dependencies": { "dependencies": {
"isexe": "^3.1.1" "isexe": "^3.1.1"
}, },
@ -4283,7 +4225,7 @@
"node-which": "bin/which.js" "node-which": "bin/which.js"
}, },
"engines": { "engines": {
"node": "^18.17.0 || >=20.5.0" "node": "^20.17.0 || >=22.9.0"
} }
}, },
"node_modules/which-boxed-primitive": { "node_modules/which-boxed-primitive": {
@ -4410,15 +4352,18 @@
} }
}, },
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.8.1", "version": "2.8.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
"license": "ISC", "license": "ISC",
"bin": { "bin": {
"yaml": "bin.mjs" "yaml": "bin.mjs"
}, },
"engines": { "engines": {
"node": ">= 14.6" "node": ">= 14.6"
},
"funding": {
"url": "https://github.com/sponsors/eemeli"
} }
}, },
"node_modules/yocto-queue": { "node_modules/yocto-queue": {

View file

@ -34,16 +34,16 @@
"@actions/http-client": "^3.0.0", "@actions/http-client": "^3.0.0",
"@octokit/plugin-retry": "^6.1.0", "@octokit/plugin-retry": "^6.1.0",
"@actions/tool-cache": "^2.0.2", "@actions/tool-cache": "^2.0.2",
"@types/node": "^24.10.0", "@types/node": "^24.10.1",
"@types/semver": "^7.7.1", "@types/semver": "^7.7.1",
"@types/tmp": "^0.2.6", "@types/tmp": "^0.2.6",
"@types/which": "^3.0.4", "@types/which": "^3.0.4",
"tmp": "^0.2.5", "tmp": "^0.2.5",
"which": "^5.0.0", "which": "^6.0.0",
"yaml": "^2.8.1" "yaml": "^2.8.2"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.46.2", "@typescript-eslint/eslint-plugin": "^8.48.1",
"@typescript-eslint/parser": "^8.32.1", "@typescript-eslint/parser": "^8.32.1",
"@vercel/ncc": "^0.38.4", "@vercel/ncc": "^0.38.4",
"eslint": "^8.57.1", "eslint": "^8.57.1",
@ -51,7 +51,7 @@
"eslint-plugin-import": "^2.32.0", "eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.4", "eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-simple-import-sort": "^12.1.1",
"prettier": "^3.6.2", "prettier": "^3.7.4",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View file

@ -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()) {

View file

@ -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

View file

@ -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

View file

@ -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
@ -34,12 +34,13 @@ export async function install(binPath: string): Promise<string> {
rootDir = process.cwd() rootDir = process.cwd()
} }
const configFile = [".custom-gcl.yml", ".custom-gcl.yaml", ".custom-gcl.json"] const configFile = ["yml", "yaml", "json"]
.map((v) => path.join(rootDir, v)) .map((ext) => `.custom-gcl.${ext}`)
.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}`)
@ -53,7 +54,7 @@ export async function install(binPath: string): Promise<string> {
const v: string = core.getInput(`version`) const v: string = core.getInput(`version`)
if (v !== "" && config.version !== v) { if (v !== "" && config.version !== v) {
core.warning( core.warning(
`The golangci-lint version (${config.version}) defined inside in ${configFile} does not match the version defined in the action (${v})` `The golangci-lint version (${config.version}) defined inside ${configFile} does not match the version defined in the action (${v})`
) )
} }
@ -73,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}`)
})
} }

View file

@ -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)

View file

@ -67,6 +67,12 @@ const isLessVersion = (a: Version, b: Version): boolean => {
const getRequestedVersion = (): Version => { const getRequestedVersion = (): Version => {
let requestedVersion = core.getInput(`version`) let requestedVersion = core.getInput(`version`)
let versionFilePath = core.getInput(`version-file`)
if (requestedVersion && versionFilePath) {
core.warning(`Both version (${requestedVersion}) and version-file (${versionFilePath}) inputs are specified, only version will be used`)
}
const workingDirectory = core.getInput(`working-directory`) const workingDirectory = core.getInput(`working-directory`)
let goMod = "go.mod" let goMod = "go.mod"
@ -83,6 +89,27 @@ const getRequestedVersion = (): Version => {
} }
} }
if (requestedVersion == "" && versionFilePath) {
if (workingDirectory) {
versionFilePath = path.join(workingDirectory, versionFilePath)
}
if (!fs.existsSync(versionFilePath)) {
throw new Error(`The specified golangci-lint version file at: ${versionFilePath} does not exist`)
}
const content = fs.readFileSync(versionFilePath, "utf-8")
if (path.basename(versionFilePath) === ".tool-versions") {
// asdf/mise file.
const match = content.match(/^golangci-lint\s+([^\n#]+)/m)
requestedVersion = match ? "v" + match[1].trim().replace(/^v/gi, "") : ""
} else {
// .golangci-lint-version file.
requestedVersion = "v" + content.trim().replace(/^v/gi, "")
}
}
const parsedRequestedVersion = parseVersion(requestedVersion) const parsedRequestedVersion = parseVersion(requestedVersion)
if (parsedRequestedVersion == null) { if (parsedRequestedVersion == null) {
return null return null