From 7e9d169e5c48191dc2b74f111be49a1a1b1b16db Mon Sep 17 00:00:00 2001 From: Zhenhua Li Date: Tue, 3 Mar 2026 11:18:16 -0800 Subject: [PATCH 1/2] Move tfplan2cai.go to mmv1/third_party/tgc/tfplan2cai.go --- mmv1/provider/terraform_tgc.go | 1 + mmv1/third_party/tgc/tfplan2cai.go | 73 ++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 mmv1/third_party/tgc/tfplan2cai.go diff --git a/mmv1/provider/terraform_tgc.go b/mmv1/provider/terraform_tgc.go index 157fde7bccec..cebeb4d72cd5 100644 --- a/mmv1/provider/terraform_tgc.go +++ b/mmv1/provider/terraform_tgc.go @@ -440,6 +440,7 @@ func (tgc TerraformGoogleConversion) CopyCommonFiles(outputFolder string, genera "../cmd/tfplan2cai/logger_test.go": "third_party/tgc/cmd/tfplan2cai/logger_test.go", "../cmd/tfplan2cai/main.go": "third_party/tgc/cmd/tfplan2cai/main.go", "../cmd/tfplan2cai/root.go": "third_party/tgc/cmd/tfplan2cai/root.go", + "tfplan2cai.go": "third_party/tgc/tfplan2cai.go", } tgc.CopyFileList(outputFolder, resourceConverters) } diff --git a/mmv1/third_party/tgc/tfplan2cai.go b/mmv1/third_party/tgc/tfplan2cai.go new file mode 100644 index 000000000000..06930b4faf52 --- /dev/null +++ b/mmv1/third_party/tgc/tfplan2cai.go @@ -0,0 +1,73 @@ +package tfplan2cai + +import ( + "context" + "fmt" + "net/http" + + "github.com/GoogleCloudPlatform/terraform-google-conversion/v7/caiasset" + "github.com/GoogleCloudPlatform/terraform-google-conversion/v7/tfplan2cai/ancestrymanager" + convert "github.com/GoogleCloudPlatform/terraform-google-conversion/v7/tfplan2cai/converters/google" + resources "github.com/GoogleCloudPlatform/terraform-google-conversion/v7/tfplan2cai/converters/google/resources" + "github.com/GoogleCloudPlatform/terraform-google-conversion/v7/tfplan2cai/tfplan" + "go.uber.org/zap" +) + +// Options struct to avoid updating function signatures all along the pipe. +type Options struct { + ConvertUnchanged bool + ErrorLogger *zap.Logger + Offline bool + DefaultProject string + DefaultRegion string + DefaultZone string + // UserAgent for all requests (if online) + UserAgent string + // HTTPClient for all requests (if online) + HTTPClient *http.Client + // Map hierarchy resource (like projects/ or folders/) + // to an ancestry path (like organizations/123/folders/456/projects/789) + AncestryCache map[string]string +} + +// Convert converts terraform json plan to CAI Assets. +func Convert(ctx context.Context, jsonPlan []byte, o *Options) ([]caiasset.Asset, error) { + // Creates ancestry manager and converter internally; they are + // implementation details private to this package. + + errorLogger := o.ErrorLogger + if errorLogger == nil { + logger, err := zap.NewDevelopment() + if err != nil { + return nil, fmt.Errorf("building logger: %w", err) + } + errorLogger = logger + } + + // contents of newConverter + // Set up config and ancestry manager using the same http client and user agent + cfg, err := resources.NewConfig(ctx, o.DefaultProject, o.DefaultZone, o.DefaultRegion, o.Offline, o.UserAgent, o.HTTPClient) + if err != nil { + return nil, fmt.Errorf("building config: %w", err) + } + + ancestryManager, err := ancestrymanager.New(cfg, o.Offline, o.AncestryCache, errorLogger) + if err != nil { + return nil, fmt.Errorf("building ancestry manager: %w", err) + } + + converter := convert.NewConverter(cfg, ancestryManager, o.Offline, o.ConvertUnchanged, errorLogger) + + // ReadResourceChanges + changes, err := tfplan.ReadResourceChanges(jsonPlan) + if err != nil { + return nil, err + } + + err = converter.AddResourceChanges(changes) + if err != nil { + return nil, err + } + + return converter.Assets(), nil +} From 812ad11f2d9ec04ff401839755fb3f54be6fe865 Mon Sep 17 00:00:00 2001 From: Zhenhua Li Date: Wed, 4 Mar 2026 17:14:25 -0800 Subject: [PATCH 2/2] Move tfplan_to_cai_test.go to mmv1/third_party/tgc/tfplan_to_cai_test.go --- mmv1/provider/terraform_tgc.go | 1 + mmv1/third_party/tgc/tfplan_to_cai_test.go | 32 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 mmv1/third_party/tgc/tfplan_to_cai_test.go diff --git a/mmv1/provider/terraform_tgc.go b/mmv1/provider/terraform_tgc.go index cebeb4d72cd5..3e0868142b99 100644 --- a/mmv1/provider/terraform_tgc.go +++ b/mmv1/provider/terraform_tgc.go @@ -441,6 +441,7 @@ func (tgc TerraformGoogleConversion) CopyCommonFiles(outputFolder string, genera "../cmd/tfplan2cai/main.go": "third_party/tgc/cmd/tfplan2cai/main.go", "../cmd/tfplan2cai/root.go": "third_party/tgc/cmd/tfplan2cai/root.go", "tfplan2cai.go": "third_party/tgc/tfplan2cai.go", + "tfplan_to_cai_test.go": "third_party/tgc/tfplan_to_cai_test.go", } tgc.CopyFileList(outputFolder, resourceConverters) } diff --git a/mmv1/third_party/tgc/tfplan_to_cai_test.go b/mmv1/third_party/tgc/tfplan_to_cai_test.go new file mode 100644 index 000000000000..a35480e7796b --- /dev/null +++ b/mmv1/third_party/tgc/tfplan_to_cai_test.go @@ -0,0 +1,32 @@ +// Package tfplan2cai converts tfplan to CAI assets. +package tfplan2cai + +import ( + "context" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestConvert_noPlanJSON(t *testing.T) { + ctx := context.Background() + jsonPlan := []byte{} + options := &Options{Offline: true} + assets, err := Convert(ctx, jsonPlan, options) + assert.Empty(t, assets) + assert.Error(t, err) +} + +func TestConvert_noResourceChanges(t *testing.T) { + ctx := context.Background() + f := "./testdata/empty-0.13.7.tfplan.json" + jsonPlan, err := os.ReadFile(f) + if err != nil { + t.Fatalf("Error parsing %s: %s", f, err) + } + options := &Options{Offline: true} + assets, err := Convert(ctx, jsonPlan, options) + assert.Empty(t, assets) + assert.Empty(t, err) +}