Skip to content

Commit 9319fc0

Browse files
authored
List all available API versions for a resource in the registry (#2809)
For each resource, this PR adds all Azure API versions that are available in the SDK to the resource's description. The goal is to make these additional versions more easily discoverable for users. - Drive-by fix: wrong make target in message - Format the versions more nicely. - Refactor to make provider available during package gen - Show only available, not all compatible other API versions. - Regenerate SDKs
1 parent e681f6d commit 9319fc0

File tree

8,655 files changed

+33011
-8550
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

8,655 files changed

+33011
-8550
lines changed

provider/cmd/pulumi-gen-azure-native/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func main() {
109109

110110
// We can't generate schema.json every time because it's slow and isn't reproducible.
111111
// So we warn in case someone's expecting to see changes to schema.json after running this.
112-
fmt.Println("Note: provider/cmd/pulumi-resource-azure-native/schema.json is generated by the `docs` target.")
112+
fmt.Println("Note: provider/cmd/pulumi-resource-azure-native/schema.json is generated by the `generate_docs` target.")
113113

114114
// Also, emit the resource metadata for the provider.
115115
if codegenMetadataOutputPath == "" {

provider/cmd/pulumi-resource-azure-native/schema.json

Lines changed: 2883 additions & 2883 deletions
Large diffs are not rendered by default.

provider/pkg/gen/schema.go

Lines changed: 79 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type ResourceDeprecation struct {
4747
type Versioning interface {
4848
ShouldInclude(provider string, version string, typeName, token string) bool
4949
GetDeprecation(token string) (ResourceDeprecation, bool)
50+
GetAllVersions(openapi.ProviderName, openapi.ResourceName) []openapi.ApiVersion
5051
}
5152

5253
type GenerationResult struct {
@@ -227,15 +228,17 @@ func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning
227228
gen := packageGenerator{
228229
pkg: &pkg,
229230
metadata: &metadata,
231+
provider: providerName,
230232
apiVersion: version,
233+
allApiVersions: versions,
231234
examples: exampleMap,
232235
versioning: versioning,
233236
caseSensitiveTypes: caseSensitiveTypes,
234237
rootDir: rootDir,
235238
}
236239

237240
// Populate C#, Java, Python and Go module mapping.
238-
module := gen.providerToModule(providerName)
241+
module := gen.moduleName()
239242
csharpNamespaces[strings.ToLower(providerName)] = providerName
240243
javaPackages[module] = strings.ToLower(providerName)
241244
if version != "" {
@@ -257,7 +260,7 @@ func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning
257260
for _, typeName := range resources {
258261
resource := items.Resources[typeName]
259262
nestedResourceBodyRefs := findNestedResourceBodyRefs(resource, items.Resources)
260-
err := gen.genResources(providerName, typeName, resource, nestedResourceBodyRefs)
263+
err := gen.genResources(typeName, resource, nestedResourceBodyRefs)
261264
if err != nil {
262265
return nil, err
263266
}
@@ -272,7 +275,7 @@ func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning
272275

273276
for _, typeName := range invokes {
274277
invoke := items.Invokes[typeName]
275-
gen.genPostFunctions(providerName, typeName, invoke.Path, invoke.PathItem, invoke.Swagger)
278+
gen.genPostFunctions(typeName, invoke.Path, invoke.PathItem, invoke.Swagger)
276279
}
277280
warnings = append(warnings, gen.warnings...)
278281
}
@@ -490,16 +493,18 @@ const (
490493
type packageGenerator struct {
491494
pkg *pschema.PackageSpec
492495
metadata *resources.AzureAPIMetadata
496+
provider string
493497
examples map[string][]resources.AzureAPIExample
494498
apiVersion string
499+
allApiVersions []openapi.ApiVersion
495500
versioning Versioning
496501
caseSensitiveTypes caseSensitiveTokens
497502
warnings []string
498503
// rootDir is used to resolve relative paths in the examples.
499504
rootDir string
500505
}
501506

502-
func (g *packageGenerator) genResources(prov, typeName string, resource *openapi.ResourceSpec, nestedResourceBodyRefs []string) error {
507+
func (g *packageGenerator) genResources(typeName string, resource *openapi.ResourceSpec, nestedResourceBodyRefs []string) error {
503508
// Resource names should consistently start with upper case.
504509
// We need to alias the previous, lowercase name so users can upgrade to v2 without replacement.
505510
// These aliases will not be required anymore with v3; their removal is tracked by #2411.
@@ -515,11 +520,11 @@ func (g *packageGenerator) genResources(prov, typeName string, resource *openapi
515520
// per each union case. We call them "variants" in the code below.
516521
variants, err := g.findResourceVariants(resource)
517522
if err != nil {
518-
return errors.Wrapf(err, "resource %s.%s", prov, titleCasedTypeName)
523+
return errors.Wrapf(err, "resource %s.%s", g.provider, titleCasedTypeName)
519524
}
520525

521526
for _, v := range variants {
522-
err = g.genResourceVariant(prov, resource, v, nestedResourceBodyRefs, typeNameAliases...)
527+
err = g.genResourceVariant(resource, v, nestedResourceBodyRefs, typeNameAliases...)
523528
if err != nil {
524529
return err
525530
}
@@ -537,7 +542,7 @@ func (g *packageGenerator) genResources(prov, typeName string, resource *openapi
537542
if resource.DeprecationMessage != "" {
538543
mainResource.deprecationMessage = resource.DeprecationMessage
539544
}
540-
return g.genResourceVariant(prov, resource, mainResource, nestedResourceBodyRefs, typeNameAliases...)
545+
return g.genResourceVariant(resource, mainResource, nestedResourceBodyRefs, typeNameAliases...)
541546
}
542547

543548
// resourceVariant points to request body's and response's schemas of a resource which is one of the variants
@@ -626,18 +631,18 @@ func (g *packageGenerator) findResourceVariants(resource *openapi.ResourceSpec)
626631
return result, nil
627632
}
628633

629-
func (g *packageGenerator) makeTypeAlias(prov, alias, apiVersion string) pschema.AliasSpec {
630-
fqAlias := fmt.Sprintf("%s:%s:%s", g.pkg.Name, providerApiToModule(prov, apiVersion), alias)
634+
func (g *packageGenerator) makeTypeAlias(alias, apiVersion string) pschema.AliasSpec {
635+
fqAlias := fmt.Sprintf("%s:%s:%s", g.pkg.Name, g.providerApiToModule(apiVersion), alias)
631636
return pschema.AliasSpec{Type: &fqAlias}
632637
}
633638

634-
func (g *packageGenerator) genResourceVariant(prov string, apiSpec *openapi.ResourceSpec, resource *resourceVariant, nestedResourceBodyRefs []string, typeNameAliases ...string) error {
635-
module := g.providerToModule(prov)
639+
func (g *packageGenerator) genResourceVariant(apiSpec *openapi.ResourceSpec, resource *resourceVariant, nestedResourceBodyRefs []string, typeNameAliases ...string) error {
640+
module := g.moduleName()
636641
swagger := resource.Swagger
637642
path := resource.PathItem
638643

639644
resourceTok := fmt.Sprintf(`%s:%s:%s`, g.pkg.Name, module, resource.typeName)
640-
if !g.versioning.ShouldInclude(prov, g.apiVersion, resource.typeName, resourceTok) {
645+
if !g.versioning.ShouldInclude(g.provider, g.apiVersion, resource.typeName, resourceTok) {
641646
return nil
642647
}
643648

@@ -646,7 +651,7 @@ func (g *packageGenerator) genResourceVariant(prov string, apiSpec *openapi.Reso
646651
pkg: g.pkg,
647652
metadata: g.metadata,
648653
module: module,
649-
prov: prov,
654+
prov: g.provider,
650655
resourceName: resource.typeName,
651656
resourceToken: resourceTok,
652657
visitedTypes: make(map[string]bool),
@@ -702,21 +707,21 @@ func (g *packageGenerator) genResourceVariant(prov string, apiSpec *openapi.Reso
702707

703708
resourceSpec := pschema.ResourceSpec{
704709
ObjectTypeSpec: pschema.ObjectTypeSpec{
705-
Description: g.formatDescription(resourceResponse.description, swagger.Info, apiSpec, additionalDocs),
710+
Description: g.formatDescription(resourceResponse.description, resource.typeName, swagger.Info.Version, apiSpec.PreviousVersion, additionalDocs),
706711
Type: "object",
707712
Properties: resourceResponse.specs,
708713
Required: resourceResponse.requiredSpecs.SortedValues(),
709714
},
710715
InputProperties: resourceRequest.specs,
711716
RequiredInputs: resourceRequest.requiredSpecs.SortedValues(),
712-
Aliases: g.generateAliases(prov, resource, typeNameAliases...),
717+
Aliases: g.generateAliases(resource, typeNameAliases...),
713718
DeprecationMessage: resource.deprecationMessage,
714719
}
715720
g.pkg.Resources[resourceTok] = resourceSpec
716721

717722
// Generate the function to get this resource.
718723
functionTok := fmt.Sprintf(`%s:%s:get%s`, g.pkg.Name, module, resource.typeName)
719-
if g.versioning.ShouldInclude(prov, g.apiVersion, resource.typeName, functionTok) {
724+
if g.versioning.ShouldInclude(g.provider, g.apiVersion, resource.typeName, functionTok) {
720725
var readOp *spec.Operation
721726
switch {
722727
case resource.PathItemList != nil:
@@ -743,7 +748,7 @@ func (g *packageGenerator) genResourceVariant(prov string, apiSpec *openapi.Reso
743748

744749
if path.Get != nil && responseFunction != nil {
745750
functionSpec := pschema.FunctionSpec{
746-
Description: g.formatFunctionDescription(readOp, resourceResponse, swagger.Info),
751+
Description: g.formatFunctionDescription(readOp, resource.typeName, resourceResponse, swagger.Info),
747752
DeprecationMessage: resource.deprecationMessage,
748753
Inputs: &pschema.ObjectTypeSpec{
749754
Description: requestFunction.description,
@@ -801,19 +806,19 @@ func (g *packageGenerator) genResourceVariant(prov string, apiSpec *openapi.Reso
801806
return nil
802807
}
803808

804-
func (g *packageGenerator) generateAliases(prov string, resource *resourceVariant, typeNameAliases ...string) []pschema.AliasSpec {
809+
func (g *packageGenerator) generateAliases(resource *resourceVariant, typeNameAliases ...string) []pschema.AliasSpec {
805810
var aliases []pschema.AliasSpec
806811

807812
for _, alias := range typeNameAliases {
808-
aliases = append(aliases, g.makeTypeAlias(prov, alias, g.apiVersion))
813+
aliases = append(aliases, g.makeTypeAlias(alias, g.apiVersion))
809814
}
810815

811816
// Add an alias for each API version that has the same path in it.
812817
for _, version := range resource.CompatibleVersions {
813-
aliases = append(aliases, g.makeTypeAlias(prov, resource.typeName, version))
818+
aliases = append(aliases, g.makeTypeAlias(resource.typeName, version))
814819

815820
for _, alias := range typeNameAliases {
816-
aliases = append(aliases, g.makeTypeAlias(prov, alias, version))
821+
aliases = append(aliases, g.makeTypeAlias(alias, version))
817822
}
818823
}
819824

@@ -877,23 +882,23 @@ func (g *packageGenerator) generateExampleReferences(resourceTok string, path *s
877882

878883
// genPostFunctions defines functions for list* (listKeys, listSecrets, etc.)
879884
// and get* (getFullUrl, getBastionShareableLink, etc.) POST endpoints.
880-
func (g *packageGenerator) genPostFunctions(prov, typeName, path string, pathItem *spec.PathItem, swagger *openapi.Spec) {
881-
module := g.providerToModule(prov)
885+
func (g *packageGenerator) genPostFunctions(typeName, path string, pathItem *spec.PathItem, swagger *openapi.Spec) {
886+
module := g.moduleName()
882887
gen := moduleGenerator{
883888
pkg: g.pkg,
884889
metadata: g.metadata,
885890
module: module,
886891
resourceToken: fmt.Sprintf(`%s:%s:%s`, g.pkg.Name, module, typeName),
887-
prov: prov,
892+
prov: g.provider,
888893
resourceName: typeName,
889894
visitedTypes: make(map[string]bool),
890895
caseSensitiveTypes: g.caseSensitiveTypes,
891896
inlineTypes: map[*openapi.ReferenceContext]codegen.StringSet{},
892897
}
893898

894899
// Generate the function to get this resource.
895-
functionTok := fmt.Sprintf(`%s:%s:%s`, g.pkg.Name, module, typeName)
896-
if !g.versioning.ShouldInclude(prov, g.apiVersion, typeName, functionTok) {
900+
functionTok := g.generateTok(typeName, g.apiVersion)
901+
if !g.shouldInclude(typeName, functionTok, g.apiVersion) {
897902
return
898903
}
899904

@@ -915,7 +920,7 @@ func (g *packageGenerator) genPostFunctions(prov, typeName, path string, pathIte
915920
}
916921

917922
functionSpec := pschema.FunctionSpec{
918-
Description: g.formatFunctionDescription(pathItem.Post, response, swagger.Info),
923+
Description: g.formatFunctionDescription(pathItem.Post, typeName, response, swagger.Info),
919924
Inputs: &pschema.ObjectTypeSpec{
920925
Description: request.description,
921926
Type: "object",
@@ -940,37 +945,68 @@ func (g *packageGenerator) genPostFunctions(prov, typeName, path string, pathIte
940945
g.metadata.Invokes[functionTok] = f
941946
}
942947

943-
// providerToModule produces the module name from the provider name and the API version (e.g. (`Compute`, `2020-07-01` => `compute/v20200701`).
944-
func (g *packageGenerator) providerToModule(prov string) string {
945-
return providerApiToModule(prov, g.apiVersion)
948+
// moduleName produces the module name from the provider name and the API version (e.g. (`Compute`, `2020-07-01` => `compute/v20200701`).
949+
func (g *packageGenerator) moduleName() string {
950+
return g.providerApiToModule(g.apiVersion)
946951
}
947-
func providerApiToModule(prov, apiVersion string) string {
952+
953+
func (g *packageGenerator) providerApiToModule(apiVersion string) string {
948954
if apiVersion == "" {
949-
return strings.ToLower(prov)
955+
return strings.ToLower(g.provider)
950956
}
951-
return fmt.Sprintf("%s/%s", strings.ToLower(prov), apiVersion)
957+
return fmt.Sprintf("%s/%s", strings.ToLower(g.provider), apiVersion)
958+
}
959+
960+
func (g *packageGenerator) generateTok(typeName string, apiVersion string) string {
961+
return fmt.Sprintf(`%s:%s:%s`, g.pkg.Name, g.providerApiToModule(apiVersion), typeName)
962+
}
963+
964+
func (g *packageGenerator) shouldInclude(typeName, tok, version string) bool {
965+
return g.versioning.ShouldInclude(g.provider, version, typeName, tok)
952966
}
953967

954-
func (g *packageGenerator) formatFunctionDescription(op *spec.Operation, response *propertyBag, info *spec.Info) string {
968+
func (g *packageGenerator) formatFunctionDescription(op *spec.Operation, typeName string, response *propertyBag, info *spec.Info) string {
955969
desc := response.description
956970
if op.Description != "" {
957971
desc = op.Description
958972
}
959-
return g.formatDescription(desc, info, nil, nil)
973+
return g.formatDescription(desc, typeName, info.Version, "", nil)
960974
}
961975

962-
func (g *packageGenerator) formatDescription(desc string, info *spec.Info, resourceSpec *openapi.ResourceSpec, additionalDocs *string) string {
963-
description := desc
976+
func (g *packageGenerator) formatDescription(desc string, typeName string, defaultVersion, previousDefaultVersion string, additionalDocs *string) string {
977+
var b strings.Builder
978+
b.WriteString(desc)
979+
964980
if g.apiVersion == "" {
965-
description = fmt.Sprintf("%s\nAzure REST API version: %s.", description, info.Version)
966-
}
967-
if resourceSpec != nil && resourceSpec.PreviousVersion != "" {
968-
description = fmt.Sprintf("%s Prior API version in Azure Native 1.x: %s", description, resourceSpec.PreviousVersion)
981+
fmt.Fprintf(&b, "\nAzure REST API version: %s.", defaultVersion)
982+
if previousDefaultVersion != "" {
983+
fmt.Fprintf(&b, " Prior API version in Azure Native 1.x: %s.", previousDefaultVersion)
984+
}
985+
986+
// List other available API versions, if any.
987+
allVersions := g.versioning.GetAllVersions(g.provider, typeName)
988+
includedVersions := []openapi.ApiVersion{}
989+
for _, v := range allVersions {
990+
// Don't list the default version twice.
991+
if v == defaultVersion {
992+
continue
993+
}
994+
tok := g.generateTok(typeName, openapi.ApiToSdkVersion(v))
995+
if g.shouldInclude(typeName, tok, v) {
996+
includedVersions = append(includedVersions, v)
997+
}
998+
}
999+
1000+
if len(includedVersions) > 0 {
1001+
fmt.Fprintf(&b, "\n\nOther available API versions: %s.", strings.Join(includedVersions, ", "))
1002+
}
9691003
}
1004+
9701005
if additionalDocs != nil {
971-
description = fmt.Sprintf("%s\n\n%s", description, *additionalDocs)
1006+
fmt.Fprintf(&b, "\n\n%s", *additionalDocs)
9721007
}
973-
return description
1008+
1009+
return b.String()
9741010
}
9751011

9761012
func (g *packageGenerator) getAsyncStyle(op *spec.Operation) string {

provider/pkg/gen/schema_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ func TestTypeAliasFormatting(t *testing.T) {
1616
generator := packageGenerator{
1717
pkg: &pschema.PackageSpec{Name: "azure-native"},
1818
apiVersion: "v20220222",
19+
provider: "Compute",
1920
}
2021

21-
actual := generator.makeTypeAlias("Compute", "VirtualMachine", "v18851225")
22+
actual := generator.makeTypeAlias("VirtualMachine", "v18851225")
2223
assert.NotNil(t, actual)
2324
assert.Equal(t, "azure-native:compute/v18851225:VirtualMachine", *actual.Type)
2425

25-
actual = generator.makeTypeAlias("Compute", "VirtualMachine", "")
26+
actual = generator.makeTypeAlias("VirtualMachine", "")
2627
assert.NotNil(t, actual)
2728
assert.Equal(t, "azure-native:compute:VirtualMachine", *actual.Type)
2829
}
@@ -42,11 +43,16 @@ func (v versioningStub) GetDeprecation(token string) (ResourceDeprecation, bool)
4243
return ResourceDeprecation{}, false
4344
}
4445

46+
func (v versioningStub) GetAllVersions(provider, resource string) []string {
47+
return []string{}
48+
}
49+
4550
func TestAliases(t *testing.T) {
4651
generator := packageGenerator{
4752
pkg: &pschema.PackageSpec{Name: "azure-native"},
4853
apiVersion: "v20220222",
4954
versioning: versioningStub{},
55+
provider: "Insights",
5056
}
5157

5258
resource := &resourceVariant{
@@ -56,7 +62,7 @@ func TestAliases(t *testing.T) {
5662
typeName: "PrivateLinkForAzureAd",
5763
}
5864

59-
aliases := generator.generateAliases("Insights", resource, "privateLinkForAzureAd")
65+
aliases := generator.generateAliases(resource, "privateLinkForAzureAd")
6066
actual := codegen.NewStringSet()
6167
for _, alias := range aliases {
6268
actual.Add(*alias.Type)

provider/pkg/openapi/versioner.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,23 @@ func calculatePathVersions(versionMap ProviderVersions) map[string]codegen.Strin
7474
return pathVersions
7575
}
7676

77+
// 2022-02-02-preview -> v20220202preview
7778
func ApiToSdkVersion(apiVersion ApiVersion) SdkVersion {
7879
return "v" + strings.ReplaceAll(apiVersion, "-", "")
7980
}
8081

82+
// v20220202preview -> 2022-02-02-preview
83+
func SdkToApiVersion(v SdkVersion) (ApiVersion, error) {
84+
if !strings.HasPrefix(v, "v") || len(v) < len("v20220202") || len(v) > len("v20220202preview") {
85+
return "", fmt.Errorf("invalid sdk version: %s", v)
86+
}
87+
res := v[1:5] + "-" + v[5:7] + "-" + v[7:9]
88+
if strings.HasSuffix(v, "preview") {
89+
res += "-preview"
90+
}
91+
return res, nil
92+
}
93+
8194
// RemovableResources represents removable resources mapped to the resource that can replace them since the two are
8295
// schema-compatible. Both are represented as fully qualified names like azure-native:azuread/v20210301:DomainService.
8396
type RemovableResources map[string]string

provider/pkg/versioning/gen.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ func (v VersionMetadata) GetDeprecation(token string) (gen.ResourceDeprecation,
7070
return gen.ResourceDeprecation{}, false
7171
}
7272

73+
func (v VersionMetadata) GetAllVersions(provider openapi.ProviderName, resource openapi.ResourceName) []openapi.ApiVersion {
74+
return v.AllResourceVersionsByResource[provider][resource]
75+
}
76+
7377
func LoadVersionMetadata(rootDir string, providers openapi.AzureProviders, majorVersion int) (VersionMetadata, error) {
7478
versionSources, err := ReadVersionSources(rootDir, majorVersion)
7579
if err != nil {

sdk/dotnet/AVS/Addon.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ namespace Pulumi.AzureNative.AVS
1111
{
1212
/// <summary>
1313
/// An addon resource
14-
/// Azure REST API version: 2022-05-01. Prior API version in Azure Native 1.x: 2020-07-17-preview
14+
/// Azure REST API version: 2022-05-01. Prior API version in Azure Native 1.x: 2020-07-17-preview.
15+
///
16+
/// Other available API versions: 2021-01-01-preview, 2023-03-01.
1517
/// </summary>
1618
[AzureNativeResourceType("azure-native:avs:Addon")]
1719
public partial class Addon : global::Pulumi.CustomResource

0 commit comments

Comments
 (0)