Skip to content

Commit 220f8a5

Browse files
authored
feat(internal/postprocessor): only regen snippets for changed modules (#7300)
This change identifies the changed modules in the PR using the commit URLs in the open OwlBot PR description. The scopes are used to limit snippet regeneration to only those modules.
1 parent 935ba3f commit 220f8a5

File tree

1 file changed

+107
-35
lines changed

1 file changed

+107
-35
lines changed

internal/postprocessor/main.go

+107-35
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,12 @@ func main() {
7272
log.Println("googleapis-dir set to", *googleapisDir)
7373
log.Println("branch set to", *branchOverride)
7474
log.Println("prFilepath is", *prFilepath)
75+
log.Println("directories are", *directories)
7576

76-
var modules []string
77+
dirSlice := []string{}
7778
if *directories != "" {
7879
dirSlice := strings.Split(*directories, ",")
79-
for _, dir := range dirSlice {
80-
modules = append(modules, filepath.Join(*clientRoot, dir))
81-
}
82-
log.Println("Postprocessor running on", modules)
80+
log.Println("Postprocessor running on", dirSlice)
8381
} else {
8482
log.Println("Postprocessor running on all modules.")
8583
}
@@ -103,11 +101,13 @@ func main() {
103101
c := &config{
104102
googleapisDir: *googleapisDir,
105103
googleCloudDir: *clientRoot,
106-
modules: modules,
104+
modules: dirSlice,
107105
branchOverride: *branchOverride,
108106
githubUsername: *githubUsername,
109107
prFilepath: *prFilepath,
110108
runAll: runAll,
109+
prTitle: "",
110+
prBody: "",
111111
}
112112

113113
if err := c.run(ctx); err != nil {
@@ -120,11 +120,19 @@ func main() {
120120
type config struct {
121121
googleapisDir string
122122
googleCloudDir string
123-
modules []string
123+
124+
// At this time modules are either provided at the time of invocation locally
125+
// and extracted from the open OwlBot PR description. If we would like
126+
// the postprocessor to be able to be run on non-OwlBot PRs, we would
127+
// need to change the method of populating this field.
128+
modules []string
129+
124130
branchOverride string
125131
githubUsername string
126132
prFilepath string
127133
runAll bool
134+
prTitle string
135+
prBody string
128136
}
129137

130138
// runAll uses git to tell if the PR being updated should run all post
@@ -150,7 +158,16 @@ func (c *config) run(ctx context.Context) error {
150158
log.Println("exiting post processing early")
151159
return nil
152160
}
153-
if err := gocmd.ModTidyAll(c.googleCloudDir); err != nil {
161+
// TODO(guadriana): Once the PR for initializing new modules is merged, we
162+
// will need to add logic here that sets c.modules to modConfigs (a slice of
163+
// all modules) if branchOverride != ""
164+
165+
// TODO(codyoss): In the future we may want to make it possible to be able
166+
// to run this locally with a user defined remote branch.
167+
if err := c.SetScopesAndPRInfo(ctx); err != nil {
168+
return err
169+
}
170+
if err := c.TidyAffectedMods(); err != nil {
154171
return err
155172
}
156173
if err := gocmd.Vet(c.googleCloudDir); err != nil {
@@ -162,28 +179,44 @@ func (c *config) run(ctx context.Context) error {
162179
if _, err := c.Manifest(generator.MicrogenGapicConfigs); err != nil {
163180
return err
164181
}
165-
// TODO(codyoss): In the future we may want to make it possible to be able
166-
// to run this locally with a user defined remote branch.
167-
if err := c.AmendPRDescription(ctx); err != nil {
182+
if err := c.WritePRInfoToFile(); err != nil {
168183
return err
169184
}
170185
return nil
171186
}
172187

188+
func (c *config) getDirs() []string {
189+
dirs := []string{}
190+
for _, module := range c.modules {
191+
dirs = append(dirs, filepath.Join(c.googleCloudDir, module))
192+
}
193+
return dirs
194+
}
195+
196+
func (c *config) TidyAffectedMods() error {
197+
dirs := c.getDirs()
198+
for _, dir := range dirs {
199+
if err := gocmd.ModTidy(dir); err != nil {
200+
return err
201+
}
202+
}
203+
return nil
204+
}
205+
173206
// RegenSnippets regenerates the snippets for all GAPICs configured to be generated.
174207
func (c *config) RegenSnippets() error {
175208
log.Println("regenerating snippets")
176-
177209
snippetDir := filepath.Join(c.googleCloudDir, "internal", "generated", "snippets")
178-
apiShortnames, err := generator.ParseAPIShortnames(c.googleapisDir, generator.MicrogenGapicConfigs, generator.ManualEntries)
179-
210+
confs := c.getChangedClientConfs()
211+
apiShortnames, err := generator.ParseAPIShortnames(c.googleapisDir, confs, generator.ManualEntries)
180212
if err != nil {
181213
return err
182214
}
183-
if err := gensnippets.GenerateSnippetsDirs(c.googleCloudDir, snippetDir, apiShortnames, c.modules); err != nil {
215+
dirs := c.getDirs()
216+
if err := gensnippets.GenerateSnippetsDirs(c.googleCloudDir, snippetDir, apiShortnames, dirs); err != nil {
184217
log.Printf("warning: got the following non-fatal errors generating snippets: %v", err)
185218
}
186-
if err := c.replaceAllForSnippets(c.googleCloudDir, snippetDir); err != nil {
219+
if err := c.replaceAllForSnippets(snippetDir); err != nil {
187220
return err
188221
}
189222
if err := gocmd.ModTidy(snippetDir); err != nil {
@@ -193,15 +226,44 @@ func (c *config) RegenSnippets() error {
193226
return nil
194227
}
195228

196-
func (c *config) replaceAllForSnippets(googleCloudDir, snippetDir string) error {
197-
return execv.ForEachMod(googleCloudDir, func(dir string) error {
229+
// getChangedClientConfs iterates through the MicrogenGapicConfigs and returns
230+
// a slice of the entries corresponding to modified modules and clients
231+
func (c *config) getChangedClientConfs() []*generator.MicrogenConfig {
232+
if len(c.modules) != 0 {
233+
runConfs := []*generator.MicrogenConfig{}
234+
for _, conf := range generator.MicrogenGapicConfigs {
235+
for _, scope := range c.modules {
236+
scopePathElement := "/" + scope + "/"
237+
if strings.Contains(conf.InputDirectoryPath, scopePathElement) {
238+
runConfs = append(runConfs, conf)
239+
}
240+
}
241+
}
242+
return runConfs
243+
}
244+
return generator.MicrogenGapicConfigs
245+
}
246+
247+
func (c *config) replaceAllForSnippets(snippetDir string) error {
248+
return execv.ForEachMod(c.googleCloudDir, func(dir string) error {
249+
processMod := false
198250
if c.modules != nil {
251+
// Checking each path component in its entirety prevents mistaken addition of modules whose names
252+
// contain the scope as a substring. For example if the scope is "video" we do not want to regenerate
253+
// snippets for "videointelligence"
254+
dirSlice := strings.Split(dir, "/")
199255
for _, mod := range c.modules {
200-
if !strings.Contains(dir, mod) {
201-
return nil
256+
for _, dirElem := range dirSlice {
257+
if mod == dirElem {
258+
processMod = true
259+
break
260+
}
202261
}
203262
}
204263
}
264+
if !processMod {
265+
return nil
266+
}
205267
if dir == snippetDir {
206268
return nil
207269
}
@@ -280,7 +342,7 @@ func docURL(cloudDir, importPath string) (string, error) {
280342
return "https://cloud.google.com/go/docs/reference/" + mod + "/latest/" + pkgPath, nil
281343
}
282344

283-
func (c *config) AmendPRDescription(ctx context.Context) error {
345+
func (c *config) SetScopesAndPRInfo(ctx context.Context) error {
284346
log.Println("Amending PR title and body")
285347
pr, err := c.getPR(ctx)
286348
if err != nil {
@@ -290,13 +352,16 @@ func (c *config) AmendPRDescription(ctx context.Context) error {
290352
if err != nil {
291353
return err
292354
}
293-
return c.writePRCommitToFile(newPRTitle, newPRBody)
355+
c.prTitle = newPRTitle
356+
c.prBody = newPRBody
357+
return nil
294358
}
295359

296360
func (c *config) processCommit(title, body string) (string, string, error) {
297361
var newPRTitle string
298362
var commitTitle string
299363
var commitTitleIndex int
364+
var modules []string
300365

301366
bodySlice := strings.Split(body, "\n")
302367
for index, line := range bodySlice {
@@ -312,7 +377,12 @@ func (c *config) processCommit(title, body string) (string, string, error) {
312377
continue
313378
}
314379
hash := extractHashFromLine(line)
315-
scope, err := c.getScopeFromGoogleapisCommitHash(hash)
380+
scopes, err := c.getScopesFromGoogleapisCommitHash(hash)
381+
modules = append(modules, scopes...)
382+
var scope string
383+
if len(scopes) == 1 {
384+
scope = scopes[0]
385+
}
316386
if err != nil {
317387
return "", "", err
318388
}
@@ -324,6 +394,7 @@ func (c *config) processCommit(title, body string) (string, string, error) {
324394
bodySlice[commitTitleIndex] = newCommitTitle
325395
}
326396
body = strings.Join(bodySlice, "\n")
397+
c.modules = append(c.modules, modules...)
327398
return newPRTitle, body, nil
328399
}
329400

@@ -349,14 +420,14 @@ func (c *config) getPR(ctx context.Context) (*github.PullRequest, error) {
349420
return owlbotPR, nil
350421
}
351422

352-
func (c *config) getScopeFromGoogleapisCommitHash(commitHash string) (string, error) {
423+
func (c *config) getScopesFromGoogleapisCommitHash(commitHash string) ([]string, error) {
353424
files, err := c.filesChanged(commitHash)
354425
if err != nil {
355-
return "", err
426+
return nil, err
356427
}
357428
// if no files changed, return empty string
358429
if len(files) == 0 {
359-
return "", nil
430+
return nil, nil
360431
}
361432
scopesMap := make(map[string]bool)
362433
scopes := []string{}
@@ -375,12 +446,7 @@ func (c *config) getScopeFromGoogleapisCommitHash(commitHash string) (string, er
375446
}
376447
}
377448
}
378-
// if no in-scope packages are found or if many packages found, return empty string
379-
if len(scopes) != 1 {
380-
return "", nil
381-
}
382-
// if single scope found, return
383-
return scopes[0], nil
449+
return scopes, nil
384450
}
385451

386452
// filesChanged returns a list of files changed in a commit for the provdied
@@ -421,8 +487,9 @@ func updateCommitTitle(title, titlePkg string) string {
421487
return newTitle
422488
}
423489

424-
// writePRCommitToFile uses OwlBot env variable specified path to write updated PR title and body at that location
425-
func (c *config) writePRCommitToFile(title, body string) error {
490+
// WritePRInfoToFile uses OwlBot env variable specified path to write updated
491+
// PR title and body at that location
492+
func (c *config) WritePRInfoToFile() error {
426493
// if file exists at location, delete
427494
if err := os.Remove(c.prFilepath); err != nil {
428495
if errors.Is(err, fs.ErrNotExist) {
@@ -436,7 +503,12 @@ func (c *config) writePRCommitToFile(title, body string) error {
436503
return err
437504
}
438505
defer f.Close()
439-
if _, err := f.WriteString(fmt.Sprintf("%s\n\n%s", title, body)); err != nil {
506+
if c.prTitle == "" && c.prBody == "" {
507+
log.Println("No updated PR info found, will not write PR title and description to file.")
508+
return nil
509+
}
510+
log.Println("Writing PR title and description to file.")
511+
if _, err := f.WriteString(fmt.Sprintf("%s\n\n%s", c.prTitle, c.prBody)); err != nil {
440512
return err
441513
}
442514
return nil

0 commit comments

Comments
 (0)