Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: CI

on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

permissions:
contents: read

jobs:
validate:
name: Validate
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: go.mod
cache: true

- name: Check formatting
run: |
if [ -n "$(gofmt -l .)" ]; then
echo "::error::Code is not formatted. Run 'gofmt -w .' to fix."
gofmt -l .
exit 1
fi

- name: Run go vet
run: go vet ./...

- name: Run golangci-lint
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
with:
version: latest

- name: Run tests
run: go test -race -cover -coverprofile=coverage.out ./...

- name: Upload coverage
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: coverage
path: coverage.out
retention-days: 7

- name: Build
run: go build -o blob .
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.claude/
CLAUDE.md

# Build output
/blob
230 changes: 230 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
# golangci-lint configuration v2
# See: https://golangci-lint.run/usage/configuration/
version: "2"

# Linter configuration
linters:
# Start with the standard set and add more
default: standard

# Enable additional linters for security and best practices
enable:
# Security linters
- gosec # Security scanner for Go code
- bodyclose # Ensure HTTP response bodies are closed
- noctx # Ensure HTTP requests use context

# Error handling
- errcheck # Check for unchecked errors
- errname # Check error variable naming conventions

# Code quality
- gocyclo # Cyclomatic complexity
- gocognit # Cognitive complexity
- goconst # Find repeated strings that could be constants
- gocritic # Comprehensive code review linter
- revive # Fast, configurable linter (golint replacement)
- unconvert # Detect unnecessary type conversions
- unparam # Detect unused function parameters
- misspell # Find commonly misspelled words
- prealloc # Suggest preallocating slices
- nilerr # Detect returning nil after checking error
- nilnil # Detect returning nil, nil
- predeclared # Detect shadowing of predeclared identifiers
- tparallel # Detect inappropriate usage of t.Parallel
- thelper # Detect test helpers without t.Helper()
- usestdlibvars # Detect using magic numbers instead of stdlib constants
- wastedassign # Find wasted assignments
- whitespace # Detect leading/trailing whitespace
- copyloopvar # Detect loop variable copies (Go 1.22+)
- intrange # Suggest using integer range loops (Go 1.22+)
- sloglint # Ensure consistent slog usage
- perfsprint # Detect fmt.Sprintf that can be replaced

# Disable linters that are too noisy or not applicable
disable:
- depguard # Requires explicit configuration, enable if needed

# Exclusion rules
exclusions:
# Built-in presets
presets:
- comments
- std-error-handling
# Custom rules
rules:
# Allow complexity in test files
- path: '_test\.go'
linters:
- gocyclo
- gocognit
- funlen
- goconst # String constants like "windows" are common in test skips
# Exclude gosec checks in test files (test code has different security requirements)
- path: '_test\.go'
linters:
- gosec
# Allow unchecked errors in test cleanup code
- path: '_test\.go'
linters:
- errcheck
# Allow issues in generated mock files
- path: 'mocks/'
linters:
- gocritic
- revive
- stylecheck
# Internal packages return unexported types accessed via interfaces
- path: 'internal/'
linters:
- revive
text: "unexported-return"

# Linter-specific settings
settings:
# Security linter settings
gosec:
# Enable all rules by default
excludes: []
# Severity levels: low, medium, high
severity: medium
# Confidence levels: low, medium, high
confidence: medium
# Include additional checks
config:
global:
audit: true

# Error checking
errcheck:
# Check type assertions
check-type-assertions: true
# Check blank identifier assignments
check-blank: true
# Exclude common functions that are safe to ignore
exclude-functions:
- (io.Closer).Close
- (*os.File).Close
- (net.Conn).Close
- golang.org/x/term.Restore
- (io.Writer).Write
# Viper bindings in init() - errors indicate programmer error
- (*github.com/spf13/viper.Viper).BindPFlag
- github.com/spf13/viper.BindPFlag

# Cyclomatic complexity threshold
gocyclo:
min-complexity: 15

# Cognitive complexity threshold
gocognit:
min-complexity: 20

# govet configuration
govet:
enable:
- shadow # Check for variable shadowing
- nilness # Check for redundant nil comparisons
- unusedwrite # Check for unused writes

# gocritic comprehensive checks
gocritic:
enabled-tags:
- diagnostic
- style
- performance
- opinionated
disabled-checks:
- whyNoLint # Can be too strict

# revive linter rules
revive:
rules:
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-return
- name: error-strings
- name: error-naming
- name: exported
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: package-comments
disabled: true # Allow packages without comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unused-parameter
disabled: true # Conflicts with unparam
- name: unreachable-code
- name: redefines-builtin-id

# misspell settings
misspell:
locale: US

# slog linter settings
sloglint:
no-mixed-args: true
kv-only: false
attr-only: false
static-msg: false
no-raw-keys: false
key-naming-case: snake

# Issue configuration
issues:
# Maximum issues per linter (0 = unlimited)
max-issues-per-linter: 50
# Maximum identical issues (0 = unlimited)
max-same-issues: 3

# Runtime configuration
run:
# Timeout for analysis
timeout: 5m
# Include test files in analysis
tests: true
# Number of parallel workers
concurrency: 4
# Go version to use (auto-detect from go.mod)
go: ""
# Build tags
build-tags: []
# Modules download mode
modules-download-mode: readonly

# Formatters configuration (v2 separates formatters from linters)
formatters:
enable:
- goimports # Format imports and code
- gofmt # Standard Go formatting
settings:
goimports:
# Group local imports separately
local-prefixes:
- github.com/meigma/blob-cli

# Output configuration
output:
formats:
text:
# Print linter name in output
print-linter-name: true
# Print lines with issues
print-issued-lines: true
# Use colors
colors: true
# Sort results for consistent output
sort-order:
- linter
- file
show-stats: true
Loading