Skip to content

Latest commit

 

History

History
159 lines (127 loc) · 5.24 KB

File metadata and controls

159 lines (127 loc) · 5.24 KB

Project Rules

Overview

devkit is a Go CLI toolkit for DevOps automation. It ships as a single static binary and exposes three subcommands: scaffold, health, and report. These rules govern how all contributors write, structure, and test code in this repository.


Repository Structure

devkit/
├── main.go                  ← calls cmd.Execute() only — no logic
├── go.mod
├── go.sum
├── Makefile
├── CLAUDE.md
├── README.md
├── .golangci.yml
├── .gosec.yaml
├── .goreleaser.yml
├── cmd/
│   ├── root.go              ← owned by scaffold lead — defines rootCmd and Execute()
│   ├── scaffold.go          ← scaffold subcommand registration and flag binding
│   ├── health.go            ← health subcommand registration and flag binding
│   └── report.go            ← report subcommand registration and flag binding
├── internal/
│   ├── scaffold/
│   │   ├── scaffold.go
│   │   └── scaffold_test.go
│   ├── health/
│   │   ├── health.go
│   │   └── health_test.go
│   └── report/
│       ├── report.go
│       └── report_test.go
├── docs/
│   └── specs/
│       ├── SPEC_scaffold.md
│       ├── SPEC_health.md
│       └── SPEC_report.md
└── website/
    └── devkit-landing.html

File Ownership

File Owner Rule
main.go scaffold lead Nobody else touches this
cmd/root.go scaffold lead Nobody else touches this
cmd/scaffold.go scaffold lead
cmd/health.go health dev
cmd/report.go report dev
internal/scaffold/* scaffold lead
internal/health/* health dev
internal/report/* report dev
Makefile scaffold lead New targets only — never modify existing
.golangci.yml scaffold lead
go.mod / go.sum all Run go mod tidy before every PR

main.go Contract

main.go must contain exactly this and nothing more:

package main

import "devkit/cmd"

func main() {
    cmd.Execute()
}

No cobra imports. No flag parsing. No logic. If you feel the urge to add something to main.go, it belongs in cmd/root.go or an internal/ package.


cmd/ Package Rules

  • Every cmd/*.go file (except root.go) must self-register using init():
    func init() {
        rootCmd.AddCommand(myCmd)
    }
  • rootCmd.AddCommand() is never called from main.go or root.go
  • All flags are registered in init(), not in RunE
  • Command files contain: var declaration, init(), and RunE only
  • RunE reads flags, builds an Options struct, calls internal/<pkg>.Run(), and handles the returned error — nothing else
  • Use RunE (not Run) on all commands so errors propagate cleanly

internal/ Package Rules

  • All business logic lives in internal/ — never in cmd/
  • Each package exposes a single Run(opts Options) error entry point
  • Options is a plain struct with exported fields matching the CLI flags
  • No os.Exit() in internal/ — return errors, let cmd/ handle exit
  • No fmt.Println in internal/ for user-facing output — use fmt.Fprintf(w io.Writer, ...) with a writer passed via Options, or write to os.Stdout explicitly when it is truly always stdout
  • internal/ packages must not import from cmd/

Makefile Rules

  • make verify — minimum gate before every commit: vet + lint + test
  • make qa — full gate before every PR: all analysis + tests + coverage + security
  • make ci — same as qa plus release validation — used in GitHub Actions
  • Never add .PHONY targets that shell out to scripts outside the Makefile
  • Tab-indent all Makefile recipe lines — never spaces

Dependencies

  • Add no runtime dependencies without team discussion
  • Dev tools (linters, security scanners) are installed via go install — they do not appear in go.mod
  • go mod tidy must pass cleanly before any merge to main
  • Check make vuln output before adding any new dependency

Error Handling

  • Every error must be handled — no blank identifier: _ = someFunc()
  • Wrap errors with context: fmt.Errorf("scaffold: create dir: %w", err)
  • Return errors up the call stack — do not swallow them with a log line
  • os.Exit() is only called in cmd/ layer after printing to os.Stderr
  • Never use panic except for programming errors that should never occur in production (e.g., nil pointer from a required dependency)

Testing Rules

  • Test files use the external package convention: package scaffold_test
  • Table-driven tests are preferred for functions with multiple input cases
  • Test function names describe behavior: TestRunReturnsErrorOnEmptyName
  • Use t.Skip("not yet implemented") for stub tests — never empty bodies
  • Coverage threshold: 60% minimum enforced by make coverage
  • Race detector is always on: go test -race ./...
  • No time.Sleep in tests — use channels or sync primitives

Cline Agent Rules

  • Do NOT run git commands of any kind
  • Do not git add, git commit, git push, or git stash
  • After completing a task, list the files changed and stop
  • The developer reviews the diff and commits manually