GitHub - golangci/golangci-lint-action: Official GitHub Action for golangci-lint from its authors (original) (raw)

golangci-lint-action

Build Status

It's the official GitHub action for golangci-lint from its authors.

The action runs golangci-lint and reports issues from linters.

GitHub Annotations

Logs

Supporting Us

GitHub Sponsors Open Collective backers and sponsors Linter Authors

golangci-lint is a free and open-source project built by volunteers.

If you value it, consider supporting us; we appreciate it! ❤️

How to use

We recommend running this action in a job separate from other jobs (go test, etc.) because different jobs run in parallel.

Add .github/workflows/golangci-lint.yml with the following contents:

Simple Example

name: golangci-lint on: push: branches: - main - master pull_request:

permissions: contents: read

Optional: allow read access to pull request. Use with only-new-issues option.

pull-requests: read

jobs: golangci: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: stable - name: golangci-lint uses: golangci/golangci-lint-action@v8 with: version: v2.1

Multiple OS Example

name: golangci-lint on: push: branches: - main - master pull_request:

permissions: contents: read

Optional: allow read access to pull request. Use with only-new-issues option.

pull-requests: read

jobs: golangci: strategy: matrix: go: [stable] os: [ubuntu-latest, macos-latest, windows-latest] name: lint runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} - name: golangci-lint uses: golangci/golangci-lint-action@v8 with: version: v2.1

You will also likely need to add the following .gitattributes file to ensure that line endings for Windows builds are properly formatted:

Go Workspace Example

name: golangci-lint

on: pull_request: push: branches: - main - master

env: GO_VERSION: stable GOLANGCI_LINT_VERSION: v2.1

jobs: detect-modules: runs-on: ubuntu-latest outputs: modules: ${{ steps.set-modules.outputs.modules }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - id: set-modules run: echo "modules=$(go list -m -json | jq -s '.' | jq -c '[.[].Dir]')" >> $GITHUB_OUTPUT

golangci-lint: needs: detect-modules runs-on: ubuntu-latest strategy: matrix: modules: ${{ fromJSON(needs.detect-modules.outputs.modules) }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: golangci-lint ${{ matrix.modules }} uses: golangci/golangci-lint-action@v8 with: version: ${{ env.GOLANGCI_LINT_VERSION }} working-directory: ${{ matrix.modules }}

Go Workspace Example (Multiple OS)

./.github/workflows/golangci-lint.yml

name: golangci-lint (multi OS)

on: pull_request: push: branches: - main - master

jobs: golangci-lint: strategy: matrix: go-version: [ stable, oldstable ] os: [ubuntu-latest, macos-latest, windows-latest] uses: ./.github/workflows/.golangci-lint-reusable.yml with: os: ${{ matrix.os }} go-version: ${{ matrix.go-version }} golangci-lint-version: v2.1

./.github/workflows/.golangci-lint-reusable.yml

name: golangci-lint-reusable

on: workflow_call: inputs: os: description: 'OS' required: true type: string go-version: description: 'Go version' required: true type: string default: stable golangci-lint-version: description: 'Golangci-lint version' type: string default: 'v2.1'

jobs: detect-modules: runs-on: ${{ inputs.os }} outputs: modules: ${{ steps.set-modules.outputs.modules }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ inputs.go-version }} - id: set-modules shell: bash # require for Windows to be able to use $GITHUB_OUTPUT https://github.com/actions/runner/issues/2224 run: echo "modules=$(go list -m -json | jq -s '.' | jq -c '[.[].Dir]')" >> $GITHUB_OUTPUT

golangci-lint: needs: detect-modules runs-on: ${{ inputs.os }} strategy: matrix: modules: ${{ fromJSON(needs.detect-modules.outputs.modules) }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ inputs.go-version }} - name: golangci-lint ${{ matrix.modules }} uses: golangci/golangci-lint-action@v8 with: version: ${{ inputs.golangci-lint-version }} working-directory: ${{ matrix.modules }}

You will also likely need to add the following .gitattributes file to ensure that line endings for Windows builds are properly formatted:

Compatibility

Options

version

(optional)

The version of golangci-lint to use.

When install-mode is:

uses: golangci/golangci-lint-action@v8 with: version: v2.1

...

install-mode

(optional)

The mode to install golangci-lint: it can be binary, goinstall, or none.

The default value is binary.

Example

