Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(create_prs): check whether PR description file has been updated #145

Merged
merged 7 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions cmd/create_prs/create_prs.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
package create_prs

import (
"fmt"
"github.com/skyscanner/turbolift/internal/prompt"
"os"
"path"
"strings"
"time"

"github.com/spf13/cobra"
Expand All @@ -32,6 +35,7 @@ import (
var (
gh github.GitHub = github.NewRealGitHub()
g git.Git = git.NewRealGit()
p prompt.Prompt = prompt.NewRealPrompt()
)

var (
Expand Down Expand Up @@ -68,6 +72,11 @@ func run(c *cobra.Command, _ []string) {
readCampaignActivity.EndWithFailure(err)
return
}
if prDescriptionUnchanged(dir) {
if !p.AskConfirm(fmt.Sprintf("It looks like the PR title and/or description may not have been updated in %s. Are you sure you want to proceed?", prDescriptionFile)) {
return
}
}
readCampaignActivity.EndWithSuccess()

doneCount := 0
Expand Down Expand Up @@ -131,3 +140,9 @@ func run(c *cobra.Command, _ []string) {
logger.Warnf("turbolift create-prs completed with %s %s(%s, %s, %s)\n", colors.Red("errors"), colors.Normal(), colors.Green(doneCount, " OK"), colors.Yellow(skippedCount, " skipped"), colors.Red(errorCount, " errored"))
}
}

func prDescriptionUnchanged(dir *campaign.Campaign) bool {
originalPrTitleTodo := "TODO: Title of Pull Request"
originalPrBodyTodo := "TODO: This file will serve as both a README and the description of the PR."
return strings.Contains(dir.PrTitle, originalPrTitleTodo) || strings.Contains(dir.PrBody, originalPrBodyTodo) || dir.PrTitle == ""
}
125 changes: 125 additions & 0 deletions cmd/create_prs/create_prs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,98 @@ import (
"bytes"
"github.com/skyscanner/turbolift/internal/git"
"github.com/skyscanner/turbolift/internal/github"
"github.com/skyscanner/turbolift/internal/prompt"
"github.com/skyscanner/turbolift/internal/testsupport"
"github.com/stretchr/testify/assert"
"testing"
)

func TestItWarnsIfDescriptionFileTemplateIsUnchanged(t *testing.T) {
fakeGitHub := github.NewAlwaysFailsFakeGitHub()
gh = fakeGitHub
fakeGit := git.NewAlwaysSucceedsFakeGit()
g = fakeGit
fakePrompt := prompt.NewFakePromptNo()
p = fakePrompt

testsupport.PrepareTempCampaign(true, "org/repo1", "org/repo2")
testsupport.UseDefaultPrDescription()

out, err := runCommand()
assert.NoError(t, err)
assert.NotContains(t, out, "Creating PR in org/repo1")
assert.NotContains(t, out, "Creating PR in org/repo2")
assert.NotContains(t, out, "turbolift create-prs completed")
assert.NotContains(t, out, "2 OK, 0 skipped")

fakePrompt.AssertCalledWith(t, "It looks like the PR title and/or description may not have been updated in README.md. Are you sure you want to proceed?")
}

func TestItWarnsIfOnlyPrTitleIsUnchanged(t *testing.T) {
fakeGitHub := github.NewAlwaysFailsFakeGitHub()
gh = fakeGitHub
fakeGit := git.NewAlwaysSucceedsFakeGit()
g = fakeGit
fakePrompt := prompt.NewFakePromptNo()
p = fakePrompt

testsupport.PrepareTempCampaign(true, "org/repo1", "org/repo2")
testsupport.UsePrTitleTodoOnly()

out, err := runCommand()
assert.NoError(t, err)
assert.NotContains(t, out, "Creating PR in org/repo1")
assert.NotContains(t, out, "Creating PR in org/repo2")
assert.NotContains(t, out, "turbolift create-prs completed")
assert.NotContains(t, out, "2 OK, 0 skipped")

fakePrompt.AssertCalledWith(t, "It looks like the PR title and/or description may not have been updated in README.md. Are you sure you want to proceed?")
}

func TestItWarnsIfOnlyPrBodyIsUnchanged(t *testing.T) {
fakeGitHub := github.NewAlwaysFailsFakeGitHub()
gh = fakeGitHub
fakeGit := git.NewAlwaysSucceedsFakeGit()
g = fakeGit
fakePrompt := prompt.NewFakePromptNo()
p = fakePrompt

testsupport.PrepareTempCampaign(true, "org/repo1", "org/repo2")
testsupport.UsePrBodyTodoOnly()

out, err := runCommand()
assert.NoError(t, err)
assert.NotContains(t, out, "Creating PR in org/repo1")
assert.NotContains(t, out, "Creating PR in org/repo2")
assert.NotContains(t, out, "turbolift create-prs completed")
assert.NotContains(t, out, "2 OK, 0 skipped")

fakePrompt.AssertCalledWith(t, "It looks like the PR title and/or description may not have been updated in README.md. Are you sure you want to proceed?")
}

func TestItWarnsIfDescriptionFileIsEmpty(t *testing.T) {
fakeGitHub := github.NewAlwaysFailsFakeGitHub()
gh = fakeGitHub
fakeGit := git.NewAlwaysSucceedsFakeGit()
g = fakeGit
fakePrompt := prompt.NewFakePromptNo()
p = fakePrompt

customDescriptionFileName := "custom.md"

testsupport.PrepareTempCampaign(true, "org/repo1", "org/repo2")
testsupport.CreateOrUpdatePrDescriptionFile(customDescriptionFileName, "", "")

out, err := runCommandWithAlternativeDescriptionFile(customDescriptionFileName)
assert.NoError(t, err)
assert.NotContains(t, out, "Creating PR in org/repo1")
assert.NotContains(t, out, "Creating PR in org/repo2")
assert.NotContains(t, out, "turbolift create-prs completed")
assert.NotContains(t, out, "2 OK, 0 skipped")

fakePrompt.AssertCalledWith(t, "It looks like the PR title and/or description may not have been updated in custom.md. Are you sure you want to proceed?")
}

func TestItLogsCreatePrErrorsButContinuesToTryAll(t *testing.T) {
fakeGitHub := github.NewAlwaysFailsFakeGitHub()
gh = fakeGitHub
Expand Down Expand Up @@ -106,6 +193,31 @@ func TestItLogsCreateDraftPr(t *testing.T) {
})
}

func TestItCreatesPrsFromAlternativeDescriptionFile(t *testing.T) {
fakeGitHub := github.NewAlwaysSucceedsFakeGitHub()
gh = fakeGitHub
fakeGit := git.NewAlwaysSucceedsFakeGit()
g = fakeGit

customDescriptionFileName := "custom.md"

testsupport.PrepareTempCampaign(true, "org/repo1", "org/repo2")
testsupport.CreateOrUpdatePrDescriptionFile(customDescriptionFileName, "custom PR title", "custom PR body")

out, err := runCommandWithAlternativeDescriptionFile(customDescriptionFileName)
assert.NoError(t, err)
assert.Contains(t, out, "Reading campaign data (repos.txt, custom.md)")
assert.Contains(t, out, "Creating PR in org/repo1")
assert.Contains(t, out, "Creating PR in org/repo2")
assert.Contains(t, out, "turbolift create-prs completed")
assert.Contains(t, out, "2 OK, 0 skipped")

fakeGitHub.AssertCalledWith(t, [][]string{
{"work/org/repo1", "custom PR title"},
{"work/org/repo2", "custom PR title"},
})
}

func runCommand() (string, error) {
cmd := NewCreatePRsCmd()
outBuffer := bytes.NewBufferString("")
Expand All @@ -118,6 +230,19 @@ func runCommand() (string, error) {
return outBuffer.String(), nil
}

func runCommandWithAlternativeDescriptionFile(fileName string) (string, error) {
cmd := NewCreatePRsCmd()
prDescriptionFile = fileName
outBuffer := bytes.NewBufferString("")
cmd.SetOut(outBuffer)
err := cmd.Execute()

if err != nil {
return outBuffer.String(), err
}
return outBuffer.String(), nil
}

func runCommandDraft() (string, error) {
cmd := NewCreatePRsCmd()
isDraft = true
Expand Down
13 changes: 11 additions & 2 deletions internal/prompt/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package prompt

import (
"strings"
"testing"

"github.com/manifoldco/promptui"
"github.com/stretchr/testify/assert"
)

type Prompt interface {
Expand Down Expand Up @@ -49,12 +51,19 @@ func (f FakePromptYes) AskConfirm(_ string) bool {
}

// Mock Prompt that always returns false
type FakePromptNo struct{}
type FakePromptNo struct {
call string
}

func NewFakePromptNo() *FakePromptNo {
return &FakePromptNo{}
}

func (f FakePromptNo) AskConfirm(_ string) bool {
func (f *FakePromptNo) AskConfirm(question string) bool {
f.call = question
return false
}

func (f *FakePromptNo) AssertCalledWith(t *testing.T, expected string) {
assert.Equal(t, expected, f.call)
}
15 changes: 15 additions & 0 deletions internal/testsupport/testsupport.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
"strings"
)

var originalPrTitleTodo = "TODO: Title of Pull Request"
var originalPrBodyTodo = "TODO: This file will serve as both a README and the description of the PR."

func Pwd() string {
dir, _ := os.Getwd()
return filepath.Base(dir)
Expand Down Expand Up @@ -81,3 +84,15 @@ func CreateOrUpdatePrDescriptionFile(filename string, prTitle string, prBody str
panic(err)
}
}

func UseDefaultPrDescription() {
CreateOrUpdatePrDescriptionFile("README.md", originalPrTitleTodo, originalPrBodyTodo)
}

func UsePrTitleTodoOnly() {
CreateOrUpdatePrDescriptionFile("README.md", originalPrTitleTodo, "updated PR body")
}

func UsePrBodyTodoOnly() {
CreateOrUpdatePrDescriptionFile("README.md", "updated PR title", originalPrBodyTodo)
}
Loading