This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Terraform provider for Cloud Foundry (CF) using the Terraform Plugin Framework v1 and the CF v3 API via go-cfclient/v3. Registry address: registry.terraform.io/cloudfoundry/cloudfoundry.
make build # Compile
make test # Unit tests (10m timeout, uses VCR fixtures — no live CF needed)
make testacc # Acceptance tests (120m timeout, TF_ACC=1)
make lint # golangci-lint
make fmt # gofmt
make generate # Regenerate docs (tfplugindocs) + format examples
make fix # go fix
make lefthook # Install pre-commit hooks (gofmt, golangci-lint, terraform fmt)Run a single test:
go test -run ^TestResourceOrg$ github.com/cloudfoundry/terraform-provider-cloudfoundry/cloudfoundry/providerRun tests matching a pattern:
go test -run ServiceCredentialBinding github.com/cloudfoundry/terraform-provider-cloudfoundry/cloudfoundry/providerForce VCR re-recording (requires CF CLI login): set TEST_FORCE_REC=true before running tests. Unset it for normal test runs.
main.go # Entry point, serves provider via RPC
cloudfoundry/provider/
├── provider.go # Provider definition, auth, resource/datasource registration
├── resource_*.go # ~24 resources (CRUD + import)
├── datasource_*.go # ~40 data sources (read-only)
├── types_*.go # Type structs + bidirectional mapper functions
├── utils.go # Shared schema helpers, metadata, error handling, polling
├── *_test.go # Tests (VCR-based)
├── managers/session.go # CF client session creation
└── fixtures/ # VCR cassettes (YAML, ~181 files)
internal/
├── mta/ # Multi-Target Application client (separate HTTP client with CSRF)
├── validation/uuidvalidator.go # Custom UUID validator
└── version/version.go # Provider version (injected via ldflags)
Every resource follows this structure:
- Struct implementing
resource.Resource,ResourceWithConfigure,ResourceWithImportState, optionallyResourceWithIdentity Configure()receives*Sessionfrom provider, storescfClientSchema()defines attributes using shared helpers fromutils.go(guidSchema(),resourceLabelsSchema(),createdAtSchema(), etc.)Create/Read/Update/Deleteuse mapper functions fromtypes_*.goto convert between Terraform types and CF API structsImportState()viaImportStatePassthroughIDor identity-based import
Key conventions:
- Async deletions use
pollJob()(20-min timeout, 2-sec interval) handleReadErrors()removes resources from state on 404- Labels/annotations use
setClientMetadataForUpdate()which removes old then adds new lo.Find,lo.Difference,lo.Intersectfrom samber/lo for collection operations
Implements datasource.DataSource + DataSourceWithConfigure. Read-only: builds list options with filters, calls CF API, uses lo.Find() to match, maps result to Terraform type.
Each entity has mapper functions in types_*.go:
map<Entity>ValuesToType()— CF API response → Terraform type structmapCreate<Entity>TypeToValues()— Terraform plan → CF Create requestmapUpdate<Entity>TypeToValues()— Terraform plan/state → CF Update request
func TestResourceOrg(t *testing.T) {
t.Parallel()
t.Run("happy path", func(t *testing.T) {
cfg := getCFHomeConf()
rec := cfg.SetupVCR(t, "fixtures/resource_org") // unique path per test
defer stopQuietly(rec)
resource.Test(t, resource.TestCase{
IsUnitTest: true,
ProtoV6ProviderFactories: getProviders(rec.GetDefaultClient()),
Steps: []resource.TestStep{...},
})
})
}- Fixtures in
cloudfoundry/provider/fixtures/— one YAML per test, path must be unique - Tests use
IsUnitTest: truewith VCR (no live CF environment) - HCL generators:
hclProvider(),hclOrg(),hclSpace(), etc. with*ModelPtrstructs - Regex validators:
regexpValidUUID,regexpValidRFC3999Format
Supports (in priority order): username/password, client credentials, access/refresh tokens, JWT assertion tokens, CF CLI config fallback (~/.cf/config.json). Environment variables: CF_API_URL, CF_USER, CF_PASSWORD, CF_CLIENT_ID, CF_CLIENT_SECRET.
- Commits: Conventional commits required (
fix:,feat:,refactor!:) - Docs: Never edit
docs/manually — generated from schema viamake generate - VCR fixtures: Never edit manually. Review for leaked credentials before committing.
- Plan modifiers:
UseStateForUnknown()for computed fields,RequiresReplace()for immutable fields - CI matrix: Tests run against Terraform 1.12, 1.13, 1.14