github.com/scorpionis/hub@v2.2.1+incompatible/commands/compare.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "regexp" 6 "strings" 7 "net/url" 8 9 "github.com/github/hub/github" 10 "github.com/github/hub/utils" 11 ) 12 13 var cmdCompare = &Command{ 14 Run: compare, 15 Usage: "compare [-u] [USER] [<START>...]<END>", 16 Short: "Open a compare page on GitHub", 17 Long: `Open a GitHub compare view page in the system's default web browser. 18 <START> to <END> are branch names, tag names, or commit SHA1s specifying 19 the range of history to compare. If a range with two dots ("a..b") is given, 20 it will be transformed into one with three dots. If <START> is omitted, 21 GitHub will compare against the base branch (the default is "master"). 22 If <END> is omitted, GitHub compare view is opened for the current branch. 23 With "-u", outputs the URL rather than opening the browser. 24 `, 25 } 26 27 var ( 28 flagCompareURLOnly bool 29 ) 30 31 func init() { 32 cmdCompare.Flag.BoolVarP(&flagCompareURLOnly, "url-only", "u", false, "URL only") 33 34 CmdRunner.Use(cmdCompare) 35 } 36 37 /* 38 $ gh compare refactor 39 > open https://github.com/CURRENT_REPO/compare/refactor 40 41 $ gh compare 1.0..1.1 42 > open https://github.com/CURRENT_REPO/compare/1.0...1.1 43 44 $ gh compare -u other-user patch 45 > open https://github.com/other-user/REPO/compare/patch 46 */ 47 func compare(command *Command, args *Args) { 48 localRepo, err := github.LocalRepo() 49 utils.Check(err) 50 51 var ( 52 branch *github.Branch 53 project *github.Project 54 r string 55 ) 56 57 branch, project, err = localRepo.RemoteBranchAndProject("", false) 58 utils.Check(err) 59 60 if args.IsParamsEmpty() { 61 if branch != nil && !branch.IsMaster() { 62 r = branch.ShortName() 63 } else { 64 err = fmt.Errorf("Usage: hub compare [USER] [<START>...]<END>") 65 utils.Check(err) 66 } 67 } else { 68 r = parseCompareRange(args.RemoveParam(args.ParamsSize() - 1)) 69 if args.IsParamsEmpty() { 70 project, err = localRepo.CurrentProject() 71 utils.Check(err) 72 } else { 73 project = github.NewProject(args.RemoveParam(args.ParamsSize()-1), "", "") 74 } 75 } 76 77 subpage := utils.ConcatPaths("compare", rangeQueryEscape(r)) 78 url := project.WebURL("", "", subpage) 79 launcher, err := utils.BrowserLauncher() 80 utils.Check(err) 81 82 if flagCompareURLOnly { 83 args.Replace("echo", url) 84 } else { 85 args.Replace(launcher[0], "", launcher[1:]...) 86 args.AppendParams(url) 87 } 88 } 89 90 func parseCompareRange(r string) string { 91 shaOrTag := fmt.Sprintf("((?:%s:)?\\w[\\w.-]+\\w)", OwnerRe) 92 shaOrTagRange := fmt.Sprintf("^%s\\.\\.%s$", shaOrTag, shaOrTag) 93 shaOrTagRangeRegexp := regexp.MustCompile(shaOrTagRange) 94 return shaOrTagRangeRegexp.ReplaceAllString(r, "$1...$2") 95 } 96 97 // characters we want to allow unencoded in compare views 98 var compareUnescaper = strings.NewReplacer( 99 "%2F", "/", 100 "%3A", ":", 101 "%5E", "^", 102 "%7E", "~", 103 "%2A", "*", 104 "%21", "!", 105 ) 106 107 func rangeQueryEscape(r string) string { 108 if strings.Contains(r, "..") { 109 return r 110 } else { 111 return compareUnescaper.Replace(url.QueryEscape(r)) 112 } 113 }