FinFocus Development Workflow
Quick Reference
make build # Build binary to bin/finfocus make test # Unit tests (fast, default) make lint # golangci-lint + markdownlint (5+ min, use extended timeout) make validate # go mod tidy + go vet make test-race # Race detector make test-integration # Cross-component tests (10min timeout) make build-all # Build binary + all plugins
Critical rules: Always run make lint and make test before claiming success.
Never run git commit (user commits manually). Never modify .golangci.yml.
Adding a CLI Command
- •Create
internal/cli/your_command.go - •Follow constructor pattern:
func NewYourCmd() *cobra.Command {
var flagVar string
cmd := &cobra.Command{
Use: "your-command",
Short: "Description",
RunE: func(cmd *cobra.Command, args []string) error {
// Use cmd.Printf() not fmt.Printf()
return nil
},
}
cmd.Flags().StringVar(&flagVar, "flag", "", "description")
return cmd
}
- •Register in parent command (e.g.,
root.goorcost.go) - •Use
RunE(notRun) for error handling - •Defer cleanup immediately:
defer cleanup()
Resource Processing Pipeline
All cost commands follow:
ingest.LoadPulumiPlan(path) -> ingest.MapResources() -> registry.Open(ctx, adapter) -> engine.GetProjectedCost/GetActualCost() -> engine.RenderResults(format, results)
Testing Standards
- •Use
testify/assertandtestify/requireexclusively (never manualif/t.Errorf) - •
require.*for setup that must succeed;assert.*for value checks - •Table-driven tests for variations
- •Package suffix
_testfor black-box testing - •
t.TempDir()for temporary files (auto-cleanup) - •Capture output:
cmd.SetOut(&buf)andcmd.SetErr(&buf) - •Target 80% coverage minimum, 95% for critical paths
See references/testing-patterns.md for detailed test patterns and examples.
Project Structure
See references/project-structure.md for the complete package map and key file locations.
Error Handling
- •Wrap errors:
fmt.Errorf("context: %w", err) - •Return early on errors
- •Plugin failures don't stop processing (graceful degradation)
- •Validation prefix:
"VALIDATION: %v", plugin error prefix:"ERROR:"
Logging (zerolog)
log := logging.FromContext(ctx)
log.Debug().Ctx(ctx).Str("component", "engine").Msg("message")
Standard fields: trace_id, component, operation, duration_ms.
Enable debug: --debug flag or FINFOCUS_LOG_LEVEL=debug.
Date Handling
Support both "2006-01-02" and RFC3339. Default --to to time.Now().
Validate ranges (to must be after from).
Output Formats
Three formats via --output flag: table (default), json, ndjson.
Always use cmd.Printf() for testability.