Skip to content

Commit 07874e7

Browse files
authored
fix(internal/librarian): update-image should skip libraries where generate is blocked by config (#2823)
`update-image` command now skips a library if it is configured with `generate_blocked` in config.yaml. Also done minor refactoring to reuse logic in identifying blocked libraries. Fixes #2773
1 parent 73cf508 commit 07874e7

File tree

6 files changed

+113
-13
lines changed

6 files changed

+113
-13
lines changed

internal/config/librarian_config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ func (g *LibrarianConfig) LibraryConfigFor(LibraryID string) *LibraryConfig {
7979
return nil
8080
}
8181

82+
// IsGenerationBlocked returns true if the library is configured to block generation.
83+
func (g *LibrarianConfig) IsGenerationBlocked(libraryID string) bool {
84+
if g == nil {
85+
return false
86+
}
87+
libConfig := g.LibraryConfigFor(libraryID)
88+
return libConfig != nil && libConfig.GenerateBlocked
89+
}
90+
8291
// GetGlobalFiles returns the global files defined in the librarian config.
8392
func (g *LibrarianConfig) GetGlobalFiles() []string {
8493
var globalFiles []string

internal/config/librarian_config_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,56 @@ func TestGetGlobalFiles(t *testing.T) {
218218
})
219219
}
220220
}
221+
222+
func TestIsGenerationBlocked(t *testing.T) {
223+
for _, test := range []struct {
224+
name string
225+
config *LibrarianConfig
226+
libraryID string
227+
want bool
228+
}{
229+
{
230+
name: "nil config",
231+
config: nil,
232+
libraryID: "lib1",
233+
want: false,
234+
},
235+
{
236+
name: "library not in config",
237+
config: &LibrarianConfig{
238+
Libraries: []*LibraryConfig{
239+
{LibraryID: "lib2", GenerateBlocked: true},
240+
},
241+
},
242+
libraryID: "lib1",
243+
want: false,
244+
},
245+
{
246+
name: "library in config, generate_blocked is false",
247+
config: &LibrarianConfig{
248+
Libraries: []*LibraryConfig{
249+
{LibraryID: "lib1", GenerateBlocked: false},
250+
},
251+
},
252+
libraryID: "lib1",
253+
want: false,
254+
},
255+
{
256+
name: "library in config, generate_blocked is true",
257+
config: &LibrarianConfig{
258+
Libraries: []*LibraryConfig{
259+
{LibraryID: "lib1", GenerateBlocked: true},
260+
},
261+
},
262+
libraryID: "lib1",
263+
want: true,
264+
},
265+
} {
266+
t.Run(test.name, func(t *testing.T) {
267+
got := test.config.IsGenerationBlocked(test.libraryID)
268+
if got != test.want {
269+
t.Errorf("IsGenerationBlocked() = %v, want %v", got, test.want)
270+
}
271+
})
272+
}
273+
}

internal/librarian/generate_command.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -426,12 +426,9 @@ func setAllAPIStatus(state *config.LibrarianState, status string) {
426426
func (r *generateRunner) shouldGenerate(library *config.LibraryState) (bool, error) {
427427
// If the library has a manual configuration which indicates generation is blocked,
428428
// the library is skipped.
429-
if r.librarianConfig != nil {
430-
libConfig := r.librarianConfig.LibraryConfigFor(library.ID)
431-
if libConfig != nil && libConfig.GenerateBlocked {
432-
slog.Info("library has generate_blocked, skipping", "id", library.ID)
433-
return false, nil
434-
}
429+
if r.librarianConfig.IsGenerationBlocked(library.ID) {
430+
slog.Info("library has generate_blocked, skipping", "id", library.ID)
431+
return false, nil
435432
}
436433

437434
// If the library has no APIs, it is skipped.

internal/librarian/test_container_generate.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,10 @@ func (r *testGenerateRunner) testSingleLibrary(ctx context.Context, libraryID, s
163163
return fmt.Errorf("library %q not found in state", libraryID)
164164
}
165165

166-
if r.librarianConfig != nil {
167-
libConfig := r.librarianConfig.LibraryConfigFor(libraryID)
168-
if libConfig != nil && libConfig.GenerateBlocked {
169-
return errGenerateBlocked
170-
}
166+
if r.librarianConfig.IsGenerationBlocked(libraryID) {
167+
return errGenerateBlocked
171168
}
169+
172170
protoFileToGUIDs, err := r.prepareForGenerateTest(libraryState, libraryID)
173171
if err != nil {
174172
return fmt.Errorf("failed in test preparing steps: %w", err)

internal/librarian/update_image.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,19 @@ func (r *updateImageRunner) run(ctx context.Context) error {
118118
// For each library, run generation at the previous commit
119119
var failedGenerations []*config.LibraryState
120120
var successfulGenerations []*config.LibraryState
121+
var skippedGenerationsCount int
121122
sourceHead, err := r.sourceRepo.HeadHash()
122123
if err != nil {
123124
return err
124125
}
125126
outputDir := filepath.Join(r.workRoot, "output")
126127
timings := map[string]time.Duration{}
127128
for _, libraryState := range r.state.Libraries {
129+
if r.librarianConfig.IsGenerationBlocked(libraryState.ID) {
130+
slog.Debug("skipping generation for library due to generate_blocked", "library", libraryState.ID)
131+
skippedGenerationsCount++
132+
continue
133+
}
128134
startTime := time.Now()
129135
err := r.regenerateSingleLibrary(ctx, libraryState, outputDir)
130136
if err != nil {
@@ -137,9 +143,14 @@ func (r *updateImageRunner) run(ctx context.Context) error {
137143
timings[libraryState.ID] = time.Since(startTime)
138144
}
139145
if len(failedGenerations) > 0 {
140-
slog.Warn("failed generations", slog.Int("num", len(failedGenerations)))
146+
slog.Warn("failed generations", "num", len(failedGenerations))
141147
}
142-
slog.Info("successful generations", slog.Int("num", len(successfulGenerations)))
148+
slog.Info(
149+
"generation statistics",
150+
"all", len(r.state.Libraries),
151+
"successes", len(successfulGenerations),
152+
"skipped", skippedGenerationsCount,
153+
"failures", len(failedGenerations))
143154
if err := writeTiming(r.workRoot, timings); err != nil {
144155
return err
145156
}

internal/librarian/update_image_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ func TestUpdateImageRunnerRun(t *testing.T) {
194194
containerClient *mockContainerClient
195195
ghClient *mockGitHubClient
196196
state *config.LibrarianState
197+
librarianConfig *config.LibrarianConfig
197198
image string
198199
build bool
199200
commit bool
@@ -728,6 +729,36 @@ func TestUpdateImageRunnerRun(t *testing.T) {
728729
wantCreateIssueCalls: 1,
729730
wantCommitMsg: "feat: update image to gcr.io/test/image@sha256:abc123",
730731
},
732+
{
733+
name: "skip generation for library",
734+
state: &config.LibrarianState{
735+
Image: "gcr.io/test/image:v1.2.3",
736+
Libraries: []*config.LibraryState{
737+
{
738+
ID: "blocked-lib",
739+
APIs: []*config.API{{Path: "some/api1"}},
740+
SourceRoots: []string{"src/a"},
741+
LastGeneratedCommit: "abcd1234",
742+
},
743+
},
744+
},
745+
746+
librarianConfig: &config.LibrarianConfig{
747+
Libraries: []*config.LibraryConfig{
748+
{
749+
LibraryID: "blocked-lib",
750+
GenerateBlocked: true,
751+
},
752+
},
753+
},
754+
containerClient: &mockContainerClient{},
755+
imagesClient: &mockImagesClient{},
756+
ghClient: &mockGitHubClient{},
757+
wantFindLatestCalls: 1,
758+
wantGenerateCalls: 0,
759+
wantBuildCalls: 0,
760+
wantCheckoutCalls: 1,
761+
},
731762
} {
732763
t.Run(test.name, func(t *testing.T) {
733764
testRepo := newTestGitRepoWithState(t, test.state)
@@ -755,6 +786,7 @@ func TestUpdateImageRunnerRun(t *testing.T) {
755786
imagesClient: test.imagesClient,
756787
ghClient: test.ghClient,
757788
state: test.state,
789+
librarianConfig: test.librarianConfig,
758790
workRoot: t.TempDir(),
759791
repo: repo,
760792
sourceRepo: sourceRepo,

0 commit comments

Comments
 (0)