diff --git a/GNUmakefile b/GNUmakefile index 909b322ad..438e94acf 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -37,6 +37,7 @@ resources: schemas: $(GO_VER) generate internal/provider/schemas.go + $(GO_VER) run internal/provider/generators/schema_rename/main.go test: $(GO_VER) test $(TEST) $(TESTARGS) -timeout=5m @@ -65,4 +66,4 @@ docs: $(GO_VER) run internal/provider/generators/import-examples/main.go rm -f docs/data-sources/*.md rm -f docs/resources/*.md - @tfplugindocs generate + @tfplugindocs generate \ No newline at end of file diff --git a/internal/provider/generators/schema_rename/README.md b/internal/provider/generators/schema_rename/README.md new file mode 100644 index 000000000..d4b2a662d --- /dev/null +++ b/internal/provider/generators/schema_rename/README.md @@ -0,0 +1,13 @@ +# AWS CloudFormation Resource Schema Renamer + +Find any reference to the **AWS CloudFormation** in the resource schema attributes / descriptions. + +This tool + +* Reads the schema files under `./internal/service/cloudformation/schemas/` +* Checks whether any reference to **AWS CloudFormation** exists in the schema attributes or description. +* Replace reference of **AWS CloudFormation** with **Terraform** + +## Allowlist + +This tool will skips any CloudFormation schema file with prefix `AWS_CloudFormation_` which denotes all AWS CloudFormation resources (stack, hooks, etc). diff --git a/internal/provider/generators/schema_rename/main.go b/internal/provider/generators/schema_rename/main.go new file mode 100644 index 000000000..47240f286 --- /dev/null +++ b/internal/provider/generators/schema_rename/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/hashicorp/terraform-provider-awscc/internal/provider/generators/schema_rename/rename" +) + +func main() { + baseDir := "./internal/service/cloudformation/schemas/" + err := filepath.Walk(baseDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if !info.IsDir() && filepath.Ext(path) == ".json" { + generator := rename.NewGenerator() + // Skip files that start with "AWS_CloudFormation_" + if !strings.HasPrefix(info.Name(), "AWS_CloudFormation_") { + err = generator.RenameCfnSchemaFile(path) + if err != nil { + return err + } + } + } + + return nil + }) + + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v", err) + } +} diff --git a/internal/provider/generators/schema_rename/rename/rename.go b/internal/provider/generators/schema_rename/rename/rename.go new file mode 100644 index 000000000..073e7e407 --- /dev/null +++ b/internal/provider/generators/schema_rename/rename/rename.go @@ -0,0 +1,116 @@ +package rename + +import ( + "encoding/json" + "io" + "os" + "reflect" + "strings" + + "github.com/hashicorp/terraform-provider-awscc/internal/provider/generators/common" +) + +type Generator struct { + *common.Generator +} + +func NewGenerator() *Generator { + return &Generator{ + Generator: common.NewGenerator(), + } +} + +const filePermMode = 0644 // Read/write for owner, read for group/others + +func (g *Generator) RenameCfnSchemaFile(filePath string) error { + // Open JSON schema file from base directory + file, err := os.Open(filePath) + if err != nil { + g.Errorf("Error opening file: %v", err) + return err + } + defer file.Close() + + // Read the JSON data + data, err := io.ReadAll(file) + if err != nil { + g.Errorf("Error reading file: %v", err) + return err + } + + // Unmarshal the JSON data into a map while preserving the order + var jsonData map[string]interface{} + err = json.Unmarshal(data, &jsonData) + if err != nil { + g.Errorf("Error unmarshaling JSON: %v", err) + return err + } + + // Create a copy of the original JSON data + originalData := make(map[string]interface{}) + for k, v := range jsonData { + originalData[k] = v + } + + // Replace "CloudFormation" with "Terraform" in the description + err = updateDescription(jsonData) + if err != nil { + g.Errorf("Error updating description: %v", err) + return err + } + + // Check if the JSON data has changed + if reflect.DeepEqual(jsonData, originalData) { + // No changes detected, skip writing the file + return nil + } + + // Marshal the updated JSON data while preserving the order + updatedDataBytes, err := json.MarshalIndent(jsonData, "", " ") + if err != nil { + g.Errorf("Error marshaling JSON: %v", err) + return err + } + + // Write the updated JSON data back to the file + err = os.WriteFile(filePath, updatedDataBytes, filePermMode) + if err != nil { + g.Errorf("Error writing file: %v", err) + return err + } + + g.Infof("File %s updated successfully\n", filePath) + return nil +} + +func updateDescription(data map[string]interface{}) error { + for key, value := range data { + if key == "description" { + description, ok := value.(string) + if ok { + updatedDescription := strings.ReplaceAll(description, "AWS CloudFormation", "Terraform") + data[key] = updatedDescription + } + } else { + switch v := value.(type) { + case map[string]interface{}: + err := updateDescription(v) + if err != nil { + return err + } + case []interface{}: + for i, item := range v { + switch item := item.(type) { + case map[string]interface{}: + err := updateDescription(item) + if err != nil { + return err + } + v[i] = item + } + } + } + } + } + return nil +}