Files
f2b/docs/linting.md
Ismo Vuorinen 98b53d84b5 fix: repair Renovate config, convert Makefile to go run, update GitHub Actions (#120)
* fix: repair Renovate config and convert Makefile to go run (#117)

- Remove non-existent `github>renovatebot/presets:golang` preset that
  broke Renovate PR creation
- Replace deprecated `fileMatch` with `managerFilePatterns` in
  customManagers
- Rewrite regex to match new Makefile pattern (renovate comment above
  version variable assignment)
- Fix `matchFileNames` glob pattern (`*.mk` -> `**/*.mk`)
- Convert all tool invocations from `go install` + global binary to
  `go run tool@version` for reproducible builds
- Convert npm global tools to `npx --yes` invocations
- Remove `dev-deps` and `check-deps` targets (tools auto-download)
- Add mdformat pre-commit hook with GFM support and config
- Add `fmt-md` Makefile target for manual markdown formatting
- Update local golangci-lint pre-commit hook to use `go run`
- Apply golangci-lint v2.10.1 auto-fixes (fmt.Fprintf optimization)
- Add nolint:gosec annotations for legitimate exec.Command usage
- Exclude .serena/ from mdformat and megalinter
- Add markdown indent_size=unset in .editorconfig for CommonMark compat

* chore(deps): update GitHub Actions to latest versions

- anthropics/claude-code-action: v1.0.34 -> v1.0.64
- actions/setup-go: v6.2.0 -> v6.3.0
- actions/upload-artifact: v6.0.0 -> v7.0.0
- goreleaser/goreleaser-action: v6.4.0 -> v7.0.0
- docker/login-action: v3.6.0 -> v3.7.0
- ivuorinen/actions: v2026.01.21 -> v2026.02.24

* fix: address code review feedback

- Fix issue template YAML frontmatter (replace underscore separators
  with proper --- delimiters); exclude templates from mdformat
- Replace string(rune(n)) with strconv.Itoa(n) in test files to produce
  deterministic numeric directory names instead of Unicode characters
- Remove stale `make dev-deps` reference in README, replace with
  `make dev-setup`
- Extract ban/unban format strings into shared.MetricsFmtBanOperations
  and shared.MetricsFmtUnbanOperations constants
- Replace hardcoded coverage percentages in README with evergreen
  phrasing

* fix: address round 2 code review feedback for PR #120

- Fix corrupted path traversal example in docs/security.md
- Fix Renovate .mk regex to match nested paths (.*\.mk$)
- Update checkmake pre-commit hook to v0.3.2 to match Makefile
- Add sync.WaitGroup to unsynchronized goroutines in security tests
- Fix fmt-md target to use pre-commit run mdformat
- Pin markdownlint-cli2 to v0.21.0 in lint-md target
- Standardize //nolint:gosec to // #nosec annotations for gosec CLI

* fix(ci): install PyYAML dependency for PR lint workflow

The pr-lint workflow uses ivuorinen/actions/pr-lint which internally
calls validate-inputs running a Python script that imports yaml.
Python was set up but PyYAML was never installed, causing
ModuleNotFoundError at runtime.

* fix: address round 3 code review feedback for PR #120

- Wrap Windows-style path traversal example in backtick code span so
  backslashes render literally in docs/security.md
- Add Renovate-managed MARKDOWNLINT_CLI2_VERSION variable in Makefile
  to match the pattern used by all other tool versions
2026-03-01 19:09:17 +02:00

8.4 KiB

Linting and Code Quality

This document describes the linting and code quality tools used in the f2b project.

Overview

The project uses a unified pre-commit approach for linting and code quality, ensuring consistency across development, CI, and pre-commit hooks.

Supported Tools

  • Go: gofmt, go-build-mod, go-mod-tidy, golangci-lint
  • Markdown: markdownlint
  • YAML: yamlfmt (Google's YAML formatter)
  • GitHub Actions: actionlint
  • EditorConfig: editorconfig-checker
  • Makefile: checkmake

Quick Start

Install Development Dependencies

make dev-deps
make pre-commit-setup
# or manually:
pip install pre-commit
pre-commit install

Run All Linters

Preferred Method (Unified Tooling):

# Run all linting and formatting checks
make lint

# Run all linters with strict mode
make lint-strict

# Run linters with auto-fix
make lint-fix

Individual Pre-commit Hooks:

# Run specific hook
pre-commit run yamlfmt --all-files
pre-commit run golangci-lint --all-files
pre-commit run markdownlint --all-files
pre-commit run checkmake --all-files

Individual Tool Commands:

make lint-go           # Go only
make lint-yaml         # YAML only
make lint-actions      # GitHub Actions only
make lint-make         # Makefile only

Configuration Files

Read these files BEFORE making changes:

  • .editorconfig: Indentation, final newlines, encoding
  • .golangci.yml: Go linting rules and timeout settings
  • .markdownlint.json: Markdown formatting rules (120 char limit)
  • .yamlfmt.yaml: YAML formatting rules
  • .pre-commit-config.yaml: Pre-commit hook configuration

Linting Tools

Go Linting

gofmt (via pre-commit-golang)

  • Purpose: Code formatting
  • Configuration: Uses Go standard formatting
  • Hook: go-fmt

go-build-mod (via pre-commit-golang)

  • Purpose: Verify code builds
  • Configuration: Uses go.mod
  • Hook: go-build-mod

go-mod-tidy (via pre-commit-golang)

  • Purpose: Clean up go.mod and go.sum
  • Configuration: Automatic
  • Hook: go-mod-tidy

golangci-lint (local hook)

  • Purpose: Comprehensive Go linting with multiple analyzers
  • Configuration: .golangci.yml
  • Features: 50+ linters, fast caching, detailed reporting
  • Hook: golangci-lint

Markdown Linting

markdownlint (local hook)

  • Purpose: Markdown formatting and style consistency
  • Configuration: .markdownlint.json
  • Key rules:
    • Line length limit: 120 characters
    • Disabled: HTML tags, bare URLs, first-line heading requirement
  • Hook: markdownlint

YAML Linting

yamlfmt (official Google repo)

  • Purpose: YAML formatting and linting
  • Configuration: .yamlfmt.yaml
  • Key features:
    • Document start markers (---)
    • Line length limit: 120 characters
    • Respects .gitignore
    • Retains single line breaks
    • EOF newlines
  • Hook: yamlfmt

GitHub Actions Linting

actionlint (local hook)

  • Purpose: GitHub Actions workflow validation
  • Configuration: Default configuration
  • Features:
    • Syntax validation
    • shellcheck integration
    • Action version checking
    • Expression validation
  • Hook: actionlint

EditorConfig

editorconfig-checker (local hook)

  • Purpose: Verify EditorConfig compliance
  • Configuration: .editorconfig
  • Features: Checks indentation, final newlines, encoding
  • Hook: editorconfig-checker

Makefile Linting

checkmake (official repo)

  • Purpose: Makefile syntax and best practices validation
  • Configuration: Default rules (no config file needed)
  • Features:
    • Checks for missing .PHONY declarations
    • Validates target dependencies
    • Enforces Makefile best practices
    • Detects syntax errors and common mistakes
  • Hook: checkmake
  • Manual Usage: checkmake Makefile

Pre-commit Integration

The project uses .pre-commit-config.yaml for unified tooling:

Hook Sources

  • pre-commit/pre-commit-hooks: Basic file checks
  • tekwizely/pre-commit-golang: Go-specific hooks
  • google/yamlfmt: Official YAML formatter
  • mrtazz/checkmake: Official Makefile linter
  • local: Custom hooks for project-specific tools

Automatic Setup

# Install pre-commit and hooks
make pre-commit-setup

# Hooks will run automatically on commit
git commit -m "your changes"

Manual Execution

# Run all hooks
pre-commit run --all-files

# Run specific hook
pre-commit run yamlfmt
pre-commit run golangci-lint
pre-commit run checkmake

# Update hook versions
pre-commit autoupdate

CI Integration

GitHub Actions

Both workflows now use unified pre-commit:

  • .github/workflows/lint.yml: Main linting workflow
  • .github/workflows/pr-lint.yml: Pull request linting

Workflow Features

  • Single pre-commit/action@v3.0.1 step
  • Automatic tool installation and caching
  • Consistent behavior with local development
  • Python and Go environment setup

Development Workflow

Before Committing

  1. Read configuration files first: .editorconfig, .golangci.yml, .markdownlint.json, .yamlfmt.yaml, .pre-commit-config.yaml
  2. Apply configuration rules during development
  3. Run pre-commit checks: pre-commit run --all-files
  4. Fix all issues across the project
  5. Run tests: go test ./...
  • Go: Use gopls language server with auto-format on save
  • Markdown: Install markdownlint extension
  • YAML: Install YAML extension with yamlfmt support
  • EditorConfig: Install EditorConfig plugin

Configuration Details

.yamlfmt.yaml

---
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/yamlfmt/main/schema.json
formatter:
  type: basic
  include_document_start: true
  gitignore_excludes: true
  retain_line_breaks_single: true
  eof_newline: true
  max_line_length: 120
  indent: 2

.markdownlint.json

{
  "default": true,
  "MD013": {
    "line_length": 120,
    "headings": false,
    "tables": false,
    "code_blocks": false
  },
  "MD033": false,
  "MD041": false,
  "MD034": false
}

.golangci.yml

Comprehensive Go linting configuration with timeout settings and enabled/disabled linters.

Schema Support

All YAML files include schema references for better IDE support:

  • GitHub workflows: $schema=https://json.schemastore.org/github-workflow.json
  • Pre-commit config: $schema=https://json.schemastore.org/pre-commit-config.json
  • GitHub labels: $schema=https://json.schemastore.org/github-labels.json

Troubleshooting

Common Issues

Pre-commit hook failures

Solution: Run pre-commit run --all-files locally to identify issues

"command not found" errors

Solution: Run make dev-deps and make pre-commit-setup

YAML formatting differences

Solution: Use yamlfmt . to format files consistently

Debugging Tips

  1. Run individual hooks to isolate issues
  2. Use --verbose flag with pre-commit
  3. Check configuration files for rule customizations
  4. Verify tool versions match CI environment

Adding New Linting Rules

Process

  1. Update configuration files (.markdownlint.json, .yamlfmt.yaml, etc.)
  2. Test changes locally: pre-commit run --all-files
  3. Update .pre-commit-config.yaml if adding new hooks
  4. Document changes in this file
  5. Consider backward compatibility

Best Practices

  • Start with warnings before making rules errors
  • Use pre-commit for consistency across environments
  • Test with existing codebase before enforcing
  • Leverage auto-fix capabilities when available

Security Considerations

Tool Installation

  • All tools installed from official repositories
  • Versions pinned in .pre-commit-config.yaml
  • Dependencies verified before execution

Code Analysis

  • Linters help identify potential security issues
  • Static analysis catches common vulnerabilities
  • Configuration validation prevents misconfigurations

Performance

Optimization Tips

  • Pre-commit caches tool installations
  • Hooks run in parallel when possible
  • Use golangci-lint cache for faster Go linting
  • Skip unchanged files automatically

Benefits of Pre-commit

  • Consistency: Same tools in dev, CI, and pre-commit
  • Speed: Cached tool installations
  • Reliability: No version mismatches
  • Maintenance: Centralized configuration