Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customise module naming #3838

Merged
merged 10 commits into from
Jan 10, 2025
69 changes: 45 additions & 24 deletions provider/pkg/gen/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ const goBasePath = "github.com/pulumi/pulumi-azure-native-sdk/v2"
const goModuleRepoPath = "github.com/pulumi/pulumi-azure-native-sdk"
const goModuleVersion = "/v2"

// pulumiProviderName is the name of the provider as used in all tokens.
const pulumiProviderName = "azure-native"

type ResourceDeprecation struct {
ReplacementToken string
}
Expand Down Expand Up @@ -323,7 +326,7 @@ func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning
javaPackages[module] = fmt.Sprintf("%s.%s", strings.ToLower(providerName), sdkVersion)
}
pythonModuleNames[module] = module
golangImportAliases[filepath.Join(goModuleRepoPath, gen.versionedModuleName())] = strings.ToLower(providerName)
golangImportAliases[goModuleName(gen.provider, gen.sdkVersion)] = strings.ToLower(providerName)

// Populate resources and get invokes.
items := versionMap[sdkVersion]
Expand Down Expand Up @@ -772,11 +775,6 @@ func (g *packageGenerator) findResourceVariants(resource *openapi.ResourceSpec)
return result, nil
}

func (g *packageGenerator) makeTypeAlias(alias string, apiVersion openapi.SdkVersion) pschema.AliasSpec {
fqAlias := g.generateTok(alias, apiVersion)
return pschema.AliasSpec{Type: &fqAlias}
}

