func (c *Config) authorizeClient(client *Client, host string) (err error) { user := c.PromptForUser(host) pass := c.PromptForPassword(host, user) var code, token string for { token, err = client.FindOrCreateToken(user, pass, code) if err == nil { break } if ae, ok := err.(*AuthError); ok && ae.IsRequired2FACodeError() { if code != "" { ui.Errorln("warning: invalid two-factor code") } code = c.PromptForOTP() } else { break } } if err == nil { client.Host.AccessToken = token } return }
func create(command *Command, args *Args) { _, err := git.Dir() if err != nil { err = fmt.Errorf("'create' must be run from inside a git repository") utils.Check(err) } var newRepoName string if args.IsParamsEmpty() { dirName, err := git.WorkdirName() utils.Check(err) newRepoName = github.SanitizeProjectName(dirName) } else { reg := regexp.MustCompile("^[^-]") if !reg.MatchString(args.FirstParam()) { err = fmt.Errorf("invalid argument: %s", args.FirstParam()) utils.Check(err) } newRepoName = args.FirstParam() } config := github.CurrentConfig() host, err := config.DefaultHost() if err != nil { utils.Check(github.FormatError("creating repository", err)) } owner := host.User if strings.Contains(newRepoName, "/") { split := strings.SplitN(newRepoName, "/", 2) owner = split[0] newRepoName = split[1] } project := github.NewProject(owner, newRepoName, host.Host) gh := github.NewClient(project.Host) if gh.IsRepositoryExist(project) { ui.Errorln("Existing repository detected. Updating git remote") } else { if !args.Noop { repo, err := gh.CreateRepository(project, flagCreateDescription, flagCreateHomepage, flagCreatePrivate) utils.Check(err) project = github.NewProject(repo.FullName, "", project.Host) } } localRepo, err := github.LocalRepo() utils.Check(err) remote, _ := localRepo.OriginRemote() if remote == nil || remote.Name != "origin" { url := project.GitURL("", "", true) args.Before("git", "remote", "add", "-f", "origin", url) } webUrl := project.WebURL("", "", "") args.NoForward() printBrowseOrCopy(args, webUrl, flagCreateBrowse, flagCreateCopy) }
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 *Command) parseArguments(args *Args) (err error) { c.Flag.SetInterspersed(true) c.Flag.Init(c.Name(), flag.ContinueOnError) c.Flag.Usage = func() { ui.Errorln("") ui.Errorln(c.Synopsis()) } if err = c.Flag.Parse(args.Params); err == nil { for _, arg := range args.Params { if arg == "--" { args.Terminator = true } } args.Params = c.Flag.Args() } return }
func main() { defer github.CaptureCrash() err := commands.CmdRunner.Execute() if !err.Ran { ui.Errorln(err.Error()) } os.Exit(err.ExitCode) }
func (c *Config) PromptForHost(host string) (h *Host, err error) { h = c.Find(host) if h != nil { return } user := c.PromptForUser(host) pass := c.PromptForPassword(host, user) client := NewClient(host) var code, token string for { token, err = client.FindOrCreateToken(user, pass, code) if err == nil { break } if ae, ok := err.(*AuthError); ok && ae.IsRequired2FACodeError() { if code != "" { ui.Errorln("warning: invalid two-factor code") } code = c.PromptForOTP() } else { break } } if err != nil { return } client.Host.AccessToken = token currentUser, err := client.CurrentUser() if err != nil { return } h = &Host{ Host: host, User: currentUser.Login, AccessToken: token, Protocol: "https", } c.Hosts = append(c.Hosts, *h) err = newConfigService().Save(configsFile(), c) return }
func (c *Command) Call(args *Args) (err error) { runCommand, err := c.lookupSubCommand(args) if err != nil { ui.Errorln(err) return } if !c.GitExtension { err = runCommand.parseArguments(args) if err != nil { return } } runCommand.Run(runCommand, args) return }
func Check(err error) { if err != nil { ui.Errorln(err) os.Exit(1) } }
func pullRequest(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) currentBranch, err := localRepo.CurrentBranch() utils.Check(err) baseProject, err := localRepo.MainProject() utils.Check(err) host, err := github.CurrentConfig().PromptForHost(baseProject.Host) if err != nil { utils.Check(github.FormatError("creating pull request", err)) } client := github.NewClientWithHost(host) trackedBranch, headProject, err := localRepo.RemoteBranchAndProject(host.User, false) utils.Check(err) var ( base, head string force bool ) force = flagPullRequestForce if flagPullRequestBase != "" { baseProject, base = parsePullRequestProject(baseProject, flagPullRequestBase) } if flagPullRequestHead != "" { headProject, head = parsePullRequestProject(headProject, flagPullRequestHead) } if args.ParamsSize() == 1 { arg := args.RemoveParam(0) flagPullRequestIssue = parsePullRequestIssueNumber(arg) } if base == "" { masterBranch := localRepo.MasterBranch() base = masterBranch.ShortName() } if head == "" && trackedBranch != nil { if !trackedBranch.IsRemote() { // the current branch tracking another branch // pretend there's no upstream at all trackedBranch = nil } else { if baseProject.SameAs(headProject) && base == trackedBranch.ShortName() { e := fmt.Errorf(`Aborted: head branch is the same as base ("%s")`, base) e = fmt.Errorf("%s\n(use `-h <branch>` to specify an explicit pull request head)", e) utils.Check(e) } } } if head == "" { if trackedBranch == nil { head = currentBranch.ShortName() } else { head = trackedBranch.ShortName() } } if headRepo, err := client.Repository(headProject); err == nil { headProject.Owner = headRepo.Owner.Login headProject.Name = headRepo.Name } fullBase := fmt.Sprintf("%s:%s", baseProject.Owner, base) fullHead := fmt.Sprintf("%s:%s", headProject.Owner, head) if !force && trackedBranch != nil { remoteCommits, _ := git.RefList(trackedBranch.LongName(), "") if len(remoteCommits) > 0 { err = fmt.Errorf("Aborted: %d commits are not yet pushed to %s", len(remoteCommits), trackedBranch.LongName()) err = fmt.Errorf("%s\n(use `-f` to force submit a pull request anyway)", err) utils.Check(err) } } var editor *github.Editor var title, body string baseTracking := base headTracking := head remote := gitRemoteForProject(baseProject) if remote != nil { baseTracking = fmt.Sprintf("%s/%s", remote.Name, base) } if remote == nil || !baseProject.SameAs(headProject) { remote = gitRemoteForProject(headProject) } if remote != nil { headTracking = fmt.Sprintf("%s/%s", remote.Name, head) } if flagPullRequestPush && remote == nil { utils.Check(fmt.Errorf("Can't find remote for %s", head)) } if cmd.FlagPassed("message") { title, body = readMsg(flagPullRequestMessage) } else if cmd.FlagPassed("file") { title, body, editor, err = readMsgFromFile(flagPullRequestFile, flagPullRequestEdit, "PULLREQ", "pull request") utils.Check(err) } else if flagPullRequestIssue == "" { headForMessage := headTracking if flagPullRequestPush { headForMessage = head } message, err := createPullRequestMessage(baseTracking, headForMessage, fullBase, fullHead) utils.Check(err) editor, err = github.NewEditor("PULLREQ", "pull request", message) utils.Check(err) title, body, err = editor.EditTitleAndBody() utils.Check(err) } if title == "" && flagPullRequestIssue == "" { utils.Check(fmt.Errorf("Aborting due to empty pull request title")) } if flagPullRequestPush { if args.Noop { args.Before(fmt.Sprintf("Would push to %s/%s", remote.Name, head), "") } else { err = git.Spawn("push", "--set-upstream", remote.Name, fmt.Sprintf("HEAD:%s", head)) utils.Check(err) } } var pullRequestURL string if args.Noop { args.Before(fmt.Sprintf("Would request a pull request to %s from %s", fullBase, fullHead), "") pullRequestURL = "PULL_REQUEST_URL" } else { params := map[string]interface{}{ "base": base, "head": fullHead, } if title != "" { params["title"] = title if body != "" { params["body"] = body } } else { issueNum, _ := strconv.Atoi(flagPullRequestIssue) params["issue"] = issueNum } startedAt := time.Now() numRetries := 0 retryDelay := 2 retryAllowance := 0 if flagPullRequestPush { if allowanceFromEnv := os.Getenv("HUB_RETRY_TIMEOUT"); allowanceFromEnv != "" { retryAllowance, err = strconv.Atoi(allowanceFromEnv) utils.Check(err) } else { retryAllowance = 9 } } var pr *github.PullRequest for { pr, err = client.CreatePullRequest(baseProject, params) if err != nil && strings.Contains(err.Error(), `Invalid value for "head"`) { if retryAllowance > 0 { retryAllowance -= retryDelay time.Sleep(time.Duration(retryDelay) * time.Second) retryDelay += 1 numRetries += 1 } else { if numRetries > 0 { duration := time.Now().Sub(startedAt) err = fmt.Errorf("%s\nGiven up after retrying for %.1f seconds.", err, duration.Seconds()) } break } } else { break } } if err == nil && editor != nil { defer editor.DeleteFile() } utils.Check(err) pullRequestURL = pr.HtmlUrl params = map[string]interface{}{} if len(flagPullRequestLabels) > 0 { params["labels"] = flagPullRequestLabels } if len(flagPullRequestAssignees) > 0 { params["assignees"] = flagPullRequestAssignees } if flagPullRequestMilestone > 0 { params["milestone"] = flagPullRequestMilestone } if len(params) > 0 { err = client.UpdateIssue(baseProject, pr.Number, params) utils.Check(err) } } if flagPullRequestIssue != "" { ui.Errorln("Warning: Issue to pull request conversion is deprecated and might not work in the future.") } args.NoForward() printBrowseOrCopy(args, pullRequestURL, flagPullRequestBrowse, flagPullRequestCopy) }