Beispiel #1
0
func authCmd(c *cli.Context) {
	config, err := gordon.LoadConfig()
	if err != nil {
		config = &gordon.Config{}
	}
	token := c.String("add")
	userName := c.String("user")
	if userName != "" {
		config.UserName = userName
		if err := gordon.SaveConfig(*config); err != nil {
			gordon.Fatalf("%s", err)
		}
	}
	if token != "" {
		config.Token = token
		if err := gordon.SaveConfig(*config); err != nil {
			gordon.Fatalf("%s", err)
		}
	}
	// Display token and user information
	if config, err := gordon.LoadConfig(); err == nil {
		if config.UserName != "" {
			fmt.Printf("Token: %s, UserName: %s\n", config.Token, config.UserName)
		} else {

			fmt.Printf("Token: %s\n", config.Token)
		}
	} else {
		fmt.Fprintf(os.Stderr, "No token registered\n")
		os.Exit(1)
	}
}
Beispiel #2
0
func displayAllPullRequests(c *cli.Context) {
	prs, err := m.GetPullRequests(c.String("state"), c.String("sort"))
	if err != nil {
		gordon.Fatalf("Error getting pull requests %s", err)
	}

	var needFullPr, needComments bool

	if c.Bool("no-merge") {
		needFullPr = true
	}
	if c.Bool("lgtm") {
		needComments = true
	}

	if needFullPr || needComments {
		prs = m.GetFullPullRequests(prs, needFullPr, needComments)
	}

	prs, err = filters.FilterPullRequests(c, prs)
	if err != nil {
		gordon.Fatalf("Error filtering pull requests %s", err)
	}

	fmt.Printf("%c[2K\r", 27)
	gordon.DisplayPullRequests(c, prs, c.Bool("no-trunc"))
}
Beispiel #3
0
//Assign a pull request to the current user.
// If it's taken, show a message with the "--steal" optional flag.
//If the user doesn't have permissions, add a comment #volunteer
func takeCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("usage: take ID")
	}
	number := c.Args()[0]
	pr, err := m.GetPullRequest(number)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	user, err := m.GetGithubUser()
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	if pr.Assignee != nil && !c.Bool("steal") {
		gordon.Fatalf("Use --steal to steal the PR from %s", pr.Assignee.Login)
	}
	pr.Assignee = user
	patchedPR, err := m.PatchPullRequest(number, pr)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	if patchedPR.Assignee.Login != user.Login {
		m.AddComment(number, "#volunteer")
		fmt.Printf("No permission to assign. You '%s' was added as #volunteer.\n", user.Login)
	} else {
		m.AddComment(number, fmt.Sprintf("#assignee=%s", patchedPR.Assignee.Login))
		fmt.Printf("Assigned PR %s to %s\n", brush.Green(number), patchedPR.Assignee.Login)
	}
}
Beispiel #4
0
//Take a specific issue. If it's taken, show a message with the overwrite optional flag
//If the user doesn't have permissions, add a comment #volunteer
func takeCmd(c *cli.Context) {
	if c.Args().Present() {
		number := c.Args()[0]
		issue, _, err := m.GetIssue(number, false)
		if err != nil {
			gordon.Fatalf("%s", err)
		}
		user, err := m.GetGithubUser()
		if err != nil {
			gordon.Fatalf("%s", err)
		}
		if user == nil {
			gordon.Fatalf("%v", gordon.ErrNoUsernameKnown)
		}
		if issue.Assignee.Login != "" && !c.Bool("overwrite") {
			fmt.Printf("Use the flag --overwrite to take the issue from %s\n", issue.Assignee.Login)
			return
		}
		issue.Assignee = *user
		patchedIssue, err := m.PatchIssue(number, issue)
		if err != nil {
			gordon.Fatalf("%s", err)
		}
		if patchedIssue.Assignee.Login != user.Login {
			m.AddComment(number, "#volunteer")
			fmt.Printf("No permission to assign. You '%s' was added as #volunteer.\n", user.Login)
		} else {
			fmt.Printf("The issue %s was assigned to %s\n", number, patchedIssue.Assignee.Login)
		}
	} else {
		fmt.Printf("Please enter the issue's number\n")
	}

}
Beispiel #5
0
func commentCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("Please enter the issue's number")
	}
	number := c.Args()[0]
	editor := os.Getenv("EDITOR")
	if editor == "" {
		editor = "nano"
	}
	tmp, err := ioutil.TempFile("", "pulls-comment-")
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	defer os.Remove(tmp.Name())
	cmd := exec.Command(editor, tmp.Name())
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		gordon.Fatalf("%v", err)
	}
	comment, err := ioutil.ReadAll(tmp)
	if err != nil {
		gordon.Fatalf("%v", err)
	}
	if _, err := m.AddComment(number, string(comment)); err != nil {
		gordon.Fatalf("%v", err)
	}
}
Beispiel #6
0
// compareCmd searches to find Merge commits that are in master that are not in the branch
func compareCmd(c *cli.Context) {

	// TODO: don't repase all history to the begining of time (--after?)

	if nArgs := len(c.Args()); nArgs == 2 {
		// git log --format=oneline upstream/master > master.log
		masterLog, err := git("log", "--format=format:%H %s %b", c.Args()[0])
		if err != nil {
			gordon.Fatalf("%v", err)
		}

		// git log --format=oneline upstream/docs > docs.log
		branchLog, err := git("log", "--format=format:%H %s %b", c.Args()[1])
		if err != nil {
			gordon.Fatalf("%v", err)
		}

		// diff -U 0 master.log docs.log  | grep "Merge pull" | sed "s/^-/- /g"
		// Parse both logs looking for 'Merge pull request #`
		reMergeLine := regexp.MustCompile(`^([0-9a-f]{40}) Merge pull request #([0-9]*) from (.*)$`)
		branchPRs := make(map[string]string)
		s := bufio.NewScanner(strings.NewReader(branchLog))
		for s.Scan() {
			res := reMergeLine.FindStringSubmatch(s.Text())
			if res == nil {
				continue
			}
			hash := res[1]
			pr := res[2]
			//desc := res[3]
			branchPRs[pr] = hash
		}

		firstMerged := ""
		s = bufio.NewScanner(strings.NewReader(masterLog))
		for s.Scan() {
			res := reMergeLine.FindStringSubmatch(s.Text())
			if res == nil {
				continue
			}
			hash := res[1]
			pr := res[2]
			desc := res[3]

			if branchPRs[pr] == "" {
				// TODO: consider reversing the order of this list to match the commit list in the GH PR
				fmt.Printf("- %s #%s : %s\n", hash, pr, desc)
			} else if firstMerged == "" {
				firstMerged = pr
				fmt.Println("------- ^^^^ un-considered candidates")
			}
		}
	} else {
		gordon.Fatalf("Usage: compare [branch] [branch]")
	}
}
Beispiel #7
0
// Approve a pr by adding a LGTM to the comments
func approveCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("usage: approve ID")
	}
	number := c.Args().First()
	if _, err := m.AddComment(number, "LGTM"); err != nil {
		gordon.Fatalf("%s", err)
	}
	fmt.Printf("Pull request %s approved\n", brush.Green(number))
}
Beispiel #8
0
func closeCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("Please enter the issue's number")
	}
	number := c.Args()[0]
	if err := m.Close(number); err != nil {
		gordon.Fatalf("%v", err)
	}
	fmt.Printf("Closed PR %s\n", number)
}
Beispiel #9
0
func commentsCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("usage: comments ID")
	}
	comments, err := m.GetComments(c.Args().First())
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	gordon.DisplayComments(comments)
}
Beispiel #10
0
func checkoutCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("usage: checkout ID")
	}
	number := c.Args()[0]
	pr, err := m.GetPullRequest(number)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	if err := m.Checkout(pr); err != nil {
		gordon.Fatalf("%s", err)
	}
}
Beispiel #11
0
func mergeCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("usage: merge ID")
	}
	number := c.Args()[0]
	merge, err := m.MergePullRequest(number, c.String("m"), c.Bool("force"))
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	if merge.Merged {
		fmt.Printf("%s\n", brush.Green(merge.Message))
	} else {
		gordon.Fatalf("%s", err)
	}
}
Beispiel #12
0
func repositoryInfoCmd(c *cli.Context) {
	r, err := m.Repository()
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	fmt.Printf("Name: %s\nForks: %d\nStars: %d\nIssues: %d\n", r.Name, r.Forks, r.Watchers, r.OpenIssues)
}
Beispiel #13
0
func buildQuery(c *cli.Context) string {
	r, err := m.Repository()
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	// standard parameters
	query := fmt.Sprintf("q=%s+repo:%s", c.Args()[0], r.FullName)
	state := c.String("state")
	if state == "" {
		state = "open"
	}
	query += fmt.Sprintf("+state:%s", state)
	// optional parameters
	var optionalParameters = []string{
		"author",
		"assignee",
		"mentions",
		"commenter",
		"involves",
		"labels"}

	for i := 0; i < len(optionalParameters); i++ {
		param := optionalParameters[i]
		value := c.String(param)
		if value != "" {
			query += fmt.Sprintf("+%s:%s", param, value)
		}
	}
	return query
}
Beispiel #14
0
func addComment(number, comment string) {
	cmt, err := m.AddComment(number, comment)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	gordon.DisplayCommentAdded(cmt)
}
Beispiel #15
0
// Show contributors stats
func contributorsCmd(c *cli.Context) {
	contributors, err := m.GetContributors()
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	gordon.DisplayContributors(c, contributors)
}
Beispiel #16
0
func alruCmd(c *cli.Context) {
	lru, err := m.GetFirstPullRequest("open", "updated")
	if err != nil {
		gordon.Fatalf("Error getting pull requests: %s", err)
	}
	fmt.Printf("%v (#%d)\n", gordon.HumanDuration(time.Since(lru.UpdatedAt)), lru.Number)
}
Beispiel #17
0
func commentCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("Please enter the issue's number")
	}
	number := c.Args()[0]
	editor := os.Getenv("EDITOR")
	if editor == "" {
		editor = "nano"
	}
	tmp, err := ioutil.TempFile("", "pulls-comment-")
	if err != nil {
		gordon.Fatalf("%v", err)
	}
	defer os.Remove(tmp.Name())

	if template := c.String("template"); template != "" {
		f, err := os.Open(template)

		if err != nil {
			path := filepath.Join(templatePath, filepath.Base(c.String("template")))

			f, err = os.Open(path)
			if err != nil {
				gordon.Fatalf("%v", err)
			}
		}

		defer f.Close()

		if _, err := io.Copy(tmp, f); err != nil {
			gordon.Fatalf("%v", err)
		}
	}

	cmd := exec.Command(editor, tmp.Name())
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		gordon.Fatalf("%v", err)
	}

	if _, err := tmp.Seek(0, 0); err != nil {
		gordon.Fatalf("%v", err)
	}

	comment, err := ioutil.ReadAll(tmp)
	if err != nil {
		gordon.Fatalf("%v", err)
	}

	if _, err := m.AddComment(number, string(comment)); err != nil {
		gordon.Fatalf("%v", err)
	}
}
Beispiel #18
0
// Show the patch in a PR
func showCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("usage: show ID")
	}
	number := c.Args()[0]
	pr, err := m.GetPullRequest(number)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	patch, err := http.Get(pr.DiffURL)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	defer patch.Body.Close()

	if err := gordon.DisplayPatch(patch.Body); err != nil {
		gordon.Fatalf("%s", err)
	}
}
Beispiel #19
0
func sendCmd(c *cli.Context) {
	if nArgs := len(c.Args()); nArgs == 0 {
		// Push the branch, then create the PR
		// Pick a remote branch name
		commitMsg, err := exec.Command("git", "log", "--no-merges", "-1", "--pretty=format:%s", "HEAD").CombinedOutput()
		if err != nil {
			gordon.Fatalf("git log: %v", err)
		}
		brName := "pr_out_" + gordon.GenBranchName(string(commitMsg))
		fmt.Printf("remote branch = %s\n", brName)
		user, err := m.GetGithubUser()
		if err != nil {
			gordon.Fatalf("%v", err)
		}
		if user == nil {
			gordon.Fatalf("%v", gordon.ErrNoUsernameKnown)
		}

		repo, err := m.Repository()
		if err != nil {
			gordon.Fatalf("%v\n", err)
		}
		// FIXME: use the github API to get our fork's url (or create the fork if needed)
		if err := gordon.Git("push", "-f", fmt.Sprintf("ssh://[email protected]/%s/%s", user.Login, repo.Name), "HEAD:refs/heads/"+brName); err != nil {
			gordon.Fatalf("git push: %v", err)
		}
		prBase := "master"
		prHead := fmt.Sprintf("%s:%s", user.Login, brName)
		fmt.Printf("Creating pull request from %s to %s\n", prBase, prHead)
		pr, err := m.CreatePullRequest(prBase, prHead, string(commitMsg), "")
		if err != nil {
			gordon.Fatalf("create pull request: %v", err)
		}
		fmt.Printf("Created %v\n", pr.Number)
	} else if nArgs == 1 {
		pr, err := m.GetPullRequest(c.Args()[0])
		if err != nil {
			gordon.Fatalf("%v", err)
		}
		if err := gordon.Git("push", "-f", pr.Head.Repo.SSHURL, "HEAD:"+pr.Head.Ref); err != nil {
			gordon.Fatalf("%v", err)
		}
		fmt.Printf("Overwrote %v\n", pr.Number)
	} else {
		gordon.Fatalf("Usage: send [ID]")
	}
}
Beispiel #20
0
func dropCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("usage: drop ID")
	}
	number := c.Args()[0]
	pr, err := m.GetPullRequest(number)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	user, err := m.GetGithubUser()
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	if user == nil {
		gordon.Fatalf("%v", gordon.ErrNoUsernameKnown)
	}
	if pr.Assignee == nil || pr.Assignee.Login != user.Login {
		gordon.Fatalf("Can't drop %s: it's not yours.", number)
	}
	pr.Assignee = nil
	if _, err := m.PatchPullRequest(number, pr); err != nil {
		gordon.Fatalf("%s", err)
	}
	fmt.Printf("Unassigned PR %s\n", brush.Green(number))
}
Beispiel #21
0
func mainCmd(c *cli.Context) {
	if !c.Args().Present() {
		var issues, err = m.GetIssues("open", c.String("assigned"))

		if err != nil {
			gordon.Fatalf("Error getting issues: %s", err)
		}
		issues, err = filters.FilterIssues(c, issues)
		if err != nil {
			gordon.Fatalf("Error filtering issues: %s", err)
		}

		fmt.Printf("%c[2K\r", 27)
		gordon.DisplayIssues(c, issues, c.Bool("no-trunc"))
		return
	}

	var (
		number  = c.Args().Get(0)
		comment = c.String("comment")
	)

	if comment != "" {
		addComment(number, comment)
		return
	}

	if c.Bool("vote") {
		addComment(number, "+1")
		fmt.Printf("Vote added to the issue: %s", number)
		return
	}

	issue, comments, err := m.GetIssue(number, true)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	gordon.DisplayIssue(issue, comments)
}
Beispiel #22
0
//Search for issues. You add some restrictions to the query. such:
// authors, assignee, state, etc. Check the command help for more options.
func searchCmd(c *cli.Context) {
	if c.Args().Present() {
		issues, err := m.GetIssuesFound(buildQuery(c))
		if err != nil {
			gordon.Fatalf("%s", err)
		}
		fmt.Printf("%c[2K\r", 27)
		gordon.DisplayIssues(c, issues, c.Bool("no-trunc"))
	} else {
		fmt.Printf("Please enter a search term\n")
	}

}
Beispiel #23
0
// Show the reviewers for this pull request
func reviewersCmd(c *cli.Context) {
	if !c.Args().Present() {
		gordon.Fatalf("usage: reviewers ID")
	}

	var (
		patch      io.Reader
		patchBytes []byte
		number     = c.Args()[0]
	)

	if number == "-" {
		patch = os.Stdin
	} else {
		pr, err := m.GetPullRequest(number)
		if err != nil {
			gordon.Fatalf("%s", err)
		}

		resp, err := http.Get(pr.DiffURL)
		if err != nil {
			gordon.Fatalf("%s", err)
		}
		patch = resp.Body
		defer resp.Body.Close()
	}

	patchBytes, err := ioutil.ReadAll(patch)
	if err != nil {
		gordon.Fatalf("%s", err)
	}

	reviewers, err := gordon.GetReviewersForPR(patchBytes, false)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	gordon.DisplayReviewers(c, reviewers)
}
Beispiel #24
0
func main() {
	app := cli.NewApp()

	app.Name = "issues"
	app.Usage = "Manage github issues"
	app.Version = gordon.Version

	app.Before = before
	loadCommands(app)

	err := app.Run(os.Args)
	if err != nil {
		gordon.Fatalf(err.Error())
	}
}
Beispiel #25
0
func main() {

	app := cli.NewApp()

	app.Name = "pulls"
	app.Usage = "Manage github pull requests for project maintainers"
	app.Version = gordon.Version

	app.Before = before
	loadCommands(app)

	err := app.Run(os.Args)
	if err != nil {
		gordon.Fatalf(err.Error())
	}
}
Beispiel #26
0
// This is the top level command for
// working with prs
func mainCmd(c *cli.Context) {
	if !c.Args().Present() {
		displayAllPullRequests(c)
		return
	}

	var (
		number  = c.Args().Get(0)
		comment = c.String("comment")
	)

	if comment != "" {
		addComment(number, comment)
		return
	}
	pr, err := m.GetPullRequest(number)
	if err != nil {
		gordon.Fatalf("%s", err)
	}
	gordon.DisplayPullRequest(pr)
}