diff --git a/README.md b/README.md index ff7266a..36ee3d7 100644 --- a/README.md +++ b/README.md @@ -172,12 +172,14 @@ Use `turbolift create-prs --sleep 30s` to, for example, force a 30s pause betwee > * create PRs in batches, for example by commenting out repositories in `repos.txt` > * Use the `--draft` flag to create the PRs as Draft -If you need to mass-close PRs, it is easy to do using `turbolift foreach` and the `gh` GitHub CLI ([docs](https://cli.github.com/manual/gh_pr_close)): +#### Working with multiple PR description files -For example: +Occasionally you may want to work with more than one PR title and description. When this is the case, use the flag `--description` to specify an alternative file when creating prs. +The first line of the file chosen will be used as the PR title and the rest as the description body. -``` -turbolift foreach gh pr close --delete-branch YOUR_USERNAME:CAMPAIGN_NAME +```console +turbolift create-prs --repos repoFile1.txt --description prDescriptionFile1.md +turbolift create-prs --repos repoFile2.txt --description prDescriptionFile2.md ``` ### After creating PRs diff --git a/cmd/create_prs/create_prs.go b/cmd/create_prs/create_prs.go index c50905e..4f58e3a 100644 --- a/cmd/create_prs/create_prs.go +++ b/cmd/create_prs/create_prs.go @@ -35,9 +35,10 @@ var ( ) var ( - isDraft bool - repoFile string - sleep time.Duration + isDraft bool + repoFile string + prDescriptionFile string + sleep time.Duration ) func NewCreatePRsCmd() *cobra.Command { @@ -50,6 +51,7 @@ func NewCreatePRsCmd() *cobra.Command { cmd.Flags().DurationVar(&sleep, "sleep", 0, "Fixed sleep in between PR creations (to spread load on CI infrastructure)") cmd.Flags().BoolVar(&isDraft, "draft", false, "Creates the Pull Request as Draft PR") cmd.Flags().StringVar(&repoFile, "repos", "repos.txt", "A file containing a list of repositories to clone.") + cmd.Flags().StringVar(&prDescriptionFile, "description", "README.md", "A file containing the title and description for the PRs.") return cmd } @@ -57,9 +59,10 @@ func NewCreatePRsCmd() *cobra.Command { func run(c *cobra.Command, _ []string) { logger := logging.NewLogger(c) - readCampaignActivity := logger.StartActivity("Reading campaign data (%s)", repoFile) + readCampaignActivity := logger.StartActivity("Reading campaign data (%s, %s)", repoFile, prDescriptionFile) options := campaign.NewCampaignOptions() options.RepoFilename = repoFile + options.PrDescriptionFilename = prDescriptionFile dir, err := campaign.OpenCampaign(options) if err != nil { readCampaignActivity.EndWithFailure(err) diff --git a/cmd/init/templates/README.md b/cmd/init/templates/README.md index bfde24b..543eba8 100644 --- a/cmd/init/templates/README.md +++ b/cmd/init/templates/README.md @@ -2,6 +2,8 @@ TODO: This file will serve as both a README and the description of the PR. Describe the pull request using markdown in this file. Make it clear why the change is being made, and make suggestions for anything that the reviewer may need to do. +By approving this PR, you are confirming that you have adequately and effectively reviewed this change. + ## How this change was made TODO: Describe the approach that was used to select repositories for this change TODO: Describe any shell commands, scripts, manual operations, etc, that were used to make changes diff --git a/internal/campaign/campaign.go b/internal/campaign/campaign.go index 22a8c21..e5f6490 100644 --- a/internal/campaign/campaign.go +++ b/internal/campaign/campaign.go @@ -44,11 +44,15 @@ func (r Repo) FullRepoPath() string { } type CampaignOptions struct { - RepoFilename string + RepoFilename string + PrDescriptionFilename string } func NewCampaignOptions() *CampaignOptions { - return &CampaignOptions{RepoFilename: "repos.txt"} + return &CampaignOptions{ + RepoFilename: "repos.txt", + PrDescriptionFilename: "README.md", + } } func OpenCampaign(options *CampaignOptions) (*Campaign, error) { @@ -60,7 +64,7 @@ func OpenCampaign(options *CampaignOptions) (*Campaign, error) { return nil, err } - prTitle, prBody, err := readPrDescriptionFile() + prTitle, prBody, err := readPrDescriptionFile(options.PrDescriptionFilename) if err != nil { return nil, err } @@ -131,10 +135,13 @@ func readReposTxtFile(filename string) ([]Repo, error) { return repos, nil } -func readPrDescriptionFile() (string, string, error) { - file, err := os.Open("README.md") +func readPrDescriptionFile(filename string) (string, string, error) { + if filename == "" { + return "", "", errors.New("no PR description file to open") + } + file, err := os.Open(filename) if err != nil { - return "", "", errors.New("unable to open README.md file") + return "", "", fmt.Errorf("unable to open PR description file: %s", filename) } defer func() { closeErr := file.Close() @@ -158,7 +165,7 @@ func readPrDescriptionFile() (string, string, error) { } if err := scanner.Err(); err != nil { - return "", "", errors.New("unable to read README.md file") + return "", "", fmt.Errorf("unable to read PR description file: %s", filename) } return prTitle, strings.Join(prBodyLines, "\n"), nil diff --git a/internal/campaign/campaign_test.go b/internal/campaign/campaign_test.go index c347e9f..dda18d6 100644 --- a/internal/campaign/campaign_test.go +++ b/internal/campaign/campaign_test.go @@ -218,7 +218,39 @@ func TestItShouldAcceptADifferentRepoFileNotExist(t *testing.T) { func TestItShouldErrorWhenRepoFileIsEmpty(t *testing.T) { testsupport.PrepareTempCampaign(false) - options := &CampaignOptions{} + options := NewCampaignOptions() + options.RepoFilename = "" + _, err := OpenCampaign(options) + assert.Error(t, err) +} + +func TestItShouldAcceptADifferentPrDescriptionFile(t *testing.T) { + testsupport.PrepareTempCampaign(false) + + testsupport.CreateAnotherPrDescriptionFile("newprdescription.txt", "new PR title", "new PR body") + options := NewCampaignOptions() + options.PrDescriptionFilename = "newprdescription.txt" + campaign, err := OpenCampaign(options) + assert.NoError(t, err) + + assert.Equal(t, "new PR title", campaign.PrTitle) + assert.Equal(t, "new PR body", campaign.PrBody) +} + +func TestItShouldErrorWhenPrDescriptionFileDoesNotExist(t *testing.T) { + testsupport.PrepareTempCampaign(false) + + options := NewCampaignOptions() + options.PrDescriptionFilename = "newprdescription.txt" + _, err := OpenCampaign(options) + assert.Error(t, err) +} + +func TestItShouldErrorWhenPrDescriptionFileNameIsEmpty(t *testing.T) { + testsupport.PrepareTempCampaign(false) + + options := NewCampaignOptions() + options.PrDescriptionFilename = "" _, err := OpenCampaign(options) assert.Error(t, err) } diff --git a/internal/testsupport/testsupport.go b/internal/testsupport/testsupport.go index 60c82c2..fab85be 100644 --- a/internal/testsupport/testsupport.go +++ b/internal/testsupport/testsupport.go @@ -16,6 +16,7 @@ package testsupport import ( + "fmt" "io/ioutil" "os" "path" @@ -72,3 +73,11 @@ func CreateAnotherRepoFile(filename string, repos ...string) { panic(err) } } + +func CreateAnotherPrDescriptionFile(filename string, prTitle string, prBody string) { + prDescription := fmt.Sprintf("# %s\n%s", prTitle, prBody) + err := os.WriteFile(filename, []byte(prDescription), os.ModePerm|0o644) + if err != nil { + panic(err) + } +}