diff --git a/internal/librarian/library.go b/internal/librarian/library.go index 6e506719d3..dd64dc5d03 100644 --- a/internal/librarian/library.go +++ b/internal/librarian/library.go @@ -22,6 +22,7 @@ import ( "github.com/googleapis/librarian/internal/config" "github.com/googleapis/librarian/internal/librarian/golang" "github.com/googleapis/librarian/internal/librarian/java" + "github.com/googleapis/librarian/internal/librarian/nodejs" "github.com/googleapis/librarian/internal/librarian/python" "github.com/googleapis/librarian/internal/librarian/rust" "github.com/googleapis/librarian/internal/librarian/swift" @@ -193,16 +194,16 @@ func mergePackageDependencies(defaults, lib []*config.RustPackageDependency) []* return result } -// isVeneer reports whether the library has handwritten code wrapping generated -// code. -func isVeneer(language string, lib *config.Library) bool { +// isMixedLibrary reports whether the library is composed of both handwritten +// and librarian-generated code. +func isMixedLibrary(language string, lib *config.Library) bool { switch language { case config.LanguageRust: - return rust.IsVeneer(lib) + return rust.IsMixedLibrary(lib) case config.LanguageSwift: - return swift.IsModule(lib) + return swift.IsMixedLibrary(lib) case config.LanguageNodejs: - return lib.Output != "" && len(lib.APIs) == 0 + return nodejs.IsMixedLibrary(lib) default: return false } @@ -215,8 +216,8 @@ func libraryOutput(language string, lib *config.Library, defaults *config.Defaul if lib.Output != "" { return lib.Output } - if isVeneer(language, lib) { - // Veneers require explicit output, so return empty if not set. + if isMixedLibrary(language, lib) { + // Mixed or non-generated libraries require explicit output, so return empty if not set. return "" } apiPath := deriveAPIPath(language, lib.Name) @@ -232,7 +233,7 @@ func libraryOutput(language string, lib *config.Library, defaults *config.Defaul // applyDefaults applies language-specific derivations and fills defaults. func applyDefaults(language string, lib *config.Library, defaults *config.Default) (*config.Library, error) { - if !isVeneer(language, lib) { + if !isMixedLibrary(language, lib) { if len(lib.APIs) == 0 && canDeriveAPIPath(language) { // Do not derive API path for some languages because the library // name doesn't contain all the required info. @@ -245,8 +246,8 @@ func applyDefaults(language string, lib *config.Library, defaults *config.Defaul } } if lib.Output == "" { - if isVeneer(language, lib) { - return nil, fmt.Errorf("veneer %q requires an explicit output path", lib.Name) + if isMixedLibrary(language, lib) { + return nil, fmt.Errorf("library %q requires an explicit output path", lib.Name) } var apiPath string if len(lib.APIs) > 0 { diff --git a/internal/librarian/library_test.go b/internal/librarian/library_test.go index 89f645e847..8d96388e06 100644 --- a/internal/librarian/library_test.go +++ b/internal/librarian/library_test.go @@ -644,7 +644,7 @@ func TestCanDeriveAPIPath(t *testing.T) { } } -func TestIsVeneer(t *testing.T) { +func TestIsMixedLibrary(t *testing.T) { for _, test := range []struct { name string language string @@ -652,7 +652,7 @@ func TestIsVeneer(t *testing.T) { want bool }{ { - name: "rust is veneer", + name: "rust is mixed library", language: config.LanguageRust, lib: &config.Library{ Rust: &config.RustCrate{ @@ -662,13 +662,13 @@ func TestIsVeneer(t *testing.T) { want: true, }, { - name: "rust is not veneer", + name: "rust is not mixed library", language: config.LanguageRust, lib: &config.Library{}, want: false, }, { - name: "nodejs handwritten tool is veneer", + name: "nodejs handwritten tool is mixed library", language: config.LanguageNodejs, lib: &config.Library{ Output: "packages/typeless-sample-bot", @@ -677,7 +677,7 @@ func TestIsVeneer(t *testing.T) { want: true, }, { - name: "nodejs gapic lib is not veneer", + name: "nodejs gapic lib is not mixed library", language: config.LanguageNodejs, lib: &config.Library{ Output: "packages/gapic-lib", @@ -687,8 +687,8 @@ func TestIsVeneer(t *testing.T) { }, } { t.Run(test.name, func(t *testing.T) { - if got := isVeneer(test.language, test.lib); got != test.want { - t.Errorf("isVeneer(%q, %+v) = %v, want %v", test.language, test.lib, got, test.want) + if got := isMixedLibrary(test.language, test.lib); got != test.want { + t.Errorf("isMixedLibrary(%q, %+v) = %v, want %v", test.language, test.lib, got, test.want) } }) } diff --git a/internal/librarian/nodejs/generate.go b/internal/librarian/nodejs/generate.go index 3a0b9a1450..12bc9e5d82 100644 --- a/internal/librarian/nodejs/generate.go +++ b/internal/librarian/nodejs/generate.go @@ -41,6 +41,12 @@ const ( commonProtos = "google/cloud/common_resources.proto" ) +// IsMixedLibrary reports whether the library has handwritten code wrapping +// generated or librarian-managed code. +func IsMixedLibrary(lib *config.Library) bool { + return lib.Output != "" && len(lib.APIs) == 0 +} + // Generate generates a Node.js client library. func Generate(ctx context.Context, cfg *config.Config, library *config.Library, srcs *sources.Sources) error { googleapisDir := srcs.Googleapis diff --git a/internal/librarian/nodejs/generate_test.go b/internal/librarian/nodejs/generate_test.go index 59946778be..a875b98f48 100644 --- a/internal/librarian/nodejs/generate_test.go +++ b/internal/librarian/nodejs/generate_test.go @@ -35,6 +35,45 @@ import ( const googleapisDir = "../../testdata/googleapis" +func TestIsMixedLibrary(t *testing.T) { + for _, test := range []struct { + name string + lib *config.Library + want bool + }{ + { + name: "mixed library case", + lib: &config.Library{ + Output: "packages/typeless-sample-bot", + APIs: nil, + }, + want: true, + }, + { + name: "standard gapic lib", + lib: &config.Library{ + Output: "packages/gapic-lib", + APIs: []*config.API{{Path: "google/example/v1"}}, + }, + want: false, + }, + { + name: "no output set", + lib: &config.Library{ + Output: "", + APIs: nil, + }, + want: false, + }, + } { + t.Run(test.name, func(t *testing.T) { + if got := IsMixedLibrary(test.lib); got != test.want { + t.Errorf("IsMixedLibrary() = %v, want %v", got, test.want) + } + }) + } +} + func TestDerivePackageName(t *testing.T) { for _, test := range []struct { name string diff --git a/internal/librarian/rust/generate.go b/internal/librarian/rust/generate.go index 2fa1018846..0463b572a9 100644 --- a/internal/librarian/rust/generate.go +++ b/internal/librarian/rust/generate.go @@ -33,21 +33,21 @@ import ( "github.com/googleapis/librarian/internal/sources" ) -// IsVeneer reports whether the library has handwritten code wrapping generated -// code. +// IsMixedLibrary reports whether the library has handwritten code wrapping +// generated code. // -// A library is a veneer when it has Rust module configuration. A library with -// no APIs and an explicit output is a veneer if its derived API path is not -// listed in sdk.yaml; libraries whose derived path appears in sdk.yaml are -// generated libraries whose APIs have not been populated yet (e.g. -// google-cloud-oslogin-common), not veneers. -func IsVeneer(lib *config.Library) bool { +// A library is a mixed library when it has Rust module configuration. A library +// with no APIs and an explicit output is a mixed library if its derived API +// path is not listed in sdk.yaml; libraries whose derived path appears in +// sdk.yaml are generated libraries whose APIs have not yet been populated +// (e.g. google-cloud-oslogin-common), not mixed libraries. +func IsMixedLibrary(lib *config.Library) bool { if lib.Rust != nil && len(lib.Rust.Modules) > 0 { return true } if len(lib.APIs) == 0 && lib.Output != "" { // If the derived API path is in sdk.yaml, this is a generated - // library whose APIs have not been populated yet, not a veneer. + // library whose APIs have not yet been populated, not a mixed library. if serviceconfig.HasAPIPath(DeriveAPIPath(lib.Name), config.LanguageRust) { return false } @@ -58,7 +58,7 @@ func IsVeneer(lib *config.Library) bool { // Generate generates a Rust client library. func Generate(ctx context.Context, cfg *config.Config, library *config.Library, sources *sources.Sources) error { - if IsVeneer(library) { + if IsMixedLibrary(library) { return generateVeneer(ctx, library, sources) } if len(library.APIs) != 1 { @@ -168,7 +168,7 @@ func generateVeneer(ctx context.Context, library *config.Library, sources *sourc // Keep returns the list of files to preserve when cleaning the output directory. func Keep(library *config.Library) ([]string, error) { - if !IsVeneer(library) { + if !IsMixedLibrary(library) { return library.Keep, nil } // For veneers, keep all files outside module output directories. We walk diff --git a/internal/librarian/rust/generate_test.go b/internal/librarian/rust/generate_test.go index d05b3734a2..faba30c5ca 100644 --- a/internal/librarian/rust/generate_test.go +++ b/internal/librarian/rust/generate_test.go @@ -87,7 +87,7 @@ func TestGenerateVeneer(t *testing.T) { } } -func TestIsVeneer(t *testing.T) { +func TestIsMixedLibrary(t *testing.T) { for _, test := range []struct { name string lib *config.Library @@ -158,8 +158,8 @@ func TestIsVeneer(t *testing.T) { }, } { t.Run(test.name, func(t *testing.T) { - if got := IsVeneer(test.lib); got != test.want { - t.Errorf("IsVeneer() = %v, want %v", got, test.want) + if got := IsMixedLibrary(test.lib); got != test.want { + t.Errorf("IsMixedLibrary() = %v, want %v", got, test.want) } }) } diff --git a/internal/librarian/swift/generate.go b/internal/librarian/swift/generate.go index d58fd73950..2e754acead 100644 --- a/internal/librarian/swift/generate.go +++ b/internal/librarian/swift/generate.go @@ -31,7 +31,7 @@ import ( // Generate generates a Swift client library. func Generate(ctx context.Context, cfg *config.Config, library *config.Library, src *sources.Sources) error { - if IsModule(library) { + if IsMixedLibrary(library) { return generateModule(ctx, library, src) } if len(library.APIs) != 1 { diff --git a/internal/librarian/swift/is_module.go b/internal/librarian/swift/is_mixed_library.go similarity index 86% rename from internal/librarian/swift/is_module.go rename to internal/librarian/swift/is_mixed_library.go index b46064f919..330c628374 100644 --- a/internal/librarian/swift/is_module.go +++ b/internal/librarian/swift/is_mixed_library.go @@ -16,10 +16,10 @@ package swift import "github.com/googleapis/librarian/internal/config" -// IsModule reports whether the library has handwritten code wrapping generated code. +// IsMixedLibrary reports whether the library has handwritten code wrapping generated code. // // At the moment, only libraries created for test protos are modules. Such libraries do not have an API and have an // explicit output directory. -func IsModule(lib *config.Library) bool { +func IsMixedLibrary(lib *config.Library) bool { return lib.Swift != nil && len(lib.Swift.Modules) > 0 } diff --git a/internal/librarian/swift/is_module_test.go b/internal/librarian/swift/is_mixed_library_test.go similarity index 78% rename from internal/librarian/swift/is_module_test.go rename to internal/librarian/swift/is_mixed_library_test.go index 23f60a4c4e..3e065d50dc 100644 --- a/internal/librarian/swift/is_module_test.go +++ b/internal/librarian/swift/is_mixed_library_test.go @@ -21,18 +21,18 @@ import ( "github.com/googleapis/librarian/internal/config" ) -func TestIsModule(t *testing.T) { +func TestIsMixedLibrary(t *testing.T) { for _, test := range []struct { name string lib *config.Library want bool }{ - {"module", &config.Library{Swift: &config.SwiftPackage{Modules: []*config.SwiftModule{{}}}}, true}, + {"mixed library", &config.Library{Swift: &config.SwiftPackage{Modules: []*config.SwiftModule{{}}}}, true}, {"nil swift", &config.Library{}, false}, - {"empty modules", &config.Library{Swift: &config.SwiftPackage{}}, false}, + {"fully generated library", &config.Library{Swift: &config.SwiftPackage{}}, false}, } { t.Run(test.name, func(t *testing.T) { - got := IsModule(test.lib) + got := IsMixedLibrary(test.lib) if diff := cmp.Diff(test.want, got); diff != "" { t.Errorf("mismatch (-want +got):\n%s", diff) } diff --git a/internal/librarian/tidy.go b/internal/librarian/tidy.go index 8192186416..6e4b961995 100644 --- a/internal/librarian/tidy.go +++ b/internal/librarian/tidy.go @@ -99,8 +99,9 @@ func tidyLibrary(cfg *config.Config, lib *config.Library) *config.Library { if lib.Output != "" && len(lib.APIs) == 1 && isDerivableOutput(cfg, lib) { lib.Output = "" } - if isVeneer(cfg.Language, lib) { - // Veneers are never generated, so ensure skip_generate is false. + if isMixedLibrary(cfg.Language, lib) { + // Mixed libraries with handwritten code or those that are fully handwritten + // are never generated, so ensure that skip_generate is false. lib.SkipGenerate = false } if len(lib.Roots) == 1 && lib.Roots[0] == "googleapis" {