Skip to content

Commit c305768

Browse files
authored
feat(internal/librarian/java): support non-cloud GroupID inference (#6078)
Java library onboarding now automatically infers the Maven GroupID and distribution name override for recognized non-cloud APIs (Shopping, Maps, and Ads) based on their API path prefixes. This reduces manual configuration steps and ensures consistency. Referenced existing rules recorded in [guide](https://github.com/googleapis/google-cloud-java/blob/main/generation/new_client_hermetic_build/README.md#special-case-example-google-maps). If a new library is added with an unrecognized non-cloud API path, prints a warning and sets a fake group id. When running generate on this fake group id, returns error. Fixes #6047
1 parent a378e26 commit c305768

4 files changed

Lines changed: 165 additions & 12 deletions

File tree

internal/librarian/java/add.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package java
1616

1717
import (
18+
"log"
1819
"strings"
1920

2021
"github.com/googleapis/librarian/internal/config"
@@ -30,14 +31,46 @@ var knownPrefixes = []string{
3031
"google/",
3132
}
3233

33-
const defaultVersion = "0.1.0-SNAPSHOT"
34+
const (
35+
defaultVersion = "0.1.0-SNAPSHOT"
36+
fakeGroupID = "please-configure-java-group-id"
37+
)
3438

3539
// Add initializes a new Java library with default values.
3640
func Add(lib *config.Library) *config.Library {
3741
lib.Version = defaultVersion
3842
// Java generation defaults to the system year for license headers,
3943
// so we reset it here to avoid redundancy in librarian.yaml.
4044
lib.CopyrightYear = ""
45+
46+
// We use the first API to infer the GroupID and distribution name override.
47+
// It is unrealistic for a single library to mix cloud and non-cloud APIs.
48+
apiPath := lib.APIs[0].Path
49+
switch {
50+
case strings.HasPrefix(apiPath, "google/shopping/"):
51+
return setJavaConfig(lib, "com.google.shopping")
52+
case strings.HasPrefix(apiPath, "google/maps/"):
53+
return setJavaConfig(lib, "com.google.maps")
54+
case strings.HasPrefix(apiPath, "google/ads/"):
55+
return setJavaConfig(lib, "com.google.api-ads")
56+
}
57+
if !strings.HasPrefix(apiPath, "google/cloud/") {
58+
log.Printf(
59+
"WARNING: unrecognized non-cloud API path %q. Setting fake GroupID %q. "+
60+
"Please manually configure java.group_id and java.distribution_name_override in librarian.yaml.",
61+
apiPath, fakeGroupID,
62+
)
63+
setJavaConfig(lib, fakeGroupID)
64+
}
65+
return lib
66+
}
67+
68+
func setJavaConfig(lib *config.Library, groupID string) *config.Library {
69+
if lib.Java == nil {
70+
lib.Java = &config.JavaModule{}
71+
}
72+
lib.Java.GroupID = groupID
73+
lib.Java.DistributionNameOverride = groupID + ":google-" + lib.Name
4174
return lib
4275
}
4376

internal/librarian/java/add_test.go

Lines changed: 113 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,119 @@ import (
2222
)
2323

2424
func TestAdd(t *testing.T) {
25-
lib := &config.Library{
26-
Name: "test-library",
27-
}
28-
want := &config.Library{
29-
Name: "test-library",
30-
Version: defaultVersion,
31-
CopyrightYear: "",
32-
}
33-
got := Add(lib)
34-
if diff := cmp.Diff(want, got); diff != "" {
35-
t.Errorf("mismatch (-want +got):\n%s", diff)
25+
for _, test := range []struct {
26+
name string
27+
lib *config.Library
28+
want *config.Library
29+
}{
30+
{
31+
name: "standard cloud API",
32+
lib: &config.Library{
33+
Name: "secretmanager",
34+
APIs: []*config.API{
35+
{Path: "google/cloud/secretmanager/v1"},
36+
},
37+
},
38+
want: &config.Library{
39+
Name: "secretmanager",
40+
APIs: []*config.API{
41+
{Path: "google/cloud/secretmanager/v1"},
42+
},
43+
Version: defaultVersion,
44+
CopyrightYear: "",
45+
},
46+
},
47+
{
48+
name: "shopping API",
49+
lib: &config.Library{
50+
Name: "shopping-css",
51+
APIs: []*config.API{
52+
{Path: "google/shopping/css/v1"},
53+
},
54+
},
55+
want: &config.Library{
56+
Name: "shopping-css",
57+
APIs: []*config.API{
58+
{Path: "google/shopping/css/v1"},
59+
},
60+
Version: defaultVersion,
61+
CopyrightYear: "",
62+
Java: &config.JavaModule{
63+
GroupID: "com.google.shopping",
64+
DistributionNameOverride: "com.google.shopping:google-shopping-css",
65+
},
66+
},
67+
},
68+
{
69+
name: "maps API",
70+
lib: &config.Library{
71+
Name: "maps-routing",
72+
APIs: []*config.API{
73+
{Path: "google/maps/routing/v1"},
74+
},
75+
},
76+
want: &config.Library{
77+
Name: "maps-routing",
78+
APIs: []*config.API{
79+
{Path: "google/maps/routing/v1"},
80+
},
81+
Version: defaultVersion,
82+
CopyrightYear: "",
83+
Java: &config.JavaModule{
84+
GroupID: "com.google.maps",
85+
DistributionNameOverride: "com.google.maps:google-maps-routing",
86+
},
87+
},
88+
},
89+
{
90+
name: "unrecognized non-cloud API",
91+
lib: &config.Library{
92+
Name: "foo-bar",
93+
APIs: []*config.API{
94+
{Path: "google/foo/bar/v1"},
95+
},
96+
},
97+
want: &config.Library{
98+
Name: "foo-bar",
99+
APIs: []*config.API{
100+
{Path: "google/foo/bar/v1"},
101+
},
102+
Version: defaultVersion,
103+
CopyrightYear: "",
104+
Java: &config.JavaModule{
105+
GroupID: "please-configure-java-group-id",
106+
DistributionNameOverride: "please-configure-java-group-id:google-foo-bar",
107+
},
108+
},
109+
},
110+
{
111+
name: "ads API",
112+
lib: &config.Library{
113+
Name: "ads-admanager",
114+
APIs: []*config.API{
115+
{Path: "google/ads/admanager/v1"},
116+
},
117+
},
118+
want: &config.Library{
119+
Name: "ads-admanager",
120+
APIs: []*config.API{
121+
{Path: "google/ads/admanager/v1"},
122+
},
123+
Version: defaultVersion,
124+
CopyrightYear: "",
125+
Java: &config.JavaModule{
126+
GroupID: "com.google.api-ads",
127+
DistributionNameOverride: "com.google.api-ads:google-ads-admanager",
128+
},
129+
},
130+
},
131+
} {
132+
t.Run(test.name, func(t *testing.T) {
133+
got := Add(test.lib)
134+
if diff := cmp.Diff(test.want, got); diff != "" {
135+
t.Errorf("mismatch (-want +got):\n%s", diff)
136+
}
137+
})
36138
}
37139
}
38140

internal/librarian/java/generate.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,14 @@ var (
4848
errNoProtos = errors.New("no protos found")
4949
errMonorepoVersion = fmt.Errorf("failed to find monorepo version for %q in config", rootLibrary)
5050
errBOMVersionMissing = errors.New("libraries bom version not found in config")
51+
errUnrecognizedAPI = errors.New("unrecognized non-cloud API: configure java.group_id and java.distribution_name_override in librarian.yaml")
5152
)
5253

5354
// Generate generates a Java client library.
5455
func Generate(ctx context.Context, cfg *config.Config, library *config.Library, srcs *sources.Sources) error {
56+
if library.Java.GroupID == fakeGroupID {
57+
return errUnrecognizedAPI
58+
}
5559
outdir, err := filepath.Abs(library.Output)
5660
if err != nil {
5761
return fmt.Errorf("failed to resolve output directory path: %w", err)

internal/librarian/java/generate_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,20 @@ func TestGenerateLibrary_Error(t *testing.T) {
582582
},
583583
wantErr: errMonorepoVersion,
584584
},
585+
{
586+
name: "fake group ID error",
587+
library: &config.Library{
588+
Name: "secretmanager",
589+
Output: t.TempDir(),
590+
APIs: []*config.API{
591+
{Path: "google/cloud/secretmanager/v1"},
592+
},
593+
Java: &config.JavaModule{
594+
GroupID: fakeGroupID,
595+
},
596+
},
597+
wantErr: errUnrecognizedAPI,
598+
},
585599
} {
586600
t.Run(test.name, func(t *testing.T) {
587601
if _, err := Fill(test.library); err != nil {

0 commit comments

Comments
 (0)