chore(ci): add linting and refine workflow dependencies

Adds a golangci-lint job to the CI pipeline to enforce code quality and style. The test job is now dependent on the new linting job.

The final image build job is also updated to depend on the successful completion of the test, docker-test, and dependency-review jobs, ensuring more checks pass before publishing.

Additionally, Go 1.25 is added to the testing matrix.
This commit is contained in:
2025-11-06 15:56:29 +01:00
parent 68c6f4e408
commit fe588dadda
4 changed files with 568 additions and 125 deletions

View File

@ -10,16 +10,36 @@ jobs:
autofix: autofix:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - name: Checkout code
- uses: actions/setup-go@v6 uses: actions/checkout@v5
with:
go-version-file: 'go.mod'
# goimports works like gofmt, but also fixes imports. - name: Install Task
# see https://pkg.go.dev/golang.org/x/tools/cmd/goimports uses: go-task/setup-task@v1
- run: go install golang.org/x/tools/cmd/goimports@latest
- run: goimports -w . - uses: actions/setup-go@v6
# of course we can also do just this instead: with: { go-version-file: 'go.mod' }
# - run: gofmt -w .
- name: Setup go deps
run: |
# Install golangci-lint
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin
# Install go-task dependencies
go install golang.org/x/tools/cmd/goimports@latest
- name: Run goimports
run: goimports -w .
- name: Run golangci-lint autofix
run: golangci-lint run --fix
- name: Run golangci-lint format
run: golangci-lint format
- name: Run go mod tidy
run: go mod tidy
- name: Run gopls modernize
run: task modernize
- uses: autofix-ci/action@v1 - uses: autofix-ci/action@v1

View File

