.
├── Makefile
├── cmd
│ └── api
│ └── main.go
├── go.mod
├── go.sum
├── internal
│ ├── api
│ │ └── api.go
│ └── log
│ ├── log.go
│ └── log_test.go
├── revive.toml
├── tools.mod
└── tools.sum
Last active
March 17, 2025 15:16
-
-
Save Integralist/d61a365912576bcef88b29bd11207df3 to your computer and use it in GitHub Desktop.
Basic Go Project Structure #go #golang #base #project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Package main is the starting point for the Ascerta API. | |
package main | |
import ( | |
"context" | |
"log/slog" | |
"os" | |
"github.com/fastly/ascerta/internal/api" | |
"github.com/fastly/ascerta/internal/log" | |
) | |
func main() { | |
l := log.New() | |
if err := api.Run(l); err != nil { | |
ctx := context.Background() | |
l.LogAttrs(ctx, slog.LevelError, "api_run", slog.Any("err", err)) | |
os.Exit(1) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module github.com/fastly/ascerta | |
go 1.24 | |
require github.com/fastly/fst-go v1.13.0 | |
require ( | |
github.com/beorn7/perks v1.0.1 // indirect | |
github.com/cespare/xxhash/v2 v2.3.0 // indirect | |
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect | |
github.com/prometheus/client_golang v1.21.1 // indirect | |
github.com/prometheus/client_model v0.6.1 // indirect | |
github.com/prometheus/common v0.63.0 // indirect | |
github.com/prometheus/procfs v0.15.1 // indirect | |
golang.org/x/sys v0.31.0 // indirect | |
google.golang.org/protobuf v1.36.5 // indirect | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= | |
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= | |
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
github.com/fastly/fst-go v1.13.0 h1:rtRF6RZUjOBMGzaNWD9M87b6yEJn8yPWHZ2dcQjR1TA= | |
github.com/fastly/fst-go v1.13.0/go.mod h1:95Gbykg+NKlc2JPo9SfZp5W6wWILlLqdc6HUIWEySsc= | |
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/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= | |
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= | |
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= | |
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= | |
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= | |
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= | |
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= | |
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= | |
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= | |
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= | |
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= | |
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= | |
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= | |
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= | |
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= | |
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | |
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= | |
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= | |
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= | |
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= | |
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | |
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Package api contains code for running an API server. | |
package api | |
import ( | |
"context" | |
"fmt" | |
"log/slog" | |
"net/http" | |
"os" | |
"os/signal" | |
"syscall" | |
"time" | |
) | |
const ( | |
apiPort = ":8080" | |
apiReadTimeout = time.Duration(5) * time.Second | |
apiWriteTimeout = time.Duration(5) * time.Second | |
) | |
// Run starts the API. | |
func Run(l *slog.Logger) error { | |
ctx := context.Background() | |
s := http.Server{ | |
Addr: apiPort, | |
ReadTimeout: apiReadTimeout, | |
WriteTimeout: apiWriteTimeout, | |
} | |
quit := make(chan os.Signal, 1) | |
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) | |
go func() { | |
signalType := <-quit | |
l.LogAttrs(ctx, slog.LevelWarn, "api_shutdown", slog.String("signal", signalType.String())) | |
if err := s.Shutdown(context.Background()); err != nil { // nolint:contextcheck // we use a separate context to avoid cancellation | |
err := fmt.Errorf("unable to gracefully stop API server: %w", err) | |
l.LogAttrs(ctx, slog.LevelError, "api_shutdown", slog.Any("error", err)) | |
} | |
}() | |
if err := s.ListenAndServe(); err != nil { | |
err := fmt.Errorf("api server failed to listen and serve requests: %w", err) | |
l.LogAttrs(ctx, slog.LevelError, "api_serve", slog.Any("error", err)) | |
return err | |
} | |
return nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Package log contains code for creating a structured logger. | |
package log | |
import ( | |
"context" | |
"io" | |
"log" | |
"log/slog" | |
"os" | |
"path/filepath" | |
"strings" | |
"github.com/fastly/fst-go/build" | |
) | |
// contextKey is used to store a logger in a context. | |
type contextKey struct{} | |
var ( | |
// ContextKey is used to store a logger in a context. | |
// Only to be used in places where a logger can't be passed in as an argument. | |
ContextKey = contextKey{} | |
// Level allows dynamically changing the output level via .Set() method. | |
// Defaults to [slog.LevelInfo]. | |
// EXAMPLE: log.Level.Set(slog.LevelDebug) | |
Level = new(slog.LevelVar) | |
) | |
// New returns a log.Logger configured for stdout. | |
func New() *slog.Logger { | |
return NewWithOutputLevel(os.Stdout, Level) | |
} | |
// NewWithOutput returns a [*slog.Logger] configured with an output writer. | |
func NewWithOutput(w io.Writer) *slog.Logger { | |
return slog.New(slog.NewJSONHandler(w, defaultOptions()).WithAttrs(defaultAttrs())) | |
} | |
// NewWithOutputLevel returns a [*slog.Logger] configured with an output writer and Level. | |
func NewWithOutputLevel(w io.Writer, l slog.Leveler) *slog.Logger { | |
opts := defaultOptions() | |
opts.Level = l | |
return slog.New(slog.NewJSONHandler(w, opts).WithAttrs(defaultAttrs())) | |
} | |
// Adapt returns a [log.Logger] for use with packages that are not yet compatible with | |
// [log/slog]. | |
func Adapt(l *slog.Logger, level slog.Level) *log.Logger { | |
return slog.NewLogLogger(l.Handler(), level) | |
} | |
// FromContext returns the logger attached to a context. | |
func FromContext(ctx context.Context) *slog.Logger { | |
logger, ok := ctx.Value(ContextKey).(*slog.Logger) | |
if !ok { | |
logger = New() | |
} | |
return logger | |
} | |
// defaultOptions defines default logger options. | |
func defaultOptions() *slog.HandlerOptions { | |
return &slog.HandlerOptions{ | |
AddSource: true, | |
ReplaceAttr: slogReplaceAttr, | |
Level: Level, | |
} | |
} | |
// defaultAttrs defines default logger attributes. | |
func defaultAttrs() []slog.Attr { | |
return []slog.Attr{ | |
slog.Group("app", | |
slog.String("name", build.Info.Project), | |
slog.String("repo", build.Info.Repository), | |
slog.String("version", build.Info.Version), | |
), | |
} | |
} | |
// slogReplaceAttr adjusts the log output. | |
// | |
// - Restricts these changes to top-level keys (not keys within groups) | |
// - Changes default time field value to UTC time zone | |
// - Replaces msg key with event | |
// - Omits event field if empty | |
// - Omits error field if when nil | |
// - Truncates source's filename to project directory | |
// | |
// See https://pkg.go.dev/log/slog#HandlerOptions.ReplaceAttr | |
// N.B: TextHandler manages quoting attribute values as necessary. | |
func slogReplaceAttr(groups []string, a slog.Attr) slog.Attr { | |
// Limit application of these rules only to top-level keys | |
if len(groups) == 0 { | |
// Set time zone to UTC | |
if a.Key == slog.TimeKey { | |
a.Value = slog.TimeValue(a.Value.Time().UTC()) | |
return a | |
} | |
// Use event as the default MessageKey, remove if empty | |
if a.Key == slog.MessageKey { | |
a.Key = "event" | |
if a.Value.String() == "" { | |
return slog.Attr{} | |
} | |
return a | |
} | |
// Display a 'partial' path. | |
// Avoids ambiguity when multiple files have the same name across packages. | |
if a.Key == slog.SourceKey { | |
if source, ok := a.Value.Any().(*slog.Source); ok { | |
a.Key = "caller" | |
if _, after, ok := strings.Cut(source.File, "ascerta"+string(filepath.Separator)); ok { | |
source.File = after | |
} | |
} | |
} | |
} | |
// Remove error key=value when error is nil | |
if a.Equal(slog.Any("error", error(nil))) { | |
return slog.Attr{} | |
} | |
// Present durations and delays etc as milliseconds | |
switch a.Key { | |
case "dur", "delay", "p95", "previous_p95", "remaining", "max_wait": | |
a.Value = slog.Float64Value(a.Value.Duration().Seconds() * 1000) //nolint:mnd | |
} | |
return a | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package log | |
import ( | |
"bytes" | |
"context" | |
"encoding/json" | |
"log/slog" | |
"path/filepath" | |
"strings" | |
"testing" | |
"time" | |
) | |
func TestLogger(t *testing.T) { | |
buf := new(bytes.Buffer) | |
l := NewWithOutput(buf) | |
type App struct { | |
Name string `json:"name"` | |
Version string `json:"version"` | |
} | |
type Caller struct { | |
Function string `json:"function"` | |
File string `json:"file"` | |
Line int `json:"line"` | |
} | |
type log struct { | |
Time string `json:"time"` | |
Level string `json:"level"` | |
Caller Caller `json:"caller"` | |
Event string `json:"event"` | |
App App `json:"app"` | |
Error string `json:"error"` | |
Dur float64 `json:"dur"` | |
Delay float64 `json:"delay"` | |
P95 float64 `json:"p95"` | |
PrevP95 float64 `json:"previous_p95"` | |
Remaining float64 `json:"remaining"` | |
MaxWait float64 `json:"max_wait"` | |
} | |
t.Run("has expected fields", func(t *testing.T) { | |
dumpLogs(t, buf) | |
l.LogAttrs(context.Background(), slog.LevelInfo, "testing") | |
var data log | |
_ = json.Unmarshal(buf.Bytes(), &data) | |
if data.Time == "" { | |
t.Error("missing field: time") | |
} | |
}) | |
t.Run("outputs debug at LevelDebug", func(t *testing.T) { | |
Level.Set(slog.LevelDebug) // change for test | |
defer func(lvl slog.Level) { Level.Set(lvl) }(Level.Level()) // ensure reset to default | |
dumpLogs(t, buf) | |
ctx := context.Background() | |
l.LogAttrs(ctx, slog.LevelDebug, "") | |
var data log | |
_ = json.Unmarshal(buf.Bytes(), &data) | |
if data.Level != "DEBUG" { | |
t.Error("missing level=DEBUG") | |
} | |
}) | |
t.Run("elides empty event message", func(t *testing.T) { | |
dumpLogs(t, buf) | |
l.LogAttrs(context.Background(), slog.LevelInfo, "") | |
var data log | |
_ = json.Unmarshal(buf.Bytes(), &data) | |
if data.Event != "" { | |
t.Error("log should not contain an event") | |
} | |
}) | |
t.Run("elides empty error", func(t *testing.T) { | |
dumpLogs(t, buf) | |
l.LogAttrs(context.Background(), slog.LevelInfo, "test message", slog.Any("error", nil)) | |
var data log | |
_ = json.Unmarshal(buf.Bytes(), &data) | |
if data.Error != "" { | |
t.Error("log should not contain an empty error") | |
} | |
}) | |
t.Run("uses UTC time zone", func(t *testing.T) { | |
dumpLogs(t, buf) | |
l.LogAttrs(context.Background(), slog.LevelInfo, "UTC") | |
var data log | |
_ = json.Unmarshal(buf.Bytes(), &data) | |
p, err := time.Parse(time.RFC3339, data.Time) | |
if err != nil { | |
t.Fatalf("time field failed to parse: %s", err) | |
} | |
if z, _ := p.Zone(); z != time.UTC.String() { | |
t.Errorf("expected time in UTC zone, got %s", z) | |
} | |
}) | |
t.Run("uses shorter source location", func(t *testing.T) { | |
dumpLogs(t, buf) | |
l.LogAttrs(context.Background(), slog.LevelInfo, "source -> caller test") | |
var data log | |
_ = json.Unmarshal(buf.Bytes(), &data) | |
// slogReplaceAttr replaces the top-level key "source" with "caller" | |
// IMPORTANT: the name of the repo is hard-coded into the slogReplaceAttr logic | |
if data.Caller.File == "" { | |
t.Error("field not found") | |
} | |
if strings.HasPrefix(data.Caller.File, string(filepath.Separator)) { | |
t.Errorf("caller includes full path: %s", data.Caller.File) | |
} | |
}) | |
t.Run("displays milliseconds", func(t *testing.T) { | |
dumpLogs(t, buf) | |
const ts = 1234567890 | |
l.LogAttrs(context.Background(), slog.LevelInfo, "", | |
slog.Duration("dur", ts), | |
slog.Duration("delay", ts), | |
slog.Duration("p95", ts), | |
slog.Duration("previous_p95", ts), | |
slog.Duration("remaining", ts), | |
slog.Duration("max_wait", ts), | |
) | |
var data log | |
_ = json.Unmarshal(buf.Bytes(), &data) | |
want := 1234.56789 | |
if data.Dur != want || data.Delay != want || data.P95 != want || data.PrevP95 != want || data.Remaining != want || data.MaxWait != want { | |
t.Errorf("log should contain: %f", want) | |
} | |
}) | |
} | |
func dumpLogs(t *testing.T, buf *bytes.Buffer) { | |
t.Helper() | |
t.Cleanup(func() { | |
t.Helper() | |
if t.Failed() || testing.Verbose() { | |
t.Log("Logs:\n", buf.String()) | |
} | |
buf.Reset() | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.DEFAULT_GOAL := run ## Default make target | |
TOOLS = "" ## List of dev tools | |
TOOLS = \ | |
github.com/mgechev/revive \ | |
golang.org/x/lint/golint \ | |
golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness \ | |
golang.org/x/vuln/cmd/govulncheck \ | |
honnef.co/go/tools/cmd/staticcheck \ | |
mvdan.cc/gofumpt | |
.PHONY: help | |
help: ## Displays list of Makefile targets and documented variables | |
@echo "Targets:" | |
@grep -h -E '^[0-9a-zA-Z_.-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' | |
@echo "" | |
@echo "Variables:" | |
@grep -h -E '^[0-9a-zA-Z_.-]+\s[?:]?=.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = "[?:]?=.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' | |
@echo "" | |
@echo "Default target:" | |
@printf " \033[36m%s\033[0m\n" $(.DEFAULT_GOAL) | |
.PHONY: api-update | |
api-update: ## Update all API application dependencies | |
go get -u -t ./... | |
go mod tidy | |
if [ -d "vendor" ]; then go mod vendor; fi | |
.PHONY: fmt | |
fmt: ## Format all Go files using gofumpt | |
go tool -modfile=tools.mod gofumpt -w . | |
.PHONY: lint-all | |
lint-all: lint-golint lint-govet lint-govul lint-nilness lint-revive lint-staticcheck ## Lint project using all linters | |
.PHONY: lint-golint | |
lint-golint: ## Lint project using golint | |
go tool -modfile=tools.mod golint -set_exit_status $(shell go list -f '{{.Dir}}' ./... ) | |
.PHONY: lint-govet | |
lint-govet: ## Lint project using go vet | |
go vet ./... | |
.PHONY: lint-govul | |
lint-govul: ## Lint project using govulncheck | |
go tool -modfile=tools.mod govulncheck ./... | |
.PHONY: lint-nilness | |
lint-nilness: ## Lint project using nilness | |
go tool -modfile=tools.mod nilness ./... | |
.PHONY: lint-revive | |
lint-revive: ## Lint project using revive | |
go tool -modfile=tools.mod revive -config revive.toml ./... | |
.PHONY: lint-staticcheck | |
lint-staticcheck: ## Lint project using staticcheck | |
go tool -modfile=tools.mod staticcheck ./... | |
.PHONY: run | |
run: ## Run the API server (opts: HUMANLOG=true) | |
@# humanlog doesn't sort keys lexicographically. | |
@# to do that we must set `--sort-longest=false` | |
@# this causes the key sorting we want (as a side effect) | |
@# while at the same time avoiding humanlog from trying to sort by key length | |
go run ./cmd/api/main.go $(if \ | |
$(filter true,$(HUMANLOG)),| \ | |
humanlog \ | |
--message-fields=event \ | |
--sort-longest=false \ | |
--truncate=false, \ | |
) | |
.PHONY: test | |
test: ## Run the Go test suite | |
go test ./... | |
.PHONY: tools-install | |
tools-install: ## Install dev tools | |
@if [ ! -f tools.mod ]; then \ | |
echo "Initializing tools.mod"; \ | |
go mod init -modfile=tools.mod github.com/fastly/ascerta/tools; \ | |
fi | |
@$(foreach tool,$(TOOLS), \ | |
if ! go tool -modfile=tools.mod | grep "$(tool)" >/dev/null; then \ | |
echo "installing $(tool)"; \ | |
go get -modfile=tools.mod -tool "$(tool)"@latest; \ | |
fi; \ | |
) | |
@[ -x "$(shell which humanlog)" ] || curl -sSL "https://humanlog.io/install.sh" | NONINTERACTIVE=true bash | |
.PHONY: tools-update | |
tools-update: ## Update dev tools | |
go get -u -modfile=tools.mod tool | |
go mod tidy | |
# checkmake (https://github.com/mrtazz/checkmake) requires these targets be set | |
.PHONY: all clean test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enableAllRules = true | |
# DISABLED RULES | |
[rule.add-constant] | |
disabled = true | |
[rule.cognitive-complexity] | |
disabled = true | |
[rule.cyclomatic] | |
disabled = true | |
[rule.line-length-limit] | |
disabled = true | |
[rule.max-public-structs] | |
disabled = true | |
[rule.unused-receiver] | |
disabled = true | |
# ACTIVE RULES | |
[rule.argument-limit] | |
severity = "warning" | |
arguments = [6] | |
[rule.atomic] | |
severity = "warning" | |
[rule.bare-return] | |
severity = "warning" | |
[rule.bool-literal-in-expr] | |
severity = "warning" | |
[rule.comment-spacings] | |
arguments = ["nolint:", "lint:ignore", "exhaustive:ignore", "codespell:ignore"] | |
[rule.confusing-naming] | |
severity = "warning" | |
[rule.confusing-results] | |
severity = "warning" | |
[rule.constant-logical-expr] | |
severity = "error" | |
[rule.context-as-argument] | |
severity = "error" | |
[rule.context-keys-type] | |
severity = "error" | |
[rule.deep-exit] | |
severity = "warning" | |
[rule.defer] | |
severity = "warning" | |
[rule.early-return] | |
severity = "warning" | |
[rule.empty-block] | |
severity = "error" | |
[rule.empty-lines] | |
severity = "warning" | |
[rule.error-naming] | |
severity = "error" | |
[rule.error-return] | |
severity = "error" | |
[rule.error-strings] | |
severity = "error" | |
[rule.errorf] | |
severity = "warning" | |
[rule.exported] | |
severity = "error" | |
[rule.flag-parameter] | |
severity = "warning" | |
[rule.function-result-limit] | |
severity = "warning" | |
arguments = [4] | |
[rule.function-length] | |
severity = "warning" | |
arguments = [50, 0] | |
[rule.get-return] | |
severity = "error" | |
[rule.identical-branches] | |
severity = "error" | |
[rule.if-return] | |
severity = "warning" | |
[rule.increment-decrement] | |
severity = "error" | |
[rule.indent-error-flow] | |
severity = "warning" | |
[rule.import-shadowing] | |
severity = "warning" | |
[rule.modifies-parameter] | |
severity = "warning" | |
[rule.modifies-value-receiver] | |
severity = "warning" | |
[rule.nested-structs] | |
severity = "warning" | |
[rule.optimize-operands-order] | |
severity = "warning" | |
[rule.package-comments] | |
severity = "warning" | |
[rule.range] | |
severity = "warning" | |
[rule.range-val-in-closure] | |
severity = "warning" | |
[rule.range-val-address] | |
severity = "warning" | |
[rule.receiver-naming] | |
severity = "warning" | |
[rule.redefines-builtin-id] | |
severity = "error" | |
[rule.string-of-int] | |
severity = "warning" | |
[rule.struct-tag] | |
severity = "warning" | |
[rule.superfluous-else] | |
severity = "warning" | |
[rule.time-equal] | |
severity = "warning" | |
[rule.time-naming] | |
severity = "warning" | |
[rule.var-declaration] | |
severity = "warning" | |
[rule.var-naming] | |
severity = "warning" | |
[rule.unconditional-recursion] | |
severity = "error" | |
[rule.unexported-naming] | |
severity = "warning" | |
[rule.unexported-return] | |
severity = "error" | |
[rule.unhandled-error] | |
severity = "warning" | |
arguments = [ | |
"fmt.Print", | |
"fmt.Printf", | |
"fmt.Println", | |
"fmt.Fprint", | |
"fmt.Fprintf", | |
"fmt.Fprintln", | |
] | |
[rule.unnecessary-stmt] | |
severity = "warning" | |
[rule.unreachable-code] | |
severity = "warning" | |
[rule.unused-parameter] | |
severity = "warning" | |
[rule.use-any] | |
severity = "warning" | |
[rule.useless-break] | |
severity = "warning" | |
[rule.waitgroup-by-value] | |
severity = "warning" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module github.com/fastly/ascerta/tools | |
go 1.24.1 | |
tool ( | |
github.com/mgechev/revive | |
golang.org/x/lint/golint | |
golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness | |
golang.org/x/vuln/cmd/govulncheck | |
honnef.co/go/tools/cmd/staticcheck | |
mvdan.cc/gofumpt | |
) | |
require ( | |
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect | |
github.com/chavacava/garif v0.1.0 // indirect | |
github.com/fatih/color v1.18.0 // indirect | |
github.com/fatih/structtag v1.2.0 // indirect | |
github.com/google/go-cmp v0.7.0 // indirect | |
github.com/hashicorp/go-version v1.7.0 // indirect | |
github.com/mattn/go-colorable v0.1.14 // indirect | |
github.com/mattn/go-isatty v0.0.20 // indirect | |
github.com/mattn/go-runewidth v0.0.16 // indirect | |
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect | |
github.com/mgechev/revive v1.7.0 // indirect | |
github.com/olekukonko/tablewriter v0.0.5 // indirect | |
github.com/rivo/uniseg v0.4.7 // indirect | |
github.com/spf13/afero v1.14.0 // indirect | |
golang.org/x/exp/typeparams v0.0.0-20250305212735-054e65f0b394 // indirect | |
golang.org/x/lint v0.0.0-20241112194109-818c5a804067 // indirect | |
golang.org/x/mod v0.24.0 // indirect | |
golang.org/x/sync v0.12.0 // indirect | |
golang.org/x/sys v0.31.0 // indirect | |
golang.org/x/telemetry v0.0.0-20250310203348-fdfaad844314 // indirect | |
golang.org/x/text v0.23.0 // indirect | |
golang.org/x/tools v0.31.0 // indirect | |
golang.org/x/vuln v1.1.4 // indirect | |
honnef.co/go/tools v0.6.1 // indirect | |
mvdan.cc/gofumpt v0.7.0 // indirect | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= | |
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= | |
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= | |
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= | |
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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= | |
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= | |
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= | |
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= | |
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= | |
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | |
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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= | |
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= | |
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-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-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | |
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/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0= | |
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= | |
github.com/mgechev/revive v1.7.0 h1:JyeQ4yO5K8aZhIKf5rec56u0376h8AlKNQEmjfkjKlY= | |
github.com/mgechev/revive v1.7.0/go.mod h1:qZnwcNhoguE58dfi96IJeSTPeZQejNeoMQLUZGi4SW4= | |
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= | |
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= | |
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= | |
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= | |
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= | |
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= | |
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= | |
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= | |
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= | |
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | |
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | |
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | |
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | |
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/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= | |
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 h1:1P7xPZEwZMoBoz0Yze5Nx2/4pxj6nw9ZqHWXqP0iRgQ= | |
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= | |
golang.org/x/exp/typeparams v0.0.0-20250305212735-054e65f0b394 h1:VI4qDpTkfFaCXEPrbojidLgVQhj2x4nzTccG0hjaLlU= | |
golang.org/x/exp/typeparams v0.0.0-20250305212735-054e65f0b394/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ= | |
golang.org/x/lint v0.0.0-20241112194109-818c5a804067 h1:adDmSQyFTCiv19j015EGKJBoaa7ElV0Q1Wovb/4G7NA= | |
golang.org/x/lint v0.0.0-20241112194109-818c5a804067/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= | |
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= | |
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= | |
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= | |
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= | |
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= | |
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= | |
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | |
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= | |
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= | |
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= | |
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | |
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= | |
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= | |
golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 h1:FemxDzfMUcK2f3YY4H+05K9CDzbSVr2+q/JKN45pey0= | |
golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= | |
golang.org/x/telemetry v0.0.0-20250310203348-fdfaad844314 h1:UY+gQAskx5vohcvUlJDKkJPt9lALCgtZs3rs8msRatU= | |
golang.org/x/telemetry v0.0.0-20250310203348-fdfaad844314/go.mod h1:16eI1RtbPZAEm3u7hpIh7JM/w5AbmlDtnrdKYaREic8= | |
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= | |
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= | |
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= | |
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= | |
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | |
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= | |
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= | |
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= | |
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= | |
golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= | |
golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s= | |
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |
honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= | |
honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= | |
mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= | |
mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment