Skip to content

Commit 8a59fff

Browse files
authored
fix(internal/librarian/golang): skip generation if library has no API (#4194)
Skip generation if library has no API. Pure handwritten libraries, `auth` for example, do not have an API path. For #3617
1 parent 1bf5684 commit 8a59fff

3 files changed

Lines changed: 36 additions & 38 deletions

File tree

internal/librarian/golang/generate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func GenerateLibraries(ctx context.Context, libraries []*config.Library, googlea
5959
// generate generates a Go client library.
6060
func generate(ctx context.Context, library *config.Library, googleapisDir string) error {
6161
if len(library.APIs) == 0 {
62-
return fmt.Errorf("no apis configured for library %q", library.Name)
62+
return nil
6363
}
6464

6565
outdir, err := filepath.Abs(library.Output)

internal/librarian/golang/generate_test.go

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"os"
2020
"path/filepath"
2121
"strings"
22+
"syscall"
2223
"testing"
2324

2425
"github.com/google/go-cmp/cmp"
@@ -86,33 +87,25 @@ func TestGenerateLibraries(t *testing.T) {
8687
}
8788

8889
func TestGenerateLibraries_Error(t *testing.T) {
89-
testhelper.RequireCommand(t, "protoc")
90-
testhelper.RequireCommand(t, "protoc-gen-go")
91-
testhelper.RequireCommand(t, "protoc-gen-go-grpc")
92-
testhelper.RequireCommand(t, "protoc-gen-go_gapic")
93-
outDir := t.TempDir()
9490
googleapisDir, err := filepath.Abs("../../testdata/googleapis")
9591
if err != nil {
9692
t.Fatal(err)
9793
}
9894

9995
libraries := []*config.Library{
10096
{
101-
Name: "no-apis",
102-
Output: outDir,
97+
Name: "non-existent-api",
98+
APIs: []*config.API{{Path: "google/cloud/non-existent/v1"}},
99+
Output: t.TempDir(),
103100
Version: "0.1.0",
104101
ReleaseLevel: "preview",
105102
CopyrightYear: "2025",
106103
Transport: "grpc",
107104
},
108105
}
109106
gotErr := GenerateLibraries(t.Context(), libraries, googleapisDir)
110-
wantErrMessage := "no apis configured for library \"no-apis\""
111-
if gotErr == nil {
112-
t.Fatalf("expected error with message %s", wantErrMessage)
113-
}
114-
if diff := cmp.Diff(wantErrMessage, gotErr.Error()); diff != "" {
115-
t.Errorf("error mismatch (-want +got):\n%s", diff)
107+
if !errors.Is(gotErr, syscall.ENOENT) {
108+
t.Fatalf("expected %v, got %v", syscall.ENOENT, gotErr)
116109
}
117110
}
118111

@@ -124,15 +117,17 @@ func TestGenerate(t *testing.T) {
124117
for _, test := range []struct {
125118
name string
126119
libraryName string
127-
apiPath string
120+
apis []*config.API
128121
transport string
129122
releaseLevel string
130123
goModule *config.GoModule
131124
want []string
132125
removed []string
133126
}{
134127
{
135-
name: "basic",
128+
name: "basic",
129+
libraryName: "secretmanager",
130+
apis: []*config.API{{Path: "google/cloud/secretmanager/v1"}},
136131
want: []string{
137132
"secretmanager/apiv1/secret_manager_client.go",
138133
"secretmanager/apiv1/secretmanagerpb/service.pb.go",
@@ -145,8 +140,10 @@ func TestGenerate(t *testing.T) {
145140
},
146141
},
147142
{
148-
name: "v2 module",
149-
goModule: &config.GoModule{ModulePathVersion: "v2"},
143+
name: "v2 module",
144+
libraryName: "secretmanager",
145+
apis: []*config.API{{Path: "google/cloud/secretmanager/v1"}},
146+
goModule: &config.GoModule{ModulePathVersion: "v2"},
150147
want: []string{
151148
"secretmanager/apiv1/secret_manager_client.go",
152149
},
@@ -155,7 +152,9 @@ func TestGenerate(t *testing.T) {
155152
},
156153
},
157154
{
158-
name: "delete paths",
155+
name: "delete paths",
156+
libraryName: "secretmanager",
157+
apis: []*config.API{{Path: "google/cloud/secretmanager/v1"}},
159158
goModule: &config.GoModule{
160159
DeleteGenerationOutputPaths: []string{"secretmanager/apiv1/secretmanagerpb"},
161160
},
@@ -168,14 +167,18 @@ func TestGenerate(t *testing.T) {
168167
},
169168
{
170169
name: "with transport and release level",
170+
libraryName: "secretmanager",
171+
apis: []*config.API{{Path: "google/cloud/secretmanager/v1"}},
171172
transport: "grpc+rest",
172173
releaseLevel: "ga",
173174
want: []string{
174175
"secretmanager/apiv1/secret_manager_client.go",
175176
},
176177
},
177178
{
178-
name: "client directory",
179+
name: "client directory",
180+
libraryName: "secretmanager",
181+
apis: []*config.API{{Path: "google/cloud/secretmanager/v1"}},
179182
goModule: &config.GoModule{
180183
GoAPIs: []*config.GoAPI{
181184
{
@@ -189,7 +192,9 @@ func TestGenerate(t *testing.T) {
189192
},
190193
},
191194
{
192-
name: "disable gapic",
195+
name: "disable gapic",
196+
libraryName: "secretmanager",
197+
apis: []*config.API{{Path: "google/cloud/secretmanager/v1"}},
193198
goModule: &config.GoModule{
194199
GoAPIs: []*config.GoAPI{
195200
{
@@ -208,7 +213,7 @@ func TestGenerate(t *testing.T) {
208213
{
209214
name: "nested protos",
210215
libraryName: "gkehub",
211-
apiPath: "google/cloud/gkehub/v1",
216+
apis: []*config.API{{Path: "google/cloud/gkehub/v1"}},
212217
goModule: &config.GoModule{
213218
GoAPIs: []*config.GoAPI{
214219
{
@@ -226,22 +231,18 @@ func TestGenerate(t *testing.T) {
226231
"gkehub/multiclusteringress/apiv1/multiclusteringresspb/multiclusteringress.pb.go",
227232
},
228233
},
234+
{
235+
name: "no api",
236+
libraryName: "auth",
237+
},
229238
} {
230239
t.Run(test.name, func(t *testing.T) {
231240
outdir := t.TempDir()
232-
libraryName := test.libraryName
233-
if libraryName == "" {
234-
libraryName = "secretmanager"
235-
}
236-
apiPath := test.apiPath
237-
if apiPath == "" {
238-
apiPath = "google/cloud/secretmanager/v1"
239-
}
240241
library := &config.Library{
241-
Name: libraryName,
242+
Name: test.libraryName,
242243
Version: "1.0.0",
243244
Output: outdir,
244-
APIs: []*config.API{{Path: apiPath}},
245+
APIs: test.apis,
245246
Transport: test.transport,
246247
ReleaseLevel: test.releaseLevel,
247248
Go: test.goModule,
@@ -250,9 +251,6 @@ func TestGenerate(t *testing.T) {
250251
if err := generate(t.Context(), library, googleapisDir); err != nil {
251252
t.Fatal(err)
252253
}
253-
if err := Format(t.Context(), library); err != nil {
254-
t.Fatal(err)
255-
}
256254

257255
for _, path := range test.want {
258256
if _, err := os.Stat(filepath.Join(outdir, path)); err != nil {

internal/librarian/library.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ func libraryOutput(language string, lib *config.Library, defaults *config.Defaul
177177

178178
// applyDefaults applies language-specific derivations and fills defaults.
179179
func applyDefaults(language string, lib *config.Library, defaults *config.Default) (*config.Library, error) {
180-
if len(lib.APIs) == 0 {
181-
lib.APIs = append(lib.APIs, &config.API{})
182-
}
183180
if !lib.Veneer {
181+
if len(lib.APIs) == 0 {
182+
lib.APIs = append(lib.APIs, &config.API{})
183+
}
184184
for _, api := range lib.APIs {
185185
if api.Path == "" {
186186
api.Path = deriveAPIPath(language, lib.Name)

0 commit comments

Comments
 (0)