Skip to content
You're viewing an older version of this GitHub Action. Do you want to see the latest version instead?
shield

GitHub Action

Golangci-lint

v5.3.0

Golangci-lint

shield

Golangci-lint

Official golangci-lint action with line-attached annotations for found issues, caching and parallel execution

Installation

Copy and paste the following snippet into your .yml file.

              

- name: Golangci-lint

uses: golangci/golangci-lint-action@v5.3.0

Learn more about this action in golangci/golangci-lint-action

Choose a version

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

Compatibility

  • v5.0.0+ removes skip-pkg-cache and skip-build-cache because the cache related to Go itself is already handled by actions/setup-go.
  • v4.0.0+ requires an explicit actions/setup-go installation step before using this action: uses: actions/setup-go@v5. The skip-go-installation option has been removed.
  • v2.0.0+ works with golangci-lint version >= v1.28.3
  • v1.2.2 is deprecated due to we forgot to change the minimum version of golangci-lint to v1.28.3 (issue)
  • v1.2.1 works with golangci-lint version >= v1.14.0 (issue)

How to use

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

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: '1.22'
      - name: golangci-lint
        uses: golangci/golangci-lint-action@v5
        with:
          version: latest

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

Multiple OS Support

If you need to run linters for specific operating systems, you will need to use the action >=v2.

Here is a sample configuration file:

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: ['1.22']
        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@v5
        with:
          version: latest

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

*.go text eol=lf

Options

version

(required)

The version of golangci-lint to use.

  • When install-mode is binary (default) the value can be v1.2 or v1.2.3 or latest to use the latest version.
  • When install-mode is goinstall the value can be v1.2.3, latest, or the hash of a commit.
uses: golangci/golangci-lint-action@v5
with:
  version: latest
  # ...

install-mode

(optional)

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

The default value is binary.

uses: golangci/golangci-lint-action@v5
with:
  install-mode: "goinstall"
  # ...

only-new-issues

(optional)

Show only new issues.

The default value is false.

uses: golangci/golangci-lint-action@v5
with:
  only-new-issues: true
  # ...
  • pull_request and pull_request_target: the action gets the diff of the PR content from the GitHub API and use it with --new-from-patch.
  • push: the action gets the diff of the push content (difference between commits before and after the push) from the GitHub API and use it with --new-from-patch.
  • merge_group: the action gets the diff by using --new-from-rev option (relies on git). You should add the option fetch-depth: 0 to actions/checkout step.

working-directory

(optional)

Working directory, useful for monorepos.

uses: golangci/golangci-lint-action@v5
with:
  working-directory: somedir
  # ...

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.

uses: golangci/golangci-lint-action@v5
with:
  skip-cache: true
  # ...

skip-save-cache

(optional)

If set to true, caches will not be saved, but they may still be restored, required skip-cache: false.

The default value is false.

uses: golangci/golangci-lint-action@v5
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.

uses: golangci/golangci-lint-action@v5
with:
  cache-invalidation-interval: 15
  # ...

If set the number is <= 0, the cache will be always invalidate (Not recommended).

annotations

(optional)

To enable/disable GitHub Action annotations.

If disabled (false), the output format(s) will follow the golangci-lint configuration file (or CLI flags from args) and use the same default as golangci-lint (i.e. colored-line-number).

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

The default value is true.

uses: golangci/golangci-lint-action@v5
with:
  annotations: false
  # ...

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=

uses: golangci/golangci-lint-action@v5
with:
  args: --timeout=30m --config=/my/path/.golangci.yml --issues-exit-code=0
  # ...

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.

To enable annotations, you need to add the checks permission to your action.

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
  # Optional: allow write access to checks to allow the action to annotate code in the PR.
  checks: write

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:

  • in parallel:
    • 4s to restore 50 MB of cache
    • 1s to find and install golangci-lint
  • 1s to run golangci-lint (it takes 35s without cache)

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.

Development of this action

  1. Install act
  2. Make a symlink for act to work properly: ln -s . golangci-lint-action
  3. Prepare deps once: npm run prepare-deps
  4. Run npm run local after any change to test it