golangci-lint-action

repository·main·Indexed 20 days ago

https://github.com/golangci/golangci-lint-action

The official GitHub Action for golangci-lint, designed to run the golangci-lint tool and report issues directly in GitHub via annotations and logs. It supports multiple operating systems (Ubuntu, macOS, Windows), Go workspaces with multiple modules, and provides configurable installation modes (binary, goinstall, none) and caching strategies to optimize analysis speed.

Tokens
4.2K
Snippets
7
Records
20
Agent score
76%

What's inside golangci-lint-action

  1. Understand the golangci-lint-action execution model

    main

    The action is implemented as a JavaScript-based action rather than a Docker-based action to improve speed and simplify caching. It supports multiple platforms including ubuntu, macos, and windows across x32 and x64 architectures.

    The action follows a three-step lifecycle:

    1. Environment Setup: Restores existing cache, fetches the latest golangci-lint patch version for the specified minor version, and installs golangci-lint using @actions/tool-cache.
    2. Execution: Runs golangci-lint using the args provided by the user.
    3. Cache Persistence: Saves the updated cache for subsequent builds.
  2. How caching works in golangci-lint-action

    main

    The action automatically manages caching for the ~/.cache/golangci-lint directory to speed up subsequent runs.

    Cache Key Strategy:

    • Primary Key: golangci-lint.cache-{runner_os}-{working_directory}-{interval_number}-{go.mod_hash}
    • Invalidation:
      • The {interval_number} ensures the cache is periodically invalidated (every 7 days).
      • The {go.mod_hash} ensures the cache is invalidated immediately if your Go dependencies change.
    • Restore Keys: If an exact match for the primary key is not found, GitHub Actions uses the prefix golangci-lint.cache-{runner_os}-{working_directory}-{interval_number}- to find the most recent compatible cache.
  3. Set up golangci-lint-action with a simple workflow

    main

    To run golangci-lint in your GitHub repository, create a .github/workflows/golangci-lint.yml file. It is recommended to run this action in a separate job from other tasks like go test to allow for parallel execution.

    Note: If you intend to use the only-new-issues option, you must grant the workflow pull-requests: read permissions.

    name: golangci-lint
    on:
      push:
        branches:
          - main
          - master
      pull_request:
    
    permissions:
      contents: read
      # Optional: allow read access to pull requests. Use with `only-new-issues` option.
      # pull-requests: read
    
    jobs:
      golangci:
        name: lint
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v6
          - uses: actions/setup-go@v6
            with:
              go-version: stable
          - name: golangci-lint
            uses: golangci/golangci-lint-action@v9
            with:
              version: v2.12
  4. Configure golangci-lint version and installation mode

    main

    You can control how golangci-lint is installed using the version, version-file, and install-mode options.

    version

    Specifies the version of golangci-lint to use. The allowed values depend on the install-mode:

    • binary (default): Supports versions like v2.3, v2.3.4, or latest.
    • goinstall: Supports v2.3.4, latest, or a specific commit hash.
    • none: The version is ignored.

    version-file

    Reads the version from a file relative to the project root or working-directory. Supports .golangci-lint-version and .tool-versions files. This only works when install-mode is set to binary.

    install-mode

    Determines the installation method:

    • binary (default)
    • goinstall (not recommended)
    • none (only use if you want to skip installation)

    install-only

    If set to true, the action installs the binary but does not execute the linting process.

    # Example: specifying a version
    uses: golangci/golangci-lint-action@v9
    with:
      version: v2.12
    
    # Example: using a version file
    uses: golangci/golangci-lint-action@v9
    with:
      version-file: .tool-versions
    
    # Example: only installing, not running
    uses: golangci/golangci-lint-action@v9
    with:
      install-only: true
  5. Enable GitHub annotations for linting issues

    main

    To see linting issues directly in the GitHub UI as annotations, ensure you use the default text output format.

    Annotations work if:

    1. You use actions/setup-go in the job, OR
    2. You set problem-matchers: true in the action configuration.

    Required Permissions:

    permissions:
      contents: read
      pull-requests: read # Required only if using 'only-new-issues'
    uses: golangci/golangci-lint-action@v9
    with:
      problem-matchers: true
  6. Run golangci-lint across multiple operating systems

    main

    You can use a GitHub Actions matrix strategy to run linting on multiple operating systems (e.g., ubuntu-latest, macos-latest, and windows-latest).

    Important for Windows users: To ensure line endings are properly formatted for Windows builds, add a .gitattributes file to your repository root with the following content:

    *.go text eol=lf
    name: golangci-lint
    on:
      push:
        branches:
          - main
          - master
      pull_request:
    
    permissions:
      contents: read
      # Optional: allow read access to pull requests. 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@v6
          - uses: actions/setup-go@v6
            with:
              go-version: ${{ matrix.go }}
          - name: golangci-lint
            uses: golangci/golangci-lint-action@v9
            with:
              version: v2.12
  7. Run golangci-lint in a Go Workspace (Multiple Modules)

    main

    In repositories using Go workspaces or multiple modules, you can dynamically detect modules and run the linter for each one using a matrix. This involves a detect-modules job that uses go list -m -json to find module directories, which are then passed to the golangci-lint job via job outputs.

    name: golangci-lint
    
    on:
      pull_request:
      push:
        branches:
          - main
          - master
    
    env:
      GO_VERSION: stable
      GOLANGCI_LINT_VERSION: v2.12
    
    jobs:
      detect-modules:
        runs-on: ubuntu-latest
        outputs:
          modules: ${{ steps.set-modules.outputs.modules }}
        steps:
          - uses: actions/checkout@v6
          - uses: actions/setup-go@v6
            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@v6
          - uses: actions/setup-go@v6
            with:
              go-version: ${{ env.GO_VERSION }}
          - name: golangci-lint ${{ matrix.modules }}
            uses: golangci/golangci-lint-action@v9
            with:
              version: ${{ env.GOLANGCI_LINT_VERSION }}
              working-directory: ${{ matrix.modules }}
  8. Configure linting execution and arguments

    main

    Control how the linter runs using these options:

    verify

    (Default: true) Validates your golangci-lint configuration file. Set to false to skip validation.

    working-directory

    Sets the directory where golangci-lint runs. Useful for monorepos. Defaults to the project root.

    args

    Pass custom command-line arguments to golangci-lint. Important: Use = between flags and values (e.g., --flag=value) because the action parses arguments based on spaces.

    only-new-issues

    (Default: false) Shows only issues introduced in the current change.

    • pull_request / pull_request_target: Uses the GitHub API to get the PR diff and applies --new-from-patch.
    • push: Uses the GitHub API to get the commit diff and applies --new-from-patch.
    • merge_group: Uses --new-from-rev (requires fetch-depth: 0 in actions/checkout).

    When using only-new-issues, you may need to provide a github-token if the default github.token lacks sufficient permissions.

    uses: golangci/golangci-lint-action@v9
    with:
      working-directory: somedir
      args: --config=/my/path/.golangci.yml --issues-exit-code=0
      only-new-issues: true
      github-token: ${{ secrets.GITHUB_TOKEN }}
  9. Configure caching for golangci-lint

    main

    The action uses @actions/cache to speed up analysis. You can manage it with these options:

    • skip-cache: (Default: false) Disables all caching functionality entirely. This takes precedence over other cache settings.
    • skip-save-cache: (Default: false) Prevents the cache from being saved at the end of the run, though it may still be restored from previous runs.
    • cache-invalidation-interval: (Default: 7) The number of days before the cache is invalidated and refreshed. Setting this to <= 0 forces invalidation every run.
    uses: golangci/golangci-lint-action@v9
    with:
      skip-cache: true
      cache-invalidation-interval: 15
  10. Use experimental options in golangci-lint-action

    main

    Experimental options are passed via the experimental key as a comma-separated string. These may be removed or converted to dedicated options in the future.

    Supported experimental options:

    • automatic-module-directories: Runs golangci-lint in each module directory. Useful for monorepos. Note that the cache key will refer to the working-directory and version detection only works for single-module projects.
    • no-run-logs-group: Disables the grouping of logs from the golangci-lint run.
  11. Determine the golangci-lint version to use

    main

    The action determines which version of golangci-lint to run using a specific priority order. You can specify the version via the version input, a version file, or by letting the action detect it from your project files.

    Version Resolution Priority

    1. version input: If provided, this takes highest precedence. If both version and version-file are provided, a warning is issued and only version is used.
    2. go.mod detection: If version is empty, the action looks for github.com/golangci/golangci-lint/v2 in your go.mod file.
    3. version-file input: If version is empty, the action reads the file specified in version-file.
      • If the file is .tool-versions (asdf/mise), it looks for a line starting with golangci-lint.
      • For other files (like .golangci-lint-version), it reads the content directly.
    4. Default: If no version is found, it defaults to latest.

    Supported Versions

    • The action requires golangci-lint v2.1.0 or later.
    • Versions where the major version is not 2 are not supported by golangci-lint-action (v7+).
  12. Build a custom golangci-lint binary using a configuration file

    main

    The action supports building a custom golangci-lint binary if a specific configuration file is present in the working directory. This allows for extending the linting process via the plugin module system.

    To trigger a custom build, place one of the following files in your working-directory:

    • .custom-gcl.yml
    • .custom-gcl.yaml
    • .custom-gcl.json

    The action will detect this file, parse it, and execute the custom command using the base golangci-lint binary. If the version input in the GitHub Action does not match the version specified in the config file, a warning will be issued.