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

356 lines
8.4 KiB
Markdown

# 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
```bash
make dev-deps
```
### Set Up Pre-commit (Recommended)
```bash
make pre-commit-setup
# or manually:
pip install pre-commit
pre-commit install
```
### Run All Linters
**Preferred Method (Unified Tooling):**
```bash
# 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:**
```bash
# 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:**
```bash
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
```bash
# Install pre-commit and hooks
make pre-commit-setup
# Hooks will run automatically on commit
git commit -m "your changes"
```
### Manual Execution
```bash
# 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`
1. **Apply configuration rules** during development
1. **Run pre-commit checks**: `pre-commit run --all-files`
1. **Fix all issues** across the project
1. **Run tests**: `go test ./...`
### Recommended IDE Setup
- **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
---
# 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`
```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
1. **Use `--verbose` flag** with pre-commit
1. **Check configuration files** for rule customizations
1. **Verify tool versions** match CI environment
## Adding New Linting Rules
### Process
1. Update configuration files (`.markdownlint.json`, `.yamlfmt.yaml`, etc.)
1. Test changes locally: `pre-commit run --all-files`
1. Update `.pre-commit-config.yaml` if adding new hooks
1. Document changes in this file
1. 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