Skip to content

Latest commit

 

History

History
170 lines (128 loc) · 4.98 KB

File metadata and controls

170 lines (128 loc) · 4.98 KB

Contributing to c3x

Read ARCHITECTURE.md first for the package map. This file is the short workflow checklist for landing the three most common kinds of change.

Quick reference

git clone https://github.com/c3xdev/c3x.git
cd c3x
go test -race ./...            # full suite
go run ./cmd/verify_catalog    # catalog health against pricing.c3x.dev

The repo enforces gofmt, go vet, and depguard (module boundaries). CI runs all three; locally:

gofmt -s -w .
go vet ./...

Adding a new resource kind (most common contribution)

  1. Create resources/<provider>/<kind>.toml. Skeleton:

    kind         = "aws_widget"
    display_name = "AWS Widget"
    provider     = "aws"
    
    [mappings.widget]
    service        = "AmazonWidget"
    product_family = "Widget"
    attribute_filters = [
      { key = "instanceType", expr = 'default(size, "small")' },
    ]
    
    [[dimensions]]
    id       = "widget_hours"
    label    = "Widget"
    unit     = "hours"
    quantity = "monthly_hours()"
    rate     = 'price("widget")'
    
    [fixture]
    attributes = { size = "small" }
    expected_monthly_cost = 0
    tolerance = 0.05
  2. Probe the upstream backend to find the right mapping shape:

    curl -s 'https://pricing.c3x.dev/graphql' \
      -H 'content-type: application/json' \
      -d '{"query":"{ products(filter: { vendorName: \"aws\", service: \"AmazonWidget\", region: \"us-east-1\" }) { productFamily attributes { key value } prices { USD } } }"}'
  3. Run the verifier to compute the actual monthly cost:

    go run ./cmd/verify_catalog | grep aws_widget
  4. Update the fixture's expected_monthly_cost to that value. The verifier now enforces it on every run as a snapshot.

  5. Add the kind to the appropriate parser's attribute extractor if the Terraform attribute names need normalization (see internal/parser/terraform/resources.go for examples).

If the upstream returns no products, fall back to inline rates:

rate = "0.05"   # static — document the gap in docs/upstream-gaps.md

exact = true in the fixture instead of tolerance so any drift fails CI loudly.

Adding a recommendation rule

  1. Pick rules_aws.go, rules_azure.go, or rules_gcp.go based on the cloud. (Cross-provider rules go in recommend.go.)

  2. Implement Rule:

    type WidgetUnderutilization struct{}
    
    func (WidgetUnderutilization) Name() string { return "aws.widget.under" }
    
    func (WidgetUnderutilization) Propose(r domain.Resource) []Proposal {
        if r.Ref.Kind != "aws_widget" {
            return nil
        }
        // … return one or more Proposals
    }
  3. Register it in the per-cloud factory (AWSRules(), etc.).

  4. Add tests in recommend_test.go and the table-driven rules_test.go.

For cross-resource recommendations use TreeRule.ProposeTree and return a TreeProposal with the Changes map. The engine re-estimates the modified set; positive net delta becomes a recommendation.

Adding an output format

  1. internal/render/<format>.go with Render<Format>(est) string (or (string, error) for serialization formats).
  2. Add the constant to internal/render/render.go's Format enum
    • String() + ParseFormat().
  3. Add a case to Render() and RenderDiff() in internal/render/dispatch.go.
  4. Test the rendering against a hand-crafted domain.Estimate — no full pipeline needed.

Adding a forge poster (PR comments on GitLab / Bitbucket / …)

  1. Implement comment.Poster in internal/comment/<forge>.go. Reuse the marker pattern (comment.Marker).
  2. Add an env-driven AutoDetect<Forge>() helper.
  3. Add a subcommand in cmd/c3x/comment.go that wires flags + constructor + dispatch.
  4. Test with httptest.NewServer stubbing the forge's API.

Writing tests

  • go test -race ./... must pass before submitting.

  • Property tests live next to the unit tests (recommend_test.go, concurrency_property_test.go).

  • Fuzz tests go in <package>/fuzz_test.go with seed corpora.

  • Golden tests update with -update:

    go test ./cmd/c3x/... -run TestEstimateGolden -update
  • Catalog snapshots regenerate by editing the affected TOML's [fixture] block + running the verifier.

Catalog drift policy

The verifier reports [DRIFT] when a kind's computed cost moves outside its snapshot tolerance. Drift is not always a bug — vendor prices change. When you see drift:

  1. Confirm against the vendor's public pricing page that the new rate is correct.
  2. Update the affected TOML's expected_monthly_cost.
  3. Bump last_verified (when we add that field — A.3.1 on the roadmap).
  4. Commit with a message like catalog: refresh aws_eks rate.

Commit conventions

Single-purpose commits. Conventional Commits style preferred:

catalog: add aws_workspaces_workspace TOML
parser: handle CFN !Sub with mid-string variables
calculator: fix cache key collision on multi-mapping filters

PR descriptions should link to the relevant ROADMAP.md item if one exists.