From 76d32efb02b03e17cfcfac8919746cbbf97296de Mon Sep 17 00:00:00 2001 From: Erik Seliger Date: Tue, 17 Aug 2021 13:24:51 +0200 Subject: [PATCH] Remove published: false from template for batch new Now that this property isn't required anymore, we can get rid of that part. Honors the feature flag for optional publish values. --- cmd/src/batch_new.go | 96 +++++------------------------ internal/batches/service/service.go | 88 ++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 80 deletions(-) diff --git a/cmd/src/batch_new.go b/cmd/src/batch_new.go index af6a894956..9d692e00ec 100644 --- a/cmd/src/batch_new.go +++ b/cmd/src/batch_new.go @@ -1,16 +1,13 @@ package main import ( + "context" "flag" "fmt" - "os" - "os/exec" - "strings" - "text/template" - - "github.com/pkg/errors" - "github.com/sourcegraph/src-cli/internal/batches" + "github.com/sourcegraph/src-cli/internal/api" + "github.com/sourcegraph/src-cli/internal/batches/service" + "github.com/sourcegraph/src-cli/internal/cmderrors" ) func init() { @@ -30,51 +27,33 @@ Examples: ` flagSet := flag.NewFlagSet("new", flag.ExitOnError) + apiFlags := api.NewFlags(flagSet) var ( fileFlag = flagSet.String("f", "batch.yaml", "The name of the batch spec file to create.") ) handler := func(args []string) error { + ctx := context.Background() + if err := flagSet.Parse(args); err != nil { return err } - f, err := os.OpenFile(*fileFlag, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) - if err != nil { - if os.IsExist(err) { - return fmt.Errorf("file %s already exists", *fileFlag) - } - return errors.Wrapf(err, "failed to create file %s", *fileFlag) + if len(flagSet.Args()) != 0 { + return cmderrors.Usage("additional arguments not allowed") } - defer f.Close() - tmpl, err := template.New("").Parse(batchSpecTmpl) - if err != nil { - return err - } + svc := service.New(&service.Opts{ + Client: cfg.apiClient(apiFlags, flagSet.Output()), + }) - author := batches.GitCommitAuthor{ - Name: "Sourcegraph", - Email: "batch-changes@sourcegraph.com", - } - - // Try to get better default values from git, ignore any errors. - if err := checkExecutable("git", "version"); err == nil { - var gitAuthorName, gitAuthorEmail string - var err1, err2 error - gitAuthorName, err1 = getGitConfig("user.name") - gitAuthorEmail, err2 = getGitConfig("user.email") - - if err1 == nil && err2 == nil && gitAuthorName != "" && gitAuthorEmail != "" { - author.Name = gitAuthorName - author.Email = gitAuthorEmail - } + if err := svc.DetermineFeatureFlags(ctx); err != nil { + return err } - err = tmpl.Execute(f, map[string]interface{}{"Author": author}) - if err != nil { - return errors.Wrap(err, "failed to write batch spec to file") + if err := svc.GenerateExampleSpec(ctx, *fileFlag); err != nil { + return err } fmt.Printf("%s created.\n", *fileFlag) @@ -92,46 +71,3 @@ Examples: }, }) } - -func getGitConfig(attribute string) (string, error) { - cmd := exec.Command("git", "config", "--get", attribute) - out, err := cmd.CombinedOutput() - if err != nil { - return "", err - } - return strings.TrimSpace(string(out)), nil -} - -const batchSpecTmpl = `name: NAME-OF-YOUR-BATCH-CHANGE -description: DESCRIPTION-OF-YOUR-BATCH-CHANGE - -# "on" specifies on which repositories to execute the "steps". -on: - # Example: find all repositories that contain a README.md file. - - repositoriesMatchingQuery: file:README.md - -# "steps" are run in each repository. Each step is run in a Docker container -# with the repository as the working directory. Once complete, each -# repository's resulting diff is captured. -steps: - # Example: append "Hello World" to every README.md - - run: echo "Hello World" | tee -a $(find -name README.md) - container: alpine:3 - -# "changesetTemplate" describes the changeset (e.g., GitHub pull request) that -# will be created for each repository. -changesetTemplate: - title: Hello World - body: This adds Hello World to the README - - branch: BRANCH-NAME-IN-EACH-REPOSITORY # Push the commit to this branch. - - commit: - author: - name: {{ .Author.Name }} - email: {{ .Author.Email }} - message: Append Hello World to all README.md files - - # Change published to true once you're ready to create changesets on the code host. - published: false -` diff --git a/internal/batches/service/service.go b/internal/batches/service/service.go index 175626170a..4124b1ee63 100644 --- a/internal/batches/service/service.go +++ b/internal/batches/service/service.go @@ -4,8 +4,11 @@ import ( "context" "encoding/json" "fmt" + "html/template" "io" "io/ioutil" + "os" + "os/exec" "path" "regexp" "strings" @@ -273,6 +276,82 @@ func (svc *Service) ParseBatchSpec(in io.Reader) (*batches.BatchSpec, string, er return spec, string(data), nil } +const exampleSpecTmpl = `name: NAME-OF-YOUR-BATCH-CHANGE +description: DESCRIPTION-OF-YOUR-BATCH-CHANGE + +# "on" specifies on which repositories to execute the "steps". +on: + # Example: find all repositories that contain a README.md file. + - repositoriesMatchingQuery: file:README.md + +# "steps" are run in each repository. Each step is run in a Docker container +# with the repository as the working directory. Once complete, each +# repository's resulting diff is captured. +steps: + # Example: append "Hello World" to every README.md + - run: echo "Hello World" | tee -a $(find -name README.md) + container: alpine:3 + +# "changesetTemplate" describes the changeset (e.g., GitHub pull request) that +# will be created for each repository. +changesetTemplate: + title: Hello World + body: This adds Hello World to the README + + branch: BRANCH-NAME-IN-EACH-REPOSITORY # Push the commit to this branch. + + commit: + author: + name: {{ .Author.Name }} + email: {{ .Author.Email }} + message: Append Hello World to all README.md files +` + +const exampleSpecPublishFlagTmpl = ` + # Change published to true once you're ready to create changesets on the code host. + published: false +` + +func (svc *Service) GenerateExampleSpec(ctx context.Context, fileName string) error { + // Try to create file. Bail out, if it already exists. + f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) + if err != nil { + if os.IsExist(err) { + return fmt.Errorf("file %s already exists", fileName) + } + return errors.Wrapf(err, "failed to create file %s", fileName) + } + defer f.Close() + + t := exampleSpecTmpl + if !svc.features.AllowOptionalPublished { + t += exampleSpecPublishFlagTmpl + } + tmpl, err := template.New("").Parse(t) + if err != nil { + return err + } + + author := batches.GitCommitAuthor{ + Name: "Sourcegraph", + Email: "batch-changes@sourcegraph.com", + } + // Try to get better default values from git, ignore any errors. + gitAuthorName, err1 := getGitConfig("user.name") + gitAuthorEmail, err2 := getGitConfig("user.email") + if err1 == nil && err2 == nil && gitAuthorName != "" && gitAuthorEmail != "" { + author.Name = gitAuthorName + author.Email = gitAuthorEmail + } + + err = tmpl.Execute(f, map[string]interface{}{"Author": author}) + if err != nil { + return errors.Wrap(err, "failed to write batch spec to file") + } + + return nil +} + const namespaceQuery = ` query NamespaceQuery($name: String!) { user(username: $name) { @@ -702,3 +781,12 @@ func (sr *searchResult) UnmarshalJSON(data []byte) error { return errors.Errorf("unknown GraphQL type %q", tn.Typename) } } + +func getGitConfig(attribute string) (string, error) { + cmd := exec.Command("git", "config", "--get", attribute) + out, err := cmd.CombinedOutput() + if err != nil { + return "", err + } + return strings.TrimSpace(string(out)), nil +}