trim fat, use Gi philosophy
This commit is contained in:
parent
f4ce4599aa
commit
0f75b279c3
@ -1,37 +1,33 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# pre-commit hook: runs on every `git commit`
|
# pre-push hook: runs quality checks before every `git push`.
|
||||||
# Install with: make setup (sets core.hooksPath = .githooks)
|
# Install with: make setup (sets core.hooksPath = .githooks)
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Collect staged Go files only — avoids re-checking untouched code.
|
echo "pre-push: running checks..."
|
||||||
STAGED=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$' || true)
|
|
||||||
|
|
||||||
if [ -z "$STAGED" ]; then
|
|
||||||
echo "pre-commit: no Go files staged — skipping."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "pre-commit: running checks on staged Go files..."
|
|
||||||
|
|
||||||
# ── 1. gofmt ──────────────────────────────────────────────────────────────────
|
# ── 1. gofmt ──────────────────────────────────────────────────────────────────
|
||||||
echo " → gofmt"
|
echo " → gofmt"
|
||||||
UNFORMATTED=$(gofmt -l $STAGED)
|
UNFORMATTED=$(gofmt -l $(git ls-files '*.go'))
|
||||||
if [ -n "$UNFORMATTED" ]; then
|
if [ -n "$UNFORMATTED" ]; then
|
||||||
echo " FAIL: the following files are not gofmt-formatted:"
|
echo " FAIL: the following files are not gofmt-formatted:"
|
||||||
echo "$UNFORMATTED" | sed 's/^/ /'
|
echo "$UNFORMATTED" | sed 's/^/ /'
|
||||||
echo " Fix with: gofmt -w <file> or make lint-fix"
|
echo " Fix with: make lint-fix"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 2. golangci-lint ──────────────────────────────────────────────────────────
|
# ── 2. go vet ─────────────────────────────────────────────────────────────────
|
||||||
|
echo " → go vet"
|
||||||
|
go vet ./...
|
||||||
|
|
||||||
|
# ── 3. golangci-lint ──────────────────────────────────────────────────────────
|
||||||
echo " → golangci-lint"
|
echo " → golangci-lint"
|
||||||
golangci-lint run ./...
|
golangci-lint run ./...
|
||||||
|
|
||||||
# ── 3. gosec (security scan) ──────────────────────────────────────────────────
|
# ── 4. gosec (security scan) ──────────────────────────────────────────────────
|
||||||
echo " → gosec"
|
echo " → gosec"
|
||||||
gosec -quiet ./...
|
gosec -quiet ./...
|
||||||
|
|
||||||
# govulncheck is intentionally omitted from pre-commit (network + slow).
|
# govulncheck is intentionally omitted (network + slow).
|
||||||
# Run it manually with: make security
|
# Run it manually with: make security
|
||||||
|
|
||||||
echo "pre-commit: all checks passed."
|
echo "pre-push: all checks passed."
|
||||||
@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
run:
|
run:
|
||||||
timeout: 5m
|
timeout: 5m
|
||||||
# Align with go.mod
|
go: '1.25'
|
||||||
# go: '1.24'
|
|
||||||
|
|
||||||
# Enable specific linters on top of the default set.
|
# Enable specific linters on top of the default set.
|
||||||
# Default set: errcheck, gosimple, govet, ineffassign, staticcheck, unused
|
# Default set: errcheck, gosimple, govet, ineffassign, staticcheck, unused
|
||||||
@ -39,7 +38,7 @@ linters-settings:
|
|||||||
|
|
||||||
goimports:
|
goimports:
|
||||||
# Put local module imports in their own group (after stdlib and external).
|
# Put local module imports in their own group (after stdlib and external).
|
||||||
local-prefixes: github.com/your-org/go-template
|
local-prefixes: gitea.djmil.dev/djmil/go-template
|
||||||
|
|
||||||
gocritic:
|
gocritic:
|
||||||
disabled-checks:
|
disabled-checks:
|
||||||
@ -65,13 +64,5 @@ issues:
|
|||||||
- unparam
|
- unparam
|
||||||
- gocritic
|
- gocritic
|
||||||
- gosec
|
- gosec
|
||||||
# Don't fail on generated files.
|
|
||||||
- path: mock_.*\.go
|
|
||||||
linters:
|
|
||||||
- all
|
|
||||||
- path: mocks/
|
|
||||||
linters:
|
|
||||||
- all
|
|
||||||
|
|
||||||
max-issues-per-linter: 50
|
max-issues-per-linter: 50
|
||||||
max-same-issues: 5
|
max-same-issues: 5
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
# mockery v2 configuration
|
|
||||||
# Docs: https://vektra.github.io/mockery/latest/configuration/
|
|
||||||
#
|
|
||||||
# Mocks are placed in mocks/<package>/ next to their source package.
|
|
||||||
# Regenerate with: make mocks
|
|
||||||
|
|
||||||
with-expecter: true # generate type-safe EXPECT() call chains
|
|
||||||
mockname: "Mock{{.InterfaceName}}"
|
|
||||||
filename: "mock_{{.InterfaceName | snakecase}}.go"
|
|
||||||
outpkg: "mocks"
|
|
||||||
dir: "mocks/{{.PackageName}}"
|
|
||||||
|
|
||||||
# Packages whose interfaces should be mocked.
|
|
||||||
# Add entries here whenever you define an interface that other packages depend on.
|
|
||||||
packages:
|
|
||||||
gitea.djmil.dev/djmil/go-template/internal/greeter:
|
|
||||||
interfaces:
|
|
||||||
Greeter:
|
|
||||||
9
.vscode/launch.json
vendored
9
.vscode/launch.json
vendored
@ -8,10 +8,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
"program": "${workspaceFolder}/cmd/app",
|
"program": "${workspaceFolder}/cmd/app",
|
||||||
"env": {
|
"args": ["-env", "dev", "-log-level", "debug"]
|
||||||
"CONFIG_PATH": "${workspaceFolder}/config/dev.yaml"
|
|
||||||
},
|
|
||||||
"args": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// ── Debug: same as above but with delve attached ───────────────────────
|
// ── Debug: same as above but with delve attached ───────────────────────
|
||||||
@ -20,9 +17,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "debug",
|
"mode": "debug",
|
||||||
"program": "${workspaceFolder}/cmd/app",
|
"program": "${workspaceFolder}/cmd/app",
|
||||||
"env": {
|
"args": ["-env", "dev", "-log-level", "debug"],
|
||||||
"CONFIG_PATH": "${workspaceFolder}/config/dev.yaml"
|
|
||||||
},
|
|
||||||
"showLog": true,
|
"showLog": true,
|
||||||
"trace": "verbose"
|
"trace": "verbose"
|
||||||
},
|
},
|
||||||
|
|||||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -33,5 +33,9 @@
|
|||||||
|
|
||||||
// ── Test explorer ──────────────────────────────────────────────────────────
|
// ── Test explorer ──────────────────────────────────────────────────────────
|
||||||
"go.testExplorer.enable": true,
|
"go.testExplorer.enable": true,
|
||||||
"makefile.configureOnOpen": false
|
"makefile.configureOnOpen": false,
|
||||||
|
"cSpell.words": [
|
||||||
|
"djmil",
|
||||||
|
"gitea"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
51
CLAUDE.md
51
CLAUDE.md
@ -7,8 +7,8 @@ Keep it concise — the agent needs signal, not essays.
|
|||||||
|
|
||||||
## Project overview
|
## Project overview
|
||||||
|
|
||||||
Go 1.24 template / PoC starter. Demonstrates: structured logging (zap),
|
Go 1.25 template / PoC starter. Demonstrates: structured logging (slog),
|
||||||
config (viper), interfaces + mocks (mockery), linting (golangci-lint),
|
config (flag), interfaces + manual fakes, linting (golangci-lint),
|
||||||
security scanning (gosec, govulncheck), git hooks, devcontainer, VSCode tasks.
|
security scanning (gosec, govulncheck), git hooks, devcontainer, VSCode tasks.
|
||||||
|
|
||||||
Module: `gitea.djmil.dev/djmil/go-template` — update this when you fork.
|
Module: `gitea.djmil.dev/djmil/go-template` — update this when you fork.
|
||||||
@ -19,15 +19,12 @@ Module: `gitea.djmil.dev/djmil/go-template` — update this when you fork.
|
|||||||
|
|
||||||
```
|
```
|
||||||
cmd/app/main.go composition root — wires deps, no logic here
|
cmd/app/main.go composition root — wires deps, no logic here
|
||||||
internal/config/ Viper config loader (config.Load)
|
internal/config/ flag-based config loader (config.Load)
|
||||||
internal/logger/ Zap wrapper with WithField / WithFields
|
internal/logger/ slog wrapper with WithField / WithFields
|
||||||
internal/greeter/ Example domain package (delete or repurpose)
|
internal/greeter/ Example domain package (delete or repurpose)
|
||||||
mocks/greeter/ Generated mocks — regenerate with `make mocks`
|
|
||||||
config/dev.yaml Local dev config (committed, no secrets)
|
|
||||||
tools.go Tool version pinning (build tag: tools)
|
tools.go Tool version pinning (build tag: tools)
|
||||||
.golangci.yml Linter rules
|
.golangci.yml Linter rules
|
||||||
.mockery.yaml Mockery code-gen config
|
.githooks/pre-push Runs gofmt + go vet + golangci-lint + gosec before push
|
||||||
.githooks/pre-commit Runs gofmt + golangci-lint + gosec before commit
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -38,9 +35,8 @@ tools.go Tool version pinning (build tag: tools)
|
|||||||
- **Packages** — keep `cmd/` thin (wiring only); business logic belongs in `internal/`
|
- **Packages** — keep `cmd/` thin (wiring only); business logic belongs in `internal/`
|
||||||
- **Interfaces** — define interfaces where they are *used*, not where they are *implemented*
|
- **Interfaces** — define interfaces where they are *used*, not where they are *implemented*
|
||||||
- **Errors** — wrap with `fmt.Errorf("context: %w", err)`; never swallow errors silently
|
- **Errors** — wrap with `fmt.Errorf("context: %w", err)`; never swallow errors silently
|
||||||
- **Logging** — use `log.WithField("key", val)` for structured context, never `fmt.Sprintf` in log messages
|
- **Logging** — use `log.WithField("key", val)` for structured context; never `fmt.Sprintf` in log messages; `log/slog` is the backend
|
||||||
- **Config** — all configuration through `internal/config`; no hard-coded values in logic packages
|
- **Config** — all configuration through `internal/config` (flag-parsed); no hard-coded values in logic packages
|
||||||
- **Secrets** — never commit `.env` files or credentials; use env var overrides of config keys
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -58,13 +54,13 @@ tools.go Tool version pinning (build tag: tools)
|
|||||||
|
|
||||||
## Testing rules
|
## Testing rules
|
||||||
|
|
||||||
- All tests use **testify** (`assert` for soft checks, `require` for stop-on-fail)
|
- Tests use only the standard `testing` package — no third-party assertion libraries
|
||||||
- Test files: `package foo_test` (black-box) unless white-box access is needed
|
- Test files: `package foo_test` (black-box) unless white-box access is needed
|
||||||
- Mock dependencies via **mockery**-generated mocks with `EXPECT()` chains
|
- Fake dependencies with **manual fakes** (implement the interface inline in `_test.go`)
|
||||||
- Use `logger.NewNop()` when the test doesn't care about log output
|
- Use `logger.NewNop()` when the test doesn't care about log output
|
||||||
- Table-driven tests with `t.Run("description", ...)` for multiple cases
|
- Table-driven tests with `t.Run("description", ...)` for multiple cases
|
||||||
- The race detector is enabled in CI (`make test-race`); don't introduce data races
|
- The race detector is enabled in CI (`make test-race`); don't introduce data races
|
||||||
- Never use `time.Sleep` in tests; use channels or `require.Eventually`
|
- Never use `time.Sleep` in tests; use channels or `t.Cleanup`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -73,15 +69,13 @@ tools.go Tool version pinning (build tag: tools)
|
|||||||
```bash
|
```bash
|
||||||
make init # first-time setup: fetch deps, install tools, git hooks
|
make init # first-time setup: fetch deps, install tools, git hooks
|
||||||
make build # compile to ./bin/app
|
make build # compile to ./bin/app
|
||||||
make run # go run with config/dev.yaml
|
make run # go run with default flags
|
||||||
make test # run all tests
|
make test # run all tests
|
||||||
make test-race # tests + race detector
|
make test-race # tests + race detector
|
||||||
make lint # golangci-lint
|
make lint # go vet + golangci-lint
|
||||||
make lint-fix # auto-fix lint issues
|
make lint-fix # go fix + golangci-lint auto-fix
|
||||||
make security # gosec + govulncheck
|
make security # gosec + govulncheck
|
||||||
make mocks # regenerate all mocks
|
make clean # remove bin/
|
||||||
make generate # run all //go:generate directives
|
|
||||||
make clean # remove bin/ and mocks/
|
|
||||||
```
|
```
|
||||||
|
|
||||||
VSCode: `Ctrl+Shift+B` = build, `Ctrl+Shift+T` = test.
|
VSCode: `Ctrl+Shift+B` = build, `Ctrl+Shift+T` = test.
|
||||||
@ -92,19 +86,17 @@ Debug: use launch config "Debug: app" (F5).
|
|||||||
## Adding new features (checklist)
|
## Adding new features (checklist)
|
||||||
|
|
||||||
1. Define the interface in `internal/<domain>/`
|
1. Define the interface in `internal/<domain>/`
|
||||||
2. Write the implementation and its unit tests
|
2. Write the implementation and its unit tests (using a manual fake for the interface)
|
||||||
3. Add the interface to `.mockery.yaml` and run `make mocks`
|
3. Wire it in `cmd/app/main.go`
|
||||||
4. Wire it in `cmd/app/main.go`
|
4. Run `make lint test` before committing
|
||||||
5. Run `make lint test` before committing
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Known pitfalls
|
## Known pitfalls
|
||||||
|
|
||||||
- `mocks/` are committed intentionally — regenerate after interface changes
|
- `govulncheck` makes network calls; excluded from pre-push hook (run manually)
|
||||||
- `govulncheck` makes network calls; excluded from pre-commit hook (run manually)
|
|
||||||
- `config/dev.yaml` is committed but never add real credentials here
|
|
||||||
- `tools.go` has `//go:build tools` — it won't compile into the binary
|
- `tools.go` has `//go:build tools` — it won't compile into the binary
|
||||||
|
- `go fix` rewrites source files; run `make lint-fix` before committing after a Go version bump
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -113,5 +105,6 @@ Debug: use launch config "Debug: app" (F5).
|
|||||||
Keep this section to ~10 entries; remove stale items.
|
Keep this section to ~10 entries; remove stale items.
|
||||||
Format: YYYY-MM-DD — what was done and why. -->
|
Format: YYYY-MM-DD — what was done and why. -->
|
||||||
|
|
||||||
- 2026-03-05 — Initial template scaffolded: config, logger, greeter example,
|
- 2026-03-29 — Stripped to stdlib-only: removed testify/mockery→manual fakes, zap→slog, viper→flag.
|
||||||
mocks, git hooks, devcontainer, VSCode tasks, golangci-lint, Makefile.
|
- 2026-03-29 — Pre-commit hook moved to pre-push; go vet + go fix added to lint pipeline.
|
||||||
|
- 2026-03-29 — Fixed stale docs and .golangci.yml local-prefixes; .vscode launch configs use CLI flags.
|
||||||
|
|||||||
31
Makefile
31
Makefile
@ -1,11 +1,9 @@
|
|||||||
.PHONY: help init setup build run test test-race lint security generate mocks clean
|
.PHONY: help init setup build run test test-race lint lint-fix security clean
|
||||||
|
|
||||||
# ── Variables ──────────────────────────────────────────────────────────────────
|
# ── Variables ──────────────────────────────────────────────────────────────────
|
||||||
BINARY_NAME := app
|
BINARY_NAME := app
|
||||||
BINARY_PATH := ./bin/$(BINARY_NAME)
|
BINARY_PATH := ./bin/$(BINARY_NAME)
|
||||||
CMD_PATH := ./cmd/app
|
CMD_PATH := ./cmd/app
|
||||||
CONFIG_PATH := ./config/dev.yaml
|
|
||||||
GO_FILES := $(shell find . -type f -name '*.go' -not -path './vendor/*')
|
|
||||||
|
|
||||||
# ── Default target ─────────────────────────────────────────────────────────────
|
# ── Default target ─────────────────────────────────────────────────────────────
|
||||||
help: ## Show this help message
|
help: ## Show this help message
|
||||||
@ -14,13 +12,7 @@ help: ## Show this help message
|
|||||||
|
|
||||||
# ── First-time setup ───────────────────────────────────────────────────────────
|
# ── First-time setup ───────────────────────────────────────────────────────────
|
||||||
init: ## First-time project init: fetch deps, install tools, configure git hooks
|
init: ## First-time project init: fetch deps, install tools, configure git hooks
|
||||||
@echo "--- Fetching application dependencies ---"
|
|
||||||
go get go.uber.org/zap@latest
|
|
||||||
go get github.com/spf13/viper@latest
|
|
||||||
go get github.com/stretchr/testify@latest
|
|
||||||
go get github.com/stretchr/objx@latest
|
|
||||||
@echo "--- Fetching tool dependencies (pinned in tools.go) ---"
|
@echo "--- Fetching tool dependencies (pinned in tools.go) ---"
|
||||||
go get github.com/vektra/mockery/v2@latest
|
|
||||||
go get github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
go get github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||||
go get github.com/securego/gosec/v2/cmd/gosec@latest
|
go get github.com/securego/gosec/v2/cmd/gosec@latest
|
||||||
go get golang.org/x/vuln/cmd/govulncheck@latest
|
go get golang.org/x/vuln/cmd/govulncheck@latest
|
||||||
@ -40,7 +32,6 @@ setup: ## Configure git to use .githooks directory
|
|||||||
tools: ## Install tool binaries to GOPATH/bin (versions from go.mod)
|
tools: ## Install tool binaries to GOPATH/bin (versions from go.mod)
|
||||||
@echo "Installing tools..."
|
@echo "Installing tools..."
|
||||||
go install github.com/go-delve/delve/cmd/dlv@latest
|
go install github.com/go-delve/delve/cmd/dlv@latest
|
||||||
go install github.com/vektra/mockery/v2@latest
|
|
||||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||||
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||||
go install golang.org/x/vuln/cmd/govulncheck@latest
|
go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||||
@ -50,8 +41,8 @@ build: ## Compile the binary to ./bin/
|
|||||||
go build -o $(BINARY_PATH) $(CMD_PATH)
|
go build -o $(BINARY_PATH) $(CMD_PATH)
|
||||||
|
|
||||||
# ── Run ────────────────────────────────────────────────────────────────────────
|
# ── Run ────────────────────────────────────────────────────────────────────────
|
||||||
run: ## Run the application with dev config
|
run: ## Run the application with default flags
|
||||||
CONFIG_PATH=$(CONFIG_PATH) go run $(CMD_PATH)/main.go
|
go run $(CMD_PATH)/main.go
|
||||||
|
|
||||||
# ── Test ───────────────────────────────────────────────────────────────────────
|
# ── Test ───────────────────────────────────────────────────────────────────────
|
||||||
test: ## Run all tests
|
test: ## Run all tests
|
||||||
@ -64,10 +55,12 @@ test-verbose: ## Run all tests with verbose output
|
|||||||
go test ./... -race -cover -v
|
go test ./... -race -cover -v
|
||||||
|
|
||||||
# ── Lint & Security ────────────────────────────────────────────────────────────
|
# ── Lint & Security ────────────────────────────────────────────────────────────
|
||||||
lint: ## Run golangci-lint
|
lint: ## Run go vet + golangci-lint
|
||||||
|
go vet ./...
|
||||||
golangci-lint run ./...
|
golangci-lint run ./...
|
||||||
|
|
||||||
lint-fix: ## Run golangci-lint with auto-fix
|
lint-fix: ## Apply go fix + golangci-lint auto-fix
|
||||||
|
go fix ./...
|
||||||
golangci-lint run --fix ./...
|
golangci-lint run --fix ./...
|
||||||
|
|
||||||
security: ## Run gosec + govulncheck
|
security: ## Run gosec + govulncheck
|
||||||
@ -76,14 +69,6 @@ security: ## Run gosec + govulncheck
|
|||||||
@echo "--- govulncheck ---"
|
@echo "--- govulncheck ---"
|
||||||
govulncheck ./...
|
govulncheck ./...
|
||||||
|
|
||||||
# ── Code generation ────────────────────────────────────────────────────────────
|
|
||||||
generate: ## Run go generate across all packages
|
|
||||||
go generate ./...
|
|
||||||
|
|
||||||
mocks: ## Regenerate all mocks via mockery (config: .mockery.yaml)
|
|
||||||
mockery
|
|
||||||
|
|
||||||
# ── Cleanup ────────────────────────────────────────────────────────────────────
|
# ── Cleanup ────────────────────────────────────────────────────────────────────
|
||||||
clean: ## Remove build artifacts and generated mocks
|
clean: ## Remove build artifacts
|
||||||
rm -rf ./bin
|
rm -rf ./bin
|
||||||
rm -rf ./mocks
|
|
||||||
|
|||||||
109
README.md
109
README.md
@ -9,14 +9,13 @@ Clone it, rename the module, run `make init`, and you're coding.
|
|||||||
|
|
||||||
| Area | Tool | Purpose |
|
| Area | Tool | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Language | Go 1.24 | Modules, toolchain directive |
|
| Language | Go 1.25 | Modules, toolchain directive |
|
||||||
| Logging | [zap](https://github.com/uber-go/zap) | Structured JSON logging + `WithField` extension |
|
| Logging | standard `log/slog` | Structured JSON/text logging + `WithField` extension |
|
||||||
| Config | [viper](https://github.com/spf13/viper) | YAML file + env var overlay |
|
| Config | standard `flag` | CLI flags with defaults, no config files |
|
||||||
| Linting | [golangci-lint](https://golangci-lint.run) | Aggregated linters, one config file |
|
| Linting | [golangci-lint](https://golangci-lint.run) | Aggregated linters, one config file |
|
||||||
| Security | [gosec](https://github.com/securego/gosec) + [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck) | SAST + dependency vulnerability scan |
|
| Security | [gosec](https://github.com/securego/gosec) + [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck) | SAST + dependency vulnerability scan |
|
||||||
| Mocks | [mockery v2](https://vektra.github.io/mockery/latest/) | Type-safe, EXPECT()-style generated mocks |
|
| Tests | standard `testing` | Table-driven tests, manual fakes, no third-party test framework |
|
||||||
| Tests | [testify](https://github.com/stretchr/testify) | Assertions (`assert`/`require`) + mock framework |
|
| Git hooks | custom pre-push | gofmt + go vet + golangci-lint + gosec on every push |
|
||||||
| Git hooks | custom pre-commit | gofmt + golangci-lint + gosec on every commit |
|
|
||||||
| Tool versions | `tools.go` + `go.mod` | Single source of truth for tool versions |
|
| Tool versions | `tools.go` + `go.mod` | Single source of truth for tool versions |
|
||||||
| Dev environment | devcontainer | Reproducible VSCode / GitHub Codespaces setup |
|
| Dev environment | devcontainer | Reproducible VSCode / GitHub Codespaces setup |
|
||||||
| IDE | VSCode | Launch configs, tasks, recommended settings |
|
| IDE | VSCode | Launch configs, tasks, recommended settings |
|
||||||
@ -27,7 +26,7 @@ Clone it, rename the module, run `make init`, and you're coding.
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- Go 1.24+
|
- Go 1.25+
|
||||||
- Git
|
- Git
|
||||||
- (Optional) [VSCode](https://code.visualstudio.com/) + [Go extension](https://marketplace.visualstudio.com/items?itemName=golang.Go)
|
- (Optional) [VSCode](https://code.visualstudio.com/) + [Go extension](https://marketplace.visualstudio.com/items?itemName=golang.Go)
|
||||||
- (Optional) Docker for devcontainer
|
- (Optional) Docker for devcontainer
|
||||||
@ -52,7 +51,7 @@ make init # fetches deps, installs tools, configures git hooks
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
make build # compiles to ./bin/app
|
make build # compiles to ./bin/app
|
||||||
make run # go run with config/dev.yaml
|
make run # go run with default flags
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -62,11 +61,9 @@ make run # go run with config/dev.yaml
|
|||||||
```bash
|
```bash
|
||||||
make test # run all tests
|
make test # run all tests
|
||||||
make test-race # … with race detector
|
make test-race # … with race detector
|
||||||
make lint # golangci-lint
|
make lint # go vet + golangci-lint
|
||||||
make lint-fix # auto-fix what can be fixed
|
make lint-fix # go fix + golangci-lint auto-fix
|
||||||
make security # gosec + govulncheck
|
make security # gosec + govulncheck
|
||||||
make mocks # regenerate mocks after interface changes
|
|
||||||
make generate # run all //go:generate directives
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Keyboard shortcut (VSCode):** `Ctrl+Shift+B` → build, `Ctrl+Shift+T` → test.
|
> **Keyboard shortcut (VSCode):** `Ctrl+Shift+B` → build, `Ctrl+Shift+T` → test.
|
||||||
@ -80,20 +77,15 @@ make generate # run all //go:generate directives
|
|||||||
├── cmd/
|
├── cmd/
|
||||||
│ └── app/
|
│ └── app/
|
||||||
│ └── main.go # Composition root (thin — just wiring)
|
│ └── main.go # Composition root (thin — just wiring)
|
||||||
├── config/
|
|
||||||
│ └── dev.yaml # Local dev config (safe to commit)
|
|
||||||
├── internal/
|
├── internal/
|
||||||
│ ├── config/ # Viper config loader
|
│ ├── config/ # flag-based config (config.Load)
|
||||||
│ ├── logger/ # Zap wrapper with WithField
|
│ ├── logger/ # slog wrapper with WithField / WithFields
|
||||||
│ └── greeter/ # Example domain package (replace with yours)
|
│ └── greeter/ # Example domain package (replace with yours)
|
||||||
├── mocks/
|
|
||||||
│ └── greeter/ # Generated by `make mocks` — commit these
|
|
||||||
├── .devcontainer/ # VSCode / Codespaces container definition
|
├── .devcontainer/ # VSCode / Codespaces container definition
|
||||||
├── .githooks/ # pre-commit hook (installed by `make setup`)
|
├── .githooks/ # pre-push hook (installed by `make setup`)
|
||||||
├── .vscode/ # launch, tasks, editor settings
|
├── .vscode/ # launch, tasks, editor settings
|
||||||
├── tools.go # Tool version pinning (build tag: tools)
|
├── tools.go # Tool version pinning (build tag: tools)
|
||||||
├── .golangci.yml # Linter configuration
|
├── .golangci.yml # Linter configuration
|
||||||
├── .mockery.yaml # Mockery configuration
|
|
||||||
└── Makefile # All development commands
|
└── Makefile # All development commands
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -101,35 +93,28 @@ make generate # run all //go:generate directives
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Config is loaded from a YAML file (default `config/dev.yaml`) with env var overrides.
|
All configuration is via CLI flags with sensible defaults:
|
||||||
|
|
||||||
```yaml
|
|
||||||
app:
|
|
||||||
name: "go-template"
|
|
||||||
port: 8080
|
|
||||||
env: "dev" # dev | staging | prod
|
|
||||||
|
|
||||||
logger:
|
|
||||||
level: "debug" # debug | info | warn | error
|
|
||||||
```
|
|
||||||
|
|
||||||
Override any key at runtime:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
APP_PORT=9090 LOGGER_LEVEL=info make run
|
./bin/app -help
|
||||||
|
-env string environment: dev | staging | prod (default "dev")
|
||||||
|
-log-level string log level: debug | info | warn | error (default "info")
|
||||||
|
-name string application name (default "go-template")
|
||||||
|
-port int listen port (default 8080)
|
||||||
```
|
```
|
||||||
|
|
||||||
The `CONFIG_PATH` env var points to the config file:
|
Override at runtime:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
CONFIG_PATH=config/staging.yaml ./bin/app
|
./bin/app -port 9090 -env prod -log-level warn
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Logging
|
## Logging
|
||||||
|
|
||||||
The logger wrapper adds `WithField` and `WithFields` for ergonomic context chaining:
|
The logger wrapper adds `WithField` and `WithFields` for ergonomic context chaining
|
||||||
|
on top of the standard `log/slog` package:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
log.WithField("request_id", rid).
|
log.WithField("request_id", rid).
|
||||||
@ -142,29 +127,32 @@ log.WithFields(map[string]any{
|
|||||||
}).Debug("generating greeting")
|
}).Debug("generating greeting")
|
||||||
```
|
```
|
||||||
|
|
||||||
In production (`app.env != dev`) the output is JSON. In development, use
|
In production (`app.env != dev`) the output is JSON (`slog.NewJSONHandler`).
|
||||||
`logger.NewDevelopment()` for coloured console output.
|
In development, `logger.NewDevelopment()` uses the human-friendly text handler.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Mocking
|
## Testing
|
||||||
|
|
||||||
1. Define your interface in an `internal/` package.
|
Tests use the standard `testing` package. For dependencies on interfaces, write
|
||||||
2. Add a `//go:generate mockery --name=YourInterface` directive.
|
a manual fake inline in the test file — no code generation required:
|
||||||
3. Register the interface in `.mockery.yaml` under `packages:`.
|
|
||||||
4. Run `make mocks`.
|
|
||||||
|
|
||||||
Generated mocks support type-safe EXPECT() call chains:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import mocks "gitea.djmil.dev/djmil/go-template/mocks/greeter"
|
type fakeGreeter struct {
|
||||||
|
greetFn func(name string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeGreeter) Greet(name string) (string, error) {
|
||||||
|
return f.greetFn(name)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSomething(t *testing.T) {
|
func TestSomething(t *testing.T) {
|
||||||
g := mocks.NewMockGreeter(t)
|
fake := &fakeGreeter{
|
||||||
g.EXPECT().Greet("Alice").Return("Hello, Alice!", nil)
|
greetFn: func(name string) (string, error) {
|
||||||
|
return "Hello, " + name + "!", nil
|
||||||
result, err := myConsumer(g)
|
},
|
||||||
require.NoError(t, err)
|
}
|
||||||
|
// pass fake to the system under test
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -172,16 +160,17 @@ func TestSomething(t *testing.T) {
|
|||||||
|
|
||||||
## Git hooks
|
## Git hooks
|
||||||
|
|
||||||
The pre-commit hook runs **gofmt + golangci-lint + gosec** before every commit.
|
The pre-push hook runs **gofmt + go vet + golangci-lint + gosec** against the
|
||||||
It checks only staged Go files to keep it fast.
|
full codebase before every `git push`. Running on push (not commit) keeps the
|
||||||
|
inner commit loop fast while still blocking bad code from reaching the remote.
|
||||||
|
|
||||||
`govulncheck` is intentionally excluded from the hook (it makes network calls
|
`govulncheck` is intentionally excluded (it makes network calls and can be
|
||||||
and can be slow). Run it manually with `make security`.
|
slow). Run it manually with `make security`.
|
||||||
|
|
||||||
To skip the hook in an emergency:
|
To skip the hook in an emergency:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git commit --no-verify -m "wip: skip hooks"
|
git push --no-verify
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -195,7 +184,7 @@ same versions.
|
|||||||
To update a tool:
|
To update a tool:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go get github.com/vektra/mockery/v2@latest
|
go get github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||||
go mod tidy
|
go mod tidy
|
||||||
make tools # reinstall binaries
|
make tools # reinstall binaries
|
||||||
```
|
```
|
||||||
@ -204,8 +193,8 @@ make tools # reinstall binaries
|
|||||||
|
|
||||||
## Devcontainer
|
## Devcontainer
|
||||||
|
|
||||||
Open this repo in VSCode and choose **"Reopen in Container"** — everything
|
Open this repo in VSCode and choose **"Reopen in Container"** — the Go
|
||||||
(Go toolchain, golangci-lint, mockery, gosec, govulncheck) is installed
|
toolchain and all tools (golangci-lint, gosec, govulncheck) are installed
|
||||||
automatically via `make init`.
|
automatically via `make init`.
|
||||||
|
|
||||||
Works with GitHub Codespaces out of the box.
|
Works with GitHub Codespaces out of the box.
|
||||||
|
|||||||
@ -21,27 +21,21 @@ func main() {
|
|||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
// ── Config ────────────────────────────────────────────────────────────────
|
// ── Config ────────────────────────────────────────────────────────────────
|
||||||
cfgPath := os.Getenv("CONFIG_PATH")
|
cfg := config.Load()
|
||||||
if cfgPath == "" {
|
|
||||||
cfgPath = "config/dev.yaml"
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg, err := config.Load(cfgPath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("loading config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Logger ────────────────────────────────────────────────────────────────
|
// ── Logger ────────────────────────────────────────────────────────────────
|
||||||
var log *logger.Logger
|
var (
|
||||||
|
log *logger.Logger
|
||||||
|
err error
|
||||||
|
)
|
||||||
if cfg.App.Env == "dev" {
|
if cfg.App.Env == "dev" {
|
||||||
log, err = logger.NewDevelopment()
|
log = logger.NewDevelopment()
|
||||||
} else {
|
} else {
|
||||||
log, err = logger.New(cfg.Logger.Level)
|
log, err = logger.New(cfg.Logger.Level)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating logger: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("creating logger: %w", err)
|
|
||||||
}
|
|
||||||
defer log.Sync()
|
|
||||||
|
|
||||||
log.WithFields(map[string]any{
|
log.WithFields(map[string]any{
|
||||||
"app": cfg.App.Name,
|
"app": cfg.App.Name,
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
# Development configuration.
|
|
||||||
# Values here are safe for local use only — never commit production secrets.
|
|
||||||
# Override any key with an environment variable: APP_PORT=9090, LOGGER_LEVEL=debug
|
|
||||||
|
|
||||||
app:
|
|
||||||
name: "go-template"
|
|
||||||
port: 8080
|
|
||||||
env: "dev"
|
|
||||||
|
|
||||||
logger:
|
|
||||||
# debug | info | warn | error
|
|
||||||
level: "debug"
|
|
||||||
31
go.mod
31
go.mod
@ -6,12 +6,9 @@ go 1.25.0
|
|||||||
// After cloning, rename the module path above to match your project.
|
// After cloning, rename the module path above to match your project.
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/go-delve/delve v1.26.1
|
||||||
github.com/golangci/golangci-lint v1.64.8
|
github.com/golangci/golangci-lint v1.64.8
|
||||||
github.com/securego/gosec/v2 v2.24.7
|
github.com/securego/gosec/v2 v2.24.7
|
||||||
github.com/spf13/viper v1.21.0
|
|
||||||
github.com/stretchr/testify v1.11.1
|
|
||||||
github.com/vektra/mockery/v2 v2.53.6
|
|
||||||
go.uber.org/zap v1.27.1
|
|
||||||
golang.org/x/vuln v1.1.4
|
golang.org/x/vuln v1.1.4
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -53,12 +50,15 @@ require (
|
|||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/charithe/durationcheck v0.0.10 // indirect
|
github.com/charithe/durationcheck v0.0.10 // indirect
|
||||||
github.com/chavacava/garif v0.1.0 // indirect
|
github.com/chavacava/garif v0.1.0 // indirect
|
||||||
github.com/chigopher/pathlib v0.19.1 // indirect
|
github.com/cilium/ebpf v0.11.0 // indirect
|
||||||
github.com/ckaznocha/intrange v0.3.0 // indirect
|
github.com/ckaznocha/intrange v0.3.0 // indirect
|
||||||
|
github.com/cosiner/argv v0.1.0 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||||
github.com/curioswitch/go-reassign v0.3.0 // indirect
|
github.com/curioswitch/go-reassign v0.3.0 // indirect
|
||||||
github.com/daixiang0/gci v0.13.5 // indirect
|
github.com/daixiang0/gci v0.13.5 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/denis-tingaikin/go-header v0.5.0 // indirect
|
github.com/denis-tingaikin/go-header v0.5.0 // indirect
|
||||||
|
github.com/derekparker/trie/v3 v3.2.0 // indirect
|
||||||
github.com/ettle/strcase v0.2.0 // indirect
|
github.com/ettle/strcase v0.2.0 // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/fatih/structtag v1.2.0 // indirect
|
github.com/fatih/structtag v1.2.0 // indirect
|
||||||
@ -68,6 +68,7 @@ require (
|
|||||||
github.com/fzipp/gocyclo v0.6.0 // indirect
|
github.com/fzipp/gocyclo v0.6.0 // indirect
|
||||||
github.com/ghostiam/protogetter v0.3.9 // indirect
|
github.com/ghostiam/protogetter v0.3.9 // indirect
|
||||||
github.com/go-critic/go-critic v0.12.0 // indirect
|
github.com/go-critic/go-critic v0.12.0 // indirect
|
||||||
|
github.com/go-delve/liner v1.2.3-0.20231231155935-4726ab1d7f62 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-toolsmith/astcast v1.1.0 // indirect
|
github.com/go-toolsmith/astcast v1.1.0 // indirect
|
||||||
@ -89,6 +90,7 @@ require (
|
|||||||
github.com/golangci/revgrep v0.8.0 // indirect
|
github.com/golangci/revgrep v0.8.0 // indirect
|
||||||
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
|
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
|
||||||
github.com/google/go-cmp v0.7.0 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
|
github.com/google/go-dap v0.12.0 // indirect
|
||||||
github.com/google/s2a-go v0.1.9 // indirect
|
github.com/google/s2a-go v0.1.9 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||||
@ -103,13 +105,11 @@ require (
|
|||||||
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
|
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
|
||||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||||
github.com/huandu/xstrings v1.5.0 // indirect
|
|
||||||
github.com/iancoleman/strcase v0.3.0 // indirect
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jgautheron/goconst v1.7.1 // indirect
|
github.com/jgautheron/goconst v1.7.1 // indirect
|
||||||
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
|
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
|
||||||
github.com/jinzhu/copier v0.4.0 // indirect
|
|
||||||
github.com/jjti/go-spancheck v0.6.4 // indirect
|
github.com/jjti/go-spancheck v0.6.4 // indirect
|
||||||
github.com/julz/importas v0.2.0 // indirect
|
github.com/julz/importas v0.2.0 // indirect
|
||||||
github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect
|
github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect
|
||||||
@ -125,6 +125,7 @@ require (
|
|||||||
github.com/ldez/usetesting v0.4.2 // indirect
|
github.com/ldez/usetesting v0.4.2 // indirect
|
||||||
github.com/leonklingele/grouper v1.1.2 // indirect
|
github.com/leonklingele/grouper v1.1.2 // indirect
|
||||||
github.com/macabu/inamedparam v0.1.3 // indirect
|
github.com/macabu/inamedparam v0.1.3 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.6 // indirect
|
||||||
github.com/maratori/testableexamples v1.0.0 // indirect
|
github.com/maratori/testableexamples v1.0.0 // indirect
|
||||||
github.com/maratori/testpackage v1.1.1 // indirect
|
github.com/maratori/testpackage v1.1.1 // indirect
|
||||||
github.com/matoous/godox v1.1.0 // indirect
|
github.com/matoous/godox v1.1.0 // indirect
|
||||||
@ -144,6 +145,7 @@ require (
|
|||||||
github.com/olekukonko/ll v0.0.8 // indirect
|
github.com/olekukonko/ll v0.0.8 // indirect
|
||||||
github.com/olekukonko/tablewriter v1.0.7 // indirect
|
github.com/olekukonko/tablewriter v1.0.7 // indirect
|
||||||
github.com/openai/openai-go/v3 v3.23.0 // indirect
|
github.com/openai/openai-go/v3 v3.23.0 // indirect
|
||||||
|
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/polyfloyd/go-errorlint v1.7.1 // indirect
|
github.com/polyfloyd/go-errorlint v1.7.1 // indirect
|
||||||
@ -159,10 +161,9 @@ require (
|
|||||||
github.com/raeperd/recvcheck v0.2.0 // indirect
|
github.com/raeperd/recvcheck v0.2.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
github.com/rs/zerolog v1.34.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/ryancurrah/gomodguard v1.3.5 // indirect
|
github.com/ryancurrah/gomodguard v1.3.5 // indirect
|
||||||
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
|
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
|
||||||
github.com/sagikazarmark/locafero v0.12.0 // indirect
|
|
||||||
github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
|
github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
|
||||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
|
||||||
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
|
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
|
||||||
@ -175,10 +176,13 @@ require (
|
|||||||
github.com/spf13/afero v1.15.0 // indirect
|
github.com/spf13/afero v1.15.0 // indirect
|
||||||
github.com/spf13/cast v1.10.0 // indirect
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
github.com/spf13/cobra v1.10.2 // indirect
|
github.com/spf13/cobra v1.10.2 // indirect
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
|
github.com/spf13/viper v1.12.0 // indirect
|
||||||
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
|
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
|
||||||
github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect
|
github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect
|
||||||
github.com/stretchr/objx v0.5.3 // indirect
|
github.com/stretchr/objx v0.5.3 // indirect
|
||||||
|
github.com/stretchr/testify v1.11.1 // indirect
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/tdakkota/asciicheck v0.4.1 // indirect
|
github.com/tdakkota/asciicheck v0.4.1 // indirect
|
||||||
github.com/tetafro/godot v1.5.0 // indirect
|
github.com/tetafro/godot v1.5.0 // indirect
|
||||||
@ -209,9 +213,14 @@ require (
|
|||||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||||
|
go.starlark.net v0.0.0-20231101134539-556fd59b42f6 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||||
|
go.uber.org/goleak v1.3.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
go.uber.org/zap v1.24.0 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
|
golang.org/x/arch v0.11.0 // indirect
|
||||||
golang.org/x/crypto v0.48.0 // indirect
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect
|
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect
|
||||||
@ -220,7 +229,6 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
golang.org/x/sys v0.41.0 // indirect
|
||||||
golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 // indirect
|
golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 // indirect
|
||||||
golang.org/x/term v0.40.0 // indirect
|
|
||||||
golang.org/x/text v0.34.0 // indirect
|
golang.org/x/text v0.34.0 // indirect
|
||||||
golang.org/x/tools v0.42.0 // indirect
|
golang.org/x/tools v0.42.0 // indirect
|
||||||
golang.org/x/tools/go/expect v0.1.1-deprecated // indirect
|
golang.org/x/tools/go/expect v0.1.1-deprecated // indirect
|
||||||
@ -229,6 +237,7 @@ require (
|
|||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||||
google.golang.org/grpc v1.75.0 // indirect
|
google.golang.org/grpc v1.75.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.8 // indirect
|
google.golang.org/protobuf v1.36.8 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
honnef.co/go/tools v0.6.1 // indirect
|
honnef.co/go/tools v0.6.1 // indirect
|
||||||
|
|||||||
69
go.sum
69
go.sum
@ -50,6 +50,8 @@ github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8ger
|
|||||||
github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
|
github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
|
||||||
github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU=
|
github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU=
|
||||||
github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4=
|
github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4=
|
||||||
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w=
|
github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w=
|
||||||
@ -76,12 +78,16 @@ github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iy
|
|||||||
github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ=
|
github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ=
|
||||||
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
||||||
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
|
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
|
||||||
github.com/chigopher/pathlib v0.19.1 h1:RoLlUJc0CqBGwq239cilyhxPNLXTK+HXoASGyGznx5A=
|
github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y=
|
||||||
github.com/chigopher/pathlib v0.19.1/go.mod h1:tzC1dZLW8o33UQpWkNkhvPwL5n4yyFRFm/jL1YGWFvY=
|
github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs=
|
||||||
github.com/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd5ZY=
|
github.com/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd5ZY=
|
||||||
github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo=
|
github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/cosiner/argv v0.1.0 h1:BVDiEL32lwHukgJKP87btEPenzrrHUjajs/8yzaqcXg=
|
||||||
|
github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
|
github.com/creack/pty v1.1.20 h1:VIPb/a2s17qNeQgDnkfZC35RScx+blkKF8GV68n80J4=
|
||||||
|
github.com/creack/pty v1.1.20/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs=
|
github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs=
|
||||||
github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88=
|
github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88=
|
||||||
github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
|
github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
|
||||||
@ -92,6 +98,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
|||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
|
github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
|
||||||
github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=
|
github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=
|
||||||
|
github.com/derekparker/trie/v3 v3.2.0 h1:fET3Qbp9xSB7yc7tz6Y2GKMNl0SycYFo3cmiRI3Gpf0=
|
||||||
|
github.com/derekparker/trie/v3 v3.2.0/go.mod h1:P94lW0LPgiaMgKAEQD59IDZD2jMK9paKok8Nli/nQbE=
|
||||||
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||||
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||||
@ -116,6 +124,10 @@ github.com/ghostiam/protogetter v0.3.9 h1:j+zlLLWzqLay22Cz/aYwTHKQ88GE2DQ6GkWSYF
|
|||||||
github.com/ghostiam/protogetter v0.3.9/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
|
github.com/ghostiam/protogetter v0.3.9/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
|
||||||
github.com/go-critic/go-critic v0.12.0 h1:iLosHZuye812wnkEz1Xu3aBwn5ocCPfc9yqmFG9pa6w=
|
github.com/go-critic/go-critic v0.12.0 h1:iLosHZuye812wnkEz1Xu3aBwn5ocCPfc9yqmFG9pa6w=
|
||||||
github.com/go-critic/go-critic v0.12.0/go.mod h1:DpE0P6OVc6JzVYzmM5gq5jMU31zLr4am5mB/VfFK64w=
|
github.com/go-critic/go-critic v0.12.0/go.mod h1:DpE0P6OVc6JzVYzmM5gq5jMU31zLr4am5mB/VfFK64w=
|
||||||
|
github.com/go-delve/delve v1.26.1 h1:V1F0hzAjXCpsBP+I/E6fVUTLC/ZBSs1YWUb8cTtIWFE=
|
||||||
|
github.com/go-delve/delve v1.26.1/go.mod h1:Ua/k2AAu4cLrUXGSRVH1b2Nzq2aCK188b9EYlAojlz4=
|
||||||
|
github.com/go-delve/liner v1.2.3-0.20231231155935-4726ab1d7f62 h1:IGtvsNyIuRjl04XAOFGACozgUD7A82UffYxZt4DWbvA=
|
||||||
|
github.com/go-delve/liner v1.2.3-0.20231231155935-4726ab1d7f62/go.mod h1:biJCRbqp51wS+I92HMqn5H8/A0PAhxn2vyOT+JqhiGI=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
@ -150,7 +162,6 @@ github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUW
|
|||||||
github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
||||||
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
|
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
@ -180,6 +191,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/go-dap v0.12.0 h1:rVcjv3SyMIrpaOoTAdFDyHs99CwVOItIJGKLQFQhNeM=
|
||||||
|
github.com/google/go-dap v0.12.0/go.mod h1:tNjCASCm5cqePi/RVXXWEVqtnNLV1KTWtYOqu6rZNzc=
|
||||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
|
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
|
||||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
|
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
|
||||||
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
||||||
@ -222,20 +235,16 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe
|
|||||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||||
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
|
||||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
|
||||||
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
|
|
||||||
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk=
|
github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk=
|
||||||
github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
|
github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
|
||||||
github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
|
github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
|
||||||
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
|
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
|
||||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
|
||||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
|
||||||
github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc=
|
github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc=
|
||||||
github.com/jjti/go-spancheck v0.6.4/go.mod h1:yAEYdKJ2lRkDA8g7X+oKUHXOWVAXSBJRv04OhF+QUjk=
|
github.com/jjti/go-spancheck v0.6.4/go.mod h1:yAEYdKJ2lRkDA8g7X+oKUHXOWVAXSBJRv04OhF+QUjk=
|
||||||
github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ=
|
github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ=
|
||||||
@ -270,6 +279,8 @@ github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84Yrj
|
|||||||
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
|
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
|
||||||
github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk=
|
github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk=
|
||||||
github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I=
|
github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I=
|
||||||
|
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||||
|
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI=
|
github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI=
|
||||||
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
|
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
|
||||||
github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
|
github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
|
||||||
@ -278,13 +289,11 @@ github.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4=
|
|||||||
github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs=
|
github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs=
|
||||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mgechev/revive v1.7.0 h1:JyeQ4yO5K8aZhIKf5rec56u0376h8AlKNQEmjfkjKlY=
|
github.com/mgechev/revive v1.7.0 h1:JyeQ4yO5K8aZhIKf5rec56u0376h8AlKNQEmjfkjKlY=
|
||||||
@ -324,8 +333,11 @@ github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJ
|
|||||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||||
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||||
|
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||||
|
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
@ -359,16 +371,12 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
|||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
|
||||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU=
|
github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU=
|
||||||
github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
|
github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
|
||||||
github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
|
github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
|
||||||
github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
|
github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
|
||||||
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
|
|
||||||
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
|
|
||||||
github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0=
|
github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0=
|
||||||
github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4=
|
github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4=
|
||||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
|
||||||
@ -397,12 +405,14 @@ github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
|||||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||||
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
|
||||||
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
|
||||||
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
|
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
|
||||||
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
|
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
|
||||||
github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4=
|
github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4=
|
||||||
@ -412,6 +422,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
|
|||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
|
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
|
||||||
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
|
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
@ -457,8 +468,6 @@ github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYR
|
|||||||
github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU=
|
github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU=
|
||||||
github.com/uudashr/iface v1.3.1 h1:bA51vmVx1UIhiIsQFSNq6GZ6VPTk3WNMZgRiCe9R29U=
|
github.com/uudashr/iface v1.3.1 h1:bA51vmVx1UIhiIsQFSNq6GZ6VPTk3WNMZgRiCe9R29U=
|
||||||
github.com/uudashr/iface v1.3.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
|
github.com/uudashr/iface v1.3.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
|
||||||
github.com/vektra/mockery/v2 v2.53.6 h1:qfUB6saauu652ZlMF/mEdlj7B/A0fw2XR0XBACBrf7Y=
|
|
||||||
github.com/vektra/mockery/v2 v2.53.6/go.mod h1:fjxC+mskIZqf67+z34pHxRRyyZnPnWNA36Cirf01Pkg=
|
|
||||||
github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
|
github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
|
||||||
github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
|
github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
@ -497,16 +506,22 @@ go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6
|
|||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||||
|
go.starlark.net v0.0.0-20231101134539-556fd59b42f6 h1:+eC0F/k4aBLC4szgOcjd7bDTEnpxADJyWJE0yowgM3E=
|
||||||
|
go.starlark.net v0.0.0-20231101134539-556fd59b42f6/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM=
|
||||||
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
|
golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4=
|
||||||
|
golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
@ -574,10 +589,10 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -596,8 +611,6 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
|||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
|
||||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@ -653,6 +666,8 @@ google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXn
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
|||||||
@ -1,61 +1,54 @@
|
|||||||
// Package config loads application configuration from a YAML file + env vars.
|
// Package config parses application configuration from command-line flags.
|
||||||
// Priority (highest → lowest): env vars → config file → defaults.
|
// Defaults are defined here; override at runtime with flags:
|
||||||
|
//
|
||||||
|
// ./app -port 9090 -env prod -log-level warn
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// cfg, err := config.Load("config/dev.yaml")
|
// cfg := config.Load()
|
||||||
// fmt.Println(cfg.App.Port)
|
// fmt.Println(cfg.App.Port)
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"flag"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config is the root configuration object. Add sub-structs as the app grows.
|
// Config is the root configuration object. Add sub-structs as the app grows.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
App AppConfig `mapstructure:"app"`
|
App AppConfig
|
||||||
Logger LoggerConfig `mapstructure:"logger"`
|
Logger LoggerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppConfig holds generic application settings.
|
// AppConfig holds generic application settings.
|
||||||
type AppConfig struct {
|
type AppConfig struct {
|
||||||
Name string `mapstructure:"name"`
|
Name string
|
||||||
Port int `mapstructure:"port"`
|
Port int
|
||||||
Env string `mapstructure:"env"` // dev | staging | prod
|
Env string // dev | staging | prod
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoggerConfig controls logging behavior.
|
// LoggerConfig controls logging behavior.
|
||||||
type LoggerConfig struct {
|
type LoggerConfig struct {
|
||||||
Level string `mapstructure:"level"` // debug | info | warn | error
|
Level string // debug | info | warn | error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load reads the YAML file at path and overlays any matching environment
|
// Load parses command-line flags and returns a Config.
|
||||||
// variables (e.g. APP_PORT overrides app.port).
|
// Call this once at startup before any other flag parsing.
|
||||||
func Load(path string) (*Config, error) {
|
func Load() *Config {
|
||||||
v := viper.New()
|
name := flag.String("name", "go-template", "application name")
|
||||||
|
port := flag.Int("port", 8080, "listen port")
|
||||||
|
env := flag.String("env", "dev", "environment: dev | staging | prod")
|
||||||
|
level := flag.String("log-level", "info", "log level: debug | info | warn | error")
|
||||||
|
|
||||||
v.SetConfigFile(path)
|
flag.Parse()
|
||||||
|
|
||||||
// Allow every config key to be overridden by an env var.
|
return &Config{
|
||||||
// e.g. APP_PORT=9090 overrides app.port
|
App: AppConfig{
|
||||||
v.AutomaticEnv()
|
Name: *name,
|
||||||
|
Port: *port,
|
||||||
// Sensible defaults so the binary works without a config file.
|
Env: *env,
|
||||||
v.SetDefault("app.name", "go-template")
|
},
|
||||||
v.SetDefault("app.port", 8080)
|
Logger: LoggerConfig{
|
||||||
v.SetDefault("app.env", "dev")
|
Level: *level,
|
||||||
v.SetDefault("logger.level", "info")
|
},
|
||||||
|
|
||||||
if err := v.ReadInConfig(); err != nil {
|
|
||||||
return nil, fmt.Errorf("config: reading %q: %w", path, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cfg Config
|
|
||||||
if err := v.Unmarshal(&cfg); err != nil {
|
|
||||||
return nil, fmt.Errorf("config: unmarshalling: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cfg, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// Package greeter is a minimal example domain package.
|
// Package greeter is a minimal example domain package.
|
||||||
// It demonstrates how to:
|
// It demonstrates how to:
|
||||||
// - define an interface (mockable via mockery)
|
// - define an interface (satisfied by manual fakes in tests)
|
||||||
// - inject dependencies (logger) through a constructor
|
// - inject dependencies (logger) through a constructor
|
||||||
// - use the logger.WithField pattern
|
// - use the logger.WithField pattern
|
||||||
//
|
//
|
||||||
@ -13,8 +13,6 @@ import (
|
|||||||
"gitea.djmil.dev/djmil/go-template/internal/logger"
|
"gitea.djmil.dev/djmil/go-template/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate mockery --name=Greeter
|
|
||||||
|
|
||||||
// Greeter produces a greeting for a given name.
|
// Greeter produces a greeting for a given name.
|
||||||
// The interface is what other packages should depend on — never the concrete type.
|
// The interface is what other packages should depend on — never the concrete type.
|
||||||
type Greeter interface {
|
type Greeter interface {
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
package greeter_test
|
package greeter_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"gitea.djmil.dev/djmil/go-template/internal/greeter"
|
"gitea.djmil.dev/djmil/go-template/internal/greeter"
|
||||||
"gitea.djmil.dev/djmil/go-template/internal/logger"
|
"gitea.djmil.dev/djmil/go-template/internal/logger"
|
||||||
)
|
)
|
||||||
@ -15,37 +13,51 @@ import (
|
|||||||
func TestGreet(t *testing.T) {
|
func TestGreet(t *testing.T) {
|
||||||
svc := greeter.New(logger.NewNop())
|
svc := greeter.New(logger.NewNop())
|
||||||
|
|
||||||
t.Run("returns personalised greeting", func(t *testing.T) {
|
t.Run("returns personalized greeting", func(t *testing.T) {
|
||||||
msg, err := svc.Greet("World")
|
msg, err := svc.Greet("World")
|
||||||
require.NoError(t, err)
|
if err != nil {
|
||||||
assert.Equal(t, "Hello, World!", msg)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if msg != "Hello, World!" {
|
||||||
|
t.Errorf("got %q, want %q", msg, "Hello, World!")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("rejects empty name", func(t *testing.T) {
|
t.Run("rejects empty name", func(t *testing.T) {
|
||||||
_, err := svc.Greet("")
|
_, err := svc.Greet("")
|
||||||
require.Error(t, err)
|
if err == nil {
|
||||||
assert.Contains(t, err.Error(), "name must not be empty")
|
t.Fatal("expected error, got nil")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "name must not be empty") {
|
||||||
|
t.Errorf("error %q does not contain %q", err.Error(), "name must not be empty")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Mock usage example ────────────────────────────────────────────────────────
|
// ── Manual fake example ───────────────────────────────────────────────────────
|
||||||
// The mock lives in mocks/greeter/mock_greeter.go and is generated by:
|
// For consumers that depend on the Greeter interface, write a manual fake.
|
||||||
//
|
// No code generation required — just implement the interface directly.
|
||||||
// make mocks
|
|
||||||
//
|
|
||||||
// This test shows how a *consumer* of the Greeter interface would use the mock.
|
|
||||||
// It lives here only for proximity to the interface definition — in a real
|
|
||||||
// project, consumer packages write their own tests with the mock.
|
|
||||||
|
|
||||||
func TestMockUsageExample(t *testing.T) {
|
type fakeGreeter struct {
|
||||||
// Import path when used in another package:
|
greetFn func(name string) (string, error)
|
||||||
// mocks "gitea.djmil.dev/djmil/go-template/mocks/greeter"
|
}
|
||||||
//
|
|
||||||
// mock := mocks.NewMockGreeter(t)
|
func (f *fakeGreeter) Greet(name string) (string, error) {
|
||||||
// mock.EXPECT().Greet("Alice").Return("Hello, Alice!", nil)
|
return f.greetFn(name)
|
||||||
//
|
}
|
||||||
// result, err := someConsumer(mock)
|
|
||||||
// require.NoError(t, err)
|
func TestFakeUsageExample(t *testing.T) {
|
||||||
// assert.Equal(t, "Hello, Alice!", result)
|
fake := &fakeGreeter{
|
||||||
t.Skip("mock usage — see comment above for pattern")
|
greetFn: func(name string) (string, error) {
|
||||||
|
return "Hello, " + name + "!", nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := fake.Greet("Alice")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if msg != "Hello, Alice!" {
|
||||||
|
t.Errorf("got %q, want %q", msg, "Hello, Alice!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// Package logger wraps go.uber.org/zap with a thin, ergonomic API.
|
// Package logger wraps log/slog with a thin, ergonomic API.
|
||||||
//
|
//
|
||||||
// The key addition over raw zap is the WithField / WithFields helpers that
|
// The key addition over raw slog is the WithField / WithFields helpers that
|
||||||
// return a *Logger (not a *zap.Logger), so callers stay in the typed world and
|
// return a *Logger (not a *slog.Logger), so callers stay in the typed world
|
||||||
// don't need to import zap just to attach context fields.
|
// and can chain field attachments without importing slog directly.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
@ -15,18 +15,18 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"go.uber.org/zap"
|
"log/slog"
|
||||||
"go.uber.org/zap/zapcore"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logger is a thin wrapper around *zap.Logger.
|
// Logger is a thin wrapper around *slog.Logger.
|
||||||
// All zap methods (Info, Error, Debug, …) are available via embedding.
|
// All slog methods (Info, Error, Debug, Warn, …) are available via embedding.
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
*zap.Logger
|
*slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a production-style JSON logger for the given level string.
|
// New creates a JSON logger writing to stderr for the given level string.
|
||||||
// Valid levels: debug, info, warn, error.
|
// Valid levels: debug, info, warn, error.
|
||||||
func New(level string) (*Logger, error) {
|
func New(level string) (*Logger, error) {
|
||||||
lvl, err := parseLevel(level)
|
lvl, err := parseLevel(level)
|
||||||
@ -34,65 +34,45 @@ func New(level string) (*Logger, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := zap.NewProductionConfig()
|
h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: lvl})
|
||||||
cfg.Level = zap.NewAtomicLevelAt(lvl)
|
|
||||||
// ISO8601 timestamps are human-readable and grep-friendly.
|
|
||||||
cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
|
||||||
|
|
||||||
z, err := cfg.Build(zap.AddCallerSkip(0))
|
return &Logger{slog.New(h)}, nil
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("logger: build: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Logger{z}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDevelopment creates a colourised, human-friendly console logger.
|
// NewDevelopment creates a human-friendly text logger writing to stderr.
|
||||||
// Use this in local dev; prefer New() in any deployed environment.
|
// Use this in local dev; prefer New() in any deployed environment.
|
||||||
func NewDevelopment() (*Logger, error) {
|
func NewDevelopment() *Logger {
|
||||||
z, err := zap.NewDevelopment()
|
h := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug})
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("logger: build dev: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Logger{z}, nil
|
return &Logger{slog.New(h)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNop returns a no-op logger. Useful in tests that don't care about logs.
|
// NewNop returns a no-op logger. Useful in tests that don't care about logs.
|
||||||
func NewNop() *Logger {
|
func NewNop() *Logger {
|
||||||
return &Logger{zap.NewNop()}
|
return &Logger{slog.New(slog.NewTextHandler(io.Discard, nil))}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithField returns a child logger that always includes key=value in every log
|
// WithField returns a child logger that always includes key=value in every log line.
|
||||||
// line. value can be any type; zap.Any is used internally.
|
|
||||||
func (l *Logger) WithField(key string, value any) *Logger {
|
func (l *Logger) WithField(key string, value any) *Logger {
|
||||||
return &Logger{l.Logger.With(zap.Any(key, value))}
|
return &Logger{l.Logger.With(key, value)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithFields returns a child logger enriched with every key/value in fields.
|
// WithFields returns a child logger enriched with every key/value in fields.
|
||||||
// Prefer WithField for one or two fields; use WithFields for structured context
|
// Prefer WithField for one or two fields; use WithFields for structured context
|
||||||
// objects (e.g. attaching a request span).
|
// objects (e.g. attaching a request span).
|
||||||
func (l *Logger) WithFields(fields map[string]any) *Logger {
|
func (l *Logger) WithFields(fields map[string]any) *Logger {
|
||||||
zapFields := make([]zap.Field, 0, len(fields))
|
args := make([]any, 0, len(fields)*2)
|
||||||
for k, v := range fields {
|
for k, v := range fields {
|
||||||
zapFields = append(zapFields, zap.Any(k, v))
|
args = append(args, k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Logger{l.Logger.With(zapFields...)}
|
return &Logger{l.Logger.With(args...)}
|
||||||
}
|
|
||||||
|
|
||||||
// Sync flushes any buffered log entries. Call this on shutdown:
|
|
||||||
//
|
|
||||||
// defer log.Sync()
|
|
||||||
func (l *Logger) Sync() {
|
|
||||||
// Intentionally ignore the error — os.Stderr sync often fails on some OSes.
|
|
||||||
_ = l.Logger.Sync()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── helpers ───────────────────────────────────────────────────────────────────
|
// ── helpers ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func parseLevel(level string) (zapcore.Level, error) {
|
func parseLevel(level string) (slog.Level, error) {
|
||||||
var lvl zapcore.Level
|
var lvl slog.Level
|
||||||
if err := lvl.UnmarshalText([]byte(level)); err != nil {
|
if err := lvl.UnmarshalText([]byte(level)); err != nil {
|
||||||
return lvl, fmt.Errorf("logger: unknown level %q (use debug|info|warn|error)", level)
|
return lvl, fmt.Errorf("logger: unknown level %q (use debug|info|warn|error)", level)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,92 +0,0 @@
|
|||||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
|
||||||
// Regenerate with: make mocks
|
|
||||||
|
|
||||||
package mocks
|
|
||||||
|
|
||||||
import mock "github.com/stretchr/testify/mock"
|
|
||||||
|
|
||||||
// MockGreeter is an autogenerated mock type for the Greeter interface.
|
|
||||||
type MockGreeter struct {
|
|
||||||
mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockGreeter_Expecter provides a type-safe wrapper around mock.Call.
|
|
||||||
type MockGreeter_Expecter struct {
|
|
||||||
mock *mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns a typed expecter for this mock.
|
|
||||||
func (_m *MockGreeter) EXPECT() *MockGreeter_Expecter {
|
|
||||||
return &MockGreeter_Expecter{mock: &_m.Mock}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Greet provides a mock function for the Greeter.Greet method.
|
|
||||||
func (_m *MockGreeter) Greet(name string) (string, error) {
|
|
||||||
ret := _m.Called(name)
|
|
||||||
|
|
||||||
var r0 string
|
|
||||||
var r1 error
|
|
||||||
|
|
||||||
if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
|
|
||||||
return rf(name)
|
|
||||||
}
|
|
||||||
if rf, ok := ret.Get(0).(func(string) string); ok {
|
|
||||||
r0 = rf(name)
|
|
||||||
} else {
|
|
||||||
r0 = ret.Get(0).(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
|
||||||
r1 = rf(name)
|
|
||||||
} else {
|
|
||||||
r1 = ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0, r1
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockGreeter_Greet_Call is a *mock.Call with a type-safe Run method.
|
|
||||||
type MockGreeter_Greet_Call struct {
|
|
||||||
*mock.Call
|
|
||||||
}
|
|
||||||
|
|
||||||
// Greet sets up an expectation on the Greet method.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// mock.EXPECT().Greet("Alice").Return("Hello, Alice!", nil)
|
|
||||||
func (_e *MockGreeter_Expecter) Greet(name any) *MockGreeter_Greet_Call {
|
|
||||||
return &MockGreeter_Greet_Call{Call: _e.mock.On("Greet", name)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run sets a side-effect function that is called when Greet is invoked.
|
|
||||||
func (_c *MockGreeter_Greet_Call) Run(run func(name string)) *MockGreeter_Greet_Call {
|
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
|
||||||
run(args[0].(string))
|
|
||||||
})
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return sets the return values for the Greet mock call.
|
|
||||||
func (_c *MockGreeter_Greet_Call) Return(greeting string, err error) *MockGreeter_Greet_Call {
|
|
||||||
_c.Call.Return(greeting, err)
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunAndReturn combines Run and Return into a single call.
|
|
||||||
func (_c *MockGreeter_Greet_Call) RunAndReturn(run func(string) (string, error)) *MockGreeter_Greet_Call {
|
|
||||||
_c.Call.Return(run)
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockGreeter creates a new MockGreeter and registers a cleanup function
|
|
||||||
// that asserts all expectations were met when the test ends.
|
|
||||||
func NewMockGreeter(t interface {
|
|
||||||
mock.TestingT
|
|
||||||
Cleanup(func())
|
|
||||||
}) *MockGreeter {
|
|
||||||
m := &MockGreeter{}
|
|
||||||
m.Mock.Test(t)
|
|
||||||
t.Cleanup(func() { m.AssertExpectations(t) })
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
90
rename.sh
90
rename.sh
@ -6,13 +6,13 @@
|
|||||||
# ./rename.sh acme-corp my-svc # non-interactive (org, project)
|
# ./rename.sh acme-corp my-svc # non-interactive (org, project)
|
||||||
#
|
#
|
||||||
# What it changes:
|
# What it changes:
|
||||||
# go.mod module path
|
# go.mod module path
|
||||||
# **/*.go import paths
|
# **/*.go import paths
|
||||||
# .mockery.yaml package path
|
|
||||||
# config/dev.yaml app.name
|
|
||||||
# .devcontainer/devcontainer.json name field
|
# .devcontainer/devcontainer.json name field
|
||||||
# README.md heading + module path references
|
# README.md heading + module path references
|
||||||
# CLAUDE.md Module line
|
# CLAUDE.md Module line
|
||||||
|
# .golangci.yml goimports local-prefixes
|
||||||
|
# git history squashed into one INIT commit
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@ -66,14 +66,19 @@ if [[ "$CURRENT_MODULE" != "$TEMPLATE_MODULE" ]]; then
|
|||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── Capture template version before touching anything ─────────────────────────
|
||||||
|
TEMPLATE_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "untagged")
|
||||||
|
|
||||||
# ── Gather inputs ─────────────────────────────────────────────────────────────
|
# ── Gather inputs ─────────────────────────────────────────────────────────────
|
||||||
heading "Go Template — Project Renamer"
|
heading "Go Template — Project Renamer"
|
||||||
echo "This script rewrites the module path and project name throughout the codebase."
|
echo "This script rewrites the module path and project name throughout the codebase."
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
INTERACTIVE=true
|
||||||
if [[ $# -ge 2 ]]; then
|
if [[ $# -ge 2 ]]; then
|
||||||
NEW_ORG="$1"
|
NEW_ORG="$1"
|
||||||
NEW_PROJECT="$2"
|
NEW_PROJECT="$2"
|
||||||
|
INTERACTIVE=false
|
||||||
else
|
else
|
||||||
while true; do
|
while true; do
|
||||||
read -rp "Org / username (e.g. djmil): " NEW_ORG
|
read -rp "Org / username (e.g. djmil): " NEW_ORG
|
||||||
@ -96,12 +101,13 @@ OLD_DISPLAY=$(to_title "$OLD_PROJECT") # e.g. Go Template
|
|||||||
|
|
||||||
# ── Preview ───────────────────────────────────────────────────────────────────
|
# ── Preview ───────────────────────────────────────────────────────────────────
|
||||||
heading "Changes to be applied"
|
heading "Changes to be applied"
|
||||||
printf " %-22s %s → %s\n" "Module path:" "$OLD_MODULE" "$NEW_MODULE"
|
printf " %-22s %s → %s\n" "Module path:" "$OLD_MODULE" "$NEW_MODULE"
|
||||||
printf " %-22s %s → %s\n" "Project name:" "$OLD_PROJECT" "$NEW_PROJECT"
|
printf " %-22s %s → %s\n" "Project name:" "$OLD_PROJECT" "$NEW_PROJECT"
|
||||||
printf " %-22s %s → %s\n" "Display name:" "$OLD_DISPLAY" "$NEW_DISPLAY"
|
printf " %-22s %s → %s\n" "Display name:" "$OLD_DISPLAY" "$NEW_DISPLAY"
|
||||||
|
printf " %-22s %s\n" "Template version:" "$TEMPLATE_TAG"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
if [[ $# -lt 2 ]]; then
|
if $INTERACTIVE; then
|
||||||
read -rp "Apply these changes? [y/N] " CONFIRM
|
read -rp "Apply these changes? [y/N] " CONFIRM
|
||||||
case "$CONFIRM" in
|
case "$CONFIRM" in
|
||||||
[yY][eE][sS]|[yY]) ;;
|
[yY][eE][sS]|[yY]) ;;
|
||||||
@ -113,10 +119,8 @@ fi
|
|||||||
# macOS sed requires an extension argument for -i; GNU sed does not.
|
# macOS sed requires an extension argument for -i; GNU sed does not.
|
||||||
sedi() {
|
sedi() {
|
||||||
if sed --version &>/dev/null 2>&1; then
|
if sed --version &>/dev/null 2>&1; then
|
||||||
# GNU sed
|
|
||||||
sed -i "$@"
|
sed -i "$@"
|
||||||
else
|
else
|
||||||
# BSD / macOS sed
|
|
||||||
sed -i '' "$@"
|
sed -i '' "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -144,43 +148,35 @@ for f in $GO_FILES; do
|
|||||||
done
|
done
|
||||||
info "${CHANGED_GO} Go source file(s)"
|
info "${CHANGED_GO} Go source file(s)"
|
||||||
|
|
||||||
# 3. .mockery.yaml — package path
|
# 3. .devcontainer/devcontainer.json — "name" field
|
||||||
if [[ -f .mockery.yaml ]]; then
|
|
||||||
sedi "s|${OLD_MODULE}|${NEW_MODULE}|g" .mockery.yaml
|
|
||||||
info ".mockery.yaml"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 4. config/dev.yaml — app.name
|
|
||||||
if [[ -f config/dev.yaml ]]; then
|
|
||||||
sedi "s|name: \"${OLD_PROJECT}\"|name: \"${NEW_PROJECT}\"|g" config/dev.yaml
|
|
||||||
info "config/dev.yaml"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 5. .devcontainer/devcontainer.json — "name" field
|
|
||||||
if [[ -f .devcontainer/devcontainer.json ]]; then
|
if [[ -f .devcontainer/devcontainer.json ]]; then
|
||||||
sedi "s|\"name\": \"${OLD_DISPLAY}\"|\"name\": \"${NEW_DISPLAY}\"|g" \
|
sedi "s|\"name\": \"${OLD_DISPLAY}\"|\"name\": \"${NEW_DISPLAY}\"|g" \
|
||||||
.devcontainer/devcontainer.json
|
.devcontainer/devcontainer.json
|
||||||
info ".devcontainer/devcontainer.json"
|
info ".devcontainer/devcontainer.json"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 6. README.md — heading + all module path occurrences
|
# 4. README.md — heading + all module path occurrences
|
||||||
if [[ -f README.md ]]; then
|
if [[ -f README.md ]]; then
|
||||||
sedi "s|^# ${OLD_PROJECT}$|# ${NEW_PROJECT}|g" README.md
|
sedi "s|^# ${OLD_PROJECT}$|# ${NEW_PROJECT}|g" README.md
|
||||||
sedi "s|${OLD_MODULE}|${NEW_MODULE}|g" README.md
|
sedi "s|${OLD_MODULE}|${NEW_MODULE}|g" README.md
|
||||||
sedi "s|name: \"${OLD_PROJECT}\"|name: \"${NEW_PROJECT}\"|g" README.md
|
|
||||||
info "README.md"
|
info "README.md"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 7. CLAUDE.md — Module line
|
# 5. CLAUDE.md — Module line
|
||||||
if [[ -f CLAUDE.md ]]; then
|
if [[ -f CLAUDE.md ]]; then
|
||||||
sedi "s|${OLD_MODULE}|${NEW_MODULE}|g" CLAUDE.md
|
sedi "s|${OLD_MODULE}|${NEW_MODULE}|g" CLAUDE.md
|
||||||
info "CLAUDE.md"
|
info "CLAUDE.md"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 8. git remote origin — rewrite URL preserving scheme (https or ssh)
|
# 6. .golangci.yml — goimports local-prefixes
|
||||||
|
if [[ -f .golangci.yml ]]; then
|
||||||
|
sedi "s|${OLD_MODULE}|${NEW_MODULE}|g" .golangci.yml
|
||||||
|
info ".golangci.yml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6. git remote origin — rewrite URL preserving scheme (https or ssh)
|
||||||
if git remote get-url origin &>/dev/null 2>&1; then
|
if git remote get-url origin &>/dev/null 2>&1; then
|
||||||
OLD_REMOTE=$(git remote get-url origin)
|
OLD_REMOTE=$(git remote get-url origin)
|
||||||
# Detect scheme and build new URL accordingly
|
|
||||||
if [[ "$OLD_REMOTE" == https://* ]]; then
|
if [[ "$OLD_REMOTE" == https://* ]]; then
|
||||||
NEW_REMOTE="https://${DEFAULT_HOST}/${NEW_ORG}/${NEW_PROJECT}.git"
|
NEW_REMOTE="https://${DEFAULT_HOST}/${NEW_ORG}/${NEW_PROJECT}.git"
|
||||||
else
|
else
|
||||||
@ -193,13 +189,37 @@ else
|
|||||||
warn "No 'origin' remote found — skipping remote update."
|
warn "No 'origin' remote found — skipping remote update."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── Squash git history into a single INIT commit ──────────────────────────────
|
||||||
|
heading "Git history"
|
||||||
|
|
||||||
|
DO_SQUASH=true
|
||||||
|
if $INTERACTIVE; then
|
||||||
|
read -rp "Squash all template history into one INIT commit? [Y/n] " SQUASH_CONFIRM
|
||||||
|
case "$SQUASH_CONFIRM" in
|
||||||
|
[nN][oO]|[nN]) DO_SQUASH=false ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $DO_SQUASH; then
|
||||||
|
# Stage rename changes, fold all commits back to root, rewrite as single commit.
|
||||||
|
git add -A
|
||||||
|
ROOT_COMMIT=$(git rev-list --max-parents=0 HEAD)
|
||||||
|
git reset --soft "$ROOT_COMMIT"
|
||||||
|
git commit --amend -m "init: bootstrap ${NEW_PROJECT} from go-template ${TEMPLATE_TAG}
|
||||||
|
|
||||||
|
Initialized from ${OLD_MODULE} @ ${TEMPLATE_TAG}.
|
||||||
|
Module renamed to ${NEW_MODULE}."
|
||||||
|
info "History squashed → single INIT commit (template: ${TEMPLATE_TAG})"
|
||||||
|
else
|
||||||
|
warn "Skipping squash — template history preserved."
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Post-rename suggestions ───────────────────────────────────────────────────
|
# ── Post-rename suggestions ───────────────────────────────────────────────────
|
||||||
heading "Done"
|
heading "Done"
|
||||||
echo "Module is now: ${BOLD}${NEW_MODULE}${RESET}"
|
echo "Module is now: ${BOLD}${NEW_MODULE}${RESET}"
|
||||||
echo
|
echo
|
||||||
echo "Recommended next steps:"
|
echo "Recommended next steps:"
|
||||||
echo " go mod tidy # sync go.sum after path change"
|
echo " go mod tidy # sync go.sum after path change"
|
||||||
echo " make mocks # regenerate mocks with new import paths"
|
echo " make build # verify it compiles"
|
||||||
echo " make build # verify it compiles"
|
echo " make test # verify tests pass"
|
||||||
echo " make test # verify tests pass"
|
echo " git push -u origin main --force-with-lease"
|
||||||
echo " git push -u origin main"
|
|
||||||
|
|||||||
1
tools.go
1
tools.go
@ -9,6 +9,5 @@ import (
|
|||||||
_ "github.com/go-delve/delve/cmd/dlv"
|
_ "github.com/go-delve/delve/cmd/dlv"
|
||||||
_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
|
_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
|
||||||
_ "github.com/securego/gosec/v2/cmd/gosec"
|
_ "github.com/securego/gosec/v2/cmd/gosec"
|
||||||
_ "github.com/vektra/mockery/v2"
|
|
||||||
_ "golang.org/x/vuln/cmd/govulncheck"
|
_ "golang.org/x/vuln/cmd/govulncheck"
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user