compare.go 3.5 KB
Newer Older
J
Jingwen Owen Ou 已提交
1 2 3 4
package commands

import (
	"fmt"
D
Darin Minamoto 已提交
5
	"net/url"
6
	"regexp"
7
	"strings"
8

J
Jingwen Owen Ou 已提交
9 10
	"github.com/github/hub/github"
	"github.com/github/hub/utils"
J
Jingwen Owen Ou 已提交
11 12 13 14
)

var cmdCompare = &Command{
	Run:   compare,
15
	Usage: "compare [-u] [-b <BASE>] [<USER>] [[<START>...]<END>]",
16 17 18
	Long: `Open a GitHub compare page in a web browser.

## Options:
19
	-u, --url
20 21
		Print the URL instead of opening it.

M
Mislav Marohnić 已提交
22 23 24
	-c, --copy
		Put the URL to clipboard instead of opening it.

25
	-b, --base=<BASE>
26 27
		Base branch to compare.

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
	[<START>...]<END>
		Branch names, tag names, or commit SHAs specifying the range to compare.
		<END> defaults to the current branch name.

		If a range with two dots ('A..B') is given, it will be transformed into a
		range with three dots.

## Examples:
		$ hub compare refactor
		> open https://github.com/USER/REPO/compare/refactor

		$ hub compare v1.0..v1.1
		> open https://github.com/USER/REPO/compare/v1.0...v1.1

		$ hub compare -u jingweno feature
		> echo https://github.com/jingweno/REPO/compare/feature
M
Mislav Marohnić 已提交
44 45 46 47

## See also:

hub-browse(1), hub(1)
J
Jingwen Owen Ou 已提交
48 49 50
`,
}

J
Jingwen Owen Ou 已提交
51
var (
M
Mislav Marohnić 已提交
52
	flagCompareCopy    bool
J
Jingwen Owen Ou 已提交
53
	flagCompareURLOnly bool
D
Darin Minamoto 已提交
54
	flagCompareBase    string
J
Jingwen Owen Ou 已提交
55
)
J
Jingwen Owen Ou 已提交
56 57

func init() {
M
Mislav Marohnić 已提交
58
	cmdCompare.Flag.BoolVarP(&flagCompareCopy, "copy", "c", false, "COPY")
59
	cmdCompare.Flag.BoolVarP(&flagCompareURLOnly, "url", "u", false, "URL only")
D
Darin Minamoto 已提交
60
	cmdCompare.Flag.StringVarP(&flagCompareBase, "base", "b", "", "BASE")
61 62

	CmdRunner.Use(cmdCompare)
J
Jingwen Owen Ou 已提交
63 64
}

J
Jingwen Owen Ou 已提交
65
func compare(command *Command, args *Args) {
66 67 68
	localRepo, err := github.LocalRepo()
	utils.Check(err)

J
Jingwen Owen Ou 已提交
69
	var (
J
Jingwen Owen Ou 已提交
70
		branch  *github.Branch
J
Jingwen Owen Ou 已提交
71 72 73 74
		project *github.Project
		r       string
	)

75 76 77 78
	usageHelp := func() {
		utils.Check(fmt.Errorf("Usage: hub compare [-u] [-b <BASE>] [<USER>] [[<START>...]<END>]"))
	}

J
Jingwen Owen Ou 已提交
79
	if args.IsParamsEmpty() {
80 81 82
		branch, project, err = localRepo.RemoteBranchAndProject("", false)
		utils.Check(err)

D
Darin Minamoto 已提交
83 84 85 86
		if branch == nil ||
			(branch.IsMaster() && flagCompareBase == "") ||
			(flagCompareBase == branch.ShortName()) {

87
			usageHelp()
D
Darin Minamoto 已提交
88 89 90 91 92
		} else {
			r = branch.ShortName()
			if flagCompareBase != "" {
				r = parseCompareRange(flagCompareBase + "..." + r)
			}
J
Jingwen Owen Ou 已提交
93
		}
J
Jingwen Owen Ou 已提交
94
	} else {
D
Darin Minamoto 已提交
95
		if flagCompareBase != "" {
96
			usageHelp()
J
Jingwen Owen Ou 已提交
97
		} else {
D
Darin Minamoto 已提交
98
			r = parseCompareRange(args.RemoveParam(args.ParamsSize() - 1))
99
			project, err = localRepo.CurrentProject()
D
Darin Minamoto 已提交
100 101 102
			if args.IsParamsEmpty() {
				utils.Check(err)
			} else {
103
				projectName := ""
104
				projectHost := ""
105 106
				if err == nil {
					projectName = project.Name
107
					projectHost = project.Host
108
				}
109
				project = github.NewProject(args.RemoveParam(args.ParamsSize()-1), projectName, projectHost)
110 111 112
				if project.Name == "" {
					utils.Check(fmt.Errorf("error: missing project name (owner: %q)\n", project.Owner))
				}
D
Darin Minamoto 已提交
113
			}
J
Jingwen Owen Ou 已提交
114
		}
J
Jingwen Owen Ou 已提交
115 116
	}

117 118 119 120 121
	if project == nil {
		project, err = localRepo.CurrentProject()
		utils.Check(err)
	}

122
	subpage := utils.ConcatPaths("compare", rangeQueryEscape(r))
J
Jingwen Owen Ou 已提交
123
	url := project.WebURL("", "", subpage)
124

125
	args.NoForward()
M
Mislav Marohnić 已提交
126
	printBrowseOrCopy(args, url, !flagCompareURLOnly && !flagCompareCopy, flagCompareCopy)
J
Jingwen Owen Ou 已提交
127 128
}

J
Jingwen Owen Ou 已提交
129
func parseCompareRange(r string) string {
130
	shaOrTag := fmt.Sprintf("((?:%s:)?\\w(?:[\\w.-]*\\w)?)", OwnerRe)
J
Jingwen Owen Ou 已提交
131 132 133 134
	shaOrTagRange := fmt.Sprintf("^%s\\.\\.%s$", shaOrTag, shaOrTag)
	shaOrTagRangeRegexp := regexp.MustCompile(shaOrTagRange)
	return shaOrTagRangeRegexp.ReplaceAllString(r, "$1...$2")
}
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

// characters we want to allow unencoded in compare views
var compareUnescaper = strings.NewReplacer(
	"%2F", "/",
	"%3A", ":",
	"%5E", "^",
	"%7E", "~",
	"%2A", "*",
	"%21", "!",
)

func rangeQueryEscape(r string) string {
	if strings.Contains(r, "..") {
		return r
	} else {
		return compareUnescaper.Replace(url.QueryEscape(r))
	}
}