diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 8d24ab3..3e5eed3 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -10,16 +10,36 @@ jobs: autofix: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 - - uses: actions/setup-go@v6 - with: - go-version-file: 'go.mod' + - name: Checkout code + uses: actions/checkout@v5 - # goimports works like gofmt, but also fixes imports. - # see https://pkg.go.dev/golang.org/x/tools/cmd/goimports - - run: go install golang.org/x/tools/cmd/goimports@latest - - run: goimports -w . - # of course we can also do just this instead: - # - run: gofmt -w . + - name: Install Task + uses: go-task/setup-task@v1 + + - uses: actions/setup-go@v6 + with: { go-version-file: 'go.mod' } + + - 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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b7ac4c0..ec26478 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,6 @@ on: push: branches: ['master', 'develop'] pull_request: - branches: ['master', 'develop', 'feature/*'] env: REGISTRY: ghcr.io @@ -15,8 +14,24 @@ concurrency: cancel-in-progress: true 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: name: Test + needs: [golangci] runs-on: ubuntu-latest permissions: contents: write @@ -27,6 +42,7 @@ jobs: - 1.22.x - 1.23.x - 1.24.x + - 1.25.x steps: - uses: actions/checkout@v5 @@ -52,11 +68,13 @@ jobs: - name: Run tests with enhanced reporting id: test run: | - echo "## ๐Ÿ”ง Test Environment" >> $GITHUB_STEP_SUMMARY - echo "- **Go Version:** ${{ matrix.go }}" >> $GITHUB_STEP_SUMMARY - echo "- **OS:** ubuntu-latest" >> $GITHUB_STEP_SUMMARY - echo "- **Timestamp:** $(date -u)" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << EOF + ## ๐Ÿ”ง Test Environment + - **Go Version:** ${{ matrix.go }} + - **OS:** ubuntu-latest + - **Timestamp:** $(date -u) + + EOF echo "Running tests with coverage..." task test:coverage 2>&1 | tee test-output.log @@ -69,30 +87,30 @@ jobs: SKIPPED_TESTS=$(grep -c "--- SKIP:" test-output.log || echo "0") # Generate test summary - echo "## ๐Ÿงช Test Results (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - 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 + cat >> $GITHUB_STEP_SUMMARY << EOF + ## ๐Ÿงช Test Results (Go ${{ matrix.go }}) - # Add package breakdown - echo "### ๐Ÿ“ฆ Package Test Results" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Package | Status |" >> $GITHUB_STEP_SUMMARY - echo "|---------|--------|" >> $GITHUB_STEP_SUMMARY + | Metric | Value | + | ----------- | ----------------------------------------------------------- | + | Total Tests | $TOTAL_TESTS | + | Passed | $PASSED_TESTS | + | Failed | $FAILED_TESTS | + | Skipped | $SKIPPED_TESTS | + | Status | $([ $TEST_STATUS -eq 0 ] && echo "PASSED" || echo "FAILED") | + + ### ๐Ÿ“ฆ Package Test Results + + | Package | Status | + |---------|--------| + EOF # 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 - pkg=$(echo $line | awk '{print $2}') + pkg=$(echo "$line" | awk '{print $2}') echo "| $pkg | โœ… PASS |" >> $GITHUB_STEP_SUMMARY elif [[ $line == FAIL* ]]; then - pkg=$(echo $line | awk '{print $2}') + pkg=$(echo "$line" | awk '{print $2}') echo "| $pkg | โŒ FAIL |" >> $GITHUB_STEP_SUMMARY fi done @@ -101,19 +119,24 @@ jobs: # Add detailed results if tests failed if [ $TEST_STATUS -ne 0 ]; then - echo "### โŒ Failed Tests Details" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << 'EOF' + ### โŒ Failed Tests Details + ``` + EOF grep -A 10 "--- FAIL:" test-output.log | head -100 >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << 'EOF' + ``` + + EOF fi # Set outputs for other steps - echo "test-status=$TEST_STATUS" >> $GITHUB_OUTPUT - echo "total-tests=$TOTAL_TESTS" >> $GITHUB_OUTPUT - echo "passed-tests=$PASSED_TESTS" >> $GITHUB_OUTPUT - echo "failed-tests=$FAILED_TESTS" >> $GITHUB_OUTPUT + cat >> $GITHUB_OUTPUT << EOF + test-status=$TEST_STATUS + total-tests=$TOTAL_TESTS + passed-tests=$PASSED_TESTS + failed-tests=$FAILED_TESTS + EOF # Exit with the original test status exit $TEST_STATUS @@ -124,33 +147,31 @@ jobs: if [ -f coverage/coverage.out ]; then COVERAGE=$(go tool cover -func=coverage/coverage.out | grep total | awk '{print $3}') - echo "## ๐Ÿ“Š Code Coverage (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Total Coverage: $COVERAGE**" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << EOF + ## ๐Ÿ“Š Code Coverage (Go ${{ matrix.go }}) - # Add coverage by package - echo "
" >> $GITHUB_STEP_SUMMARY - echo "Click to expand ๐Ÿ“‹ Coverage by Package details" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Package | Coverage |" >> $GITHUB_STEP_SUMMARY - echo "|---------|----------|" >> $GITHUB_STEP_SUMMARY + **Total Coverage: $COVERAGE** + +
+ Click to expand ๐Ÿ“‹ Coverage by Package details + + | Package | Coverage | + | ------- | -------- | + EOF # Create temporary file for package coverage aggregation temp_coverage=$(mktemp) # 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 # Extract package path from file path (everything before the filename) 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/%//') # Use root package if no subdirectory - if [[ "$pkg_path" == "." || "$pkg_path" == "" ]]; then - pkg_path="root" - fi + [[ "$pkg_path" == "." || "$pkg_path" == "" ]] && pkg_path="root" echo "$pkg_path $coverage" >> "$temp_coverage" fi @@ -158,7 +179,7 @@ jobs: # Aggregate coverage by package (average) awk '{ - packages[$1] += $2; + packages[$1] += $2 counts[$1]++ } END { @@ -166,17 +187,21 @@ jobs: avg = packages[pkg] / counts[pkg] 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 "
" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << 'EOF' - echo "" >> $GITHUB_STEP_SUMMARY +
+ + EOF else - echo "## โš ๏ธ Coverage Report" >> $GITHUB_STEP_SUMMARY - echo "No coverage file generated" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << 'EOF' + ## โš ๏ธ Coverage Report + No coverage file generated + + EOF fi - name: Upload test artifacts @@ -191,8 +216,11 @@ jobs: - name: Run linters run: | - echo "## ๐Ÿ” Static Analysis (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + # Initialize summary + cat >> $GITHUB_STEP_SUMMARY << EOF + ## ๐Ÿ” Static Analysis (Go ${{ matrix.go }}) + + EOF # Run go vet VET_OUTPUT=$(task lint:vet 2>&1 || echo "") @@ -201,11 +229,13 @@ jobs: if [ $VET_STATUS -eq 0 ]; then echo "โœ… **go vet:** No issues found" >> $GITHUB_STEP_SUMMARY else - echo "โŒ **go vet:** Issues found" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << 'EOF' + โŒ **go vet:** Issues found + + ``` + EOF echo "$VET_OUTPUT" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY fi echo "" >> $GITHUB_STEP_SUMMARY @@ -216,32 +246,33 @@ jobs: if [ $FMT_STATUS -eq 0 ]; then echo "โœ… **go fmt:** All files properly formatted" >> $GITHUB_STEP_SUMMARY else - echo "โŒ **go fmt:** Files need formatting" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << 'EOF' + โŒ **go fmt:** Files need formatting + + ``` + EOF echo "$FMT_OUTPUT" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY fi # Exit with error if any linter failed - if [ $VET_STATUS -ne 0 ] || [ $FMT_STATUS -ne 0 ]; then - exit 1 - fi + [ $VET_STATUS -eq 0 ] && [ $FMT_STATUS -eq 0 ] || exit 1 - name: Job Summary if: always() run: | - echo "## ๐Ÿ“‹ Job Summary (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Step | Status |" >> $GITHUB_STEP_SUMMARY - echo "|------|--------|" >> $GITHUB_STEP_SUMMARY - echo "| Dependencies | โœ… Success |" >> $GITHUB_STEP_SUMMARY - echo "| Build | โœ… Success |" >> $GITHUB_STEP_SUMMARY - echo "| Tests | ${{ steps.test.outcome == 'success' && 'โœ… Success' || 'โŒ Failed' }} |" >> $GITHUB_STEP_SUMMARY - echo "| Coverage | ${{ job.status == 'success' && 'โœ… Generated' || 'โš ๏ธ Partial' }} |" >> $GITHUB_STEP_SUMMARY - echo "| Static Analysis | ${{ job.status == 'success' && 'โœ… Clean' || 'โŒ Issues' }} |" >> $GITHUB_STEP_SUMMARY - echo "| Code Formatting | ${{ job.status == 'success' && 'โœ… Clean' || 'โŒ Issues' }} |" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << 'EOF' + ## ๐Ÿ“‹ Job Summary (Go ${{ matrix.go }}) + + | Step | Status | + | --------------- | --------------------------------------------------------------- | + | Dependencies | Success | + | Build | Success | + | Tests | ${{ steps.test.outcome == 'success' && 'Success' || 'Failed' }} | + | Coverage | ${{ job.status == 'success' && 'Generated' || 'Partial' }} | + | Static Analysis | ${{ job.status == 'success' && 'Clean' || 'Issues' }} | + | Code Formatting | ${{ job.status == 'success' && 'Clean' || 'Issues' }} | + EOF - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v5 @@ -285,16 +316,18 @@ jobs: - name: Test Docker image using Task run: | - echo "## ๐Ÿงช Docker Image Tests" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << 'EOF' + ## ๐Ÿงช Docker Image Tests + + EOF # Run Task docker test task docker:test 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 - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Test image size @@ -324,8 +357,11 @@ jobs: permissions: contents: read packages: write - needs: ['test'] - if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/heads/feature/docker')) + 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')) steps: - name: Checkout repository uses: actions/checkout@v5 @@ -400,35 +436,39 @@ jobs: - name: Generate Docker summary run: | - echo "## ๐Ÿณ Docker Build Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Image:** \`ghcr.io/${{ github.repository }}\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Tags built:**" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - 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 - echo "- **Multi-arch image description:** โœ… Enabled" >> $GITHUB_STEP_SUMMARY - echo "- **SBOM (Software Bill of Materials):** โœ… Generated" >> $GITHUB_STEP_SUMMARY - echo "- **Provenance attestation:** โœ… Generated" >> $GITHUB_STEP_SUMMARY - echo "- **Security scanning:** Ready for vulnerability analysis" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Usage:**" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY - echo "# Pull the image" >> $GITHUB_STEP_SUMMARY - echo "docker pull ghcr.io/${{ github.repository }}:latest" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "# Run with help" >> $GITHUB_STEP_SUMMARY - echo "docker run --rm ghcr.io/${{ github.repository }}:latest --help" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "# Process a local file (mount current directory)" >> $GITHUB_STEP_SUMMARY - echo "docker run --rm -v \$(pwd):/workspace ghcr.io/${{ github.repository }}:latest /workspace/input.json markdown /workspace/output.md" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + cat >> $GITHUB_STEP_SUMMARY << 'EOF' + ## ๐Ÿณ Docker Build Summary + + **Image:** `ghcr.io/${{ github.repository }}` + + **Tags built:** + + ```text + ${{ steps.meta.outputs.tags }} + ``` + + **Features:** + - **Platforms:** linux/amd64, linux/arm64, linux/arm/v7, linux/386, linux/ppc64le, linux/s390x + - **Architecture optimization:** Native compilation for each platform + - **Multi-arch image description:** Enabled + - **SBOM (Software Bill of Materials):** Generated + - **Provenance attestation:** Generated + - **Security scanning:** Ready for vulnerability analysis + + **Usage:** + + ```bash + # Pull the image + docker pull ghcr.io/${{ github.repository }}:latest + + # Run with help + docker run --rm ghcr.io/${{ github.repository }}:latest --help + + # 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 codeql-analysis: diff --git a/.gitignore b/.gitignore index 1aadfdb..0627806 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,5 @@ main_coverage **/*.local.* .claude/ + +NUL diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..8c52b25 --- /dev/null +++ b/.golangci.yml @@ -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