diff --git a/internal/librariangen/module/module.go b/internal/librariangen/module/module.go index 4de19ba96611..6e36dcb9ecfe 100644 --- a/internal/librariangen/module/module.go +++ b/internal/librariangen/module/module.go @@ -74,7 +74,8 @@ func UpdateSnippetsMetadata(lib *request.Library, sourceDir string, destDir stri version := lib.Version slog.Debug("librariangen: updating snippets metadata") - snpDir := filepath.Join("internal", "generated", "snippets", moduleName) + sharedSnpDir := filepath.Join("internal", "generated", "snippets", moduleName) + snippetDir := filepath.Join(moduleName, "examples") for _, api := range lib.APIs { apiConfig := moduleConfig.GetAPIConfig(api.Path) @@ -82,45 +83,46 @@ func UpdateSnippetsMetadata(lib *request.Library, sourceDir string, destDir stri if err != nil { return err } - snippetFile := "snippet_metadata." + apiConfig.GetProtoPackage() + ".json" - path := filepath.Join(snpDir, clientDirName, snippetFile) - slog.Info("librariangen: updating snippet metadata file", "path", path) - read, err := os.ReadFile(filepath.Join(sourceDir, path)) - if err != nil { - // If the snippet metadata doesn't exist, that's probably because this API path - // is proto-only (so the GAPIC generator hasn't run). Continue to the next API path. - if errors.Is(err, os.ErrNotExist) { - slog.Info("librariangen: snippet metadata file not found; assuming proto-only package", "path", path) - continue - } - return err - } - - content := string(read) - var newContent string - var oldVersion string - - if strings.Contains(content, "$VERSION") { - newContent = strings.Replace(content, "$VERSION", version, 1) - oldVersion = "$VERSION" - } else if foundVersion := versionRegexp.FindString(content); foundVersion != "" { - newContent = strings.Replace(content, foundVersion, version, 1) - oldVersion = foundVersion - } - - if newContent == "" { - return fmt.Errorf("librariangen: no version number or placeholder found in '%s'", snippetFile) + paths := []string{ + filepath.Join(sharedSnpDir, clientDirName, snippetFile), + filepath.Join(snippetDir, clientDirName, snippetFile), } - - destPath := filepath.Join(destDir, path) - slog.Info("librariangen: updating version in snippets metadata file", "destPath", path, "old", oldVersion, "new", version) - if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil { - return fmt.Errorf("librariangen: creating directory for snippet file: %w", err) + var found bool + for _, path := range paths { + slog.Info("librariangen: updating snippet metadata file", "path", path) + read, err := os.ReadFile(filepath.Join(sourceDir, path)) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + continue + } + return err + } + found = true + content := string(read) + var newContent string + var oldVersion string + if strings.Contains(content, "$VERSION") { + newContent = strings.Replace(content, "$VERSION", version, 1) + oldVersion = "$VERSION" + } else if foundVersion := versionRegexp.FindString(content); foundVersion != "" { + newContent = strings.Replace(content, foundVersion, version, 1) + oldVersion = foundVersion + } + if newContent == "" { + return fmt.Errorf("librariangen: no version number or placeholder found in '%s'", path) + } + destPath := filepath.Join(destDir, path) + slog.Info("librariangen: updating version in snippets metadata file", "destPath", destPath, "old", oldVersion, "new", version) + if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil { + return fmt.Errorf("librariangen: creating directory for snippet file: %w", err) + } + if err := os.WriteFile(destPath, []byte(newContent), 0644); err != nil { + return err + } } - err = os.WriteFile(destPath, []byte(newContent), 0644) - if err != nil { - return err + if !found { + slog.Info("librariangen: snippet metadata files not found; assuming proto-only package", "paths", paths) } } return nil diff --git a/internal/librariangen/module/module_test.go b/internal/librariangen/module/module_test.go index e4ad2933befa..0ee04115b265 100644 --- a/internal/librariangen/module/module_test.go +++ b/internal/librariangen/module/module_test.go @@ -104,6 +104,62 @@ func TestUpdateSnippetsMetadata(t *testing.T) { "internal/generated/snippets/secretmanager/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"2.3.4"}}`, }, }, + { + name: "version placeholder in library output", + lib: &request.Library{ + ID: "secretmanager", + Version: "2.3.4", + APIs: []request.API{ + { + Path: "google/cloud/secretmanager/v1", + }, + }, + }, + moduleConfig: &config.ModuleConfig{ + Name: "secretmanager", + APIs: []*config.APIConfig{ + { + Path: "google/cloud/secretmanager/v1", + ProtoPackage: "google.cloud.secretmanager.v1", + }, + }, + }, + files: map[string]string{ + "secretmanager/examples/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"$VERSION"}}`, + }, + want: map[string]string{ + "secretmanager/examples/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"2.3.4"}}`, + }, + }, + { + name: "version placeholder in two directories", + lib: &request.Library{ + ID: "secretmanager", + Version: "2.3.4", + APIs: []request.API{ + { + Path: "google/cloud/secretmanager/v1", + }, + }, + }, + moduleConfig: &config.ModuleConfig{ + Name: "secretmanager", + APIs: []*config.APIConfig{ + { + Path: "google/cloud/secretmanager/v1", + ProtoPackage: "google.cloud.secretmanager.v1", + }, + }, + }, + files: map[string]string{ + "internal/generated/snippets/secretmanager/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"$VERSION"}}`, + "secretmanager/examples/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"$VERSION"}}`, + }, + want: map[string]string{ + "internal/generated/snippets/secretmanager/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"2.3.4"}}`, + "secretmanager/examples/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"2.3.4"}}`, + }, + }, { name: "existing version", lib: &request.Library{ @@ -207,6 +263,32 @@ func TestUpdateSnippetsMetadata(t *testing.T) { want: map[string]string{}, wantErr: true, }, + { + name: "no version string in library output", + lib: &request.Library{ + ID: "secretmanager", + Version: "2.3.4", + APIs: []request.API{ + { + Path: "google/cloud/secretmanager/v1", + }, + }, + }, + moduleConfig: &config.ModuleConfig{ + Name: "secretmanager", + APIs: []*config.APIConfig{ + { + Path: "google/cloud/secretmanager/v1", + ProtoPackage: "google.cloud.secretmanager.v1", + }, + }, + }, + files: map[string]string{ + "secretmanager/examples/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{}}`, + }, + want: map[string]string{}, + wantErr: true, + }, { name: "multiple api versions and a sub-API", lib: &request.Library{ @@ -252,6 +334,57 @@ func TestUpdateSnippetsMetadata(t *testing.T) { "internal/generated/snippets/secretmanager/subapi/apiv1/snippet_metadata.google.cloud.secretmanager.subapi.v1.json": `{"clientLibrary":{"version":"1.0.0"}}`, }, }, + { + name: "multiple api versions and a sub-API in two snippet directories", + lib: &request.Library{ + ID: "secretmanager", + Version: "1.0.0", + APIs: []request.API{ + { + Path: "google/cloud/secretmanager/v1", + }, + { + Path: "google/cloud/secretmanager/v2", + }, + { + Path: "google/cloud/secretmanager/subapi/v1", + }, + }, + }, + moduleConfig: &config.ModuleConfig{ + Name: "secretmanager", + APIs: []*config.APIConfig{ + { + Path: "google/cloud/secretmanager/v1", + ProtoPackage: "google.cloud.secretmanager.v1", + }, + { + Path: "google/cloud/secretmanager/v2", + ProtoPackage: "google.cloud.secretmanager.v2", + }, + { + Path: "google/cloud/secretmanager/subapi/v1", + ProtoPackage: "google.cloud.secretmanager.subapi.v1", + }, + }, + }, + files: map[string]string{ + "internal/generated/snippets/secretmanager/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"$VERSION"}}`, + "internal/generated/snippets/secretmanager/apiv2/snippet_metadata.google.cloud.secretmanager.v2.json": `{"clientLibrary":{"version":"0.1.0"}}`, + "internal/generated/snippets/secretmanager/subapi/apiv1/snippet_metadata.google.cloud.secretmanager.subapi.v1.json": `{"clientLibrary":{"version":"0.1.0"}}`, + "secretmanager/examples/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"$VERSION"}}`, + "secretmanager/examples/apiv2/snippet_metadata.google.cloud.secretmanager.v2.json": `{"clientLibrary":{"version":"0.1.0"}}`, + "secretmanager/examples/subapi/apiv1/snippet_metadata.google.cloud.secretmanager.subapi.v1.json": `{"clientLibrary":{"version":"0.1.0"}}`, + }, + want: map[string]string{ + "internal/generated/snippets/secretmanager/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"1.0.0"}}`, + "internal/generated/snippets/secretmanager/apiv2/snippet_metadata.google.cloud.secretmanager.v2.json": `{"clientLibrary":{"version":"1.0.0"}}`, + "internal/generated/snippets/secretmanager/subapi/apiv1/snippet_metadata.google.cloud.secretmanager.subapi.v1.json": `{"clientLibrary":{"version":"1.0.0"}}`, + "secretmanager/examples/apiv1/snippet_metadata.google.cloud.secretmanager.v1.json": `{"clientLibrary":{"version":"1.0.0"}}`, + "secretmanager/examples/apiv2/snippet_metadata.google.cloud.secretmanager.v2.json": `{"clientLibrary":{"version":"1.0.0"}}`, + "secretmanager/examples/subapi/apiv1/snippet_metadata.google.cloud.secretmanager.subapi.v1.json": `{"clientLibrary":{"version":"1.0.0"}}`, + }, + }, } for _, tc := range testdata {