feat(shared-skills): batch 85 (10 files)
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{yml,yaml,json,md}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
@@ -0,0 +1,95 @@
|
||||
version: "2"
|
||||
|
||||
run:
|
||||
timeout: 5m
|
||||
tests: true
|
||||
modules-download-mode: readonly
|
||||
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- govet
|
||||
- staticcheck
|
||||
- errcheck
|
||||
- errorlint
|
||||
- nilerr
|
||||
- nilnil
|
||||
- bodyclose
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- contextcheck
|
||||
- fatcontext
|
||||
- copyloopvar
|
||||
- intrange
|
||||
- usetesting
|
||||
- testifylint
|
||||
- gofumpt
|
||||
- goimports
|
||||
- whitespace
|
||||
- misspell
|
||||
- unconvert
|
||||
- unparam
|
||||
- ineffassign
|
||||
- dupword
|
||||
- gocognit
|
||||
- gocyclo
|
||||
- funlen
|
||||
- lll
|
||||
- nestif
|
||||
- dupl
|
||||
- revive
|
||||
- unused
|
||||
- exhaustive
|
||||
- gosec
|
||||
- sloglint
|
||||
- perfsprint
|
||||
- prealloc
|
||||
- makezero
|
||||
|
||||
linters-settings:
|
||||
errcheck:
|
||||
check-type-assertions: true
|
||||
check-blank: true
|
||||
errorlint:
|
||||
errorf: true
|
||||
asserts: true
|
||||
comparison: true
|
||||
gocognit:
|
||||
min-complexity: 25
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
funlen:
|
||||
lines: 90
|
||||
statements: 60
|
||||
lll:
|
||||
line-length: 120
|
||||
tab-width: 4
|
||||
nestif:
|
||||
min-complexity: 4
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: false
|
||||
check: [switch, map]
|
||||
sloglint:
|
||||
no-mixed-args: true
|
||||
attr-only: true
|
||||
no-global: all
|
||||
context: scope
|
||||
static-msg: true
|
||||
no-raw-keys: true
|
||||
key-naming-case: snake
|
||||
|
||||
formatters:
|
||||
enable:
|
||||
- gofumpt
|
||||
- goimports
|
||||
|
||||
issues:
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
exclude-rules:
|
||||
- path: _test\\.go
|
||||
linters: [funlen, lll, dupl, gosec]
|
||||
- path: \\.pb\\.go$
|
||||
linters: [all]
|
||||
- path: \\.connect\\.go$
|
||||
linters: [all]
|
||||
@@ -0,0 +1,24 @@
|
||||
# AGENTS.md
|
||||
|
||||
Go 1.23+ $short_purpose service.
|
||||
|
||||
## Commands
|
||||
- `task` — fmt + lint + test
|
||||
- `task build` — produce ./bin/server
|
||||
- `task ci` — full CI pipeline locally
|
||||
|
||||
## Architecture
|
||||
- `cmd/server/main.go` — entrypoint, ≤50 LOC
|
||||
- `internal/cmd/` — root command, signal wiring
|
||||
- `internal/api/` — HTTP handlers + middleware (gin)
|
||||
- `internal/domain/` — smart-constructor types, no I/O
|
||||
- `internal/store/` — DB layer (sqlc-generated, never hand-edited)
|
||||
- `internal/config/` — env-driven Config
|
||||
- `internal/obs/` — slog setup, observability
|
||||
|
||||
## Conventions
|
||||
- `slog` for all logs; never `log.*`, never `fmt.Println` in libs
|
||||
- `context.Context` first arg for every public function with I/O
|
||||
- Errors wrapped with `%w`; check with `errors.Is/As`
|
||||
- 250 pure LOC ceiling per file
|
||||
- Tests follow Given/When/Then; less mock the better
|
||||
@@ -0,0 +1,12 @@
|
||||
# $name
|
||||
|
||||
Bootstrapped with the `programming` skill's Go scaffold.
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
task # fmt + lint + test
|
||||
task run # build + run server
|
||||
```
|
||||
|
||||
See `AGENTS.md` for architecture conventions.
|
||||
@@ -0,0 +1,40 @@
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
BINARY: server
|
||||
PKG: ./cmd/server
|
||||
|
||||
tasks:
|
||||
default:
|
||||
deps: [fmt, lint, test]
|
||||
|
||||
fmt:
|
||||
cmds:
|
||||
- gofumpt -w .
|
||||
- goimports -w -local "$(go list -m)" .
|
||||
|
||||
lint:
|
||||
cmds:
|
||||
- golangci-lint run --timeout 5m ./...
|
||||
- nilaway ./... || true
|
||||
|
||||
test:
|
||||
cmds:
|
||||
- go test -race -shuffle=on -count=1 ./...
|
||||
|
||||
test-cover:
|
||||
cmds:
|
||||
- go test -race -shuffle=on -count=1 -coverprofile=coverage.out ./...
|
||||
- go tool cover -html=coverage.out -o coverage.html
|
||||
|
||||
build:
|
||||
cmds:
|
||||
- go build -trimpath -ldflags="-s -w" -o bin/{{.BINARY}} {{.PKG}}
|
||||
|
||||
run:
|
||||
deps: [build]
|
||||
cmds:
|
||||
- ./bin/{{.BINARY}}
|
||||
|
||||
ci:
|
||||
deps: [fmt, lint, test, build]
|
||||
@@ -0,0 +1,37 @@
|
||||
name: ci
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
cache: true
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
go install mvdan.cc/gofumpt@latest
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v2.0.0
|
||||
go install go.uber.org/nilaway/cmd/nilaway@latest
|
||||
go install github.com/go-task/task/v3/cmd/task@latest
|
||||
|
||||
- name: Format check
|
||||
run: gofumpt -l . | (! grep .)
|
||||
|
||||
- name: Lint
|
||||
run: golangci-lint run --timeout 5m ./...
|
||||
|
||||
- name: Nilaway
|
||||
run: nilaway ./... || true
|
||||
|
||||
- name: Test
|
||||
run: go test -race -shuffle=on -count=1 ./...
|
||||
|
||||
- name: Build
|
||||
run: go build -trimpath ./...
|
||||
@@ -0,0 +1,24 @@
|
||||
// Package config loads typed config from env.
|
||||
package config
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caarlos0/env/v11"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Host string `env:"HOST" envDefault:"0.0.0.0"`
|
||||
Port int `env:"PORT" envDefault:"8080"`
|
||||
ShutdownTimeout time.Duration `env:"SHUTDOWN_TIMEOUT" envDefault:"20s"`
|
||||
LogLevel string `env:"LOG_LEVEL" envDefault:"info"`
|
||||
LogFormat string `env:"LOG_FORMAT" envDefault:"json"`
|
||||
}
|
||||
|
||||
func Load() (Config, error) {
|
||||
var cfg Config
|
||||
if err := env.Parse(&cfg); err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
bin/
|
||||
coverage.out
|
||||
coverage.html
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
|
||||
.env
|
||||
.env.local
|
||||
|
||||
*.pem
|
||||
*.key
|
||||
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"$module/internal/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, stop := signal.NotifyContext(context.Background(),
|
||||
syscall.SIGINT, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
if err := cmd.Execute(ctx); err != nil {
|
||||
slog.Error("fatal", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Package cmd wires the root command and subcommands.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Execute runs the root command. Wire cobra/subcommands here.
|
||||
func Execute(ctx context.Context) error {
|
||||
slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))
|
||||
slog.InfoContext(ctx, "starting")
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user