func (g *packageGenerator) genResourceVariant(apiSpec *openapi.ResourceSpec, resource *resourceVariant, nestedResourceBodyRefs []string, typeNameAliases ...string) error {
module := g.moduleName()
swagger := resource.Swagger
Expand Down Expand Up @@ -967,16 +965,41 @@ func isSingleton(resource *resourceVariant) bool {
func (g *packageGenerator) generateAliases(resource *resourceVariant, typeNameAliases ...string) []pschema.AliasSpec {
var aliases []pschema.AliasSpec

addAlias := func(module, typeName string, version openapi.SdkVersion) {
alias := generateTok(module, typeName, version)
aliases = append(aliases, pschema.AliasSpec{Type: &alias})
}

// Add an alias for the same version of the resource, but in its old module.
if resource.PreviousProviderName != nil {
addAlias(*resource.PreviousProviderName, resource.typeName, g.sdkVersion)
}

for _, alias := range typeNameAliases {
aliases = append(aliases, g.makeTypeAlias(alias, g.sdkVersion))
addAlias(g.provider, alias, g.sdkVersion)
// Add an alias for the same alias, but in its old module.
if resource.PreviousProviderName != nil {
addAlias(*resource.PreviousProviderName, alias, g.sdkVersion)
}
}

// Add an alias for each API version that has the same path in it.
for _, version := range resource.CompatibleVersions {
aliases = append(aliases, g.makeTypeAlias(resource.typeName, version))
addAlias(g.provider, resource.typeName, version)

// Add an alias for the other versions, but from its old module.
if resource.PreviousProviderName != nil {
addAlias(*resource.PreviousProviderName, resource.typeName, version)
}

// Add type name aliases for each compatible version.
for _, alias := range typeNameAliases {
aliases = append(aliases, g.makeTypeAlias(alias, version))
addAlias(g.provider, alias, version)

// Add an alias for the other version, with alias, from its old module.
if resource.PreviousProviderName != nil {
addAlias(*resource.PreviousProviderName, alias, version)
}
}
}

Expand Down Expand Up @@ -1056,7 +1079,7 @@ func (g *packageGenerator) genFunctions(typeName, path string, specParams []spec
}

// Generate the function to get this resource.
functionTok := g.generateTok(typeName, g.sdkVersion)
functionTok := generateTok(g.provider, typeName, g.sdkVersion)
if !g.shouldInclude(typeName, functionTok, g.apiVersion) {
return
}
Expand Down Expand Up @@ -1106,27 +1129,25 @@ func (g *packageGenerator) genFunctions(typeName, path string, specParams []spec

// moduleName produces the module name from the provider name and the version e.g. `compute/v20200701`.
func (g *packageGenerator) moduleName() string {
return g.providerApiToModule(g.sdkVersion)
return providerApiToModule(g.provider, g.sdkVersion)
}

func (g *packageGenerator) versionedModuleName() string {
versionedModule := strings.ToLower(g.provider) + goModuleVersion
if g.sdkVersion == "" {
return versionedModule
}
return fmt.Sprintf("%s/%s", versionedModule, g.sdkVersion)
// goModuleName produces the *Go* module name from the provider name and the version e.g. `compute/v20200701`.
// or just the provider name if the version is empty (default version) e.g. `compute`.
func goModuleName(provider openapi.ProviderName, sdkVersion openapi.SdkVersion) string {
return filepath.Join(goModuleRepoPath, strings.ToLower(provider), goModuleVersion, string(sdkVersion))
}

// providerApiToModule produces the module name from the provider name (g.provider), and the version if not empty, e.g. `compute/v20200701`.
func (g *packageGenerator) providerApiToModule(apiVersion openapi.SdkVersion) string {
if apiVersion == "" {
return strings.ToLower(g.provider)
func providerApiToModule(provider openapi.ProviderName, sdkVersion openapi.SdkVersion) string {
if sdkVersion == "" {
return strings.ToLower(provider)
}
return fmt.Sprintf("%s/%s", strings.ToLower(g.provider), apiVersion)
return fmt.Sprintf("%s/%s", strings.ToLower(provider), sdkVersion)
}

func (g *packageGenerator) generateTok(typeName string, apiVersion openapi.SdkVersion) string {
return fmt.Sprintf(`%s:%s:%s`, g.pkg.Name, g.providerApiToModule(apiVersion), typeName)
func generateTok(provider openapi.ProviderName, typeName string, apiVersion openapi.SdkVersion) string {
return fmt.Sprintf(`%s:%s:%s`, pulumiProviderName, providerApiToModule(provider, apiVersion), typeName)
}

func (g *packageGenerator) shouldInclude(typeName, tok string, version *openapi.ApiVersion) bool {
Expand Down Expand Up @@ -1159,7 +1180,7 @@ func (g *packageGenerator) formatDescription(desc string, typeName string, defau
if v == defaultVersion {
continue
}
tok := g.generateTok(typeName, openapi.ApiToSdkVersion(v))
tok := generateTok(g.provider, typeName, openapi.ApiToSdkVersion(v))
if g.shouldInclude(typeName, tok, &v) {
includedVersions = append(includedVersions, string(v))
}
Expand Down
151 changes: 111 additions & 40 deletions provider/pkg/gen/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,11 @@ import (

"github.com/go-openapi/spec"
"github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi"
"github.com/pulumi/pulumi/pkg/v3/codegen"
pschema "github.com/pulumi/pulumi/pkg/v3/codegen/schema"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestTypeAliasFormatting(t *testing.T) {
generator := packageGenerator{
pkg: &pschema.PackageSpec{Name: "azure-native"},
sdkVersion: "v20220222",
provider: "Compute",
}

actual := generator.makeTypeAlias("VirtualMachine", "v18851225")
assert.NotNil(t, actual)
assert.Equal(t, "azure-native:compute/v18851225:VirtualMachine", *actual.Type)

actual = generator.makeTypeAlias("VirtualMachine", "")
assert.NotNil(t, actual)
assert.Equal(t, "azure-native:compute:VirtualMachine", *actual.Type)
}

// Ensure our VersionMetadata type implements the gen.Versioning interface
// The compiler will raise an error here if the interface isn't implemented
var _ Versioning = (*versioningStub)(nil)
Expand Down Expand Up @@ -61,32 +44,110 @@ func (v versioningStub) GetAllVersions(provider, resource string) []openapi.ApiV
}

func TestAliases(t *testing.T) {
generator := packageGenerator{
pkg: &pschema.PackageSpec{Name: "azure-native"},
sdkVersion: "v20220222",
versioning: versioningStub{},
provider: "Insights",
majorVersion: 2,
}
// Wrap the generation of type aliases in a function to make it easier to test
generateTypeAliases := func(provider, typeName string, sdkVersion openapi.SdkVersion, previousProviderName string, typeNameAliases []string, versions []openapi.SdkVersion) []string {
generator := packageGenerator{
pkg: &pschema.PackageSpec{Name: "azure-native"},
sdkVersion: sdkVersion,
versioning: versioningStub{},
provider: provider,
majorVersion: 2,
}

resource := &resourceVariant{
ResourceSpec: &openapi.ResourceSpec{
CompatibleVersions: []openapi.SdkVersion{"v20210111"},
},
typeName: "PrivateLinkForAzureAd",
}
resource := &resourceVariant{
ResourceSpec: &openapi.ResourceSpec{
CompatibleVersions: versions,
},
typeName: typeName,
}
if previousProviderName != "" {
resource.PreviousProviderName = &previousProviderName
}

aliases := generator.generateAliases(resource, "privateLinkForAzureAd")
actual := codegen.NewStringSet()
for _, alias := range aliases {
actual.Add(*alias.Type)
aliasSpecs := generator.generateAliases(resource, typeNameAliases...)
typeAliases := []string{}
for _, alias := range aliasSpecs {
typeAliases = append(typeAliases, *alias.Type)
}
return typeAliases
}
expected := codegen.NewStringSet(
"azure-native:insights/v20210111:privateLinkForAzureAd",
"azure-native:insights/v20210111:PrivateLinkForAzureAd",
"azure-native:insights/v20220222:privateLinkForAzureAd",
)
assert.Equal(t, expected, actual)

t.Run("compatible version", func(t *testing.T) {
actual := generateTypeAliases("Insights", "PrivateLinkForAzureAd", "v20220222", "", nil, []openapi.SdkVersion{"v20200110", "v20210111"})
expected := []string{
"azure-native:insights/v20200110:PrivateLinkForAzureAd",
"azure-native:insights/v20210111:PrivateLinkForAzureAd",
}
assert.ElementsMatch(t, expected, actual)
})

t.Run("type alias", func(t *testing.T) {
actual := generateTypeAliases("Insights", "PrivateLinkForAzureAd", "v20220222", "", []string{"privateLinkForAzureAd"}, []openapi.SdkVersion{})
expected := []string{
"azure-native:insights/v20220222:privateLinkForAzureAd",
}
assert.ElementsMatch(t, expected, actual)
})

t.Run("compatible version & type alias", func(t *testing.T) {
actual := generateTypeAliases("Insights", "PrivateLinkForAzureAd", "v20220222", "", []string{"privateLinkForAzureAd"}, []openapi.SdkVersion{"v20200110", "v20210111"})
expected := []string{
"azure-native:insights/v20200110:privateLinkForAzureAd",
"azure-native:insights/v20200110:PrivateLinkForAzureAd",
"azure-native:insights/v20210111:privateLinkForAzureAd",
"azure-native:insights/v20210111:PrivateLinkForAzureAd",
"azure-native:insights/v20220222:privateLinkForAzureAd",
}
assert.ElementsMatch(t, expected, actual)
})

t.Run("previous provider", func(t *testing.T) {
actual := generateTypeAliases("Monitor", "PrivateLinkForAzureAd", "v20220222", "Insights", nil, []openapi.SdkVersion{})
expected := []string{
"azure-native:insights/v20220222:PrivateLinkForAzureAd",
}
assert.ElementsMatch(t, expected, actual)
})

t.Run("previous provider & type alias", func(t *testing.T) {
actual := generateTypeAliases("Monitor", "PrivateLinkForAzureAd", "v20220222", "Insights", []string{"privateLinkForAzureAd"}, []openapi.SdkVersion{})
expected := []string{
"azure-native:monitor/v20220222:privateLinkForAzureAd", // change case
"azure-native:insights/v20220222:PrivateLinkForAzureAd", // change module
"azure-native:insights/v20220222:privateLinkForAzureAd", // change module and case
}
assert.ElementsMatch(t, expected, actual)
})

t.Run("previous provider & compatible version", func(t *testing.T) {
actual := generateTypeAliases("Monitor", "PrivateLinkForAzureAd", "v20220222", "Insights", nil, []openapi.SdkVersion{"v20200110", "v20210111"})
expected := []string{
"azure-native:monitor/v20200110:PrivateLinkForAzureAd", // change version
"azure-native:insights/v20200110:PrivateLinkForAzureAd", // change version & module
"azure-native:monitor/v20210111:PrivateLinkForAzureAd", // change version
"azure-native:insights/v20210111:PrivateLinkForAzureAd", // change version & module
"azure-native:insights/v20220222:PrivateLinkForAzureAd", // change module
}
assert.ElementsMatch(t, expected, actual)
})

t.Run("previous provider, compatible version & type alias", func(t *testing.T) {
actual := generateTypeAliases("Monitor", "PrivateLinkForAzureAd", "v20220222", "Insights", []string{"privateLinkForAzureAd"}, []openapi.SdkVersion{"v20200110", "v20210111"})
expected := []string{
"azure-native:monitor/v20200110:PrivateLinkForAzureAd", // change version
"azure-native:monitor/v20200110:privateLinkForAzureAd", // change version & case
"azure-native:insights/v20200110:PrivateLinkForAzureAd", // change version & module
"azure-native:insights/v20200110:privateLinkForAzureAd", // change version & module & case
"azure-native:monitor/v20210111:PrivateLinkForAzureAd", // change version
"azure-native:monitor/v20210111:privateLinkForAzureAd", // change version & case
"azure-native:insights/v20210111:PrivateLinkForAzureAd", // change version & module
"azure-native:insights/v20210111:privateLinkForAzureAd", // change version & module & case
"azure-native:insights/v20220222:PrivateLinkForAzureAd", // change module
"azure-native:insights/v20220222:privateLinkForAzureAd", // change module & case
"azure-native:monitor/v20220222:privateLinkForAzureAd", // change case
}
assert.ElementsMatch(t, expected, actual)
})
}

func TestFindNestedResources(t *testing.T) {
Expand Down Expand Up @@ -288,3 +349,13 @@ func TestResourceIsSingleton(t *testing.T) {
assert.False(t, isSingleton(res))
})
}

func TestGoModuleName(t *testing.T) {
t.Run("explicit version", func(t *testing.T) {
assert.Equal(t, "github.com/pulumi/pulumi-azure-native-sdk/network/v2/v20220222", goModuleName("Network", "v20220222"))
})

t.Run("default version", func(t *testing.T) {
assert.Equal(t, "github.com/pulumi/pulumi-azure-native-sdk/network/v2", goModuleName("Network", ""))
})
}
35 changes: 19 additions & 16 deletions provider/pkg/openapi/discover.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi/paths"
"github.com/pulumi/pulumi-azure-native/v2/provider/pkg/resources"
"github.com/pulumi/pulumi-azure-native/v2/provider/pkg/resources/customresources"
"github.com/pulumi/pulumi-azure-native/v2/provider/pkg/version"
"github.com/pulumi/pulumi/pkg/v3/codegen"
)

Expand Down Expand Up @@ -206,14 +207,15 @@ func (v VersionResources) All() map[string]*ResourceSpec {

// ResourceSpec contains a pointer in an Open API Spec that defines a resource and related metadata.
type ResourceSpec struct {
Path string
PathItem *spec.PathItem
PathItemList *spec.PathItem
Swagger *Spec
CompatibleVersions []SdkVersion
DefaultBody map[string]interface{}
DeprecationMessage string
PreviousVersion ApiVersion
Path string
PathItem *spec.PathItem
PathItemList *spec.PathItem
Swagger *Spec
CompatibleVersions []SdkVersion
DefaultBody map[string]interface{}
DeprecationMessage string
PreviousVersion ApiVersion
PreviousProviderName *string
}

// ApplyProvidersTransformations adds the default version for each provider and deprecates and removes specified API versions.
Expand Down Expand Up @@ -507,7 +509,7 @@ func exclude(filePath string) bool {
// addAPIPath considers whether an API path contains resources and/or invokes and adds corresponding entries to the
// provider map. `providers` are mutated in-place.
func (providers AzureProviders) addAPIPath(specsDir, fileLocation, path string, swagger *Spec) DiscoveryDiagnostics {
prov, err := resources.ResourceProvider(filepath.Join(specsDir, fileLocation), path)
prov, oldProvider, err := resources.ResourceProvider(version.GetVersion().Major, filepath.Join(specsDir, fileLocation), path)
if err != nil {
return DiscoveryDiagnostics{
ProviderNameErrors: []ProviderNameError{
Expand Down Expand Up @@ -536,10 +538,10 @@ func (providers AzureProviders) addAPIPath(specsDir, fileLocation, path string,
versionMap[sdkVersion] = version
}

return addResourcesAndInvokes(version, fileLocation, path, prov, swagger)
return addResourcesAndInvokes(version, fileLocation, path, prov, oldProvider, swagger)
}

func addResourcesAndInvokes(version VersionResources, fileLocation, path, provider string, swagger *Spec) DiscoveryDiagnostics {
func addResourcesAndInvokes(version VersionResources, fileLocation, path, provider string, oldProvider *string, swagger *Spec) DiscoveryDiagnostics {
apiVersion := ApiVersion(swagger.Info.Version)
sdkVersion := ApiToSdkVersion(apiVersion)

Expand Down Expand Up @@ -569,11 +571,12 @@ func addResourcesAndInvokes(version VersionResources, fileLocation, path, provid
foundResourceOrInvoke := false
addResource := func(typeName string, defaultBody map[string]interface{}, pathItemList *spec.PathItem) {
version.Resources[typeName] = &ResourceSpec{
Path: path,
PathItem: &pathItem,
Swagger: swagger,
DefaultBody: defaultBody,
PathItemList: pathItemList,
Path: path,
PathItem: &pathItem,
Swagger: swagger,
DefaultBody: defaultBody,
PathItemList: pathItemList,
PreviousProviderName: oldProvider,
}
foundResourceOrInvoke = true
}
Expand Down
4 changes: 2 additions & 2 deletions provider/pkg/openapi/discover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestAddInvokes(t *testing.T) {
version := NewVersionResources()
spec := createTestSwaggerForInvoke(tc.path, tc.operationId, tc.httpMethod)

addResourcesAndInvokes(version, "/file/path", tc.path, "foo", &spec)
addResourcesAndInvokes(version, "/file/path", tc.path, "foo", nil, &spec)

assert.Empty(t, version.Resources, tcName)
assert.NotEmpty(t, version.Invokes, tcName)
Expand Down Expand Up @@ -126,7 +126,7 @@ func TestDefaultState(t *testing.T) {
swagger := makeSwagger(path)
version := NewVersionResources()

addResourcesAndInvokes(version, "/file/path", path, "insights", &swagger)
addResourcesAndInvokes(version, "/file/path", path, "insights", nil, &swagger)

require.NotEmpty(t, version.Resources)
res, ok := version.Resources["DiagnosticSettingsCategory"]
Expand Down
Loading
Loading