NeuroAgent

Remote Linting Configuration Management for Go Projects

Manage Go project linting settings centrally with remote repositories and URLs. Discover best practices for versioning and GitLab CI/CD integration.

Question

What is the most common approach to remote storage of linting settings for Go projects?

I have several Go projects in GitLab, and all of them require the use of linters. Instead of duplicating settings in each project in the .golangci.yml file, I would like to import them from a common repository specifically designed for storing linting configurations.

Are there examples of such projects (for example, templates in GitLab or on other platforms) with an established structure that is accepted by the Go developer community? I’m also interested in how to version such common configurations.

NeuroAgent

The most common approach to remote configuration storage for Go projects is using remote configuration files via URLs, which allows centralized management of golangci-lint settings for multiple projects without code duplication. This approach is implemented through the --config parameter with a URL to a shared configuration file, which can be stored in a separate repository, GitLab template, or file storage systems like S3/Nexus. There are several established practices, including using tagged versions of configurations for managing compatibility and GitLab CI/CD templates for automatic integration of linting into projects.


Table of Contents


Main Approaches to Remote Configuration

golangci-lint supports several methods for working with remote configuration files, allowing centralized management of linting settings for multiple projects.

URL Configuration

The simplest and most common approach is specifying a URL to a configuration file through the --config parameter. This allows storing shared settings anywhere accessible via HTTP/S:

bash
golangci-lint run --config=https://team.repository.com/lint/.golangci-lint.yaml

As noted in a GitHub discussion, this approach allows “creating a CI/CD pipeline that pushes the latest rules to an S3 bucket, nexus repository, or something similar, and for each project/service the Makefile would look like this”.

Tagged Version Repositories

A more complex but more controlled approach is using separate Git repositories with tagged versions of configurations. One participant in the discussion suggested:

“golangci-lint could do a shallow git clone of this repository by tag to get the configuration file”

This approach allows:

  • Using version control for configurations
  • Tracking change history
  • Rolling back to previous versions when necessary
  • Managing compatibility with golangci-lint versions

Mixed Approaches

In practice, combined methods are often used, where a project first tries to use a local .golangci.yml, and if it doesn’t exist, loads the configuration from a remote source. As described in one guide:

“The YAML file (.golangci.yml) can be used to configure enabled linters, settings for each linter, etc. The task is set to use .golangci.yml in the project root if it exists, otherwise it fetches a default file from a URL (which can be overridden via a variable)”.


Examples of Implementation in GitLab

GitLab provides several capabilities for implementing remote golangci-lint configuration through CI/CD pipelines and templates.

GitLab CI/CD Templates

The official GitLab documentation mentions the possibility of using templates for shared settings:

“Including .golangci.yml in the project root directory allows you to configure golangci-lint. Once recursive includes become available, you’ll be able to share job templates like this analyzer”.

A real implementation example from Reddit shows how to configure linting in GitLab CI:

yaml
lint:
  image: registry.gitlab.com/gitlab-org/gitlab-build-images:golangci-lint-alpine
  stage: test
  script: |
    golangci-lint run --config .golangci.yml --out-format code-climate | tee gl-code-quality-report.json | jq -r '.[] | "\(.location.path):\(.location.lines.begin) \(.description)"'
  artifacts:
    reports:
      codequality: gl-code-quality-report.json
  paths:
    - gl-code-quality-report.json
  allow_failure: false
  include:
    - template: "Workflows/MergeRequest-Pipelines.gitlab-ci.yml"

Specialized Templates for Go Projects

There’s a “to be continuous” project that implements a GitLab CI/CD template for building, testing, and analyzing Go projects:

“This project implements a GitLab CI/CD template for building, testing, and analyzing your Go projects”

Such templates often include:

  • Standard linting settings
  • Integration with GitLab Code Quality
  • Optimizations for working with changes in merge requests
  • Support for caching and artifacts

Versioning of Shared Configurations

Proper versioning of shared configurations is critically important for maintaining linting stability across multiple projects.

Git Tag System in Repositories

It’s recommended to use a tag system for versioning configurations, where each tag corresponds to a specific configuration version:

bash
# Example tags
v1.0.0
v1.1.0
v1.2.0

This practice allows:

  • Clear tracking of version compatibility
  • Rolling back to previous versions when necessary
  • Using semantic versioning
  • Automatically selecting a configuration version based on the golangci-lint version

Versioning by golangci-lint Version

One of the best practices is to synchronize configuration versions with golangci-lint versions. As suggested in one gist:

“By the way… has anyone considered storing this file in a special repository and tagging it according to the golangci-lint version it’s intended for?”