@ -4,7 +4,6 @@ on:
push: push:
branches: ['master', 'develop'] branches: ['master', 'develop']
pull_request: pull_request:
branches: ['master', 'develop', 'feature/*']
env: env:
REGISTRY: ghcr.io REGISTRY: ghcr.io
@ -15,8 +14,24 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
golangci:
name: lint
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with:
go-version: stable
- name: golangci-lint
uses: golangci/golangci-lint-action@v8
with: { version: latest }
test: test:
name: Test name: Test
needs: [golangci]
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write
@ -27,6 +42,7 @@ jobs:
- 1.22.x - 1.22.x
- 1.23.x - 1.23.x
- 1.24.x - 1.24.x
- 1.25.x
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
@ -52,11 +68,13 @@ jobs:
- name: Run tests with enhanced reporting - name: Run tests with enhanced reporting
id: test id: test
run: | run: |
echo "## 🔧 Test Environment" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << EOF
echo "- **Go Version:** ${{ matrix.go }}" >> $GITHUB_STEP_SUMMARY ## 🔧 Test Environment
echo "- **OS:** ubuntu-latest" >> $GITHUB_STEP_SUMMARY - **Go Version:** ${{ matrix.go }}
echo "- **Timestamp:** $(date -u)" >> $GITHUB_STEP_SUMMARY - **OS:** ubuntu-latest
echo "" >> $GITHUB_STEP_SUMMARY - **Timestamp:** $(date -u)
EOF
echo "Running tests with coverage..." echo "Running tests with coverage..."
task test:coverage 2>&1 | tee test-output.log task test:coverage 2>&1 | tee test-output.log
@ -69,30 +87,30 @@ jobs:
SKIPPED_TESTS=$(grep -c "--- SKIP:" test-output.log || echo "0") SKIPPED_TESTS=$(grep -c "--- SKIP:" test-output.log || echo "0")
# Generate test summary # Generate test summary
echo "## 🧪 Test Results (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << EOF
echo "" >> $GITHUB_STEP_SUMMARY ## 🧪 Test Results (Go ${{ matrix.go }})
echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Total Tests | $TOTAL_TESTS |" >> $GITHUB_STEP_SUMMARY
echo "| Passed | ✅ $PASSED_TESTS |" >> $GITHUB_STEP_SUMMARY
echo "| Failed | ❌ $FAILED_TESTS |" >> $GITHUB_STEP_SUMMARY
echo "| Skipped | ⏭️ $SKIPPED_TESTS |" >> $GITHUB_STEP_SUMMARY
echo "| Status | $([ $TEST_STATUS -eq 0 ] && echo "✅ PASSED" || echo "❌ FAILED") |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Add package breakdown | Metric | Value |
echo "### 📦 Package Test Results" >> $GITHUB_STEP_SUMMARY | ----------- | ----------------------------------------------------------- |
echo "" >> $GITHUB_STEP_SUMMARY | Total Tests | $TOTAL_TESTS |
echo "| Package | Status |" >> $GITHUB_STEP_SUMMARY | Passed | $PASSED_TESTS |
echo "|---------|--------|" >> $GITHUB_STEP_SUMMARY | Failed | $FAILED_TESTS |
| Skipped | $SKIPPED_TESTS |
| Status | $([ $TEST_STATUS -eq 0 ] && echo "PASSED" || echo "FAILED") |
### 📦 Package Test Results
| Package | Status |
|---------|--------|
EOF
# Extract package results # Extract package results
grep "^ok\|^FAIL" test-output.log | while read line; do grep "^ok\|^FAIL" test-output.log | while read -r line; do
if [[ $line == ok* ]]; then if [[ $line == ok* ]]; then
pkg=$(echo $line | awk '{print $2}') pkg=$(echo "$line" | awk '{print $2}')
echo "| $pkg | ✅ PASS |" >> $GITHUB_STEP_SUMMARY echo "| $pkg | ✅ PASS |" >> $GITHUB_STEP_SUMMARY
elif [[ $line == FAIL* ]]; then elif [[ $line == FAIL* ]]; then
pkg=$(echo $line | awk '{print $2}') pkg=$(echo "$line" | awk '{print $2}')
echo "| $pkg | ❌ FAIL |" >> $GITHUB_STEP_SUMMARY echo "| $pkg | ❌ FAIL |" >> $GITHUB_STEP_SUMMARY
fi fi
done done
@ -101,19 +119,24 @@ jobs:
# Add detailed results if tests failed # Add detailed results if tests failed
if [ $TEST_STATUS -ne 0 ]; then if [ $TEST_STATUS -ne 0 ]; then
echo "### ❌ Failed Tests Details" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << 'EOF'
echo "" >> $GITHUB_STEP_SUMMARY ### ❌ Failed Tests Details
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY ```
EOF
grep -A 10 "--- FAIL:" test-output.log | head -100 >> $GITHUB_STEP_SUMMARY grep -A 10 "--- FAIL:" test-output.log | head -100 >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << 'EOF'
echo "" >> $GITHUB_STEP_SUMMARY ```
EOF
fi fi
# Set outputs for other steps # Set outputs for other steps
echo "test-status=$TEST_STATUS" >> $GITHUB_OUTPUT cat >> $GITHUB_OUTPUT << EOF
echo "total-tests=$TOTAL_TESTS" >> $GITHUB_OUTPUT test-status=$TEST_STATUS
echo "passed-tests=$PASSED_TESTS" >> $GITHUB_OUTPUT total-tests=$TOTAL_TESTS
echo "failed-tests=$FAILED_TESTS" >> $GITHUB_OUTPUT passed-tests=$PASSED_TESTS
failed-tests=$FAILED_TESTS
EOF
# Exit with the original test status # Exit with the original test status
exit $TEST_STATUS exit $TEST_STATUS
@ -124,33 +147,31 @@ jobs:
if [ -f coverage/coverage.out ]; then if [ -f coverage/coverage.out ]; then
COVERAGE=$(go tool cover -func=coverage/coverage.out | grep total | awk '{print $3}') COVERAGE=$(go tool cover -func=coverage/coverage.out | grep total | awk '{print $3}')
echo "## 📊 Code Coverage (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << EOF
echo "" >> $GITHUB_STEP_SUMMARY ## 📊 Code Coverage (Go ${{ matrix.go }})
echo "**Total Coverage: $COVERAGE**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Add coverage by package **Total Coverage: $COVERAGE**
echo "<details>" >> $GITHUB_STEP_SUMMARY
echo "<summary>Click to expand 📋 Coverage by Package details</summary>" >> $GITHUB_STEP_SUMMARY <details>
echo "" >> $GITHUB_STEP_SUMMARY <summary>Click to expand 📋 Coverage by Package details</summary>
echo "| Package | Coverage |" >> $GITHUB_STEP_SUMMARY
echo "|---------|----------|" >> $GITHUB_STEP_SUMMARY | Package | Coverage |
| ------- | -------- |
EOF
# Create temporary file for package coverage aggregation # Create temporary file for package coverage aggregation
temp_coverage=$(mktemp) temp_coverage=$(mktemp)
# Extract package-level coverage data # Extract package-level coverage data
go tool cover -func=coverage/coverage.out | grep -v total | while read line; do go tool cover -func=coverage/coverage.out | grep -v total | while read -r line; do
if [[ $line == *".go:"* ]]; then if [[ $line == *".go:"* ]]; then
# Extract package path from file path (everything before the filename) # Extract package path from file path (everything before the filename)
filepath=$(echo "$line" | awk '{print $1}') filepath=$(echo "$line" | awk '{print $1}')
pkg_path=$(dirname "$filepath" | sed 's|github.com/kjanat/articulate-parser/||' | sed 's|^\./||') pkg_path=$(dirname "$filepath" | sed 's|github.com/kjanat/articulate-parser/||; s|^\./||')
coverage=$(echo "$line" | awk '{print $3}' | sed 's/%//') coverage=$(echo "$line" | awk '{print $3}' | sed 's/%//')
# Use root package if no subdirectory # Use root package if no subdirectory
if [[ "$pkg_path" == "." || "$pkg_path" == "" ]]; then [[ "$pkg_path" == "." || "$pkg_path" == "" ]] && pkg_path="root"
pkg_path="root"
fi
echo "$pkg_path $coverage" >> "$temp_coverage" echo "$pkg_path $coverage" >> "$temp_coverage"
fi fi
@ -158,7 +179,7 @@ jobs:
# Aggregate coverage by package (average) # Aggregate coverage by package (average)
awk '{ awk '{
packages[$1] += $2; packages[$1] += $2
counts[$1]++ counts[$1]++
} }
END { END {
@ -166,17 +187,21 @@ jobs:
avg = packages[pkg] / counts[pkg] avg = packages[pkg] / counts[pkg]
printf "| %s | %.1f%% |\n", pkg, avg printf "| %s | %.1f%% |\n", pkg, avg
} }
}' $temp_coverage | sort >> $GITHUB_STEP_SUMMARY }' "$temp_coverage" | sort >> $GITHUB_STEP_SUMMARY
rm -f $temp_coverage rm -f "$temp_coverage"
echo "</details>" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << 'EOF'
echo "" >> $GITHUB_STEP_SUMMARY </details>
EOF
else else
echo "## ⚠️ Coverage Report" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << 'EOF'
echo "No coverage file generated" >> $GITHUB_STEP_SUMMARY ## ⚠️ Coverage Report
echo "" >> $GITHUB_STEP_SUMMARY No coverage file generated
EOF
fi fi
- name: Upload test artifacts - name: Upload test artifacts
@ -191,8 +216,11 @@ jobs:
- name: Run linters - name: Run linters
run: | run: |
echo "## 🔍 Static Analysis (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY # Initialize summary
echo "" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << EOF
## 🔍 Static Analysis (Go ${{ matrix.go }})
EOF
# Run go vet # Run go vet
VET_OUTPUT=$(task lint:vet 2>&1 || echo "") VET_OUTPUT=$(task lint:vet 2>&1 || echo "")
@ -201,11 +229,13 @@ jobs:
if [ $VET_STATUS -eq 0 ]; then if [ $VET_STATUS -eq 0 ]; then
echo "✅ **go vet:** No issues found" >> $GITHUB_STEP_SUMMARY echo "✅ **go vet:** No issues found" >> $GITHUB_STEP_SUMMARY
else else
echo "❌ **go vet:** Issues found" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << 'EOF'
echo "" >> $GITHUB_STEP_SUMMARY ❌ **go vet:** Issues found
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
```
EOF
echo "$VET_OUTPUT" >> $GITHUB_STEP_SUMMARY echo "$VET_OUTPUT" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY
fi fi
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
@ -216,32 +246,33 @@ jobs:
if [ $FMT_STATUS -eq 0 ]; then if [ $FMT_STATUS -eq 0 ]; then
echo "✅ **go fmt:** All files properly formatted" >> $GITHUB_STEP_SUMMARY echo "✅ **go fmt:** All files properly formatted" >> $GITHUB_STEP_SUMMARY
else else
echo "❌ **go fmt:** Files need formatting" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << 'EOF'
echo "" >> $GITHUB_STEP_SUMMARY ❌ **go fmt:** Files need formatting
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
```
EOF
echo "$FMT_OUTPUT" >> $GITHUB_STEP_SUMMARY echo "$FMT_OUTPUT" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY
fi fi
# Exit with error if any linter failed # Exit with error if any linter failed
if [ $VET_STATUS -ne 0 ] || [ $FMT_STATUS -ne 0 ]; then [ $VET_STATUS -eq 0 ] && [ $FMT_STATUS -eq 0 ] || exit 1
exit 1
fi
- name: Job Summary - name: Job Summary
if: always() if: always()
run: | run: |
echo "## 📋 Job Summary (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << 'EOF'
echo "" >> $GITHUB_STEP_SUMMARY ## 📋 Job Summary (Go ${{ matrix.go }})
echo "| Step | Status |" >> $GITHUB_STEP_SUMMARY
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY | Step | Status |
echo "| Dependencies | ✅ Success |" >> $GITHUB_STEP_SUMMARY | --------------- | --------------------------------------------------------------- |
echo "| Build | ✅ Success |" >> $GITHUB_STEP_SUMMARY | Dependencies | Success |
echo "| Tests | ${{ steps.test.outcome == 'success' && '✅ Success' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY | Build | Success |
echo "| Coverage | ${{ job.status == 'success' && '✅ Generated' || '⚠️ Partial' }} |" >> $GITHUB_STEP_SUMMARY | Tests | ${{ steps.test.outcome == 'success' && 'Success' || 'Failed' }} |
echo "| Static Analysis | ${{ job.status == 'success' && '✅ Clean' || '❌ Issues' }} |" >> $GITHUB_STEP_SUMMARY | Coverage | ${{ job.status == 'success' && 'Generated' || 'Partial' }} |
echo "| Code Formatting | ${{ job.status == 'success' && 'Clean' || 'Issues' }} |" >> $GITHUB_STEP_SUMMARY | Static Analysis | ${{ job.status == 'success' && 'Clean' || 'Issues' }} |
echo "" >> $GITHUB_STEP_SUMMARY | Code Formatting | ${{ job.status == 'success' && 'Clean' || 'Issues' }} |
EOF
- name: Upload coverage reports to Codecov - name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v5
@ -285,16 +316,18 @@ jobs:
- name: Test Docker image using Task - name: Test Docker image using Task
run: | run: |
echo "## 🧪 Docker Image Tests" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << 'EOF'
echo "" >> $GITHUB_STEP_SUMMARY ## 🧪 Docker Image Tests
EOF
# Run Task docker test # Run Task docker test
task docker:test task docker:test
echo "**Testing help command:**" >> $GITHUB_STEP_SUMMARY echo "**Testing help command:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo '```terminaloutput' >> $GITHUB_STEP_SUMMARY
docker run --rm articulate-parser:latest --help >> $GITHUB_STEP_SUMMARY docker run --rm articulate-parser:latest --help >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
# Test image size # Test image size
@ -324,8 +357,11 @@ jobs:
permissions: permissions:
contents: read contents: read
packages: write packages: write
needs: ['test'] needs: [test, docker-test, dependency-review]
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/heads/feature/docker')) if: |
github.event_name == 'push' && (github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/develop' ||
startsWith(github.ref, 'refs/heads/feature/docker'))
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v5
@ -400,35 +436,39 @@ jobs:
- name: Generate Docker summary - name: Generate Docker summary
run: | run: |
echo "## 🐳 Docker Build Summary" >> $GITHUB_STEP_SUMMARY cat >> $GITHUB_STEP_SUMMARY << 'EOF'
echo "" >> $GITHUB_STEP_SUMMARY ## 🐳 Docker Build Summary
echo "**Image:** \`ghcr.io/${{ github.repository }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY **Image:** `ghcr.io/${{ github.repository }}`
echo "**Tags built:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY **Tags built:**
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY ```text
echo "" >> $GITHUB_STEP_SUMMARY ${{ steps.meta.outputs.tags }}
echo "**Features:**" >> $GITHUB_STEP_SUMMARY ```
echo "- **Platforms:** linux/amd64, linux/arm64, linux/arm/v7, linux/386, linux/ppc64le, linux/s390x" >> $GITHUB_STEP_SUMMARY
echo "- **Architecture optimization:** ✅ Native compilation for each platform" >> $GITHUB_STEP_SUMMARY **Features:**
echo "- **Multi-arch image description:** ✅ Enabled" >> $GITHUB_STEP_SUMMARY - **Platforms:** linux/amd64, linux/arm64, linux/arm/v7, linux/386, linux/ppc64le, linux/s390x
echo "- **SBOM (Software Bill of Materials):** ✅ Generated" >> $GITHUB_STEP_SUMMARY - **Architecture optimization:** Native compilation for each platform
echo "- **Provenance attestation:** ✅ Generated" >> $GITHUB_STEP_SUMMARY - **Multi-arch image description:** Enabled
echo "- **Security scanning:** Ready for vulnerability analysis" >> $GITHUB_STEP_SUMMARY - **SBOM (Software Bill of Materials):** Generated
echo "" >> $GITHUB_STEP_SUMMARY - **Provenance attestation:** Generated
echo "**Usage:**" >> $GITHUB_STEP_SUMMARY - **Security scanning:** Ready for vulnerability analysis
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "# Pull the image" >> $GITHUB_STEP_SUMMARY **Usage:**
echo "docker pull ghcr.io/${{ github.repository }}:latest" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY ```bash
echo "# Run with help" >> $GITHUB_STEP_SUMMARY # Pull the image
echo "docker run --rm ghcr.io/${{ github.repository }}:latest --help" >> $GITHUB_STEP_SUMMARY docker pull ghcr.io/${{ github.repository }}:latest
echo "" >> $GITHUB_STEP_SUMMARY
echo "# Process a local file (mount current directory)" >> $GITHUB_STEP_SUMMARY # Run with help
echo "docker run --rm -v \$(pwd):/workspace ghcr.io/${{ github.repository }}:latest /workspace/input.json markdown /workspace/output.md" >> $GITHUB_STEP_SUMMARY docker run --rm ghcr.io/${{ github.repository }}:latest --help
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY # Process a local file (mount current directory)
docker run --rm -v $(pwd):/workspace ghcr.io/${{ github.repository }}:latest /workspace/input.json markdown /workspace/output.md
```
EOF
# Security and quality analysis workflows # Security and quality analysis workflows
codeql-analysis: codeql-analysis:

