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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: golangci-lint
on:
push:
tags:
- v*
branches:
- master
- main
pull_request:
paths-ignore:
- "*.md"
permissions:
contents: read
pull-requests: read
jobs:
golangci:
name: Run golangci-lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- uses: golangci/golangci-lint-action@v8
with:
version: v2.2.2
args: --verbose
15 changes: 15 additions & 0 deletions .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: "Issue Labeler"
on:
issues:
types: [opened]

jobs:
triage:
name: "Triage issues"
runs-on: ubuntu-latest
steps:
- uses: github/issue-labeler@v3.0
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: .github/labeler.yml
enable-versioned-regex: 0
27 changes: 27 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: "Close stale issues and PRs"
on:
schedule:
# Runs at 15:00 UTC every day.
# Actions schedules run at most every 5 minutes.
- cron: "0 15 * * *"
permissions:
issues: write
pull-requests: write
jobs:
stale:
name: Manage stale issues and PRs
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v7
with:
stale-issue-message: "This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 365 days."
stale-pr-message: "This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 365 days."
close-issue-message: "This issue was closed because it has been stalled for 365 days with no activity."
close-pr-message: "This PR was closed because it has been stalled for 365 days with no activity."
days-before-issue-stale: 30
days-before-pr-stale: 30
days-before-issue-close: 365
days-before-pr-close: 365
stale-issue-label: stale
stale-pr-label: stale
exempt-issue-labels: accepted
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ jobs:
with:
terraform_version: "1.0.11"

- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24"

- uses: actions/checkout@v4
go-version-file: go.mod

- name: Run Tests
run: |
Expand Down
183 changes: 136 additions & 47 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,62 +1,151 @@
version: "2"
run:
skip-dirs-use-default: true
skip-dirs:
- vendor
- ent
- graph
skip-files:
- ".*\\.peg\\.go$"
- ".*ignored_.*.go$"
- "generated.go$"
- model_gen.go

modules-download-mode: readonly
issues-exit-code: 1
tests: true
linters:
disable-all: true
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- depguard
- dogsled
- containedctx
- contextcheck
- cyclop
- dupl
- durationcheck
- errorlint
- exhaustive
- funlen
- gocognit
- goconst
- gocritic
- gocyclo
- gofmt
- goimports
- revive
- gomnd
#- godot
- goheader
- gomoddirectives
- gomodguard
- goprintffuncname
- gosec
- makezero
- misspell
- mnd
- nakedret
- nestif
- nilerr
- nilnil
- noctx
- nolintlint
- prealloc
- predeclared
- promlinter
- reassign
- rowserrcheck
- sqlclosecheck
- staticcheck
- testableexamples
- thelper
- unconvert
- typecheck
- unparam
- usestdlibvars
- wastedassign
- whitespace
settings:
cyclop:
max-complexity: 11
dupl:
threshold: 100
errcheck:
check-type-assertions: true
check-blank: false
errorlint:
errorf: true
asserts: true
comparison: true
exhaustive:
default-signifies-exhaustive: false
funlen:
lines: 100
statements: 50
gocognit:
min-complexity: 15
goconst:
min-len: 3
min-occurrences: 3
gocritic:
disabled-checks:
- dupImport
- ifElseChain
- octalLiteral
- whyNoLint
- wrapperFunc
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
gocyclo:
min-complexity: 15
godot:
scope: declarations
exclude:
- "^fixme:"
- "^todo:"
capital: false
misspell:
locale: US
nestif:
min-complexity: 4
prealloc:
simple: true
range-loops: true
for-loops: false
staticcheck:
checks:
- all
- -ST1000
- -ST1003
- -ST1016
- -ST1020
- -ST1021
- -ST1022
dot-import-whitelist:
- fmt
unparam:
check-exported: false
whitespace:
multi-if: false
multi-func: false
exclusions:
generated: lax

# default
- errcheck
#- govet
- ineffassign
#- staticcheck
- unused
presets:
- comments
- common-false-positives
- legacy
- std-error-handling

linters-settings:
dupl:
threshold: 100
funlen:
lines: 100
statements: 60
depguard:
list-type: blacklist
packages:
- golang.org/x/net/context
- github.com/prometheus/common/log
# gocyclo:
# min-complexity: 15
rules: []

