func verboseLog(cmd *Cmd) { if os.Getenv("HUB_VERBOSE") != "" { msg := fmt.Sprintf("$ %s %s", cmd.Name, strings.Join(cmd.Args, " ")) if ui.IsTerminal(os.Stderr) { msg = fmt.Sprintf("\033[35m%s\033[0m", msg) } ui.Errorln(msg) } }
func (c *Config) PromptForPassword(host, user string) (pass string) { pass = os.Getenv("GITHUB_PASSWORD") if pass != "" { return } ui.Printf("%s password for %s (never stored): ", host, user) if ui.IsTerminal(os.Stdout) { pass = string(gopass.GetPasswd()) } else { pass = c.scanLine() } return }
func newHttpClient(testHost string, verbose bool) *http.Client { var testURL *url.URL if testHost != "" { testURL, _ = url.Parse(testHost) } tr := &verboseTransport{ Transport: &http.Transport{ Proxy: proxyFromEnvironment, Dial: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).Dial, TLSHandshakeTimeout: 10 * time.Second, }, Verbose: verbose, OverrideURL: testURL, Out: ui.Stderr, Colorized: ui.IsTerminal(os.Stderr), } // Implement CheckRedirect callback to fix issues with net/http. fixupCheckRedirect := func(req *http.Request, via []*http.Request) error { // net/http doesn't send a Host header on redirect requests. // TODO: Find or file a Go bug. if req.Host == "" { req.Host = req.URL.Host } // Maintain headers after redirect. // https://github.com/golang/go/issues/4800 for key, val := range via[0].Header { if req.Host != via[0].Host && strings.EqualFold(key, "Authorization") { continue } req.Header[key] = val } // remainder should match http/Client.defaultCheckRedirect() if len(via) >= 10 { return errors.New("stopped after 10 redirects") } return nil } return &http.Client{Transport: tr, CheckRedirect: fixupCheckRedirect} }
func (c *Config) PromptForPassword(host, user string) (pass string) { pass = os.Getenv("GITHUB_PASSWORD") if pass != "" { return } ui.Printf("%s password for %s (never stored): ", host, user) if ui.IsTerminal(os.Stdin) { if password, err := getPassword(); err == nil { pass = password } } else { pass = c.scanLine() } return }
func listIssues(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) gh := github.NewClient(project.Host) if args.Noop { ui.Printf("Would request list of issues for %s\n", project) } else { filters := map[string]interface{}{} if cmd.FlagPassed("state") { filters["state"] = flagIssueState } if cmd.FlagPassed("assignee") { filters["assignee"] = flagIssueAssignee } issues, err := gh.FetchIssues(project, filters) utils.Check(err) maxNumWidth := 0 for _, issue := range issues { if numWidth := len(strconv.Itoa(issue.Number)); numWidth > maxNumWidth { maxNumWidth = numWidth } } colorize := ui.IsTerminal(os.Stdout) for _, issue := range issues { if issue.PullRequest != nil { continue } ui.Printf(formatIssue(issue, flagIssueFormat, colorize)) } } os.Exit(0) }
func newHttpClient(testHost string, verbose bool) *http.Client { var testURL *url.URL if testHost != "" { testURL, _ = url.Parse(testHost) } tr := &verboseTransport{ Transport: &http.Transport{ Proxy: proxyFromEnvironment, Dial: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).Dial, TLSHandshakeTimeout: 10 * time.Second, }, Verbose: verbose, OverrideURL: testURL, Out: ui.Stderr, Colorized: ui.IsTerminal(os.Stderr), } return &http.Client{Transport: tr} }
func newHttpClient(testHost string, verbose bool) *http.Client { var testURL *url.URL if testHost != "" { testURL, _ = url.Parse(testHost) } tr := &verboseTransport{ Transport: &http.Transport{ Proxy: proxyFromEnvironment, Dial: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).Dial, TLSHandshakeTimeout: 10 * time.Second, }, Verbose: verbose, OverrideURL: testURL, Out: ui.Stderr, Colorized: ui.IsTerminal(os.Stderr), } return &http.Client{ Transport: tr, CheckRedirect: func(req *http.Request, via []*http.Request) error { if len(via) > 2 { return fmt.Errorf("too many redirects") } else { for key, vals := range via[0].Header { lkey := strings.ToLower(key) if !strings.HasPrefix(lkey, "x-original-") && via[0].Host == req.URL.Host || lkey != "authorization" { req.Header[key] = vals } } return nil } }, } }
func verboseFormat(statuses []github.CIStatus) { colorize := ui.IsTerminal(os.Stdout) contextWidth := 0 for _, status := range statuses { if len(status.Context) > contextWidth { contextWidth = len(status.Context) } } for _, status := range statuses { var color int var stateMarker string switch status.State { case "success": stateMarker = "✔︎" color = 32 case "failure", "error": stateMarker = "✖︎" color = 31 case "pending": stateMarker = "●" color = 33 } if colorize { stateMarker = fmt.Sprintf("\033[%dm%s\033[0m", color, stateMarker) } if status.TargetUrl == "" { ui.Printf("%s\t%s\n", stateMarker, status.Context) } else { ui.Printf("%s\t%-*s\t%s\n", stateMarker, contextWidth, status.Context, status.TargetUrl) } } }
func sync(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) remote, err := localRepo.MainRemote() utils.Check(err) defaultBranch := localRepo.MasterBranch().ShortName() fullDefaultBranch := fmt.Sprintf("refs/remotes/%s/%s", remote.Name, defaultBranch) currentBranch := "" if curBranch, err := localRepo.CurrentBranch(); err == nil { currentBranch = curBranch.ShortName() } err = git.Spawn("fetch", "--prune", "--quiet", "--progress", remote.Name) utils.Check(err) branchToRemote := map[string]string{} if lines, err := git.ConfigAll("branch.*.remote"); err == nil { configRe := regexp.MustCompile(`^branch\.(.+?)\.remote (.+)`) for _, line := range lines { if matches := configRe.FindStringSubmatch(line); len(matches) > 0 { branchToRemote[matches[1]] = matches[2] } } } branches, err := git.LocalBranches() utils.Check(err) var green, lightGreen, red, lightRed, resetColor string if ui.IsTerminal(os.Stdout) { green = "\033[32m" lightGreen = "\033[32;1m" red = "\033[31m" lightRed = "\033[31;1m" resetColor = "\033[0m" } for _, branch := range branches { fullBranch := fmt.Sprintf("refs/heads/%s", branch) remoteBranch := fmt.Sprintf("refs/remotes/%s/%s", remote.Name, branch) gone := false if branchToRemote[branch] == remote.Name { if upstream, err := git.SymbolicFullName(fmt.Sprintf("%s@{upstream}", branch)); err == nil { remoteBranch = upstream } else { remoteBranch = "" gone = true } } else if !git.HasFile(strings.Split(remoteBranch, "/")...) { remoteBranch = "" } if remoteBranch != "" { diff, err := git.NewRange(fullBranch, remoteBranch) utils.Check(err) if diff.IsIdentical() { continue } else if diff.IsAncestor() { if branch == currentBranch { git.Quiet("merge", "--ff-only", "--quiet", remoteBranch) } else { git.Quiet("update-ref", fullBranch, remoteBranch) } ui.Printf("%sUpdated branch %s%s%s (was %s).\n", green, lightGreen, branch, resetColor, diff.A[0:7]) } else { ui.Errorf("warning: `%s' seems to contain unpushed commits\n", branch) } } else if gone { diff, err := git.NewRange(fullBranch, fullDefaultBranch) utils.Check(err) if diff.IsAncestor() { if branch == currentBranch { git.Quiet("checkout", "--quiet", defaultBranch) currentBranch = defaultBranch } git.Quiet("branch", "-D", branch) ui.Printf("%sDeleted branch %s%s%s (was %s).\n", red, lightRed, branch, resetColor, diff.A[0:7]) } else { ui.Errorf("warning: `%s' was deleted on %s, but appears not merged into %s\n", branch, remote.Name, defaultBranch) } } } args.NoForward() }
func listIssues(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) gh := github.NewClient(project.Host) if args.Noop { ui.Printf("Would request list of issues for %s\n", project) } else { flagFilters := map[string]string{ "state": flagIssueState, "assignee": flagIssueAssignee, "milestone": flagIssueMilestoneFilter, "creator": flagIssueCreator, "mentioned": flagIssueMentioned, "labels": flagIssueLabelsFilter, "sort": flagIssueSort, } filters := map[string]interface{}{} for flag, filter := range flagFilters { if cmd.FlagPassed(flag) { filters[flag] = filter } } if flagIssueSortAscending { filters["direction"] = "asc" } if cmd.FlagPassed("since") { if sinceTime, err := time.ParseInLocation("2006-01-02", flagIssueSince, time.Local); err == nil { filters["since"] = sinceTime.Format(time.RFC3339) } else { filters["since"] = flagIssueSince } } issues, err := gh.FetchIssues(project, filters) utils.Check(err) maxNumWidth := 0 for _, issue := range issues { if numWidth := len(strconv.Itoa(issue.Number)); numWidth > maxNumWidth { maxNumWidth = numWidth } } colorize := ui.IsTerminal(os.Stdout) for _, issue := range issues { if issue.PullRequest != nil { continue } ui.Printf(formatIssue(issue, flagIssueFormat, colorize)) } } args.NoForward() }