2
.gitignore vendored
View File

@ -75,3 +75,5 @@ main_coverage
**/*.local.* **/*.local.*
.claude/ .claude/
NUL

381
.golangci.yml Normal file
View File

@ -0,0 +1,381 @@
# golangci-lint configuration for articulate-parser
# https://golangci-lint.run/usage/configuration/
version: "2"
# Options for analysis running
run:
# Timeout for total work
timeout: 5m
# Skip directories (not allowed in config v2, will use issues exclude instead)
# Go version
go: "1.24"
# Include test files
tests: true
# Use Go module mode
modules-download-mode: readonly
# Output configuration
output:
# Format of output
formats:
text:
print-issued-lines: true
print-linter-name: true
# Sort results
sort-order:
- linter
- severity
- file
# Show statistics
show-stats: true
# Issues configuration
issues:
# Maximum issues count per one linter
max-issues-per-linter: 0
# Maximum count of issues with the same text
max-same-issues: 3
# Show only new issues
new: false
# Fix found issues (if linter supports)
fix: false
# Formatters configuration
formatters:
enable:
- gofmt
- goimports
- gofumpt
settings:
# gofmt settings
gofmt:
simplify: true
# goimports settings
goimports:
local-prefixes:
- github.com/kjanat/articulate-parser
# gofumpt settings
gofumpt:
module-path: github.com/kjanat/articulate-parser
extra-rules: true
# Linters configuration
linters:
# Default set of linters
default: none
# Enable specific linters
enable:
# Default/standard linters
- errcheck # Check for unchecked errors
- govet # Go vet
- ineffassign # Detect ineffectual assignments
- staticcheck # Staticcheck
- unused # Find unused code
# Code quality
- revive # Fast, configurable linter
- gocritic # Opinionated Go source code linter
- godot # Check comment periods
- godox # Detect TODO/FIXME comments
- gocognit # Cognitive complexity
- gocyclo # Cyclomatic complexity
- funlen # Function length
- maintidx # Maintainability index
# Security
- gosec # Security problems
# Performance
- prealloc # Find slice preallocation opportunities
- bodyclose # Check HTTP response body closed
# Style and formatting
- goconst # Find repeated strings
- misspell # Find misspellings
- whitespace # Find unnecessary blank lines
- unconvert # Remove unnecessary type conversions
- dupword # Check for duplicate words
# Error handling
- errorlint # Error handling improvements
- wrapcheck # Check error wrapping
# Testing
- testifylint # Testify usage
- tparallel # Detect improper t.Parallel() usage
- thelper # Detect test helpers without t.Helper()
# Best practices
- exhaustive # Check exhaustiveness of enum switches
- nolintlint # Check nolint directives
- nakedret # Find naked returns
- nilnil # Check for redundant nil checks
- noctx # Check sending HTTP requests without context
- contextcheck # Check context propagation
- asciicheck # Check for non-ASCII identifiers
- bidichk # Check for dangerous unicode sequences
- durationcheck # Check for multiplied durations
- makezero # Find slice declarations with non-zero length
- nilerr # Find code returning nil with non-nil error
- predeclared # Find code shadowing predeclared identifiers
- promlinter # Check Prometheus metrics naming
- reassign # Check reassignment of package variables
- usestdlibvars # Use variables from stdlib
- wastedassign # Find wasted assignments
# Documentation
- godoclint # Check godoc comments
# New
- modernize # Suggest simplifications using new Go features
# Exclusion rules for linters
exclusions:
rules:
# Exclude some linters from test files
- path: _test\.go
linters:
- gosec
- dupl
- errcheck
- goconst
- funlen
- goerr113
# Exclude benchmarks from some linters
- path: _bench_test\.go
linters:
- gosec
- dupl
- errcheck
- goconst
- funlen
- goerr113
- wrapcheck
# Exclude example tests
- path: _example_test\.go
linters:
- gosec
- errcheck
- funlen
- goerr113
- wrapcheck
- revive
# Exclude linters for main.go
- path: ^main\.go$
linters:
- forbidigo
# Exclude certain linters for generated files
- path: internal/version/version.go
linters:
- gochecknoglobals
- gochecknoinits
# Allow fmt.Print* in main package
- path: ^main\.go$
text: "use of fmt.Print"
linters:
- forbidigo
# Exclude common false positives
- text: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked"
linters:
- errcheck
# Exclude error wrapping suggestions for well-known errors
- text: "non-wrapping format verb for fmt.Errorf"
linters:
- errorlint
# Linters settings
settings:
# errcheck settings
errcheck:
check-type-assertions: true
check-blank: false
# govet settings
govet:
enable-all: true
disable:
- fieldalignment # Too many false positives
- shadow # Can be noisy
# goconst settings
goconst:
min-len: 3
min-occurrences: 3
# godot settings
godot:
scope: toplevel
exclude:
- "^fixme:"
- "^todo:"
capital: true
period: true
# godox settings
godox:
keywords:
- TODO
- FIXME
- HACK
- BUG
- XXX
# misspell settings
misspell:
locale: US
# funlen settings
funlen:
lines: 100
statements: 50
# gocognit settings
gocognit:
min-complexity: 20
# gocyclo settings
gocyclo:
min-complexity: 15
# gocritic settings
gocritic:
enabled-tags:
- diagnostic
- style
- performance
- experimental
disabled-checks:
- ifElseChain
- singleCaseSwitch
- commentedOutCode
settings:
hugeParam:
sizeThreshold: 512
rangeValCopy:
sizeThreshold: 512
# gosec settings
gosec:
severity: medium
confidence: medium
excludes:
- G104 # Handled by errcheck
- G304 # File path provided as taint input
# revive settings
revive:
severity: warning
rules:
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: empty-block
- name: error-naming
- name: error-return
- name: error-strings
- name: errorf
- name: exported
- name: if-return
- name: increment-decrement
- name: indent-error-flow
- name: package-comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: var-declaration
- name: var-naming
# errorlint settings
errorlint:
errorf: true
errorf-multi: true
asserts: true
comparison: true
# wrapcheck settings
wrapcheck:
ignore-sigs:
- .Errorf(
- errors.New(
- errors.Unwrap(
- errors.Join(
- .WithMessage(
- .WithMessagef(
- .WithStack(
ignore-package-globs:
- github.com/kjanat/articulate-parser/*
# exhaustive settings
exhaustive:
check:
- switch
- map
default-signifies-exhaustive: true
# nolintlint settings
nolintlint:
allow-unused: false
require-explanation: true
require-specific: true
# stylecheck settings
staticcheck:
checks: ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"]
# maintidx settings
maintidx:
under: 20
# testifylint settings
testifylint:
enable-all: true
disable:
- float-compare
# thelper settings
thelper:
test:
first: true
name: true
begin: true
benchmark:
first: true
name: true
begin: true
# Severity rules
severity:
default: warning
rules:
- linters:
- gosec
severity: error
- linters:
- errcheck
- staticcheck
severity: error
- linters:
- godox
severity: info