warn-unused: true
issues:
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
- path: _test\.go
linters:
- gomnd
# https://github.com/go-critic/go-critic/issues/926
- linters:
- gocritic
text: "unnecessaryDefer:"
max-issues-per-linter: 0
max-same-issues: 0
new: false
fix: false
formatters:
enable:
- gci
- gofmt
- gofumpt
- goimports
settings:
gci:
sections:
- standard
- default
- prefix(github.com/robmorgan/infraspec)
goimports:
local-prefixes:
- github.com/robmorgan/infraspec
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ deps: ## install dependencies
go install mvdan.cc/gofumpt@latest
go install github.com/daixiang0/gci@latest
go install golang.org/x/tools/cmd/goimports@latest
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.2.1
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.2.2

.PHONY: tidy
tidy: ## go mod tidy
Expand Down
2 changes: 1 addition & 1 deletion cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func runInit(cmd *cobra.Command, args []string) error {
}

// Create the features directory
if err := os.MkdirAll(featuresDir, 0o755); err != nil {
if err := os.MkdirAll(featuresDir, 0o755); err != nil { //nolint:mnd
return fmt.Errorf("failed to create features directory: %w", err)
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func runNew(cmd *cobra.Command, args []string) error {
}

// Create features directory if it doesn't exist
if err := os.MkdirAll("features", 0o755); err != nil {
if err := os.MkdirAll("features", 0o755); err != nil { //nolint:mnd
return fmt.Errorf("failed to create features directory: %w", err)
}

Expand All @@ -63,7 +63,7 @@ func runNew(cmd *cobra.Command, args []string) error {
Then the service should be healthy
`

if err := os.WriteFile(filePath, []byte(template), 0o644); err != nil {
if err := os.WriteFile(filePath, []byte(template), 0o600); err != nil { //nolint:mnd
return fmt.Errorf("failed to create feature file: %w", err)
}

Expand All @@ -86,7 +86,7 @@ func getFeatureName(filePath string) string {
// Simple title case conversion
words := strings.Fields(name)
for i, word := range words {
if len(word) > 0 {
if word != "" {
words[i] = strings.ToUpper(word[:1]) + strings.ToLower(word[1:])
}
}
Expand Down
14 changes: 12 additions & 2 deletions internal/collections/collections.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package collections

import (
"math/rand"
"crypto/rand"
"math/big"
"slices"
)

Expand Down Expand Up @@ -53,13 +54,22 @@ func Subtract[T comparable](a, b []T) []T {
return result
}

// cryptoRandInt generates a cryptographically secure random integer in range [0, limit)
func cryptoRandInt(limit int) int {
n, err := rand.Int(rand.Reader, big.NewInt(int64(limit)))
if err != nil {
panic(err) // TODO - we may wish to handle this more gracefully
}
return int(n.Int64())
}

// RandomElement returns a random element from the slice, and a boolean indicating whether the slice was empty.
func RandomElement[T any](slice []T) (T, bool) {
if len(slice) == 0 {
var zero T
return zero, false
}

index := rand.Intn(len(slice))
index := cryptoRandInt(len(slice))
return slice[index], true
}
6 changes: 3 additions & 3 deletions internal/collections/collections_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func TestSubtractWithStrings(t *testing.T) {
}
}

func TestRandomElement(t *testing.T) {
func TestRandomElement(t *testing.T) { //nolint:gocognit
tests := []struct {
name string
slice []interface{}
Expand Down Expand Up @@ -244,7 +244,7 @@ func TestRandomElement(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.iterations == 1 {
if tt.iterations == 1 { //nolint:nestif
value, ok := RandomElement(tt.slice)
if ok != tt.wantOk {
t.Errorf("RandomElement() ok = %v, want %v", ok, tt.wantOk)
Expand Down Expand Up @@ -273,7 +273,7 @@ func TestRandomElement(t *testing.T) {
}
}

func TestRandomElementTyped(t *testing.T) {
func TestRandomElementTyped(t *testing.T) { //nolint:gocognit
tests := []struct {
name string
slice interface{}
Expand Down
Loading