Architecture
Package overview
go-libs is organized as a set of independent packages under pkg/. All packages import utils; no other cross-package imports are allowed except prometheus → k8sclient.
pkg/utils ← foundation: display, arg parsing, debug flag, exit hook
↑
├── pkg/k8sclient ← Kubernetes client (wraps client-go)
│ ↑
│ └── pkg/prometheus ← Prometheus query client
│
├── pkg/kubeconfig ← kubeconfig YAML load/save
├── pkg/incrementor ← resource.Quantity parser and arithmetic
├── pkg/mailer ← SMTP email with HTML body and attachments
├── pkg/gdrive ← Google Drive / Sheets via service account
└── pkg/confluence ← Confluence Cloud REST API
Design patterns
Builder (fluent API)
ArgParser, MailerMail, Incrementor, and Kubeconfig follow a fluent builder pattern where each setter returns *Self:
mail := mailer.NewMailerMail().
SetTo("user@example.com").
SetSubject("Report").
SetBody("Hello").
SetBodyHTML("<p>Hello</p>")
Constructor pairs
Each type has an exported constructor (NewFoo) that delegates to an unexported one (newFoo). Business logic lives in the unexported variant.
Interfaces for mocking
k8sclient.K8sClientIface— use in callers to allow test mocking of the Kubernetes clientprometheus.PrometheusIface— use in callers to allow test mocking of the Prometheus client
Thread safety
utils.SetDebug(bool)/utils.GetDebug() boolare backed bysync/atomic.Booland are safe to call from multiple goroutines.utils.ExitFuncis a package-level variable and is not goroutine-safe. Override it only in tests, and restore it withdefer.
Key invariants
| Package | Invariant |
|---|---|
kubeconfig |
GetConfigBytes() returns []byte(kc.Config) — the string is already valid YAML, no marshalling needed |
gdrive |
SetCredentialsContent(*SACreds) fills missing fields with placeholder defaults and logs a warning for each |
mailer |
MailerMail.BodyHTML — when non-empty, added as text/html alternative part via gomail.AddAlternative |
k8sclient |
NewK8sClient("", false, false) calls ExitFunc internally when no kubeconfig is found — never call it in tests without overriding ExitFunc |