From 3b6a655c00d17e9955cc4c6fde2d8a0e6f536f6d Mon Sep 17 00:00:00 2001 From: Tom Bamford Date: Wed, 25 Sep 2024 18:30:22 +0100 Subject: [PATCH] generator-go-sdk: allow configurable deletion of existing resources within an API version prior to generation, and enable for Microsoft Graph --- .../generator-go-sdk/internal/cmd/generate.go | 13 +++++++ .../internal/generator/helpers.go | 20 ++++++++++ .../internal/generator/service.go | 24 +----------- .../internal/generator/settings.go | 37 ++++++++++++++++--- 4 files changed, 66 insertions(+), 28 deletions(-) diff --git a/tools/generator-go-sdk/internal/cmd/generate.go b/tools/generator-go-sdk/internal/cmd/generate.go index 7129cfd8a1f..35b794de4d0 100644 --- a/tools/generator-go-sdk/internal/cmd/generate.go +++ b/tools/generator-go-sdk/internal/cmd/generate.go @@ -60,6 +60,7 @@ func (g GenerateCommand) Run(args []string) int { if g.sourceDataType == models.MicrosoftGraphSourceDataType { input.settings.AllowOmittingDiscriminatedValue = true + input.settings.DeleteExistingResourcesForVersion = true input.settings.GenerateDescriptionsForModels = true input.settings.RecurseParentModels = false @@ -73,6 +74,7 @@ func (g GenerateCommand) Run(args []string) int { } } else if g.sourceDataType == models.ResourceManagerSourceDataType { input.settings.AllowOmittingDiscriminatedValue = false + input.settings.DeleteExistingResourcesForVersion = false input.settings.GenerateDescriptionsForModels = false input.settings.RecurseParentModels = true @@ -170,6 +172,17 @@ func (g GenerateCommand) run(ctx context.Context, input GeneratorInput) error { commonTypes = v } + if input.settings.DeleteExistingResourcesForVersion { + logging.Debugf("Deleting existing definitions for Service %q / Version %q", serviceName, versionNumber) + servicePackageName := strings.ToLower(serviceName) + versionDirectoryName := strings.ToLower(versionNumber) + versionOutputPath := filepath.Join(input.outputDirectory, servicePackageName, versionDirectoryName) + if err = generator.CleanAndRecreateWorkingDirectory(versionOutputPath); err != nil { + addErr(fmt.Errorf("cleaning/recreating working directory %q: %+v", versionOutputPath, err)) + return + } + } + for resourceName, resourceDetails := range versionDetails.Resources { logging.Debugf(" Resource %q", resourceName) serviceGeneratorInput := generator.ServiceGeneratorInput{ diff --git a/tools/generator-go-sdk/internal/generator/helpers.go b/tools/generator-go-sdk/internal/generator/helpers.go index 4a7d71f1cb5..02b2e4bde70 100644 --- a/tools/generator-go-sdk/internal/generator/helpers.go +++ b/tools/generator-go-sdk/internal/generator/helpers.go @@ -2,11 +2,31 @@ package generator import ( "fmt" + "os" "strings" "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" ) +func CleanAndRecreateWorkingDirectory(path string) error { + // rm -r 💥 + if err := os.RemoveAll(path); err != nil { + return fmt.Errorf("deleting %q: %+v", path, err) + } + + return EnsureWorkingDirectoryExists(path) +} + +func EnsureWorkingDirectoryExists(path string) error { + if err := os.MkdirAll(path, 0777); err != nil { + if !os.IsExist(err) { + return fmt.Errorf("creating %q: %+v", path, err) + } + } + + return nil +} + func alternateCasingOnEveryLetter(input string) string { output := "" caps := false diff --git a/tools/generator-go-sdk/internal/generator/service.go b/tools/generator-go-sdk/internal/generator/service.go index 3da6c946b97..74ada5c0f18 100644 --- a/tools/generator-go-sdk/internal/generator/service.go +++ b/tools/generator-go-sdk/internal/generator/service.go @@ -5,7 +5,6 @@ package generator import ( "fmt" - "os" "os/exec" "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" @@ -38,7 +37,7 @@ type ServiceGeneratorInput struct { func (s *Generator) Generate(input ServiceGeneratorInput) error { data := input.generatorData(s.settings) - if err := cleanAndRecreateWorkingDirectory(data.resourceOutputPath); err != nil { + if err := CleanAndRecreateWorkingDirectory(data.resourceOutputPath); err != nil { return fmt.Errorf("cleaning/recreating working directory %q: %+v", data.resourceOutputPath, err) } @@ -98,7 +97,7 @@ func (s *Generator) GenerateForVersion(input VersionGeneratorInput) error { func (s *Generator) GenerateCommonTypes(input VersionGeneratorInput) error { data := input.generatorData(s.settings) - if err := cleanAndRecreateWorkingDirectory(data.commonTypesOutputPath); err != nil { + if err := CleanAndRecreateWorkingDirectory(data.commonTypesOutputPath); err != nil { return fmt.Errorf("cleaning/recreating working directory %q: %+v", data.commonTypesOutputPath, err) } @@ -131,22 +130,3 @@ func runGoImports(path string) { _ = cmd.Start() _ = cmd.Wait() } - -func cleanAndRecreateWorkingDirectory(path string) error { - // rm -r 💥 - if err := os.RemoveAll(path); err != nil { - return fmt.Errorf("deleting %q: %+v", path, err) - } - - return ensureWorkingDirectoryExists(path) -} - -func ensureWorkingDirectoryExists(path string) error { - if err := os.MkdirAll(path, 0777); err != nil { - if !os.IsExist(err) { - return fmt.Errorf("creating %q: %+v", path, err) - } - } - - return nil -} diff --git a/tools/generator-go-sdk/internal/generator/settings.go b/tools/generator-go-sdk/internal/generator/settings.go index b4cf65e4700..f7088accbf7 100644 --- a/tools/generator-go-sdk/internal/generator/settings.go +++ b/tools/generator-go-sdk/internal/generator/settings.go @@ -10,13 +10,38 @@ import ( ) type Settings struct { - CanonicalApiVersions map[string]string - CommonTypesPackageName string + // Whether model structs should have an `OmitDiscriminatedValue` field, to allow the caller to omit the + // discriminated type value when marhalling. Used in Microsoft Graph for buggy APIs that don't parse this. AllowOmittingDiscriminatedValue bool - GenerateDescriptionsForModels bool - RecurseParentModels bool - VersionsToGenerateCommonTypes map[string]models.SourceDataOrigin - servicesUsingOldBaseLayer map[string]struct{} + + // CanonicalApiVersions is a map of API version names to use in the SDK, where the key is the SDK-friendly + // name, and the value is the upstream API version. Used in Microsoft Graph to translate `v1.0` to `stable`. + CanonicalApiVersions map[string]string + + // CommonTypesPackageName is the name of the Go package that should be output with common models, constants + // and resource IDs. Each API version will get a package below this containing the respective types. Used + // in Microsoft Graph. Could be used in Resource Manager or other SDKs. + CommonTypesPackageName string + + // DeleteExistingResourcesForVersion toggles whether any existing resources within a given API version should + // be removed prior to generating. This is not compatible when more than one SourceDataType is being used to + // generate an SDK. Used in Microsoft Graph because breaking removals are allowed. + DeleteExistingResourcesForVersion bool + + // GenerateDescriptionsForModels enables nicely-formatted Go comments for model fields to be generated. + GenerateDescriptionsForModels bool + + // RecurseParentModels is a behavioral toggle for discriminated types. When true, the full ancestry for child + // models will be output in the SDK. When false, only the youngest ancestor containing the necessary type + // information will be output. Used in Microsoft Graph to properly express model inheritance. + RecurseParentModels bool + + // VersionsToGenerateCommonTypes is a map of API versions to SourceDataOrigin, to specify the API versions + // for which common types should be generated. This is necessary because common types are enumerated separately + // from service definitions. Used in Microsoft Graph. + VersionsToGenerateCommonTypes map[string]models.SourceDataOrigin + + servicesUsingOldBaseLayer map[string]struct{} } func (s *Settings) CanonicalApiVersion(version string) *string {