summaryrefslogtreecommitdiffstats
path: root/pkg/commands/pull_request.go
blob: 3b08090e7af48bd229035f9a603b66f32cda4a69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package commands

import (
	"fmt"
	"strings"

	"github.com/go-errors/errors"
	"github.com/jesseduffield/lazygit/pkg/config"
)

// Service is a service that repository is on (Github, Bitbucket, ...)
type Service struct {
	Name           string
	PullRequestURL string
}

// PullRequest opens a link in browser to create new pull request
// with selected branch
type PullRequest struct {
	GitServices []*Service
	GitCommand  *GitCommand
}

// RepoInformation holds some basic information about the repo
type RepoInformation struct {
	Owner      string
	Repository string
}

// NewService builds a Service based on the host type
func NewService(typeName string, repositoryDomain string, siteDomain string) *Service {
	switch typeName {
	case "github":
		return &Service{
			Name:           repositoryDomain,
			PullRequestURL: fmt.Sprintf("https://%s%s", siteDomain, "/%s/%s/compare/%s?expand=1"),
		}
	case "bitbucket":
		return &Service{
			Name:           repositoryDomain,
			PullRequestURL: fmt.Sprintf("https://%s%s", siteDomain, "/%s/%s/pull-requests/new?source=%s&t=1"),
		}
	case "gitlab":
		return &Service{
			Name:           repositoryDomain,
			PullRequestURL: fmt.Sprintf("https://%s%s", siteDomain, "/%s/%s/merge_requests/new?merge_request[source_branch]=%s"),
		}
	}

	return nil
}

func getServices(config config.AppConfigurer) []*Service {
	services := []*Service{
		NewService("github", "github.com", "github.com"),
		NewService("bitbucket", "bitbucket.org", "bitbucket.org"),
		NewService("gitlab", "gitlab.com", "gitlab.com"),
	}

	configServices := config.GetUserConfig().GetStringMapString("services")

	for repoDomain, typeAndDomain := range configServices {
		splitData := strings.Split(typeAndDomain, ":")
		if len(splitData) == 2 {
			services = append(services, NewService(splitData[0], repoDomain, splitData[1]))
		}
	}

	return services
}

// NewPullRequest creates new instance of PullRequest
func NewPullRequest(gitCommand *GitCommand) *PullRequest {
	return &PullRequest{
		GitServices: getServices(gitCommand.Config),
		GitCommand:  gitCommand,
	}
}

// Create opens link to new pull request in browser
func (pr *PullRequest) Create(branch *Branch) error {
	branchExistsOnRemote := pr.GitCommand.CheckRemoteBranchExists(branch)

	if !branchExistsOnRemote {
		return errors.New(pr.GitCommand.Tr.SLocalize("NoBranchOnRemote"))
	}

	repoURL := pr.GitCommand.GetRemoteURL()
	var gitService *Service

	for _, service := range pr.GitServices {
		if strings.Contains(repoURL, service.Name) {
			gitService = service
			break
		}
	}

	if gitService == nil {
		return errors.New(pr.GitCommand.Tr.SLocalize("UnsupportedGitService"))
	}

	repoInfo := getRepoInfoFromURL(repoURL)

	return pr.GitCommand.OSCommand.OpenLink(fmt.Sprintf(
		gitService.PullRequestURL, repoInfo.Owner, repoInfo.Repository, branch.Name,
	))
}

func getRepoInfoFromURL(url string) *RepoInformation {
	isHTTP := strings.HasPrefix(url, "http")

	if isHTTP {
		splits := strings.Split(url, "/")
		owner := strings.Join(splits[3:len(splits)-1], "/")
		repo := strings.TrimSuffix(splits[len(splits)-1], ".git")

		return &RepoInformation{
			Owner:      owner,
			Repository: repo,
		}
	}

	tmpSplit := strings.Split(url, ":")
	splits := strings.Split(tmpSplit[1], "/")
	owner := strings.Join(splits[0:len(splits)-1], "/")
	repo := strings.TrimSuffix(splits[len(splits)-1], ".git")

	return &RepoInformation{
		Owner:      owner,
		Repository: repo,
	}
}