Skip to content

Commit 1cf5f7f

Browse files
authored
feat(provider): [134193389]framework (#4143)
* feat: Support terraform-plugin-framework * fix: Adjusting Provider Discrepancies * fix: check mux * fix: modify doc config * fix: modify go version * fix: modify go version * fix: modify tfproivder lint * fix: modify golangci lint * fxi: modify golangci linit * fix: modify changelog * fix: modify framework directory
1 parent 46b13bb commit 1cf5f7f

3,292 files changed

Lines changed: 298233 additions & 133917 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changelog/4143.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
provider: introduce dual-stack architecture combining terraform-plugin-sdk/v2 and terraform-plugin-framework via tf5muxserver. New resources and data sources can now be implemented in either stack while continuing to share credentials and the underlying TencentCloud SDK client. Existing resources are unaffected.
3+
```

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!--
2+
Thanks for contributing to terraform-provider-tencentcloud!
3+
Please fill in the sections below to help reviewers understand your change.
4+
See CONTRIBUTING.md for project conventions.
5+
-->
6+
7+
## What
8+
9+
<!-- Describe the change in 1-3 sentences. -->
10+
11+
## Why
12+
13+
<!-- The problem this change solves, or the new capability it enables. -->
14+
15+
## Type of change
16+
17+
- [ ] New SDKv2 resource / data source
18+
- [ ] New framework resource / data source
19+
- [ ] Modification to an existing resource / data source
20+
- [ ] Bug fix
21+
- [ ] Refactor / internal-only change
22+
- [ ] Documentation only
23+
24+
## Checklist
25+
26+
- [ ] `make build` succeeds locally
27+
- [ ] `make fmt` produces no diff
28+
- [ ] `make lint` passes (or pre-existing failures are unrelated)
29+
- [ ] `make check-mux` passes (SDKv2 + framework mux compatibility)
30+
- [ ] **Confirmed the resource/data source type name is not already
31+
registered in the other stack** (CI's `make check-mux` enforces
32+
this; please double-check before opening the PR)
33+
- [ ] Acceptance tests added or updated (or skipped with justification)
34+
- [ ] Website docs updated under `website/docs/r/` or `website/docs/d/`
35+
- [ ] `go.mod` changes are accompanied by `go mod vendor` in the same commit
36+
- [ ] Changelog entry added under `.changelog/<PR>.txt` (if user-facing)
37+
38+
## Notes for reviewers
39+
40+
<!-- Anything reviewers should pay extra attention to: tricky logic,
41+
unusual SDK quirks, breaking changes, etc. -->

.github/workflows/golangci-lint.yml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,21 @@ jobs:
3030

3131
- uses: actions/setup-go@v5
3232
with:
33-
go-version-file: .go-version
34-
go-version: '1.21'
35-
cache: false
33+
go-version-file: go.mod
34+
cache: false
3635

3736
# Runs a set of commands using the runners shell
3837
- name: golangci-lint
39-
uses: golangci/golangci-lint-action@v4
38+
uses: golangci/golangci-lint-action@v8
4039
with:
4140
skip-cache: true
42-
version: v1.54
41+
# v2.4.0 is the first v2 release built with Go 1.25 toolchain. The v1
42+
# series ended at v1.64.8 (Go 1.24-built) and refuses to lint code
43+
# whose go.mod declares `go 1.25` with:
44+
# "the Go language version (go1.24) used to build golangci-lint
45+
# is lower than the targeted Go version (1.25.8)"
46+
# Configuration file (.golangci.yml) is also v2 schema (version: "2").
47+
version: v2.4.0
4348
working-directory: ./tencentcloud
4449
args: --new-from-rev=origin/master -v
4550
#args: --enable-all --max-same-issues=0 --max-issues-per-linter=0 --new-from-rev=origin/master -v

.github/workflows/tfprovider-lint.yml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,22 @@ jobs:
2121
# Steps represent a sequence of tasks that will be executed as part of the job
2222
steps:
2323
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
24-
- uses: actions/checkout@v3
24+
- uses: actions/checkout@v4
2525
with:
2626
fetch-depth: 0
2727
ref: ${{ github.event.pull_request.head.sha }}
2828

29-
- uses: actions/setup-go@v3
29+
- uses: actions/setup-go@v5
3030
with:
31-
go-version: 1.18.1
32-
cache: false
31+
go-version-file: go.mod
32+
cache: false
3333

3434
- name: install tfproviderlint
35-
run: cd .ci/tools && go install github.com/bflad/tfproviderlint/cmd/tfproviderlint
35+
# Pin to v0.31.0: this version pulls in golang.org/x/tools v0.25+, which is
36+
# compatible with Go 1.25's internal token package layout. Older versions
37+
# (e.g. v0.28.1) bundle x/tools v0.13 and fail to compile under Go 1.25
38+
# with: "invalid array length -delta * delta" in tokeninternal.go.
39+
run: go install github.com/bflad/tfproviderlint/cmd/tfproviderlint@v0.31.0
3640

3741
# Runs a set of commands using the runners shell
3842
- name: tfprovider-lint

.github/workflows/unit-tests.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,8 @@ jobs:
2929
# Runs a set of commands using the runners shell
3030
- name: unit
3131
run: go test -v ./tencentcloud -test.run 'TestProvider'
32+
33+
# Verify SDKv2 + framework provider mux compatibility (no schema clash,
34+
# no duplicate resource/data source type names across stacks).
35+
- name: mux compatibility
36+
run: make check-mux

.go-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.17.1
1+
1.25.0

.golangci.yml

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,41 @@
1-
issues:
2-
exclude-rules:
3-
# Exclude issues bypassing staticcheck.conf
4-
- linters:
5-
- staticcheck
6-
text: "SA1019:"
7-
max-per-linter: 0
8-
max-same-issues: 0
1+
version: "2"
2+
3+
run:
4+
modules-download-mode: vendor
5+
timeout: 60m
6+
# The default concurrency value is the number of available CPU.
7+
concurrency: 4
8+
# Allow multiple parallel golangci-lint instances running.
9+
# If false (default) - golangci-lint acquires file lock on start.
10+
allow-parallel-runners: true
11+
12+
output:
13+
show-stats: true
914

1015
linters:
11-
disable-all: true
16+
default: none
1217
enable:
1318
- errcheck
14-
- gofmt
1519
- ineffassign
1620
- misspell
1721
- unconvert
1822
- unused
19-
- vet
23+
- govet
24+
settings:
25+
errcheck:
26+
exclude-functions:
27+
- github.com/hashicorp/terraform-plugin-sdk/helper/schema:ForceNew
28+
- github.com/hashicorp/terraform-plugin-sdk/helper/schema:Set
29+
- fmt:.*
30+
- io:Close
31+
exclusions:
32+
rules:
33+
# Mirror the historical SA1019 bypass: deprecated API references are
34+
# tracked separately and should not block lint runs here.
35+
- linters:
36+
- staticcheck
37+
text: "SA1019:"
2038

21-
linters-settings:
22-
errcheck:
23-
exclude-functions: github.com/hashicorp/terraform-plugin-sdk/helper/schema:ForceNew|Set,fmt:.*,io:Close
24-
25-
run:
26-
modules-download-mode: vendor
27-
timeout: 60m
28-
# The default concurrency value is the number of available CPU.
29-
concurrency: 4
30-
# Allow multiple parallel golangci-lint instances running.
31-
# If false (default) - golangci-lint acquires file lock on start.
32-
allow-parallel-runners: true
39+
formatters:
40+
enable:
41+
- gofmt

CONTRIBUTING.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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

GNUmakefile

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ sweep:
1818
test: fmtcheck
1919
go test $(TEST) -timeout=30s -parallel=4
2020

21+
# check-mux validates SDKv2 + framework dual-stack mux compatibility without
22+
# making any remote calls. It boots tf5muxserver to merge schemas (including
23+
# an actual GetProviderSchema call so byte-level schema drift that
24+
# NewMuxServer cannot detect is caught here), and asserts that the resource /
25+
# data source type-name sets across the two stacks are disjoint. Any PR that
26+
# adds framework references or changes the SDKv2 / framework provider top
27+
# Schema / MetaSchema MUST keep this target green.
28+
check-mux: fmtcheck
29+
@echo "==> Checking SDKv2/framework provider mux compatibility..."
30+
@go test -count=1 -run 'TestMuxServer_NoStartupError|TestMuxServer_GetProviderSchemaNoError|TestFrameworkProvider_NoTypeNameCollision' ./$(PKG_NAME)/framework/
31+
32+
2133
testacc: fmtcheck
2234
TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 120m
2335

@@ -108,6 +120,46 @@ tools:
108120
GO111MODULE=on cd .ci/tools && go install github.com/client9/misspell/cmd/misspell && cd ../..
109121
GO111MODULE=on cd .ci/tools && go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.45.2 && cd ../..
110122

123+
# tfproviderlint-local mirrors .github/workflows/tfprovider-lint.yml byte for
124+
# byte locally: it installs the same tfproviderlint v0.31.0 used by CI
125+
# (already verified to compile under Go 1.25) and runs the identical set of
126+
# checkers (AT/R/S/V) against ./tencentcloud. Whenever the CI yaml changes,
127+
# please keep this target in sync.
128+
TFPROVIDERLINT_VERSION ?= v0.31.0
129+
TFPROVIDERLINT_BIN ?= $(shell go env GOPATH)/bin/tfproviderlint
130+
131+
tfproviderlint-install:
132+
@echo "==> Installing tfproviderlint $(TFPROVIDERLINT_VERSION)..."
133+
@go install github.com/bflad/tfproviderlint/cmd/tfproviderlint@$(TFPROVIDERLINT_VERSION)
134+
135+
tfproviderlint-local: tfproviderlint-install
136+
@echo "==> Running tfproviderlint against ./$(PKG_NAME) (mirrors CI)..."
137+
@$(TFPROVIDERLINT_BIN) \
138+
-c 1 \
139+
-AT002 -AT005 -AT006 -AT007 -AT008 \
140+
-R003 -R012 -R013 \
141+
-S001 -S002 -S003 -S004 -S005 -S007 -S008 -S009 -S010 -S011 -S012 \
142+
-S013 -S014 -S015 -S016 -S017 -S019 -S020 -S021 -S023 -S024 -S025 \
143+
-S026 -S027 -S028 -S029 -S030 -S031 -S032 -S033 -S034 -S035 -S036 -S037 \
144+
-V002 -V003 -V004 -V005 -V006 -V007 -V008 \
145+
./$(PKG_NAME)
146+
147+
# golangci-lint-local mirrors .github/workflows/golangci-lint.yml byte for
148+
# byte locally: it installs the same golangci-lint v2.4.0 used by CI (built
149+
# with the Go 1.25 toolchain) and runs from inside ./tencentcloud, picking up
150+
# the repo-root .golangci.yml and reporting only issues introduced relative
151+
# to master.
152+
GOLANGCI_LINT_VERSION ?= v2.4.0
153+
GOLANGCI_LINT_BIN ?= $(shell go env GOPATH)/bin/golangci-lint
154+
155+
golangci-lint-install:
156+
@echo "==> Installing golangci-lint $(GOLANGCI_LINT_VERSION)..."
157+
@go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)
158+
159+
golangci-lint-local: golangci-lint-install
160+
@echo "==> Running golangci-lint against ./$(PKG_NAME) (mirrors CI)..."
161+
@cd ./$(PKG_NAME) && $(GOLANGCI_LINT_BIN) run --new-from-rev=origin/master -v
162+
111163
test-compile:
112164
@if [ "$(TEST)" = "./..." ]; then \
113165
echo "ERROR: Set TEST to a specific package. For example,"; \
@@ -195,6 +247,6 @@ endif
195247
changelog:
196248
./scripts/generate-changelog.sh
197249

198-
.PHONY: build sweep test testacc fmt fmtcheck lint tools test-compile doc hooks website website-lint website-test
250+
.PHONY: build sweep test testacc fmt fmtcheck lint tools tfproviderlint-install tfproviderlint-local golangci-lint-install golangci-lint-local test-compile doc hooks website website-lint website-test check-mux
199251

200252
ready: doc fmt-faster

0 commit comments

Comments
 (0)