This allows:

  • Guaranteeing configuration compatibility with the linter version
  • Preventing errors related to golangci-lint API changes
  • Automatically updating configurations when the linter is updated

Configuration Dependency Management

It’s important to note that changes in configuration can affect linting results in projects. It’s recommended to:

  1. Test configuration changes in a pilot project before deployment
  2. Use version control to track changes
  3. Document configuration changes
  4. Provide projects with the ability to “pin” to a specific configuration version

Best Practices and Recommendations

Based on the experience of the Go developer community, several key practices can be identified when working with shared linting configurations.

Configuration Structure Organization

The following structure for the .golangci.yml file is recommended:

yaml
# Configuration version
version: 1.52.1 # Corresponds to golangci-lint version

# Linter configuration
linters:
  enable:
    - gofmt
    - golint
    - govet
    - ineffassign
    # ... other linters
  
  disable-all: false
  presets:
    - bugs
    - format
    - style

# Settings for specific linters
linters-settings:
  gofmt:
    simplify: true
  
  golint:
    min-confidence: 0.8

Compatibility Management

To ensure compatibility between configuration versions:

  1. Use semantic versioning
  2. Test configurations with different golangci-lint versions
  3. Document changes that affect linting results
  4. Provide a migration path for projects when configuration changes

CI/CD Integration

For optimal integration with CI/CD pipelines:

  1. Use the --new-from-rev=HEAD~ parameter to check only changed files
  2. Save results in a format compatible with GitLab Code Quality
  3. Configure artifacts to store linting reports
  4. Use caching to speed up linter execution

Structure of a Common Configuration Repository

An optimal repository structure for shared configurations might look like this:

lint-configs/
├── .gitignore
├── README.md
├── CHANGELOG.md
├── v1.0.0/
│   └── .golangci.yml
├── v1.1.0/
│   └── .golangci.yml
├── v1.2.0/
│   └── .golangci.yml
├── latest/
│   └── .golangci.yml (symbolic link to the latest stable version)
└── scripts/
    ├── update-config.sh
    └── validate-config.sh

Repository Components

README.md — Documentation containing:

  • Description of configurations
  • Usage instructions
  • List of available versions
  • Project requirements

CHANGELOG.md — Change log with descriptions of:

  • New features
  • Changed settings
  • Deprecated options
  • Migration recommendations

Versioned directories — Each configuration version in a separate folder with the tag as the name.

Scripts — Utilities for:

  • Configuration validation
  • Version updates
  • Changelog generation
  • Automated testing

Example Usage in a Project

In each Go project, the configuration might look like this:

yaml
# .gitlab-ci.yml
lint:
  script: |
    if [ -f .golangci.yml ]; then
      golangci-lint run --config .golangci.yml
    else
      golangci-lint run --config https://gitlab.company.com/lint-configs/v1.2.0/.golangci.yml
    fi

Or using environment variables:

bash
golangci-lint run --config="${LINT_CONFIG_URL:-https://gitlab.company.com/lint-configs/latest/.golangci.yml}"

Sources

  1. GitLab Docs - Go standards and style guidelines - Official GitLab documentation on Go standards
  2. GitHub Issue - Add support for remote config file - Discussion on supporting remote configuration files
  3. Golangci-lint Docs - Install - Documentation on installing golangci-lint
  4. Reddit - How to integrate golangci-lint into a project? - Example of configuring linting in GitLab CI
  5. GitLab MR - documentation for golangci-lint for go project CI - Merge request with documentation on golangci-lint
  6. Aaron Goldenthal - GitLab CI Pipeline for Go Projects - Guide on CI pipelines for Go projects
  7. GitHub Discussion - Sharing Configurations Across Repos - Discussion on sharing configurations between repositories
  8. Golangci-lint Docs - Settings - Documentation on linter configuration
  9. Oleg Kovalov - Go linters configuration, the right version - Article on proper versioning of linter configurations
  10. Freshman.tech - A Complete Guide to Linting Go Programs - Complete guide to linting Go programs

Conclusion

  1. Centralized configuration management through remote repositories or URLs is the most common approach to avoiding code duplication and ensuring consistent coding standards across multiple Go projects.

  2. GitLab CI/CD templates provide powerful capabilities for automating linting integration, including using shared configurations, managing artifacts, and integration with Code Quality widgets.

  3. Semantic versioning of configurations using Git tags in repositories allows controlling compatibility, rolling back changes, and managing dependencies between projects and golangci-lint versions.

  4. An optimal common repository structure includes versioned configurations, documentation, scripts for automation, and validation tools, ensuring long-term support and ease of use.

For successful implementation, it’s recommended to start small: create a basic configuration in a separate repository, test it in a few projects, and then gradually expand functionality and add new configuration versions as needed.