Skip to content

Commit

Permalink
feat: Define prompter interface
Browse files Browse the repository at this point in the history
  • Loading branch information
johnmanjiro13 committed Jun 12, 2023
1 parent 8d1c8c4 commit 4196777
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 27 deletions.
50 changes: 27 additions & 23 deletions bumper.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ type Gh interface {
CreateRelease(version string, repo string, isCurrent bool, option *ReleaseOption) (sout, eout *bytes.Buffer, err error)
}

//go:generate mockgen -source=$GOFILE -package=mock -destination=./mock/mock_${GOPACKAGE}.go
type Prompter interface {
Input(question string, validator survey.Validator) (string, error)
Select(question string, options []string) (string, error)
Confirm(question string) (bool, error)
}

type ReleaseOption struct {
IsDraft bool
IsPrerelease bool
Expand All @@ -30,6 +37,7 @@ type ReleaseOption struct {

type bumper struct {
gh Gh
prompter Prompter
repository string
isCurrent bool
isDraft bool
Expand All @@ -45,7 +53,10 @@ type bumper struct {
}

func NewBumper(gh Gh) *bumper {
return &bumper{gh: gh}
return &bumper{
gh: gh,
prompter: newPrompter(),
}
}

func (b *bumper) WithRepository(repository string) error {
Expand Down Expand Up @@ -128,15 +139,15 @@ func (b *bumper) Bump() error {
return err
}
} else {
nextVer, err = nextVersion(current)
nextVer, err = b.nextVersion(current)
if err != nil {
return err
}
}

// Skip approval if --yes is set
if !b.yes {
ok, err := approve(nextVer)
ok, err := b.approve(nextVer)
if err != nil {
return err
}
Expand Down Expand Up @@ -177,7 +188,7 @@ func (b *bumper) currentVersion() (current *semver.Version, isInitial bool, err
sout, eout, err := b.gh.ViewRelease(b.repository, b.isCurrent)
if err != nil {
if strings.Contains(eout.String(), "release not found") {
current, err = newVersion()
current, err = b.newVersion()
if err != nil {
return nil, false, err
}
Expand All @@ -194,7 +205,7 @@ func (b *bumper) currentVersion() (current *semver.Version, isInitial bool, err
return current, false, nil
}

func newVersion() (*semver.Version, error) {
func (b *bumper) newVersion() (*semver.Version, error) {
validate := func(v interface{}) error {
input, ok := v.(string)
if !ok {
Expand All @@ -207,23 +218,18 @@ func newVersion() (*semver.Version, error) {
return nil
}

prompt := &survey.Input{
Message: "New version",
}
var version string
if err := survey.AskOne(prompt, &version, survey.WithValidator(validate)); err != nil {
version, err := b.prompter.Input("New version", validate)
if err != nil {
return nil, fmt.Errorf("failed to prompt. err: %w", err)
}
return semver.NewVersion(version)
}

func nextVersion(current *semver.Version) (*semver.Version, error) {
prompt := &survey.Select{
Message: fmt.Sprintf("Select next version. current: %s", current.Original()),
Options: []string{"patch", "minor", "major"},
}
var bumpType string
if err := survey.AskOne(prompt, &bumpType); err != nil {
func (b *bumper) nextVersion(current *semver.Version) (*semver.Version, error) {
question := fmt.Sprintf("Select next version. current: %s", current.Original())
options := []string{"patch", "minor", "major"}
bumpType, err := b.prompter.Select(question, options)
if err != nil {
return nil, fmt.Errorf("failed to prompt. err: %w", err)
}
return incrementVersion(current, bumpType)
Expand All @@ -244,12 +250,10 @@ func incrementVersion(current *semver.Version, bumpType string) (*semver.Version
return &next, nil
}

func approve(next *semver.Version) (bool, error) {
var isApproved bool
prompt := &survey.Confirm{
Message: fmt.Sprintf("Create release %s ?", next.Original()),
}
if err := survey.AskOne(prompt, &isApproved); err != nil {
func (b *bumper) approve(next *semver.Version) (bool, error) {
question := fmt.Sprintf("Create release %s ?", next.Original())
isApproved, err := b.prompter.Confirm(question)
if err != nil {
return false, fmt.Errorf("failed to prompt. err: %w", err)
}
return isApproved, nil
Expand Down
97 changes: 96 additions & 1 deletion bumper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,106 @@ import (
const (
repoDocs = `name: johnmanjiro13/gh-bump
description: gh extension for bumping version of a repository`
tagList = `v0.2.1 Latest v0.2.1 2021-12-08T04:19:16Z`
tagList = `v0.1.0 Latest v0.1.0 2021-12-08T04:19:16Z`
releaseView = `title: v0.1.0
tag: v0.1.0`
)

func TestBumper_Bump(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

gh := mock.NewMockGh(ctrl)
prompter := mock.NewMockPrompter(ctrl)
bumper := bump.NewBumper(gh)
bumper.SetPrompter(prompter)

t.Run("bump semver", func(t *testing.T) {
tests := map[string]struct {
bumpType string
next string
}{
"patch": {bumpType: "patch", next: "v0.1.1"},
"minor": {bumpType: "minor", next: "v0.2.0"},
"major": {bumpType: "major", next: "v1.0.0"},
}

for name, tt := range tests {
t.Run(name, func(t *testing.T) {
gh.EXPECT().ListRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(tagList), nil, nil)
gh.EXPECT().ViewRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(releaseView), nil, nil)

prompter.EXPECT().Select("Select next version. current: v0.1.0", []string{"patch", "minor", "major"}).Return(tt.bumpType, nil)
prompter.EXPECT().Confirm(fmt.Sprintf("Create release %s ?", tt.next)).Return(true, nil)
gh.EXPECT().CreateRelease(tt.next, bumper.Repository(), bumper.IsCurrent(), &bump.ReleaseOption{}).Return(nil, nil, nil)
assert.NoError(t, bumper.Bump())
})
}
})

t.Run("bump semver with option", func(t *testing.T) {
tests := map[string]struct {
bumpType string
next string
hasError bool
}{
"patch": {bumpType: "patch", next: "v0.1.1", hasError: false},
"minor": {bumpType: "minor", next: "v0.2.0", hasError: false},
"major": {bumpType: "major", next: "v1.0.0", hasError: false},
"invalid": {bumpType: "invalid", next: "", hasError: true},
}

for name, tt := range tests {
t.Run(name, func(t *testing.T) {
if tt.hasError {
assert.ErrorIsf(t, bumper.WithBumpType(tt.bumpType), bump.ErrInvalidBumpType, "got %s", tt.bumpType)
return
} else {
assert.NoError(t, bumper.WithBumpType(tt.bumpType))
}

gh.EXPECT().ListRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(tagList), nil, nil)
gh.EXPECT().ViewRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(releaseView), nil, nil)
prompter.EXPECT().Confirm(fmt.Sprintf("Create release %s ?", tt.next)).Return(true, nil)
gh.EXPECT().CreateRelease(tt.next, bumper.Repository(), bumper.IsCurrent(), &bump.ReleaseOption{}).Return(nil, nil, nil)
assert.NoError(t, bumper.Bump())
})
}
})

t.Run("cancel bump", func(t *testing.T) {
gh.EXPECT().ListRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(tagList), nil, nil)
gh.EXPECT().ViewRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(releaseView), nil, nil)

prompter.EXPECT().Select("Select next version. current: v0.1.0", []string{"patch", "minor", "major"}).Return("patch", nil)
prompter.EXPECT().Confirm("Create release v0.1.1 ?").Return(false, nil)
assert.NoError(t, bumper.Bump())
})

t.Run("bump another repository", func(t *testing.T) {
const repo = "johnmanjiro13/gh-bump"
assert.NoError(t, bumper.WithRepository("johnmanjiro13/gh-bump"))

gh.EXPECT().ListRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(tagList), nil, nil)
gh.EXPECT().ViewRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(releaseView), nil, nil)

prompter.EXPECT().Select("Select next version. current: v0.1.0", []string{"patch", "minor", "major"}).Return("patch", nil)
prompter.EXPECT().Confirm("Create release v0.1.1 ?").Return(true, nil)
gh.EXPECT().CreateRelease("v0.1.1", repo, false, &bump.ReleaseOption{}).Return(nil, nil, nil)
assert.NoError(t, bumper.Bump())
})

t.Run("bump with -y option", func(t *testing.T) {
bumper.WithYes()
gh.EXPECT().ListRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(tagList), nil, nil)
gh.EXPECT().ViewRelease(bumper.Repository(), bumper.IsCurrent()).Return(bytes.NewBufferString(releaseView), nil, nil)

prompter.EXPECT().Select("Select next version. current: v0.1.0", []string{"patch", "minor", "major"}).Return("patch", nil)
gh.EXPECT().CreateRelease("v0.1.1", bumper.Repository(), bumper.IsCurrent(), &bump.ReleaseOption{}).Return(nil, nil, nil)
assert.NoError(t, bumper.Bump())
})
}

func TestBumper_WithRepository(t *testing.T) {
tests := map[string]struct {
repository string
Expand Down
7 changes: 4 additions & 3 deletions export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ var (
ListReleases = (*bumper).listReleases
CreateRelease = (*bumper).createRelease
CurrentVersion = (*bumper).currentVersion
NewVersion = newVersion
NextVersion = nextVersion
IncrementVersion = incrementVersion
Approve = approve
)

func (b *bumper) SetPrompter(prompter Prompter) {
b.prompter = prompter
}

func (b *bumper) Repository() string {
return b.repository
}
Expand Down
69 changes: 69 additions & 0 deletions mock/mock_bump.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions prompt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package bump

import "github.com/AlecAivazis/survey/v2"

type prompter struct{}

func newPrompter() Prompter {
return &prompter{}
}

func (p *prompter) Input(question string, validator survey.Validator) (string, error) {
var result string
if err := survey.AskOne(&survey.Input{Message: question}, &result, survey.WithValidator(validator)); err != nil {
return "", err
}
return result, nil
}

func (p *prompter) Select(question string, options []string) (string, error) {
var result string
if err := survey.AskOne(&survey.Select{Message: question, Options: options}, &result); err != nil {
return "", err
}
return result, nil
}

func (p *prompter) Confirm(question string) (bool, error) {
var result bool
if err := survey.AskOne(&survey.Confirm{Message: question}, &result); err != nil {
return false, err
}
return result, nil
}

0 comments on commit 4196777

Please sign in to comment.