From 9e4263978fe85adf61557a636fac0d82eb2de102 Mon Sep 17 00:00:00 2001 From: Cody Oss <6331106+codyoss@users.noreply.github.com> Date: Fri, 23 Apr 2021 11:38:53 -0600 Subject: [PATCH] refactor(internal/gapicgen): moved things around for future reuse (#3995) - move git operations to its own package - fix compile error in gensnippets - move ForEachMod into execv - fix a couple of lint errors --- internal/gapicgen/cmd/genbot/bot.go | 4 +- internal/gapicgen/cmd/genbot/generate.go | 44 +++---------- internal/gapicgen/cmd/genbot/update.go | 56 +--------------- internal/gapicgen/cmd/gensnippets/main.go | 4 +- internal/gapicgen/execv/command.go | 21 ++++++ internal/gapicgen/generator/gapics.go | 30 ++------- internal/gapicgen/generator/generator.go | 17 +++-- internal/gapicgen/generator/genproto.go | 5 +- internal/gapicgen/{generator => git}/git.go | 44 ++++++++++--- .../gapicgen/{generator => git}/git_test.go | 4 +- .../gapicgen/{cmd/genbot => git}/github.go | 65 ++++++++++++++++--- 11 files changed, 147 insertions(+), 147 deletions(-) rename internal/gapicgen/{generator => git}/git.go (84%) rename internal/gapicgen/{generator => git}/git_test.go (97%) rename internal/gapicgen/{cmd/genbot => git}/github.go (85%) diff --git a/internal/gapicgen/cmd/genbot/bot.go b/internal/gapicgen/cmd/genbot/bot.go index 9fe37764676..b75115b32b4 100644 --- a/internal/gapicgen/cmd/genbot/bot.go +++ b/internal/gapicgen/cmd/genbot/bot.go @@ -22,6 +22,8 @@ import ( "fmt" "log" "time" + + "cloud.google.com/go/internal/gapicgen/git" ) func genBot(ctx context.Context, githubAccessToken, githubUsername, githubName, githubEmail string) error { @@ -38,7 +40,7 @@ func genBot(ctx context.Context, githubAccessToken, githubUsername, githubName, } // Setup the client and git environment. - githubClient, err := NewGithubClient(ctx, githubUsername, githubName, githubEmail, githubAccessToken) + githubClient, err := git.NewGithubClient(ctx, githubUsername, githubName, githubEmail, githubAccessToken) if err != nil { return err } diff --git a/internal/gapicgen/cmd/genbot/generate.go b/internal/gapicgen/cmd/genbot/generate.go index f5d27328e84..170090a34ba 100644 --- a/internal/gapicgen/cmd/genbot/generate.go +++ b/internal/gapicgen/cmd/genbot/generate.go @@ -17,24 +17,21 @@ package main import ( - "bytes" "context" "fmt" - "io" "io/ioutil" "log" "os" "path/filepath" - "cloud.google.com/go/internal/gapicgen/execv" "cloud.google.com/go/internal/gapicgen/generator" + "cloud.google.com/go/internal/gapicgen/git" "golang.org/x/sync/errgroup" - "gopkg.in/src-d/go-git.v4" ) // generate downloads sources and generates pull requests for go-genproto and // google-cloud-go if needed. -func generate(ctx context.Context, githubClient *GithubClient) error { +func generate(ctx context.Context, githubClient *git.GithubClient) error { log.Println("creating temp dir") tmpDir, err := ioutil.TempDir("", "update-genproto") if err != nil { @@ -53,16 +50,16 @@ func generate(ctx context.Context, githubClient *GithubClient) error { grp, _ := errgroup.WithContext(ctx) grp.Go(func() error { - return gitDeepClone("https://github.com/googleapis/googleapis", googleapisDir) + return git.DeepClone("https://github.com/googleapis/googleapis", googleapisDir) }) grp.Go(func() error { - return gitDeepClone("https://github.com/googleapis/go-genproto", genprotoDir) + return git.DeepClone("https://github.com/googleapis/go-genproto", genprotoDir) }) grp.Go(func() error { - return gitDeepClone("https://github.com/googleapis/google-cloud-go", gocloudDir) + return git.DeepClone("https://github.com/googleapis/google-cloud-go", gocloudDir) }) grp.Go(func() error { - return gitDeepClone("https://github.com/protocolbuffers/protobuf", protoDir) + return git.DeepClone("https://github.com/protocolbuffers/protobuf", protoDir) }) if err := grp.Wait(); err != nil { log.Println(err) @@ -81,12 +78,12 @@ func generate(ctx context.Context, githubClient *GithubClient) error { } // Create PRs. - genprotoHasChanges, err := hasChanges(genprotoDir) + genprotoHasChanges, err := git.HasChanges(genprotoDir) if err != nil { return err } - gocloudHasChanges, err := hasChanges(gocloudDir) + gocloudHasChanges, err := git.HasChanges(gocloudDir) if err != nil { return err } @@ -138,28 +135,3 @@ func generate(ctx context.Context, githubClient *GithubClient) error { } return nil } - -// gitClone clones a repository in the given directory. -func gitDeepClone(repo, dir string) error { - log.Printf("cloning %s\n", repo) - - _, err := git.PlainClone(dir, false, &git.CloneOptions{ - URL: repo, - Progress: os.Stdout, - }) - return err -} - -// hasChanges reports whether the given directory has uncommitted git changes. -func hasChanges(dir string) (bool, error) { - // Write command output to both os.Stderr and local, so that we can check - // whether there are modified files. - inmem := &bytes.Buffer{} - w := io.MultiWriter(os.Stderr, inmem) - - c := execv.Command("bash", "-c", "git status --short") - c.Dir = dir - c.Stdout = w - err := c.Run() - return inmem.Len() > 0, err -} diff --git a/internal/gapicgen/cmd/genbot/update.go b/internal/gapicgen/cmd/genbot/update.go index c78e353e791..d2eaeac0179 100644 --- a/internal/gapicgen/cmd/genbot/update.go +++ b/internal/gapicgen/cmd/genbot/update.go @@ -19,20 +19,18 @@ package main import ( "context" "fmt" - "io/ioutil" "log" - "os" - "cloud.google.com/go/internal/gapicgen/execv" + "cloud.google.com/go/internal/gapicgen/git" ) -func updateGocloudPR(ctx context.Context, githubClient *GithubClient, pr *PullRequest) error { +func updateGocloudPR(ctx context.Context, githubClient *git.GithubClient, pr *git.PullRequest) error { if pr.Author != githubClient.Username { return fmt.Errorf("pull request author %q does not match authenticated user %q", pr.Author, githubClient.Username) } // Checkout PR and update go.mod - if err := updateGocloudGoMod(pr); err != nil { + if err := githubClient.UpdateGocloudGoMod(pr); err != nil { return err } @@ -46,51 +44,3 @@ func updateGocloudPR(ctx context.Context, githubClient *GithubClient, pr *PullRe log.Printf("done updating google-cloud-go PR: %s\n", pr.URL) return nil } - -// updateGocloudGoMod updates the go.mod to include latest version of genproto -// for the given gocloud ref. -func updateGocloudGoMod(pr *PullRequest) error { - tmpDir, err := ioutil.TempDir("", "finalize-gerrit-cl") - if err != nil { - return err - } - defer os.RemoveAll(tmpDir) - - c := execv.Command("/bin/bash", "-c", ` -set -ex - -git init -git remote add origin https://github.com/googleapis/google-cloud-go -git fetch --all -git checkout $BRANCH_NAME - -# tidyall -go mod tidy -for i in $(find . -name go.mod); do - pushd $(dirname $i); - # Update genproto and api to latest for every module (latest version is - # always correct version). tidy will remove the dependencies if they're not - # actually used by the client. - go get -d google.golang.org/api | true # We don't care that there's no files at root. - go get -d google.golang.org/genproto | true # We don't care that there's no files at root. - go mod tidy; - popd; -done - -git add -A -filesUpdated=$( git status --short | wc -l ) -if [ $filesUpdated -gt 0 ]; -then - git config credential.helper store # cache creds from ~/.git-credentials - git commit --amend --no-edit - git push -f origin $BRANCH_NAME -fi -`) - c.Env = []string{ - fmt.Sprintf("BRANCH_NAME=%s", gocloudBranchName), - fmt.Sprintf("PATH=%s", os.Getenv("PATH")), // TODO(deklerk): Why do we need to do this? Doesn't seem to be necessary in other exec.Commands. - fmt.Sprintf("HOME=%s", os.Getenv("HOME")), // TODO(deklerk): Why do we need to do this? Doesn't seem to be necessary in other exec.Commands. - } - c.Dir = tmpDir - return c.Run() -} diff --git a/internal/gapicgen/cmd/gensnippets/main.go b/internal/gapicgen/cmd/gensnippets/main.go index 522ea658889..5063016adfa 100644 --- a/internal/gapicgen/cmd/gensnippets/main.go +++ b/internal/gapicgen/cmd/gensnippets/main.go @@ -35,8 +35,8 @@ func main() { if flag.NArg() > 0 { rootDir = flag.Arg(0) } - - if err := gensnippets.Generate(rootDir, *outDir); err != nil { + // TODO(tbp): route proper api short names + if err := gensnippets.Generate(rootDir, *outDir, map[string]string{}); err != nil { log.Fatal(err) } } diff --git a/internal/gapicgen/execv/command.go b/internal/gapicgen/execv/command.go index 09f0399a5b8..9794bc8a34c 100644 --- a/internal/gapicgen/execv/command.go +++ b/internal/gapicgen/execv/command.go @@ -16,9 +16,11 @@ package execv import ( + "io/fs" "log" "os" "os/exec" + "path/filepath" "strings" ) @@ -42,3 +44,22 @@ func (c *CmdWrapper) Run() error { log.Printf("[%s] >>>> %v <<<<", c.Dir, strings.Join(c.Args, " ")) // NOTE: we have some multi-line commands, make it clear where the command starts and ends return c.Cmd.Run() } + +// ForEachMod runs the given function with the directory of +// every non-internal module. +func ForEachMod(rootDir string, fn func(dir string) error) error { + return filepath.WalkDir(rootDir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if strings.Contains(path, "internal") { + return filepath.SkipDir + } + if d.Name() == "go.mod" { + if err := fn(filepath.Dir(path)); err != nil { + return err + } + } + return nil + }) +} diff --git a/internal/gapicgen/generator/gapics.go b/internal/gapicgen/generator/gapics.go index f2b309e2e90..9aeba1962b4 100644 --- a/internal/gapicgen/generator/gapics.go +++ b/internal/gapicgen/generator/gapics.go @@ -18,7 +18,6 @@ import ( "context" "encoding/json" "fmt" - "io/fs" "log" "os" "path/filepath" @@ -77,7 +76,7 @@ func (g *GapicGenerator) Regen(ctx context.Context) error { return err } - if err := forEachMod(g.googleCloudDir, g.addModReplaceGenproto); err != nil { + if err := execv.ForEachMod(g.googleCloudDir, g.addModReplaceGenproto); err != nil { return err } @@ -104,32 +103,13 @@ func (g *GapicGenerator) Regen(ctx context.Context) error { return err } - if err := forEachMod(g.googleCloudDir, g.dropModReplaceGenproto); err != nil { + if err := execv.ForEachMod(g.googleCloudDir, g.dropModReplaceGenproto); err != nil { return err } return nil } -// forEachMod runs the given function with the directory of -// every non-internal module. -func forEachMod(rootDir string, fn func(dir string) error) error { - return filepath.WalkDir(rootDir, func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if strings.Contains(path, "internal") { - return filepath.SkipDir - } - if d.Name() == "go.mod" { - if err := fn(filepath.Dir(path)); err != nil { - return err - } - } - return nil - }) -} - func goModTidy(dir string) error { log.Printf("[%s] running go mod tidy", dir) c := execv.Command("go", "mod", "tidy") @@ -142,7 +122,7 @@ func goModTidy(dir string) error { } func replaceAllForSnippets(googleCloudDir, snippetDir string) error { - return forEachMod(googleCloudDir, func(dir string) error { + return execv.ForEachMod(googleCloudDir, func(dir string) error { if dir == snippetDir { return nil } @@ -439,7 +419,7 @@ func (g *GapicGenerator) manifest(confs []*microgenConfig) error { Title string `yaml:"title"` // We only need the title field. }{} if err := yaml.NewDecoder(yamlFile).Decode(&yamlConfig); err != nil { - return fmt.Errorf("Decode: %v", err) + return fmt.Errorf("decode: %v", err) } entry := manifestEntry{ DistributionName: conf.importPath, @@ -483,7 +463,7 @@ func (g *GapicGenerator) parseAPIShortnames(confs []*microgenConfig, manualEntri Name string `yaml:"name"` }{} if err := yaml.NewDecoder(yamlFile).Decode(&config); err != nil { - return nil, fmt.Errorf("Decode: %v", err) + return nil, fmt.Errorf("decode: %v", err) } shortname := strings.TrimSuffix(config.Name, ".googleapis.com") shortnames[conf.importPath] = shortname diff --git a/internal/gapicgen/generator/generator.go b/internal/gapicgen/generator/generator.go index 219bc3e2868..6d65fb91d88 100644 --- a/internal/gapicgen/generator/generator.go +++ b/internal/gapicgen/generator/generator.go @@ -26,6 +26,7 @@ import ( "path/filepath" "cloud.google.com/go/internal/gapicgen/execv" + "cloud.google.com/go/internal/gapicgen/git" ) // Config contains inputs needed to generate sources. @@ -40,7 +41,7 @@ type Config struct { } // Generate generates genproto and gapics. -func Generate(ctx context.Context, conf *Config) ([]*ChangeInfo, error) { +func Generate(ctx context.Context, conf *Config) ([]*git.ChangeInfo, error) { if !conf.OnlyGenerateGapic { protoGenerator := NewGenprotoGenerator(conf.GenprotoDir, conf.GoogleapisDir, conf.ProtoDir) if err := protoGenerator.Regen(ctx); err != nil { @@ -52,7 +53,7 @@ func Generate(ctx context.Context, conf *Config) ([]*ChangeInfo, error) { return nil, fmt.Errorf("error generating gapics (may need to check logs for more errors): %v", err) } - var changes []*ChangeInfo + var changes []*git.ChangeInfo if !conf.LocalMode { var err error changes, err = gatherChanges(conf.GoogleapisDir, conf.GenprotoDir) @@ -67,17 +68,21 @@ func Generate(ctx context.Context, conf *Config) ([]*ChangeInfo, error) { return changes, nil } -func gatherChanges(googleapisDir, genprotoDir string) ([]*ChangeInfo, error) { +func gatherChanges(googleapisDir, genprotoDir string) ([]*git.ChangeInfo, error) { // Get the last processed googleapis hash. lastHash, err := ioutil.ReadFile(filepath.Join(genprotoDir, "regen.txt")) if err != nil { return nil, err } - commits, err := CommitsSinceHash(googleapisDir, string(lastHash), false) + commits, err := git.CommitsSinceHash(googleapisDir, string(lastHash), false) if err != nil { return nil, err } - changes, err := ParseChangeInfo(googleapisDir, commits) + gapicPkgs := make(map[string]string) + for _, v := range microgenGapicConfigs { + gapicPkgs[v.inputDirectoryPath] = git.ParseConventionalCommitPkg(v.importPath) + } + changes, err := git.ParseChangeInfo(googleapisDir, commits, gapicPkgs) if err != nil { return nil, err } @@ -88,7 +93,7 @@ func gatherChanges(googleapisDir, genprotoDir string) ([]*ChangeInfo, error) { // recordGoogleapisHash parses the latest commit in googleapis and records it to // regen.txt in go-genproto. func recordGoogleapisHash(googleapisDir, genprotoDir string) error { - commits, err := CommitsSinceHash(googleapisDir, "HEAD", true) + commits, err := git.CommitsSinceHash(googleapisDir, "HEAD", true) if err != nil { return err } diff --git a/internal/gapicgen/generator/genproto.go b/internal/gapicgen/generator/genproto.go index 9e1d65fafd9..6ee1c15d5c3 100644 --- a/internal/gapicgen/generator/genproto.go +++ b/internal/gapicgen/generator/genproto.go @@ -26,6 +26,7 @@ import ( "strings" "cloud.google.com/go/internal/gapicgen/execv" + "cloud.google.com/go/internal/gapicgen/git" "golang.org/x/sync/errgroup" ) @@ -176,9 +177,9 @@ func (g *GenprotoGenerator) protoc(fileNames []string) error { // getUpdatedPackages parses all of the new commits to find what packages need // to be regenerated. func (g *GenprotoGenerator) getUpdatedPackages(googleapisHash string) (map[string][]string, error) { - files, err := UpdateFilesSinceHash(g.googleapisDir, googleapisHash) + files, err := git.UpdateFilesSinceHash(g.googleapisDir, googleapisHash) if err != nil { - + return nil, err } pkgFiles := make(map[string][]string) for _, v := range files { diff --git a/internal/gapicgen/generator/git.go b/internal/gapicgen/git/git.go similarity index 84% rename from internal/gapicgen/generator/git.go rename to internal/gapicgen/git/git.go index 98b3d563872..f4118e84969 100644 --- a/internal/gapicgen/generator/git.go +++ b/internal/gapicgen/git/git.go @@ -12,14 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package generator +package git import ( "bytes" "fmt" + "io" + "log" + "os" "strings" "cloud.google.com/go/internal/gapicgen/execv" + "gopkg.in/src-d/go-git.v4" ) // ChangeInfo represents a change and its associated metadata. @@ -76,15 +80,8 @@ func FormatChanges(changes []*ChangeInfo, onlyGapicChanges bool) string { } // ParseChangeInfo gets the ChangeInfo for a given googleapis hash. -func ParseChangeInfo(googleapisDir string, hashes []string) ([]*ChangeInfo, error) { +func ParseChangeInfo(googleapisDir string, hashes []string, gapicPkgs map[string]string) ([]*ChangeInfo, error) { var changes []*ChangeInfo - // gapicPkgs is a map of googleapis inputDirectoryPath to the gapic package - // name used for conventional commits. - gapicPkgs := make(map[string]string) - for _, v := range microgenGapicConfigs { - gapicPkgs[v.inputDirectoryPath] = parseConventionalCommitPkg(v.importPath) - } - for _, hash := range hashes { // Get commit title and body rawBody := bytes.NewBuffer(nil) @@ -135,7 +132,9 @@ func ParseChangeInfo(googleapisDir string, hashes []string) ([]*ChangeInfo, erro return changes, nil } -func parseConventionalCommitPkg(importPath string) string { +// ParseConventionalCommitPkg parses the package context for conventional commit +// messages. +func ParseConventionalCommitPkg(importPath string) string { s := strings.TrimPrefix(importPath, "cloud.google.com/go/") ss := strings.Split(s, "/") // remove the version, i.e /apiv1 @@ -181,6 +180,31 @@ func UpdateFilesSinceHash(gitDir, hash string) ([]string, error) { return strings.Split(out.String(), "\n"), nil } +// HasChanges reports whether the given directory has uncommitted git changes. +func HasChanges(dir string) (bool, error) { + // Write command output to both os.Stderr and local, so that we can check + // whether there are modified files. + inmem := &bytes.Buffer{} + w := io.MultiWriter(os.Stderr, inmem) + + c := execv.Command("bash", "-c", "git status --short") + c.Dir = dir + c.Stdout = w + err := c.Run() + return inmem.Len() > 0, err +} + +// DeepClone clones a repository in the given directory. +func DeepClone(repo, dir string) error { + log.Printf("cloning %s\n", repo) + + _, err := git.PlainClone(dir, false, &git.CloneOptions{ + URL: repo, + Progress: os.Stdout, + }) + return err +} + // filesChanged returns a list of files changed in a commit for the provdied // hash in the given gitDir. func filesChanged(gitDir, hash string) ([]string, error) { diff --git a/internal/gapicgen/generator/git_test.go b/internal/gapicgen/git/git_test.go similarity index 97% rename from internal/gapicgen/generator/git_test.go rename to internal/gapicgen/git/git_test.go index 9d5f57e1fcc..d100ff4e4fc 100644 --- a/internal/gapicgen/generator/git_test.go +++ b/internal/gapicgen/git/git_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package generator +package git import "testing" @@ -28,7 +28,7 @@ func TestParseConventionalCommitPkg(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - if got := parseConventionalCommitPkg(tc.importPath); got != tc.want { + if got := ParseConventionalCommitPkg(tc.importPath); got != tc.want { t.Errorf("parseConventionalCommitPkg(%q) = %q, want %q", tc.importPath, got, tc.want) } }) diff --git a/internal/gapicgen/cmd/genbot/github.go b/internal/gapicgen/git/github.go similarity index 85% rename from internal/gapicgen/cmd/genbot/github.go rename to internal/gapicgen/git/github.go index 9a4f6f03f4e..37bf4317ddb 100644 --- a/internal/gapicgen/cmd/genbot/github.go +++ b/internal/gapicgen/git/github.go @@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build !windows - -package main +package git import ( "context" @@ -28,7 +26,6 @@ import ( "time" "cloud.google.com/go/internal/gapicgen/execv" - "cloud.google.com/go/internal/gapicgen/generator" "github.com/google/go-github/v34/github" "github.com/shurcooL/githubv4" "golang.org/x/oauth2" @@ -175,13 +172,13 @@ func (gc *GithubClient) GetRegenPR(ctx context.Context, repo string, status stri // CreateGenprotoPR creates a PR for a given genproto change. // // hasCorrespondingPR indicates that there is a corresponding google-cloud-go PR. -func (gc *GithubClient) CreateGenprotoPR(ctx context.Context, genprotoDir string, hasCorrespondingPR bool, changes []*generator.ChangeInfo) (prNumber int, _ error) { +func (gc *GithubClient) CreateGenprotoPR(ctx context.Context, genprotoDir string, hasCorrespondingPR bool, changes []*ChangeInfo) (prNumber int, _ error) { log.Println("creating genproto PR") var sb strings.Builder sb.WriteString(genprotoCommitBody) if !hasCorrespondingPR { sb.WriteString("\n\nThere is no corresponding google-cloud-go PR.\n") - sb.WriteString(generator.FormatChanges(changes, false)) + sb.WriteString(FormatChanges(changes, false)) } body := sb.String() @@ -243,7 +240,7 @@ git push origin $BRANCH_NAME } // CreateGocloudPR creates a PR for a given google-cloud-go change. -func (gc *GithubClient) CreateGocloudPR(ctx context.Context, gocloudDir string, genprotoPRNum int, changes []*generator.ChangeInfo) (prNumber int, _ error) { +func (gc *GithubClient) CreateGocloudPR(ctx context.Context, gocloudDir string, genprotoPRNum int, changes []*ChangeInfo) (prNumber int, _ error) { log.Println("creating google-cloud-go PR") var sb strings.Builder @@ -255,7 +252,7 @@ func (gc *GithubClient) CreateGocloudPR(ctx context.Context, gocloudDir string, } else { sb.WriteString("\n\nThere is no corresponding genproto PR.\n") } - sb.WriteString(generator.FormatChanges(changes, true)) + sb.WriteString(FormatChanges(changes, true)) body := sb.String() c := execv.Command("/bin/bash", "-c", ` @@ -302,11 +299,11 @@ git push origin $BRANCH_NAME // AmendGenprotoPR amends the given genproto PR with a link to the given // google-cloud-go PR. -func (gc *GithubClient) AmendGenprotoPR(ctx context.Context, genprotoPRNum int, genprotoDir string, gocloudPRNum int, changes []*generator.ChangeInfo) error { +func (gc *GithubClient) AmendGenprotoPR(ctx context.Context, genprotoPRNum int, genprotoDir string, gocloudPRNum int, changes []*ChangeInfo) error { var body strings.Builder body.WriteString(genprotoCommitBody) body.WriteString(fmt.Sprintf("\n\nCorresponding google-cloud-go PR: googleapis/google-cloud-go#%d\n", gocloudPRNum)) - body.WriteString(generator.FormatChanges(changes, false)) + body.WriteString(FormatChanges(changes, false)) sBody := body.String() c := execv.Command("/bin/bash", "-c", ` set -ex @@ -352,3 +349,51 @@ func (gc *GithubClient) MarkPRReadyForReview(ctx context.Context, repo string, n } return nil } + +// UpdateGocloudGoMod updates the go.mod to include latest version of genproto +// for the given gocloud ref. +func (gc *GithubClient) UpdateGocloudGoMod(pr *PullRequest) error { + tmpDir, err := ioutil.TempDir("", "finalize-gerrit-cl") + if err != nil { + return err + } + defer os.RemoveAll(tmpDir) + + c := execv.Command("/bin/bash", "-c", ` +set -ex + +git init +git remote add origin https://github.com/googleapis/google-cloud-go +git fetch --all +git checkout $BRANCH_NAME + +# tidyall +go mod tidy +for i in $(find . -name go.mod); do + pushd $(dirname $i); + # Update genproto and api to latest for every module (latest version is + # always correct version). tidy will remove the dependencies if they're not + # actually used by the client. + go get -d google.golang.org/api | true # We don't care that there's no files at root. + go get -d google.golang.org/genproto | true # We don't care that there's no files at root. + go mod tidy; + popd; +done + +git add -A +filesUpdated=$( git status --short | wc -l ) +if [ $filesUpdated -gt 0 ]; +then + git config credential.helper store # cache creds from ~/.git-credentials + git commit --amend --no-edit + git push -f origin $BRANCH_NAME +fi +`) + c.Env = []string{ + fmt.Sprintf("BRANCH_NAME=%s", "regen_gocloud"), + fmt.Sprintf("PATH=%s", os.Getenv("PATH")), // TODO(deklerk): Why do we need to do this? Doesn't seem to be necessary in other exec.Commands. + fmt.Sprintf("HOME=%s", os.Getenv("HOME")), // TODO(deklerk): Why do we need to do this? Doesn't seem to be necessary in other exec.Commands. + } + c.Dir = tmpDir + return c.Run() +}