uses: golangci/golangci-lint-action@v8 with: install-mode: "goinstall"

...

github-token

(optional)

When using only-new-issues option, the GitHub API is used, so a token is required.

By default, it uses the github.token from the action.

Example

uses: golangci/golangci-lint-action@v8 with: github-token: xxx

...

verify

(optional)

This option is true by default.

If the GitHub Action detects a configuration file, the validation will be performed unless this option is set to false. If there is no configuration file, the validation is skipped.

The JSON Schema used to validate the configuration depends on the version of golangci-lint you are using.

Example

uses: golangci/golangci-lint-action@v8 with: verify: false

...

only-new-issues

(optional)

Show only new issues.

The default value is false.

uses: golangci/golangci-lint-action@v8 with: only-new-issues: true

...

working-directory

(optional)

Working directory, useful for monorepos.

Example

uses: golangci/golangci-lint-action@v8 with: working-directory: somedir

...

args

(optional)

golangci-lint command line arguments.

Note

By default, the .golangci.yml file should be at the root of the repository. The location of the configuration file can be changed by using --config=.

Important

Adding a = between the flag name and its value is important because the action parses the arguments on spaces.

Example

uses: golangci/golangci-lint-action@v8 with:

In some rare cases,

you could have to use ${{ github.workspace }} as base directory to reference your configuration file.

args: --config=/my/path/.golangci.yml --issues-exit-code=0

...

problem-matchers

(optional)

Force the usage of the embedded problem matchers.

By default, the problem matcher of Go (actions/setup-go) already handles the default golangci-lint output (text).

Works only with text format (the golangci-lint default).

https://golangci-lint.run/usage/configuration/#output-configuration

The default value is false.

Example

uses: golangci/golangci-lint-action@v8 with: problem-matchers: true

...

skip-cache

(optional)

If set to true, then all caching functionality will be completely disabled, takes precedence over all other caching options.

The default value is false.

Example

uses: golangci/golangci-lint-action@v8 with: skip-cache: true

...

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.

Example

uses: golangci/golangci-lint-action@v8 with: skip-save-cache: true

...

cache-invalidation-interval

(optional)

Periodically invalidate the 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).

Example

uses: golangci/golangci-lint-action@v8 with: cache-invalidation-interval: 15

...

Annotations

Currently, GitHub parses the action's output and creates annotations.

The restrictions of annotations are the following:

  1. Currently, they don't support Markdown formatting (see the feature request)
  2. They aren't shown in the list of comments. If you would like to have comments - please, up-vote the issue.
  3. The number of annotations is limited.

Permissions required:

permissions:

Required: allow read access to the content for analysis.

contents: read

Optional: allow read access to pull request. Use with only-new-issues option.

pull-requests: read

For annotations to work, use the default format output (text) and either use actions/setup-go in the job or enable the internal problem matchers.

Performance

The action was implemented with performance in mind:

  1. We cache data from golangci-lint analysis between builds by using @actions/cache.
  2. We don't use Docker because image pulling is slow.
  3. We do as much as we can in parallel, e.g. we download cache, and golangci-lint binary in parallel.

For example, in a repository of golangci-lint running this action without the cache takes 50s, but with cache takes 14s:

Internals

We use JavaScript-based action. We don't use Docker-based action because:

  1. Docker pulling is slow currently
  2. it's easier to use caching from @actions/cache

We support different platforms, such as ubuntu, macos, and windows with x32 and x64 archs.

Inside our action, we perform 3 steps:

  1. Setup environment running in parallel:
    • restore cache of previous analyses
    • fetch action config and find the latest golangci-lint patch version for needed version (users of this action can specify only minor version of golangci-lint). After that install golangci-lint using @actions/tool-cache
  2. Run golangci-lint with specified by user args
  3. Save cache for later builds

Caching internals

  1. We save and restore the following directory: ~/.cache/golangci-lint.
  2. The primary caching key looks like golangci-lint.cache-{runner_os}-{working_directory}-{interval_number}-{go.mod_hash}. Interval number ensures that we periodically invalidate our cache (every 7 days).go.mod hash ensures that we invalidate the cache early - as soon as dependencies have changed.
  3. We use restore keys:golangci-lint.cache-{runner_os}-{working_directory}-{interval_number}-. GitHub matches keys by prefix if we have no exact match for the primary cache.

This scheme is basic and needs improvements. Pull requests and ideas are welcome.