diff --git a/git/helpers.go b/git/helpers.go index 8faba68..b116058 100644 --- a/git/helpers.go +++ b/git/helpers.go @@ -10,6 +10,7 @@ import ( "github.com/rs/zerolog/log" ) +// GetLocalBranchName returns the current local git branch func GetLocalBranchName(gitcmd GitInterface) string { var output string err := gitcmd.Git("branch --no-color", &output) @@ -23,6 +24,11 @@ func GetLocalBranchName(gitcmd GitInterface) string { panic("cannot determine local git branch name") } +func BranchNameFromCommit(commit Commit) string { + return "spr/" + commit.CommitID +} + +// GetRemoteBranchName func GetRemoteBranchName(repoConfig *config.RepoConfig, gitcmd GitInterface) string { localBranchName := GetLocalBranchName(gitcmd) @@ -34,7 +40,20 @@ func GetRemoteBranchName(repoConfig *config.RepoConfig, gitcmd GitInterface) str return repoConfig.GitHubBranch } -// getLocalCommitStack returns a list of unmerged commits +// GetLocalTopCommit returns the top unmerged commit in the stack +// +// return nil if there are no unmerged commits in the stack +func GetLocalTopCommit(repoConfig *config.RepoConfig, gitcmd GitInterface) *Commit { + commits := GetLocalCommitStack(repoConfig, gitcmd) + if len(commits) == 0 { + return nil + } + return &commits[len(commits)-1] +} + +// GetLocalCommitStack returns a list of unmerged commits +// +// the list is ordered with the bottom commit in the stack first func GetLocalCommitStack(repoConfig *config.RepoConfig, gitcmd GitInterface) []Commit { var commitLog string targetBranch := GetRemoteBranchName(repoConfig, gitcmd) diff --git a/git/mockgit/mockgit.go b/git/mockgit/mockgit.go index 18b71ac..43ba709 100644 --- a/git/mockgit/mockgit.go +++ b/git/mockgit/mockgit.go @@ -80,7 +80,7 @@ func (m *Mock) ExpectPushCommits(commits []*git.Commit) { var refNames []string for _, c := range commits { - branchName := "spr/master/" + c.CommitID + branchName := "spr/" + c.CommitID refNames = append(refNames, c.CommitHash+":refs/heads/"+branchName) } m.expect("git push --force --atomic origin " + strings.Join(refNames, " ")) diff --git a/github/githubclient/client.go b/github/githubclient/client.go index 4034101..ae80f7c 100644 --- a/github/githubclient/client.go +++ b/github/githubclient/client.go @@ -174,7 +174,7 @@ type client struct { api genclient.Client } -var BranchNameRegex = regexp.MustCompile(`spr/([a-zA-Z0-9_\-/\.]+)/([a-f0-9]{8})$`) +var BranchNameRegex = regexp.MustCompile(`spr/([a-f0-9]{8})$`) func (c *client) GetInfo(ctx context.Context, gitcmd git.GitInterface) *github.GitHubInfo { if c.config.User.LogGitHubCalls { @@ -185,13 +185,41 @@ func (c *client) GetInfo(ctx context.Context, gitcmd git.GitInterface) *github.G c.config.Repo.GitHubRepoName) check(err) - branchname := git.GetLocalBranchName(gitcmd) + targetBranch := git.GetRemoteBranchName(c.config.Repo, gitcmd) + localCommitStack := git.GetLocalCommitStack(c.config.Repo, gitcmd) - var requests []*github.PullRequest - for _, node := range *resp.Repository.PullRequests.Nodes { - if resp.Repository.Id != node.Repository.Id { - continue + pullRequests := matchPullRequestStack(targetBranch, localCommitStack, resp.Repository.PullRequests) + for _, pr := range pullRequests { + if pr.Ready(c.config) { + pr.MergeStatus.Stacked = true + } else { + break } + } + + info := &github.GitHubInfo{ + UserName: resp.Viewer.Login, + RepositoryID: resp.Repository.Id, + LocalBranch: git.GetLocalBranchName(gitcmd), + PullRequests: pullRequests, + } + + log.Debug().Interface("Info", info).Msg("GetInfo") + return info +} + +func matchPullRequestStack( + targetBranch string, + localCommitStack []git.Commit, + allPullRequests genclient.PullRequestsRepositoryPullRequests) []*github.PullRequest { + + if len(localCommitStack) == 0 || allPullRequests.Nodes == nil { + return []*github.PullRequest{} + } + + // pullRequestMap is a map from commit-id to pull request + pullRequestMap := make(map[string]*github.PullRequest) + for _, node := range *allPullRequests.Nodes { pullRequest := &github.PullRequest{ ID: node.Id, Number: node.Number, @@ -202,10 +230,10 @@ func (c *client) GetInfo(ctx context.Context, gitcmd git.GitInterface) *github.G } matches := BranchNameRegex.FindStringSubmatch(node.HeadRefName) - if matches != nil && matches[1] == branchname { + if matches != nil { commit := (*node.Commits.Nodes)[0].Commit pullRequest.Commit = git.Commit{ - CommitID: matches[2], + CommitID: matches[1], CommitHash: commit.Oid, Subject: commit.MessageHeadline, Body: commit.MessageBody, @@ -227,23 +255,49 @@ func (c *client) GetInfo(ctx context.Context, gitcmd git.GitInterface) *github.G NoConflicts: node.Mergeable == "MERGEABLE", } - requests = append(requests, pullRequest) + pullRequestMap[pullRequest.Commit.CommitID] = pullRequest } } - targetBranch := git.GetRemoteBranchName(c.config.Repo, gitcmd) - requests = sortPullRequests(requests, c.config, targetBranch) + var pullRequests []*github.PullRequest - info := &github.GitHubInfo{ - UserName: resp.Viewer.Login, - RepositoryID: resp.Repository.Id, - LocalBranch: branchname, - PullRequests: requests, + // find top pr + var currpr *github.PullRequest + var found bool + for i := len(localCommitStack) - 1; i >= 0; i-- { + currpr, found = pullRequestMap[localCommitStack[i].CommitID] + if found { + break + } } - log.Debug().Interface("Info", info).Msg("GetInfo") + // The list of commits from the command line actually starts at the + // most recent commit. In order to reverse the list we use a + // custom prepend function instead of append + prepend := func(l []*github.PullRequest, pr *github.PullRequest) []*github.PullRequest { + l = append(l, &github.PullRequest{}) + copy(l[1:], l) + l[0] = pr + return l + } - return info + // build pr stack + for currpr != nil { + pullRequests = prepend(pullRequests, currpr) + if currpr.ToBranch == targetBranch { + break + } + + matches := BranchNameRegex.FindStringSubmatch(currpr.ToBranch) + if matches == nil { + panic(fmt.Errorf("invalid base branch for pull request:%s", currpr.ToBranch)) + } + nextCommitID := matches[1] + + currpr = pullRequestMap[nextCommitID] + } + + return pullRequests } // GetAssignableUsers is taken from github.com/cli/cli/api and is the approach used by the official gh @@ -288,9 +342,9 @@ func (c *client) CreatePullRequest(ctx context.Context, gitcmd git.GitInterface, baseRefName := git.GetRemoteBranchName(c.config.Repo, gitcmd) if prevCommit != nil { - baseRefName = branchNameFromCommit(info, *prevCommit) + baseRefName = git.BranchNameFromCommit(*prevCommit) } - headRefName := branchNameFromCommit(info, commit) + headRefName := git.BranchNameFromCommit(commit) log.Debug().Interface("Commit", commit). Str("FromBranch", headRefName).Str("ToBranch", baseRefName). @@ -447,7 +501,7 @@ func (c *client) UpdatePullRequest(ctx context.Context, gitcmd git.GitInterface, baseRefName := git.GetRemoteBranchName(c.config.Repo, gitcmd) if prevCommit != nil { - baseRefName = branchNameFromCommit(info, *prevCommit) + baseRefName = git.BranchNameFromCommit(*prevCommit) } log.Debug().Interface("Commit", commit). @@ -580,44 +634,6 @@ func (c *client) ClosePullRequest(ctx context.Context, pr *github.PullRequest) { } } -func branchNameFromCommit(info *github.GitHubInfo, commit git.Commit) string { - return "spr/" + info.LocalBranch + "/" + commit.CommitID -} - -// sortPullRequests sorts the pull requests so that the one that is on top of -// the target branch will come first followed by the ones that are stacked on top. -// The stack order is maintained so that multiple pull requests can be merged in -// the correct order. -func sortPullRequests(prs []*github.PullRequest, config *config.Config, targetBranch string) []*github.PullRequest { - swap := func(i int, j int) { - buf := prs[i] - prs[i] = prs[j] - prs[j] = buf - } - - j := 0 - for i := 0; i < len(prs); i++ { - for j = i; j < len(prs); j++ { - if prs[j].ToBranch == targetBranch { - targetBranch = prs[j].FromBranch - swap(i, j) - break - } - } - } - - // update stacked merge status flag - for _, pr := range prs { - if pr.Ready(config) { - pr.MergeStatus.Stacked = true - } else { - break - } - } - - return prs -} - func check(err error) { if err != nil { msg := err.Error() diff --git a/github/githubclient/client_test.go b/github/githubclient/client_test.go index 111087f..c9c9840 100644 --- a/github/githubclient/client_test.go +++ b/github/githubclient/client_test.go @@ -7,25 +7,415 @@ import ( "github.com/ejoffe/spr/config" "github.com/ejoffe/spr/git" "github.com/ejoffe/spr/github" + "github.com/ejoffe/spr/github/githubclient/gen/genclient" + "github.com/stretchr/testify/require" ) +func TestMatchPullRequestStack(t *testing.T) { + tests := []struct { + name string + commits []git.Commit + prs genclient.PullRequestsRepositoryPullRequests + expect []*github.PullRequest + }{ + { + name: "Empty", + commits: []git.Commit{}, + prs: genclient.PullRequestsRepositoryPullRequests{}, + expect: []*github.PullRequest{}, + }, + { + name: "FirstCommit", + commits: []git.Commit{{CommitID: "00000001"}}, + prs: genclient.PullRequestsRepositoryPullRequests{}, + expect: []*github.PullRequest{}, + }, + { + name: "SecondCommit", + commits: []git.Commit{ + {CommitID: "00000001"}, + {CommitID: "00000002"}, + }, + prs: genclient.PullRequestsRepositoryPullRequests{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodes{ + { + Id: "1", + HeadRefName: "spr/00000001", + BaseRefName: "master", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "1"}, + }, + }, + }, + }, + }, + }, + expect: []*github.PullRequest{ + { + ID: "1", + FromBranch: "spr/00000001", + ToBranch: "master", + Commit: git.Commit{ + CommitID: "00000001", + CommitHash: "1", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + }, + }, + { + name: "ThirdCommit", + commits: []git.Commit{ + {CommitID: "00000001"}, + {CommitID: "00000002"}, + {CommitID: "00000003"}, + }, + prs: genclient.PullRequestsRepositoryPullRequests{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodes{ + { + Id: "1", + HeadRefName: "spr/00000001", + BaseRefName: "master", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "1"}, + }, + }, + }, + }, + { + Id: "2", + HeadRefName: "spr/00000002", + BaseRefName: "spr/00000001", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "2"}, + }, + }, + }, + }, + }, + }, + expect: []*github.PullRequest{ + { + ID: "1", + FromBranch: "spr/00000001", + ToBranch: "master", + Commit: git.Commit{ + CommitID: "00000001", + CommitHash: "1", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + { + ID: "2", + FromBranch: "spr/00000002", + ToBranch: "spr/00000001", + Commit: git.Commit{ + CommitID: "00000002", + CommitHash: "2", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + }, + }, + { + name: "RemoveOnlyCommit", + commits: []git.Commit{}, + prs: genclient.PullRequestsRepositoryPullRequests{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodes{ + { + Id: "1", + HeadRefName: "spr/00000001", + BaseRefName: "master", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "1"}, + }, + }, + }, + }, + }, + }, + expect: []*github.PullRequest{}, + }, + { + name: "RemoveTopCommit", + commits: []git.Commit{ + {CommitID: "00000001"}, + {CommitID: "00000002"}, + }, + prs: genclient.PullRequestsRepositoryPullRequests{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodes{ + { + Id: "1", + HeadRefName: "spr/00000001", + BaseRefName: "master", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "1"}, + }, + }, + }, + }, + { + Id: "3", + HeadRefName: "spr/00000003", + BaseRefName: "spr/00000002", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "2"}, + }, + }, + }, + }, + { + Id: "2", + HeadRefName: "spr/00000002", + BaseRefName: "spr/00000001", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "2"}, + }, + }, + }, + }, + }, + }, + expect: []*github.PullRequest{ + { + ID: "1", + FromBranch: "spr/00000001", + ToBranch: "master", + Commit: git.Commit{ + CommitID: "00000001", + CommitHash: "1", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + { + ID: "2", + FromBranch: "spr/00000002", + ToBranch: "spr/00000001", + Commit: git.Commit{ + CommitID: "00000002", + CommitHash: "2", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + }, + }, + { + name: "RemoveMiddleCommit", + commits: []git.Commit{ + {CommitID: "00000001"}, + {CommitID: "00000003"}, + }, + prs: genclient.PullRequestsRepositoryPullRequests{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodes{ + { + Id: "1", + HeadRefName: "spr/00000001", + BaseRefName: "master", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "1"}, + }, + }, + }, + }, + { + Id: "2", + HeadRefName: "spr/00000002", + BaseRefName: "spr/00000001", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "2"}, + }, + }, + }, + }, + { + Id: "3", + HeadRefName: "spr/00000003", + BaseRefName: "spr/00000002", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "3"}, + }, + }, + }, + }, + }, + }, + expect: []*github.PullRequest{ + { + ID: "1", + FromBranch: "spr/00000001", + ToBranch: "master", + Commit: git.Commit{ + CommitID: "00000001", + CommitHash: "1", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + { + ID: "2", + FromBranch: "spr/00000002", + ToBranch: "spr/00000001", + Commit: git.Commit{ + CommitID: "00000002", + CommitHash: "2", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + { + ID: "3", + FromBranch: "spr/00000003", + ToBranch: "spr/00000002", + Commit: git.Commit{ + CommitID: "00000003", + CommitHash: "3", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + }, + }, + { + name: "RemoveBottomCommit", + commits: []git.Commit{ + {CommitID: "00000002"}, + {CommitID: "00000003"}, + }, + prs: genclient.PullRequestsRepositoryPullRequests{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodes{ + { + Id: "1", + HeadRefName: "spr/00000001", + BaseRefName: "master", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "1"}, + }, + }, + }, + }, + { + Id: "2", + HeadRefName: "spr/00000002", + BaseRefName: "spr/00000001", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "2"}, + }, + }, + }, + }, + { + Id: "3", + HeadRefName: "spr/00000003", + BaseRefName: "spr/00000002", + Commits: genclient.PullRequestsRepositoryPullRequestsNodesCommits{ + Nodes: &genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodes{ + { + genclient.PullRequestsRepositoryPullRequestsNodesCommitsNodesCommit{Oid: "3"}, + }, + }, + }, + }, + }, + }, + expect: []*github.PullRequest{ + { + ID: "1", + FromBranch: "spr/00000001", + ToBranch: "master", + Commit: git.Commit{ + CommitID: "00000001", + CommitHash: "1", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + + { + ID: "2", + FromBranch: "spr/00000002", + ToBranch: "spr/00000001", + Commit: git.Commit{ + CommitID: "00000002", + CommitHash: "2", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + { + ID: "3", + FromBranch: "spr/00000003", + ToBranch: "spr/00000002", + Commit: git.Commit{ + CommitID: "00000003", + CommitHash: "3", + }, + MergeStatus: github.PullRequestMergeStatus{ + ChecksPass: github.CheckStatusFail, + }, + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := matchPullRequestStack("master", tc.commits, tc.prs) + require.Equal(t, tc.expect, actual) + }) + } +} + func TestPullRequestRegex(t *testing.T) { tests := []struct { input string - branch string commit string }{ - {input: "spr/branchname/deadbeef", branch: "branchname", commit: "deadbeef"}, - {input: "spr/branch/name/deadbeef", branch: "branch/name", commit: "deadbeef"}, + {input: "spr/deadbeef", commit: "deadbeef"}, } for _, tc := range tests { matches := BranchNameRegex.FindStringSubmatch(tc.input) - if tc.branch != matches[1] { - t.Fatalf("expected: '%v', actual: '%v'", tc.branch, matches[1]) - } - if tc.commit != matches[2] { - t.Fatalf("expected: '%v', actual: '%v'", tc.commit, matches[2]) + if tc.commit != matches[1] { + t.Fatalf("expected: '%v', actual: '%v'", tc.commit, matches[1]) } } } @@ -268,67 +658,3 @@ func TestInsertBodyIntoPRTemplateErrors(t *testing.T) { }) } } - -func TestSortPullRequests(t *testing.T) { - prs := []*github.PullRequest{ - { - Number: 3, - FromBranch: "third", - ToBranch: "second", - }, - { - Number: 2, - FromBranch: "second", - ToBranch: "first", - }, - { - Number: 1, - FromBranch: "first", - ToBranch: "master", - }, - } - - config := config.DefaultConfig() - prs = sortPullRequests(prs, config, "master") - if prs[0].Number != 1 { - t.Fatalf("prs not sorted correctly %v\n", prs) - } - if prs[1].Number != 2 { - t.Fatalf("prs not sorted correctly %v\n", prs) - } - if prs[2].Number != 3 { - t.Fatalf("prs not sorted correctly %v\n", prs) - } -} - -func TestSortPullRequestsMixed(t *testing.T) { - prs := []*github.PullRequest{ - { - Number: 3, - FromBranch: "third", - ToBranch: "second", - }, - { - Number: 1, - FromBranch: "first", - ToBranch: "master", - }, - { - Number: 2, - FromBranch: "second", - ToBranch: "first", - }, - } - - config := config.DefaultConfig() - prs = sortPullRequests(prs, config, "master") - if prs[0].Number != 1 { - t.Fatalf("prs not sorted correctly %v\n", prs) - } - if prs[1].Number != 2 { - t.Fatalf("prs not sorted correctly %v\n", prs) - } - if prs[2].Number != 3 { - t.Fatalf("prs not sorted correctly %v\n", prs) - } -} diff --git a/github/interface.go b/github/interface.go index d5ed7a2..0824c88 100644 --- a/github/interface.go +++ b/github/interface.go @@ -8,13 +8,28 @@ import ( ) type GitHubInterface interface { + // GetInfo returns the list of pull requests from GitHub which match the local stack of commits GetInfo(ctx context.Context, gitcmd git.GitInterface) *GitHubInfo + + // GetAssignableUsers returns a list of valid GitHub users that can review the pull request GetAssignableUsers(ctx context.Context) []RepoAssignee + + // CreatePullRequest creates a pull request CreatePullRequest(ctx context.Context, gitcmd git.GitInterface, info *GitHubInfo, commit git.Commit, prevCommit *git.Commit) *PullRequest + + // UpdatePullRequest updates a pull request with current commit UpdatePullRequest(ctx context.Context, gitcmd git.GitInterface, info *GitHubInfo, pr *PullRequest, commit git.Commit, prevCommit *git.Commit) + + // AddReviewers adds a reviewer to the given pull request AddReviewers(ctx context.Context, pr *PullRequest, userIDs []string) + + // CommentPullRequest add a comment to the given pull request CommentPullRequest(ctx context.Context, pr *PullRequest, comment string) + + // MergePullRequest merged the given pull request MergePullRequest(ctx context.Context, pr *PullRequest, mergeMethod genclient.PullRequestMergeMethod) + + // ClosePullRequest closes the given pull request ClosePullRequest(ctx context.Context, pr *PullRequest) } diff --git a/go.mod b/go.mod index 6e3d397..8fce1a5 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/jessevdk/go-flags v1.5.0 github.com/rs/zerolog v1.26.1 github.com/stretchr/testify v1.7.0 + github.com/tidwall/pretty v1.2.0 github.com/urfave/cli/v2 v2.3.0 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 diff --git a/pretty/pretty.go b/pretty/pretty.go new file mode 100644 index 0000000..8de9fae --- /dev/null +++ b/pretty/pretty.go @@ -0,0 +1,54 @@ +package pretty + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "os" + + "github.com/tidwall/pretty" +) + +// PrettyWriter uses json marshal to pretty output an interface object +func PrettyWriter(object interface{}, writer io.Writer) { + objectString, err := json.MarshalIndent(object, "", " ") + check(err) + _, err = writer.Write(objectString) + check(err) +} + +// PrefixPrettyWriter uses json marshal to pretty output an interface object +func PrefixPrettyWriter(writer io.Writer, prefix string, object interface{}) { + objectString, err := json.Marshal(object) + check(err) + + if prefix != "" { + prefix += ": " + } + + _, err = fmt.Fprintf(writer, "%s%s\n", prefix, pretty.Pretty(objectString)) + check(err) +} + +// PrefixPretty uses json marshal to pretty print an interface object +func PrefixPretty(prefix string, object interface{}) { + PrefixPrettyWriter(os.Stdout, prefix, object) +} + +// PrettyPrint uses json marshal to pretty print an interface object +func PrettyPrint(object interface{}) { + PrefixPretty("", object) +} + +func PrettyString(object interface{}) string { + var buf bytes.Buffer + PrefixPrettyWriter(&buf, "", object) + return buf.String() +} + +func check(err error) { + if err != nil { + panic(err) + } +} diff --git a/spr/spr.go b/spr/spr.go index 2e54063..e2c66c7 100644 --- a/spr/spr.go +++ b/spr/spr.go @@ -507,7 +507,7 @@ func (sd *stackediff) syncCommitStackToGitHub(ctx context.Context, var refNames []string for _, commit := range updatedCommits { - branchName := sd.branchNameFromCommit(info, commit) + branchName := git.BranchNameFromCommit(commit) refNames = append(refNames, commit.CommitHash+":refs/heads/"+branchName) } @@ -520,10 +520,6 @@ func (sd *stackediff) syncCommitStackToGitHub(ctx context.Context, return true } -func (sd *stackediff) branchNameFromCommit(info *github.GitHubInfo, commit git.Commit) string { - return "spr/" + info.LocalBranch + "/" + commit.CommitID -} - func check(err error) { if err != nil { if os.Getenv("SPR_DEBUG") == "1" {