|
| 1 | +# Contributing to terraform-provider-tencentcloud |
| 2 | + |
| 3 | +Thank you for taking the time to contribute! This document captures the |
| 4 | +project conventions you should follow when adding or modifying provider |
| 5 | +resources and data sources. |
| 6 | + |
| 7 | +## Provider Architecture: SDKv2 + Framework |
| 8 | + |
| 9 | +The provider serves both [`terraform-plugin-sdk/v2`][sdkv2] and |
| 10 | +[`terraform-plugin-framework`][framework] resources via a single |
| 11 | +[`tf5muxserver`][mux] in `main.go`. The two stacks share the same |
| 12 | +`*connectivity.TencentCloudClient`, so credentials and SDK clients are |
| 13 | +configured exactly once. |
| 14 | + |
| 15 | +[sdkv2]: https://github.com/hashicorp/terraform-plugin-sdk |
| 16 | +[framework]: https://github.com/hashicorp/terraform-plugin-framework |
| 17 | +[mux]: https://github.com/hashicorp/terraform-plugin-mux |
| 18 | + |
| 19 | +### When to use which stack |
| 20 | + |
| 21 | +| Situation | Use | |
| 22 | +|---|---| |
| 23 | +| New resource or data source | **framework** (preferred) | |
| 24 | +| Modifying an existing SDKv2 resource (small change) | SDKv2 (do not migrate) | |
| 25 | +| Migrating an existing SDKv2 resource to framework | Separate change with full acceptance test, **one resource per PR** | |
| 26 | + |
| 27 | +The default for **all new development** is the framework stack, mirroring |
| 28 | +the approach taken by [`terraform-provider-google`][google] and |
| 29 | +[`terraform-provider-aws`][aws]. |
| 30 | + |
| 31 | +[google]: https://github.com/hashicorp/terraform-provider-google |
| 32 | +[aws]: https://github.com/hashicorp/terraform-provider-aws |
| 33 | + |
| 34 | +### Hard rules (enforced by CI) |
| 35 | + |
| 36 | +1. **No type-name collisions across stacks.** A given Terraform resource |
| 37 | + type name (e.g. `tencentcloud_foo_bar`) must be registered in *exactly |
| 38 | + one* of: `Provider().ResourcesMap` (SDKv2) or |
| 39 | + `FrameworkProvider.Resources()` (framework). The same applies to data |
| 40 | + sources. CI runs `make check-mux` to enforce this. |
| 41 | +2. **Backward compatibility is non-negotiable.** Do not change the schema, |
| 42 | + ID format, or state shape of any released resource without a state |
| 43 | + migration and a separate change document. |
| 44 | +3. **No new credential parsing in framework provider.** Credentials are |
| 45 | + parsed by the SDKv2 provider's `providerConfigure` function and shared |
| 46 | + via `sharedmeta.SetSharedMeta`. The framework provider must only |
| 47 | + *read* the shared client, never re-parse environment variables or |
| 48 | + shared credentials files. |
| 49 | +4. **Vendor sync.** Any change to `go.mod` must be followed by |
| 50 | + `go mod vendor` in the same commit; CI compares `vendor/modules.txt`. |
| 51 | + |
| 52 | +## Adding a Framework Resource |
| 53 | + |
| 54 | +framework resources/data sources/functions/ephemerals/lists/actions are |
| 55 | +organized under `tencentcloud/framework/` in a **product-by-type** layout. |
| 56 | +There is **no** `tencentcloud/services/<service>/framework.go` middle layer — |
| 57 | +the registry imports product subpackages directly. |
| 58 | + |
| 59 | +```text |
| 60 | +tencentcloud/framework/<product>/<type>/ |
| 61 | +├── <resource_name>_resource.go # implementation |
| 62 | +├── <resource_name>_resource_test.go # unit/acceptance test |
| 63 | +└── ... |
| 64 | +``` |
| 65 | + |
| 66 | +Concrete examples already in the repo: |
| 67 | + |
| 68 | +```text |
| 69 | +tencentcloud/framework/meta/resources/local_note_resource.go # package metaresources |
| 70 | +tencentcloud/framework/meta/datasources/provider_runtime_data_source.go |
| 71 | +tencentcloud/framework/meta/functions/parse_resource_id_function.go |
| 72 | +tencentcloud/framework/meta/ephemerals/temp_credential_ephemeral_resource.go |
| 73 | +tencentcloud/framework/cvm/actions/reboot_instance_action.go # package cvmactions |
| 74 | +``` |
| 75 | + |
| 76 | +Steps: |
| 77 | + |
| 78 | +1. Pick the product directory. If the resource is clearly tied to a |
| 79 | + TencentCloud service (CVM, VPC, CBS, ...), use |
| 80 | + `tencentcloud/framework/<product>/<type>/`. Only resources that are |
| 81 | + **cross-product or not bound to any specific service** belong under |
| 82 | + `tencentcloud/framework/meta/<type>/`. |
| 83 | +2. The package name is `<product><type-plural>`, e.g. `cvmresources`, |
| 84 | + `metafunctions`, `cvmactions`. This prefix avoids cross-product |
| 85 | + collisions when `registry.go` imports several `<x>resources` subpackages. |
| 86 | +3. Implement the resource using the `terraform-plugin-framework` interfaces. |
| 87 | + Use `tencentcloud/framework/internal/helper` helpers for retries, error |
| 88 | + translation, type conversions, and the `timeouts` block. |
| 89 | +4. In your `Configure` method, type-assert |
| 90 | + `req.ProviderData.(*sharedmeta.ProviderMeta)` and store the |
| 91 | + `Client` field. Be defensive against `nil` provider data. |
| 92 | +5. Wire the factory into `tencentcloud/framework/registry.go` by adding an |
| 93 | + `import` for your product subpackage and appending the factory in the |
| 94 | + matching aggregator (`frameworkResources` / `frameworkDataSources` / |
| 95 | + `frameworkFunctions` / `frameworkEphemeralResources` / |
| 96 | + `frameworkListResources` / `frameworkActions`). No change to |
| 97 | + `tencentcloud/framework/provider.go` is needed. |
| 98 | +6. Use `tcfwacctest.AccProtoV5ProviderFactories` (alias for |
| 99 | + `tencentcloud/framework/acctest`, NOT `AccProviders`) in acceptance |
| 100 | + tests so the test exercises the muxed binary. The framework-only |
| 101 | + factory now lives under `tencentcloud/framework/acctest/`; the |
| 102 | + shared `AccPreCheck` / test helpers remain in `tencentcloud/acctest/`, |
| 103 | + so framework tests typically import both packages with aliases |
| 104 | + `tcacctest` (PreCheck/test_util) and `tcfwacctest` (factories). |
| 105 | +7. Add documentation to `website/docs/r/<service>_<name>.html.markdown` |
| 106 | + (or `d/...` for data sources). The current `gendoc` generator does not |
| 107 | + yet understand framework schemas — handwrite the doc until the |
| 108 | + generator is upgraded (tracked separately). |
| 109 | + |
| 110 | +> Note: the framework `Action` interface's execution method is named |
| 111 | +> **`Invoke`** (not `Run`). Only the framework `Function` interface uses |
| 112 | +> `Run`. The schema-side method for `Function` is `Definition` (returning |
| 113 | +> `function.Definition{Parameters, Return}`), not `Schema`. |
| 114 | +
|
| 115 | +## Useful Make targets |
| 116 | + |
| 117 | +| Target | Purpose | |
| 118 | +|---|---| |
| 119 | +| `make build` | Compile the provider | |
| 120 | +| `make fmt` | Format code with `gofmt` | |
| 121 | +| `make lint` | golangci-lint + tfproviderlint | |
| 122 | +| `make test` | Unit tests, 30s timeout | |
| 123 | +| `make check-mux` | Verify SDKv2 + framework mux compatibility (no panics, no duplicate type names) | |
| 124 | +| `make testacc` | Acceptance tests (requires `TENCENTCLOUD_SECRET_ID`/`KEY`) | |
| 125 | +| `make doc` | Regenerate website docs (SDKv2 only — handwrite docs for framework resources for now) | |
| 126 | + |
| 127 | +## PR Checklist |
| 128 | + |
| 129 | +Before opening a PR, please confirm: |
| 130 | + |
| 131 | +- [ ] `make build` succeeds |
| 132 | +- [ ] `make fmt` shows no diff |
| 133 | +- [ ] `make lint` passes (or pre-existing failures are unrelated) |
| 134 | +- [ ] `make check-mux` passes |
| 135 | +- [ ] For new framework resources/data sources: their type name is **not** |
| 136 | + already registered in SDKv2 (`tencentcloud/provider.go` ResourcesMap) |
| 137 | +- [ ] Acceptance tests added (or skipped with justification) |
| 138 | +- [ ] Website docs updated under `website/docs/r/` or `website/docs/d/` |
| 139 | +- [ ] If `go.mod` changed: `go mod vendor` was run in the same commit |
0 commit comments