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: added --merge-type flag #64

Merged
merged 2 commits into from
Jan 21, 2021
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
1 change: 1 addition & 0 deletions cmd/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func MergeCmd() *cobra.Command {
}

cmd.Flags().StringP("branch", "B", "multi-gitter-branch", "The name of the branch where changes are committed.")
cmd.Flags().StringSliceP("merge-type", "", []string{"merge", "squash", "rebase"}, "The type of merge that should be done (GitHub). Multiple types can be used as backup strategies if the first one is not allowed.")
cmd.Flags().AddFlagSet(platformFlags())
cmd.Flags().AddFlagSet(logFlags("-"))

Expand Down
13 changes: 12 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"time"

"github.com/lindell/multi-gitter/internal/domain"
"github.com/lindell/multi-gitter/internal/github"
"github.com/lindell/multi-gitter/internal/gitlab"
"github.com/lindell/multi-gitter/internal/multigitter"
Expand Down Expand Up @@ -138,6 +139,7 @@ func createGithubClient(flag *flag.FlagSet) (multigitter.VersionController, erro
orgs, _ := flag.GetStringSlice("org")
users, _ := flag.GetStringSlice("user")
repos, _ := flag.GetStringSlice("repo")
mergeTypeStrs, _ := flag.GetStringSlice("merge-type") // Only used for the merge command

if len(orgs) == 0 && len(users) == 0 && len(repos) == 0 {
return nil, errors.New("no organization or user set")
Expand All @@ -156,11 +158,20 @@ func createGithubClient(flag *flag.FlagSet) (multigitter.VersionController, erro
}
}

// Convert all defined merge types (if any)
mergeTypes := make([]domain.MergeType, len(mergeTypeStrs))
for i, mt := range mergeTypeStrs {
mergeTypes[i], err = domain.ParseMergeType(mt)
if err != nil {
return nil, err
}
}

vc, err := github.New(token, ghBaseURL, github.RepositoryListing{
Organizations: orgs,
Users: users,
Repositories: repoRefs,
})
}, mergeTypes)
if err != nil {
return nil, err
}
Expand Down
43 changes: 43 additions & 0 deletions internal/domain/pr.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package domain

import (
"fmt"
"strings"
)

// NewPullRequest is the data needed to create a new pull request
type NewPullRequest struct {
Title string
Expand Down Expand Up @@ -46,3 +51,41 @@ type PullRequest interface {
Status() PullRequestStatus
String() string
}

// MergeType is the way a pull request is "merged" into the base branch
type MergeType int

// All MergeTypes
const (
MergeTypeUnknown MergeType = iota
MergeTypeMerge
MergeTypeRebase
MergeTypeSquash
)

// ParseMergeType parses a merge type
func ParseMergeType(typ string) (MergeType, error) {
switch strings.ToLower(typ) {
case "merge":
return MergeTypeMerge, nil
case "rebase":
return MergeTypeRebase, nil
case "squash":
return MergeTypeSquash, nil
}
return MergeTypeUnknown, fmt.Errorf(`not a valid merge type: "%s"`, typ)
}

// MergeTypeIntersection calculates the intersection of two merge type slices,
// The order of the first slice will be preserved
func MergeTypeIntersection(mergeTypes1, mergeTypes2 []MergeType) []MergeType {
res := []MergeType{}
for _, mt := range mergeTypes1 {
for _, mt2 := range mergeTypes2 {
if mt == mt2 {
res = append(res, mt)
}
}
}
return res
}
23 changes: 20 additions & 3 deletions internal/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package github

import (
"context"
"errors"
"fmt"
"net/url"
"sort"
Expand All @@ -16,7 +17,7 @@ import (
)

// New create a new Github client
func New(token, baseURL string, repoListing RepositoryListing) (*Github, error) {
func New(token, baseURL string, repoListing RepositoryListing, mergeTypes []domain.MergeType) (*Github, error) {
ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
Expand All @@ -39,14 +40,16 @@ func New(token, baseURL string, repoListing RepositoryListing) (*Github, error)

return &Github{
RepositoryListing: repoListing,
MergeTypes: mergeTypes,
ghClient: client,
}, nil
}

// Github contain github configuration
type Github struct {
RepositoryListing
ghClient *github.Client
MergeTypes []domain.MergeType
ghClient *github.Client
}

// RepositoryListing contains information about which repositories that should be fetched
Expand Down Expand Up @@ -365,7 +368,21 @@ func (g Github) GetPullRequestStatuses(ctx context.Context, branchName string) (
func (g Github) MergePullRequest(ctx context.Context, pullReq domain.PullRequest) error {
pr := pullReq.(pullRequest)

_, _, err := g.ghClient.PullRequests.Merge(ctx, pr.ownerName, pr.repoName, pr.number, "", nil)
// We need to fetch the repo again since no AllowXMerge is present in listings of repositories
repo, _, err := g.ghClient.Repositories.Get(ctx, pr.ownerName, pr.repoName)
if err != nil {
return err
}

// Filter out all merge types to only the allowed ones, but keep the order of the ones left
mergeTypes := domain.MergeTypeIntersection(g.MergeTypes, repoMergeTypes(repo))
if len(mergeTypes) == 0 {
return errors.New("none of the configured merge types was permitted")
}

_, _, err = g.ghClient.PullRequests.Merge(ctx, pr.ownerName, pr.repoName, pr.number, "", &github.PullRequestOptions{
MergeMethod: mergeTypeGhName[mergeTypes[0]],
})
if err != nil {
return err
}
Expand Down
28 changes: 28 additions & 0 deletions internal/github/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package github

import (
"github.com/google/go-github/v32/github"
"github.com/lindell/multi-gitter/internal/domain"
)

// maps merge types to what they are called in the github api
var mergeTypeGhName = map[domain.MergeType]string{
domain.MergeTypeMerge: "merge",
domain.MergeTypeRebase: "rebase",
domain.MergeTypeSquash: "squash",
}

// repoMergeTypes returns a list of all allowed merge types
func repoMergeTypes(repo *github.Repository) []domain.MergeType {
ret := []domain.MergeType{}
if repo.GetAllowMergeCommit() {
ret = append(ret, domain.MergeTypeMerge)
}
if repo.GetAllowRebaseMerge() {
ret = append(ret, domain.MergeTypeRebase)
}
if repo.GetAllowSquashMerge() {
ret = append(ret, domain.MergeTypeSquash)
}
return ret
}