diff --git a/provider/pkg/resources/resources.go b/provider/pkg/resources/resources.go index 22f30779c722..4e82711032e5 100644 --- a/provider/pkg/resources/resources.go +++ b/provider/pkg/resources/resources.go @@ -283,9 +283,9 @@ func GetModuleName(majorVersion uint64, filePath, apiUri string) (ModuleNaming, // We extract the module name from two sources: // - from the folder name of the Open API spec // - from the URI of the API endpoint (we take the last namespace in the URI) - specFolderName := getSpecFolderName(filePath) + specFolderName, specFilePath := getSpecFolderNameAndFilePath(filePath) namespaceWithoutPrefixFromSpecFilePath := findNamespaceWithoutPrefixFromPath(filePath, "") - namespace, err := findSpecNamespace(filePath) + namespace, err := findSpecNamespace(specFilePath) if err != nil { return ModuleNaming{}, err } @@ -419,15 +419,18 @@ func findNamespaceWithoutPrefixFromPath(path, defaultValue string) string { return defaultValue } -var folderModulePattern = regexp.MustCompile(`.*/specification/([a-zA-Z-]+)/resource-manager/.*`) +var folderModulePattern = regexp.MustCompile(`.*/specification/([a-zA-Z0-9-]+)/resource-manager/(.*)`) -func getSpecFolderName(path string) string { +func getSpecFolderNameAndFilePath(path string) (string, string) { + // Note that this returns last match, e.g. the following path matches `C`, `D`: + // specification/A/resource-manager/B/specification/C/resource-manager/D subMatches := folderModulePattern.FindStringSubmatch(path) - if len(subMatches) > 1 { + if len(subMatches) > 2 { moduleAlias := subMatches[1] - return moduleAlias + filePath := subMatches[2] + return moduleAlias, filePath } - return "" + return "", "" } var verbReplacer = strings.NewReplacer( diff --git a/provider/pkg/resources/resources_test.go b/provider/pkg/resources/resources_test.go index 385c63c6fcf8..2f392e0b8457 100644 --- a/provider/pkg/resources/resources_test.go +++ b/provider/pkg/resources/resources_test.go @@ -364,6 +364,42 @@ func TestResourceModuleNaming(t *testing.T) { RpNamespace: "Microsoft.Network", }, naming) }) + t.Run("Module name with numbers", func(t *testing.T) { + naming, err := GetModuleName(2, + "/go/pulumi-azure-native/azure-rest-api-specs/specification/storsimple8000series/resource-manager/Microsoft.StorSimple/stable/2017-06-01/storsimple.json", + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.StorSimple/managers/{managerName}") + assert.Nil(t, err) + assert.Equal(t, ModuleNaming{ + ResolvedName: "StorSimple", + SpecFolderName: "storsimple8000series", + NamespaceWithoutPrefix: "StorSimple", + RpNamespace: "Microsoft.StorSimple", + }, naming) + }) + t.Run("File path with dots uses last match", func(t *testing.T) { + naming, err := GetModuleName(2, + "/go/pulumi.azure.native/azure-rest-api-specs/specification/videoanalyzer/resource-manager/Microsoft.Media/preview/2021-11-01-preview/PipelineTopologies.json", + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Media/videoAnalyzers/{accountName}/edgeModules/{edgeModuleName}") + assert.Nil(t, err) + assert.Equal(t, ModuleNaming{ + ResolvedName: "VideoAnalyzer", + SpecFolderName: "videoanalyzer", + NamespaceWithoutPrefix: "Media", + RpNamespace: "Microsoft.Media", + }, naming) + }) + t.Run("Nested specifications file path uses last match", func(t *testing.T) { + naming, err := GetModuleName(2, + "/go/pulumi-azure-native/azure-rest-api-specs/specification/dns/resource-manager/Microsoft.Network/specification/videoanalyzer/resource-manager/Microsoft.Media/preview/2021-11-01-preview/PipelineTopologies.json", + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Media/videoAnalyzers/{accountName}/edgeModules/{edgeModuleName}") + assert.Nil(t, err) + assert.Equal(t, ModuleNaming{ + ResolvedName: "VideoAnalyzer", + SpecFolderName: "videoanalyzer", + NamespaceWithoutPrefix: "Media", + RpNamespace: "Microsoft.Media", + }, naming) + }) } func ptr[T any](s T) *T {