Skip to content

Commit c538c3e

Browse files
authored
Merge branch 'main' into go-omit-snippets
2 parents dd64cbb + 9d47a48 commit c538c3e

File tree

5 files changed

+132
-40
lines changed

5 files changed

+132
-40
lines changed

internal/librarian/java/generate.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,9 @@ const (
3838
)
3939

4040
var (
41-
// errExtractVersion is returned when an API version cannot be extracted from its path.
42-
errExtractVersion = errors.New("failed to extract version")
43-
// errNoProtos is returned when no proto files are found in an API directory.
44-
errNoProtos = errors.New("no protos found")
41+
errExtractVersion = errors.New("failed to extract version")
42+
errNoProtos = errors.New("no protos found")
43+
errMonorepoVersion = fmt.Errorf("failed to find monorepo version for %q in config", rootLibrary)
4544
)
4645

4746
// Generate generates a Java client library.
@@ -65,16 +64,32 @@ func Generate(ctx context.Context, cfg *config.Config, library *config.Library,
6564
if err != nil {
6665
return fmt.Errorf("failed to generate .repo-metadata.json: %w", err)
6766
}
67+
68+
transports := make(map[string]serviceconfig.Transport)
6869
for _, api := range library.APIs {
70+
apiCfg, err := serviceconfig.Find(googleapisDir, api.Path, config.LanguageJava)
71+
if err != nil {
72+
return fmt.Errorf("failed to find api config for %s: %w", api.Path, err)
73+
}
74+
transports[api.Path] = apiCfg.Transport(config.LanguageJava)
6975
// metadata is needed for pom.xml generation in post process
70-
if err := generateAPI(ctx, cfg, api, library, googleapisDir, outdir, metadata); err != nil {
76+
if err := generateAPI(ctx, cfg, api, library, googleapisDir, outdir, metadata, apiCfg); err != nil {
7177
return fmt.Errorf("failed to generate api %q: %w", api.Path, err)
7278
}
7379
}
80+
81+
monorepoVersion, err := findMonorepoVersion(cfg)
82+
if err != nil {
83+
return err
84+
}
85+
if err := generatePomsIfMissing(library, outdir, monorepoVersion, metadata, transports); err != nil {
86+
return fmt.Errorf("failed to generate poms: %w", err)
87+
}
88+
7489
return nil
7590
}
7691

77-
func generateAPI(ctx context.Context, cfg *config.Config, api *config.API, library *config.Library, googleapisDir, outdir string, metadata *repoMetadata) error {
92+
func generateAPI(ctx context.Context, cfg *config.Config, api *config.API, library *config.Library, googleapisDir, outdir string, metadata *repoMetadata, apiCfg *serviceconfig.API) error {
7893
version := serviceconfig.ExtractVersion(api.Path)
7994
if version == "" {
8095
return fmt.Errorf("%s: %w", api.Path, errExtractVersion)
@@ -125,10 +140,6 @@ func generateAPI(ctx context.Context, cfg *config.Config, api *config.API, libra
125140
return fmt.Errorf("failed to generate proto: %w", err)
126141
}
127142
// 2. Generate gRPC service stubs (skipped if transport is rest).
128-
apiCfg, err := serviceconfig.Find(googleapisDir, api.Path, config.LanguageJava)
129-
if err != nil {
130-
return fmt.Errorf("failed to find api config: %w", err)
131-
}
132143
transport := apiCfg.Transport(config.LanguageJava)
133144
if transport != "rest" {
134145
if err := runProtoc(ctx, grpcProtocArgs(apiProtos, googleapisDir, grpcDir)); err != nil {

internal/librarian/java/generate_test.go

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,11 @@ func TestGenerateAPI(t *testing.T) {
389389
if err := os.MkdirAll(templatesDir, 0755); err != nil {
390390
t.Fatal(err)
391391
}
392-
err := generateAPI(
392+
apiCfg, err := serviceconfig.Find(googleapisDir, "google/cloud/secretmanager/v1", config.LanguageJava)
393+
if err != nil {
394+
t.Fatal(err)
395+
}
396+
err = generateAPI(
393397
t.Context(),
394398
cfg,
395399
&config.API{Path: "google/cloud/secretmanager/v1"},
@@ -400,6 +404,7 @@ func TestGenerateAPI(t *testing.T) {
400404
NamePretty: "Secret Manager",
401405
APIDescription: "Secret Manager API",
402406
},
407+
apiCfg,
403408
)
404409
if err != nil {
405410
t.Fatal(err)
@@ -453,10 +458,14 @@ func TestGenerateAPI_NoTools(t *testing.T) {
453458
if err := os.MkdirAll(templatesDir, 0755); err != nil {
454459
t.Fatal(err)
455460
}
456-
err := generateAPI(t.Context(), cfg, api, library, googleapisDir, outdir, &repoMetadata{
461+
apiCfg, err := serviceconfig.Find(googleapisDir, api.Path, config.LanguageJava)
462+
if err != nil {
463+
t.Fatal(err)
464+
}
465+
err = generateAPI(t.Context(), cfg, api, library, googleapisDir, outdir, &repoMetadata{
457466
NamePretty: "Secret Manager",
458467
APIDescription: "Secret Manager API",
459-
})
468+
}, apiCfg)
460469
if err != nil {
461470
t.Fatal(err)
462471
}
@@ -525,12 +534,46 @@ func TestGenerateLibrary_Error(t *testing.T) {
525534
},
526535
wantErr: syscall.ENOTDIR,
527536
},
537+
{
538+
name: "missing monorepo version",
539+
library: &config.Library{
540+
Name: "secretmanager",
541+
Output: t.TempDir(),
542+
APIs: []*config.API{
543+
{Path: "google/cloud/secretmanager/v1"},
544+
},
545+
},
546+
setup: func(t *testing.T, library *config.Library) {
547+
// Ensure output artifacts exist for postProcessAPI to succeed.
548+
for _, artifact := range []string{"google-cloud-secretmanager", "proto-google-cloud-secretmanager-v1", "grpc-google-cloud-secretmanager-v1", "google-cloud-secretmanager-bom"} {
549+
if err := os.MkdirAll(filepath.Join(library.Output, artifact), 0755); err != nil {
550+
t.Fatal(err)
551+
}
552+
}
553+
if err := os.WriteFile(filepath.Join(library.Output, "owlbot.py"), []byte("#!/usr/bin/env python3\npass"), 0755); err != nil {
554+
t.Fatal(err)
555+
}
556+
templatesDir := filepath.Join(filepath.Dir(library.Output), owlbotTemplatesRelPath)
557+
if err := os.MkdirAll(templatesDir, 0755); err != nil {
558+
t.Fatal(err)
559+
}
560+
},
561+
wantErr: errMonorepoVersion,
562+
},
528563
} {
529564
t.Run(test.name, func(t *testing.T) {
565+
// Temporarily mock runProtoc to avoid external tool requirements.
566+
oldRunProtoc := runProtoc
567+
defer func() { runProtoc = oldRunProtoc }()
568+
runProtoc = func(ctx context.Context, args []string) error { return nil }
569+
530570
if test.setup != nil {
531571
test.setup(t, test.library)
532572
}
533-
cfg := &config.Config{Language: "java"}
573+
cfg := &config.Config{
574+
Language: config.LanguageJava,
575+
Libraries: []*config.Library{test.library},
576+
}
534577
err := Generate(t.Context(), cfg, test.library, &sources.Sources{Googleapis: googleapisDir})
535578
if !errors.Is(err, test.wantErr) {
536579
t.Errorf("generate() error = %v, wantErr %v", err, test.wantErr)
@@ -539,6 +582,54 @@ func TestGenerateLibrary_Error(t *testing.T) {
539582
}
540583
}
541584

585+
func TestGenerate_Logic(t *testing.T) {
586+
// Tests the orchestration logic, temporarily mock runProtoc to avoid external tool requirements.
587+
oldRunProtoc := runProtoc
588+
defer func() { runProtoc = oldRunProtoc }()
589+
runProtoc = func(ctx context.Context, args []string) error { return nil }
590+
591+
outdir := t.TempDir()
592+
library := &config.Library{
593+
Name: "secretmanager",
594+
Version: "0.1.2",
595+
Output: outdir,
596+
APIs: []*config.API{
597+
{Path: "google/cloud/secretmanager/v1"},
598+
},
599+
}
600+
cfg := &config.Config{
601+
Language: config.LanguageJava,
602+
Repo: "googleapis/google-cloud-java",
603+
Libraries: []*config.Library{
604+
library,
605+
{Name: rootLibrary, Version: "1.2.3"},
606+
},
607+
}
608+
// Setup mandatory files for postProcessAPI and generatePomsIfMissing
609+
for _, artifact := range []string{"google-cloud-secretmanager", "proto-google-cloud-secretmanager-v1", "grpc-google-cloud-secretmanager-v1", "google-cloud-secretmanager-bom"} {
610+
if err := os.MkdirAll(filepath.Join(outdir, artifact), 0755); err != nil {
611+
t.Fatal(err)
612+
}
613+
}
614+
if err := os.WriteFile(filepath.Join(outdir, "owlbot.py"), []byte("#!/usr/bin/env python3\npass"), 0755); err != nil {
615+
t.Fatal(err)
616+
}
617+
templatesDir := filepath.Join(filepath.Dir(outdir), owlbotTemplatesRelPath)
618+
if err := os.MkdirAll(templatesDir, 0755); err != nil {
619+
t.Fatal(err)
620+
}
621+
622+
err := Generate(t.Context(), cfg, library, &sources.Sources{Googleapis: googleapisDir})
623+
if err != nil {
624+
t.Fatal(err)
625+
}
626+
627+
// Verify that parent pom was generated in the library root.
628+
if _, err := os.Stat(filepath.Join(outdir, "pom.xml")); err != nil {
629+
t.Errorf("expected parent pom.xml to exist: %v", err)
630+
}
631+
}
632+
542633
func TestFormat_Success(t *testing.T) {
543634
testhelper.RequireCommand(t, "google-java-format")
544635
for _, test := range []struct {

internal/librarian/java/pom.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ type javaModule struct {
7878
}
7979

8080
// generatePomsIfMissing generates missing proto-*, grpc-*, and client POMs.
81-
func generatePomsIfMissing(library *config.Library, libraryDir, googleapisDir, monorepoVersion string, metadata *repoMetadata) error {
82-
modules, err := collectModules(library, libraryDir, googleapisDir, monorepoVersion, metadata)
81+
func generatePomsIfMissing(library *config.Library, libraryDir, monorepoVersion string, metadata *repoMetadata, transports map[string]serviceconfig.Transport) error {
82+
modules, err := collectModules(library, libraryDir, monorepoVersion, metadata, transports)
8383
if err != nil {
8484
return err
8585
}
@@ -101,7 +101,7 @@ func generatePomsIfMissing(library *config.Library, libraryDir, googleapisDir, m
101101
// All expected modules are collected (even if they exist) because the client
102102
// module's POM requires a full list of all proto and gRPC dependencies
103103
// to ensure its dependency list is fully synchronized.
104-
func collectModules(library *config.Library, libraryDir, googleapisDir, monorepoVersion string, metadata *repoMetadata) ([]javaModule, error) {
104+
func collectModules(library *config.Library, libraryDir, monorepoVersion string, metadata *repoMetadata, transports map[string]serviceconfig.Transport) ([]javaModule, error) {
105105
distName := deriveDistributionName(library)
106106
parts := strings.SplitN(distName, ":", 2)
107107
if len(parts) != 2 {
@@ -121,12 +121,7 @@ func collectModules(library *config.Library, libraryDir, googleapisDir, monorepo
121121

122122
names := deriveModuleNames(gapicArtifactID, version)
123123

124-
apiCfg, err := serviceconfig.Find(googleapisDir, api.Path, config.LanguageJava)
125-
if err != nil {
126-
return nil, fmt.Errorf("failed to find api config for %s: %w", api.Path, err)
127-
}
128-
transport := apiCfg.Transport(config.LanguageJava)
129-
124+
transport := transports[api.Path]
130125
protoGrpcID := protoGroupID(gapicGroupID)
131126
data := grpcProtoPomData{
132127
Proto: coordinates{
@@ -284,7 +279,7 @@ func findMonorepoVersion(cfg *config.Config) (string, error) {
284279
return lib.Version, nil
285280
}
286281
}
287-
return "", fmt.Errorf("could not find monorepo version for %s in config", rootLibrary)
282+
return "", errMonorepoVersion
288283
}
289284

290285
// protoGroupID returns the Maven Group ID for the generated proto and gRPC

internal/librarian/java/pom_test.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/google/go-cmp/cmp"
2525
"github.com/googleapis/librarian/internal/config"
26+
"github.com/googleapis/librarian/internal/serviceconfig"
2627
)
2728

2829
// update is used to refresh the golden files in testdata/ when template
@@ -31,10 +32,6 @@ import (
3132
var update = flag.Bool("update", false, "update golden files")
3233

3334
func TestSyncPoms_Golden(t *testing.T) {
34-
googleapisDir, err := filepath.Abs("../../testdata/googleapis")
35-
if err != nil {
36-
t.Fatal(err)
37-
}
3835
testdataDir := filepath.Join("testdata", "syncpoms", "secretmanager-v1")
3936
library := &config.Library{
4037
Name: "secretmanager",
@@ -43,6 +40,10 @@ func TestSyncPoms_Golden(t *testing.T) {
4340
{Path: "google/cloud/secretmanager/v1"},
4441
},
4542
}
43+
apiPath := library.APIs[0].Path
44+
transports := map[string]serviceconfig.Transport{
45+
apiPath: serviceconfig.GRPC,
46+
}
4647
tmpDir := t.TempDir()
4748
// Pre-create the directories that generatePomsIfMissing expects to exist.
4849
protoArtifactID := "proto-google-cloud-secretmanager-v1"
@@ -58,7 +59,7 @@ func TestSyncPoms_Golden(t *testing.T) {
5859
NamePretty: "Secret Manager",
5960
APIDescription: "Stores sensitive data such as API keys, passwords, and certificates.\nProvides convenience while improving security.",
6061
}
61-
if err := generatePomsIfMissing(library, tmpDir, googleapisDir, "1.2.3", metadata); err != nil {
62+
if err := generatePomsIfMissing(library, tmpDir, "1.2.3", metadata, transports); err != nil {
6263
t.Fatal(err)
6364
}
6465
artifacts := []string{protoArtifactID, grpcArtifactID, gapicArtifactID, "google-cloud-secretmanager-bom", "google-cloud-secretmanager-parent"}
@@ -93,8 +94,9 @@ func TestSyncPoms_Golden(t *testing.T) {
9394

9495
func TestCollectModules_Error(t *testing.T) {
9596
for _, test := range []struct {
96-
name string
97-
library *config.Library
97+
name string
98+
library *config.Library
99+
transports map[string]serviceconfig.Transport
98100
}{
99101
{
100102
name: "invalid distribution name",
@@ -111,10 +113,11 @@ func TestCollectModules_Error(t *testing.T) {
111113
{Path: "google/ads/unrecognized/v1"},
112114
},
113115
},
116+
transports: map[string]serviceconfig.Transport{},
114117
},
115118
} {
116119
t.Run(test.name, func(t *testing.T) {
117-
if _, err := collectModules(test.library, t.TempDir(), "/nonexistent", "1.2.3", &repoMetadata{}); err == nil {
120+
if _, err := collectModules(test.library, t.TempDir(), "1.2.3", &repoMetadata{}, test.transports); err == nil {
118121
t.Error("collectModules() error = nil, want non-nil")
119122
}
120123
})

internal/librarian/java/postprocess.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,6 @@ func postProcessAPI(ctx context.Context, p postProcessParams) error {
7878
return fmt.Errorf("failed to run owlbot.py: %w", err)
7979
}
8080

81-
monorepoVersion, err := findMonorepoVersion(p.cfg)
82-
if err != nil {
83-
return fmt.Errorf("failed to find monorepo version: %w", err)
84-
}
85-
if err := generatePomsIfMissing(p.library, p.outDir, p.googleapisDir, monorepoVersion, p.metadata); err != nil {
86-
return fmt.Errorf("failed to sync poms: %w", err)
87-
}
88-
8981
// Generate clirr-ignored-differences.xml for the proto module.
9082
modules := p.modules()
9183
protoModuleRoot := filepath.Join(p.outDir, modules.proto)

0 commit comments

Comments
 (0)