mirror of
https://gitea.com/jolheiser/sip
synced 2024-11-22 19:51:58 +01:00
Split up funcs, add PR create/status/checkout
Signed-off-by: jolheiser <john.olheiser@gmail.com>
This commit is contained in:
parent
20d5d36202
commit
8958c4a312
27
README.md
27
README.md
@ -1,2 +1,29 @@
|
||||
# Tea (alternative)
|
||||
CLI for interacting with Gitea
|
||||
|
||||
### Features
|
||||
|
||||
Understands the concepts of an origin vs remote repository.
|
||||
By default uses remotes `origin` and `upstream`.
|
||||
If no `upstream` repository is found, `upstream` becomes synonymous with `origin` for the sake of defaults.
|
||||
|
||||
* Configuration `tea config`
|
||||
* Change the default `origin` remote name `tea config origin`
|
||||
* Change the default `upstream` remote name `tea config upstrea`
|
||||
* Login `tea login`
|
||||
* Add a user token for API usage
|
||||
* Generate a new token from CLI `tea login auto`
|
||||
* Authenticate with username/password to get a new token without leaving the terminal
|
||||
* List available logins `tea login list`
|
||||
* Logout `tea logout`
|
||||
* Remove user tokens
|
||||
* Repository status `tea repo`
|
||||
* Get basic information about the `upstream` repository
|
||||
* Issue search `tea issues`
|
||||
* Search issues based on keyword(s)
|
||||
* Create a new issue `tea issues create`
|
||||
* Pull request search `tea pulls`
|
||||
* Search pull requests based on keyword(s)
|
||||
* Create a new pull request `tea pulls create`
|
||||
* Check pull request status (default based on current branch) `tea pulls status`
|
||||
* Checkout a pull request to test locally `tea pulls checkout`
|
13
cmd/cmd.go
13
cmd/cmd.go
@ -14,6 +14,16 @@ import (
|
||||
|
||||
var (
|
||||
Flags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "origin",
|
||||
Usage: "The origin remote",
|
||||
Value: config.Origin,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "upstream",
|
||||
Usage: "The upstream remote",
|
||||
Value: config.Upstream,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "url",
|
||||
Aliases: []string{"u"},
|
||||
@ -82,6 +92,9 @@ func getClient(ctx *cli.Context) *gitea.Client {
|
||||
func getUpstreamRepo() []string {
|
||||
upstreamOnce.Do(func() {
|
||||
upstreamRepo = git.GetRepo(config.Upstream)
|
||||
if upstreamRepo == nil {
|
||||
upstreamRepo = git.GetRepo(config.Origin)
|
||||
}
|
||||
})
|
||||
return upstreamRepo
|
||||
}
|
||||
|
@ -10,13 +10,13 @@ import (
|
||||
var Config = cli.Command{
|
||||
Name: "config",
|
||||
Aliases: []string{"cfg"},
|
||||
Usage: "Modify Tea config",
|
||||
Usage: "Modify tea config",
|
||||
Action: doConfig,
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "remote",
|
||||
Usage: "Specify default remote name",
|
||||
Action: doConfigRemote,
|
||||
Name: "origin",
|
||||
Usage: "Specify default origin name",
|
||||
Action: doConfigOrigin,
|
||||
},
|
||||
{
|
||||
Name: "upstream",
|
||||
@ -27,15 +27,15 @@ var Config = cli.Command{
|
||||
}
|
||||
|
||||
func doConfig(ctx *cli.Context) error {
|
||||
if err := doConfigRemote(ctx); err != nil {
|
||||
if err := doConfigOrigin(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return doConfigUpstream(ctx)
|
||||
}
|
||||
|
||||
func doConfigRemote(ctx *cli.Context) error {
|
||||
func doConfigOrigin(ctx *cli.Context) error {
|
||||
question := &survey.Input{
|
||||
Message: "Default remote name",
|
||||
Message: "Default origin name",
|
||||
Default: "origin",
|
||||
}
|
||||
var answer string
|
||||
|
100
cmd/issues.go
100
cmd/issues.go
@ -3,7 +3,6 @@ package cmd
|
||||
import (
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"fmt"
|
||||
"gitea.com/jolheiser/beaver"
|
||||
"gitea.com/jolheiser/beaver/color"
|
||||
"gitea.com/jolheiser/tea/modules/markdown"
|
||||
"gitea.com/jolheiser/tea/modules/sdk"
|
||||
@ -20,27 +19,30 @@ var Issues = cli.Command{
|
||||
Usage: "Commands for interacting with issues",
|
||||
Action: doIssuesSearch,
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "create",
|
||||
Usage: "Create a new issue",
|
||||
Action: doIssueCreate,
|
||||
},
|
||||
&IssuesCreate,
|
||||
},
|
||||
}
|
||||
|
||||
func issuesSearch(ctx *cli.Context, pulls bool) error {
|
||||
func doIssuesSearch(ctx *cli.Context) error {
|
||||
if _, err := issuesSearch(ctx, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func issuesSearch(ctx *cli.Context, pulls bool) (*gitea.Issue, error) {
|
||||
typ := "issues"
|
||||
if pulls {
|
||||
typ = "pulls"
|
||||
}
|
||||
issues, err := queryIssues(ctx, getClient(ctx), false)
|
||||
issues, err := queryIssues(ctx, getClient(ctx), pulls)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(issues) == 0 {
|
||||
stdout.Red("No " + typ + " found")
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
issueMap := make(map[string]*gitea.Issue)
|
||||
@ -68,85 +70,19 @@ func issuesSearch(ctx *cli.Context, pulls bool) error {
|
||||
for key := range issueMap {
|
||||
list = append(list, key)
|
||||
}
|
||||
sel := &survey.Select{Options: list, Message: "Matching " + typ + ", select one to see more details"}
|
||||
sel := &survey.Select{Options: list, Message: "Matching " + typ}
|
||||
var selection string
|
||||
if err := survey.AskOne(sel, &selection); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
body, err := markdown.Render(issueMap[selection].Body)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Println(body)
|
||||
return nil
|
||||
}
|
||||
|
||||
func doIssuesSearch(ctx *cli.Context) error {
|
||||
return issuesSearch(ctx, false)
|
||||
}
|
||||
|
||||
func doIssueCreate(ctx *cli.Context) error {
|
||||
beaver.Infof("Creating a new issue for %s/%s/%s", ctx.String("url"), ctx.String("owner"), ctx.String("repo"))
|
||||
|
||||
token, err := requireToken(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var confirmed bool
|
||||
var title, body string
|
||||
|
||||
for !confirmed {
|
||||
questions := []*survey.Question{
|
||||
{
|
||||
Name: "title",
|
||||
Prompt: &survey.Input{Message: "Title", Default: title},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "body",
|
||||
Prompt: &survey.Multiline{Message: "Description", Default: body},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
}
|
||||
answers := struct {
|
||||
Title string
|
||||
Body string
|
||||
}{}
|
||||
|
||||
if err := survey.Ask(questions, &answers); err != nil {
|
||||
return err
|
||||
}
|
||||
title = answers.Title
|
||||
body = answers.Body
|
||||
|
||||
preview, err := markdown.Render(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n\n%s\n", title, preview)
|
||||
confirm := &survey.Confirm{Message: "Preview above, enter to create or 'n' to edit", Default: true}
|
||||
|
||||
if err := survey.AskOne(confirm, &confirmed); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
client := gitea.NewClient(ctx.String("url"), token)
|
||||
|
||||
issue, err := client.CreateIssue(ctx.String("owner"), ctx.String("repo"), gitea.CreateIssueOption{Title: title, Body: body})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info := color.Info
|
||||
cyan := color.New(color.FgCyan)
|
||||
fmt.Println(info.Format("Issue"), cyan.Format(fmt.Sprintf("#%d", issue.Index)), info.Format("created!"))
|
||||
fmt.Println(cyan.Format(fmt.Sprintf("%s/%s/%s/issues/%d", ctx.String("url"), ctx.String("owner"), ctx.String("repo"), issue.Index)))
|
||||
return nil
|
||||
return issueMap[selection], nil
|
||||
}
|
||||
|
||||
func queryIssues(ctx *cli.Context, client *gitea.Client, pulls bool) ([]*gitea.Issue, error) {
|
||||
@ -178,8 +114,10 @@ func queryIssues(ctx *cli.Context, client *gitea.Client, pulls bool) ([]*gitea.I
|
||||
|
||||
filtered := make([]*gitea.Issue, 0)
|
||||
for _, issue := range issues {
|
||||
if issue.PullRequest != nil && pulls {
|
||||
if pulls {
|
||||
if issue.PullRequest != nil {
|
||||
filtered = append(filtered, issue)
|
||||
}
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, issue)
|
||||
|
79
cmd/issues_create.go
Normal file
79
cmd/issues_create.go
Normal file
@ -0,0 +1,79 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"fmt"
|
||||
"gitea.com/jolheiser/beaver/color"
|
||||
"gitea.com/jolheiser/tea/modules/markdown"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var IssuesCreate = cli.Command{
|
||||
Name: "create",
|
||||
Usage: "Create a new issue",
|
||||
Action: doIssueCreate,
|
||||
}
|
||||
|
||||
func doIssueCreate(ctx *cli.Context) error {
|
||||
fmt.Println()
|
||||
url := color.New(color.FgYellow).Format(fmt.Sprintf("%s/%s/%s", ctx.String("url"), ctx.String("owner"), ctx.String("repo")))
|
||||
fmt.Println(color.New(color.FgCyan).Format("Creating a new issue for"), url)
|
||||
|
||||
token, err := requireToken(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var confirmed bool
|
||||
var title, body string
|
||||
|
||||
for !confirmed {
|
||||
questions := []*survey.Question{
|
||||
{
|
||||
Name: "title",
|
||||
Prompt: &survey.Input{Message: "Title", Default: title},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "body",
|
||||
Prompt: &survey.Multiline{Message: "Description", Default: body},
|
||||
},
|
||||
}
|
||||
answers := struct {
|
||||
Title string
|
||||
Body string
|
||||
}{}
|
||||
|
||||
if err := survey.Ask(questions, &answers); err != nil {
|
||||
return err
|
||||
}
|
||||
title = answers.Title
|
||||
body = answers.Body
|
||||
|
||||
preview, err := markdown.Render(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n\n%s\n", title, preview)
|
||||
confirm := &survey.Confirm{Message: "Preview above, enter to create or 'n' to edit", Default: true}
|
||||
|
||||
if err := survey.AskOne(confirm, &confirmed); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
client := gitea.NewClient(ctx.String("url"), token)
|
||||
|
||||
issue, err := client.CreateIssue(ctx.String("owner"), ctx.String("repo"), gitea.CreateIssueOption{Title: title, Body: body})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info := color.Info
|
||||
cyan := color.New(color.FgCyan)
|
||||
fmt.Println(info.Format("Issue"), cyan.Format(fmt.Sprintf("#%d", issue.Index)), info.Format("created!"))
|
||||
fmt.Println(cyan.Format(fmt.Sprintf("%s/%s/%s/issues/%d", ctx.String("url"), ctx.String("owner"), ctx.String("repo"), issue.Index)))
|
||||
return nil
|
||||
}
|
120
cmd/pulls.go
120
cmd/pulls.go
@ -1,134 +1,24 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"fmt"
|
||||
"gitea.com/jolheiser/beaver"
|
||||
"gitea.com/jolheiser/beaver/color"
|
||||
"gitea.com/jolheiser/tea/modules/git"
|
||||
"gitea.com/jolheiser/tea/modules/markdown"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var Pulls = cli.Command{
|
||||
Name: "pulls",
|
||||
Aliases: []string{"pr"},
|
||||
Aliases: []string{"pull", "pr"},
|
||||
Usage: "Commands for interacting with pull requests",
|
||||
Action: doPullsSearch,
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "create",
|
||||
Usage: "Create a new pull request",
|
||||
Action: doPullCreate,
|
||||
},
|
||||
&PullsCreate,
|
||||
&PullsStatus,
|
||||
&PullsCheckout,
|
||||
},
|
||||
}
|
||||
|
||||
func doPullsSearch(ctx *cli.Context) error {
|
||||
return issuesSearch(ctx, true)
|
||||
}
|
||||
|
||||
func doPullCreate(ctx *cli.Context) error {
|
||||
beaver.Infof("Creating a new pull request for %s/%s/%s", ctx.String("url"), ctx.String("owner"), ctx.String("repo"))
|
||||
|
||||
token, err := requireToken(ctx)
|
||||
if err != nil {
|
||||
if _, err := issuesSearch(ctx, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := gitea.NewClient(ctx.String("url"), token)
|
||||
|
||||
upstreams, err := client.ListRepoBranches(getUpstreamRepo()[1], getUpstreamRepo()[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bases := make([]string, len(upstreams))
|
||||
defUpstream := upstreams[0].Name
|
||||
for idx, upstream := range upstreams {
|
||||
if upstream.Name == "master" {
|
||||
defUpstream = upstream.Name
|
||||
}
|
||||
bases[idx] = upstream.Name
|
||||
}
|
||||
|
||||
origins, err := client.ListRepoBranches(getOriginRepo()[1], getOriginRepo()[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
heads := make([]string, len(origins))
|
||||
defOrigin := origins[0].Name
|
||||
for idx, origin := range origins {
|
||||
if origin.Name == git.Branch() {
|
||||
defOrigin = origin.Name
|
||||
}
|
||||
heads[idx] = origin.Name
|
||||
}
|
||||
|
||||
var confirmed bool
|
||||
var title, body string
|
||||
base := defUpstream
|
||||
head := defOrigin
|
||||
|
||||
for !confirmed {
|
||||
questions := []*survey.Question{
|
||||
{
|
||||
Name: "title",
|
||||
Prompt: &survey.Input{Message: "Title", Default: title},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "body",
|
||||
Prompt: &survey.Multiline{Message: "Description", Default: body},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "base",
|
||||
Prompt: &survey.Select{Message: "Base target", Options: bases, Default: base},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "head",
|
||||
Prompt: &survey.Select{Message: "Head target", Options: heads, Default: head},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
}
|
||||
answers := struct {
|
||||
Title string
|
||||
Body string
|
||||
Base string
|
||||
Head string
|
||||
}{}
|
||||
|
||||
if err := survey.Ask(questions, &answers); err != nil {
|
||||
return err
|
||||
}
|
||||
title = answers.Title
|
||||
body = answers.Body
|
||||
base = answers.Base
|
||||
head = answers.Head
|
||||
|
||||
preview, err := markdown.Render(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n\n%s\n", title, preview)
|
||||
confirm := &survey.Confirm{Message: "Preview above, enter to create or 'n' to edit", Default: true}
|
||||
|
||||
if err := survey.AskOne(confirm, &confirmed); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pull, err := client.CreatePullRequest(ctx.String("owner"), ctx.String("repo"), gitea.CreatePullRequestOption{Title: title, Body: body, Base: base, Head: head})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info := color.Info
|
||||
cyan := color.New(color.FgCyan)
|
||||
fmt.Println(info.Format("PR"), cyan.Format(fmt.Sprintf("#%d", pull.Index)), info.Format("created!"))
|
||||
fmt.Println(cyan.Format(fmt.Sprintf("%s/%s/%s/pulls/%d", ctx.String("url"), ctx.String("owner"), ctx.String("repo"), pull.Index)))
|
||||
return nil
|
||||
}
|
||||
|
83
cmd/pulls_checkout.go
Normal file
83
cmd/pulls_checkout.go
Normal file
@ -0,0 +1,83 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gitea.com/jolheiser/beaver"
|
||||
"gitea.com/jolheiser/tea/modules/config"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/huandu/xstrings"
|
||||
"github.com/urfave/cli/v2"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var PullsCheckout = cli.Command{
|
||||
Name: "checkout",
|
||||
Usage: "Checkout a pull request for testing",
|
||||
Action: doPullCheckout,
|
||||
}
|
||||
|
||||
func doPullCheckout(ctx *cli.Context) error {
|
||||
var issue *gitea.Issue
|
||||
questions := []*survey.Question{
|
||||
{
|
||||
Name: "index",
|
||||
Prompt: &survey.Input{Message: "Pull request number", Help: "Don't worry if you aren't sure! Just say -1 and we'll search for it instead!"},
|
||||
Validate: validatePRNum,
|
||||
},
|
||||
}
|
||||
prNum := struct {
|
||||
Index int64
|
||||
}{}
|
||||
if err := survey.Ask(questions, &prNum); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if prNum.Index < 0 {
|
||||
var confirmed bool
|
||||
for !confirmed {
|
||||
iss, err := issuesSearch(ctx, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
issue = iss
|
||||
confirmation := &survey.Confirm{Message: "Is this the pull request you want to checkout?"}
|
||||
if err := survey.AskOne(confirmation, &confirmed); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iss, err := getClient(ctx).GetIssue(upstreamRepo[1], upstreamRepo[2], prNum.Index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
issue = iss
|
||||
}
|
||||
|
||||
if issue == nil {
|
||||
return errors.New("no pull request selected")
|
||||
}
|
||||
|
||||
branch := fmt.Sprintf("pr%d-%s", issue.Index, xstrings.ToKebabCase(issue.Title))
|
||||
cmd := exec.Command("git", "fetch", config.Upstream, fmt.Sprintf("pull/%d/head:%s", issue.Index, branch))
|
||||
cmd.Stdout = os.Stdout
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
beaver.Infof("Pull request successfully checked out. Switch to it using `git checkout %s`", branch)
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePRNum(ans interface{}) error {
|
||||
if err := survey.Required(ans); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := strconv.Atoi(ans.(string)); err != nil {
|
||||
return errors.New("pull request number must be an number")
|
||||
}
|
||||
return nil
|
||||
}
|
142
cmd/pulls_create.go
Normal file
142
cmd/pulls_create.go
Normal file
@ -0,0 +1,142 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"fmt"
|
||||
"gitea.com/jolheiser/beaver/color"
|
||||
"gitea.com/jolheiser/tea/modules/git"
|
||||
"gitea.com/jolheiser/tea/modules/markdown"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var PullsCreate = cli.Command{
|
||||
Name: "create",
|
||||
Usage: "Create a new pull request",
|
||||
Action: doPullCreate,
|
||||
}
|
||||
|
||||
func doPullCreate(ctx *cli.Context) error {
|
||||
fmt.Println()
|
||||
url := color.New(color.FgYellow).Format(fmt.Sprintf("%s/%s/%s", ctx.String("url"), ctx.String("owner"), ctx.String("repo")))
|
||||
fmt.Println(color.New(color.FgCyan).Format("Creating a new pull request for"), url)
|
||||
|
||||
token, err := requireToken(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := gitea.NewClient(ctx.String("url"), token)
|
||||
|
||||
upstreams, err := client.ListRepoBranches(getUpstreamRepo()[1], getUpstreamRepo()[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bases := make([]string, len(upstreams))
|
||||
defUpstream := upstreams[0].Name
|
||||
for idx, upstream := range upstreams {
|
||||
if upstream.Name == "master" {
|
||||
defUpstream = upstream.Name
|
||||
}
|
||||
bases[idx] = upstream.Name
|
||||
}
|
||||
|
||||
origins, err := client.ListRepoBranches(getOriginRepo()[1], getOriginRepo()[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
heads := make([]string, len(origins))
|
||||
defOrigin := origins[0].Name
|
||||
for idx, origin := range origins {
|
||||
if origin.Name == git.Branch() {
|
||||
defOrigin = getOriginRepo()[1] + ":" + origin.Name
|
||||
}
|
||||
heads[idx] = getOriginRepo()[1] + ":" + origin.Name
|
||||
}
|
||||
|
||||
var confirmed bool
|
||||
var title, body string
|
||||
base := defUpstream
|
||||
head := defOrigin
|
||||
|
||||
for !confirmed {
|
||||
questions := []*survey.Question{
|
||||
{
|
||||
Name: "title",
|
||||
Prompt: &survey.Input{Message: "Title", Default: title},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "body",
|
||||
Prompt: &survey.Multiline{Message: "Description", Default: body},
|
||||
},
|
||||
{
|
||||
Name: "base",
|
||||
Prompt: &survey.Select{Message: "Base target", Options: bases, Default: base},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "head",
|
||||
Prompt: &survey.Select{Message: "Head target", Options: heads, Default: head},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
}
|
||||
answers := struct {
|
||||
Title string
|
||||
Body string
|
||||
Base string
|
||||
Head string
|
||||
}{}
|
||||
|
||||
if err := survey.Ask(questions, &answers); err != nil {
|
||||
return err
|
||||
}
|
||||
title = answers.Title
|
||||
body = answers.Body
|
||||
base = answers.Base
|
||||
head = answers.Head
|
||||
|
||||
preview, err := markdown.Render(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n\n%s\n", title, preview)
|
||||
confirm := &survey.Confirm{Message: "Preview above, enter to create or 'n' to edit", Default: true}
|
||||
|
||||
if err := survey.AskOne(confirm, &confirmed); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pull, err := client.CreatePullRequest(ctx.String("owner"), ctx.String("repo"), gitea.CreatePullRequestOption{Title: title, Body: body, Base: base, Head: head})
|
||||
if err != nil {
|
||||
if fmt.Sprint(err) == "409 Conflict" { // Hard-coded in the SDK
|
||||
return existingPR(client, getUpstreamRepo()[1], getUpstreamRepo()[2], head, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
info := color.Info
|
||||
cyan := color.New(color.FgCyan)
|
||||
fmt.Println(info.Format("PR"), cyan.Format(fmt.Sprintf("#%d", pull.Index)), info.Format("created!"))
|
||||
fmt.Println(cyan.Format(fmt.Sprintf("%s/%s/%s/pulls/%d", ctx.String("url"), ctx.String("owner"), ctx.String("repo"), pull.Index)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func existingPR(client *gitea.Client, owner, repo, head string, pullErr error) error {
|
||||
pulls, err := client.ListRepoPullRequests(owner, repo, gitea.ListPullRequestsOptions{State: "open"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pull := range pulls {
|
||||
compare := fmt.Sprintf("%s:%s", pull.Head.Repository.Owner.UserName, pull.Head.Name)
|
||||
if compare == head {
|
||||
fmt.Println(color.New(color.FgCyan).Format("PR already exists at"), color.New(color.FgYellow).Format(pull.HTMLURL))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return pullErr
|
||||
}
|
58
cmd/pulls_status.go
Normal file
58
cmd/pulls_status.go
Normal file
@ -0,0 +1,58 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"fmt"
|
||||
"gitea.com/jolheiser/beaver/color"
|
||||
"gitea.com/jolheiser/tea/modules/git"
|
||||
"gitea.com/jolheiser/tea/modules/sdk"
|
||||
"github.com/urfave/cli/v2"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var PullsStatus = cli.Command{
|
||||
Name: "status",
|
||||
Usage: "View the status of a pull request",
|
||||
Action: doPullStatus,
|
||||
}
|
||||
|
||||
func doPullStatus(ctx *cli.Context) error {
|
||||
client := getClient(ctx)
|
||||
head := fmt.Sprintf("%s:%s", getOriginRepo()[1], git.Branch())
|
||||
|
||||
pulls, err := sdk.GetPulls(client, getUpstreamRepo()[1], getUpstreamRepo()[2], gitea.ListPullRequestsOptions{State: "all"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pr *gitea.PullRequest
|
||||
for _, pull := range pulls {
|
||||
compare := fmt.Sprintf("%s:%s", pull.Head.Repository.Owner.UserName, pull.Head.Name)
|
||||
if compare == head {
|
||||
pr = pull
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if pr == nil {
|
||||
return fmt.Errorf("no pull request found with head target %s", color.New(color.FgMagenta).Format(head))
|
||||
}
|
||||
|
||||
index := color.New(color.FgCyan).Format("#" + strconv.Itoa(int(pr.Index)))
|
||||
title := color.New(color.FgYellow).Format(pr.Title)
|
||||
state := color.New(color.FgGreen).Format("[open]")
|
||||
if pr.HasMerged {
|
||||
state = color.New(color.FgMagenta).Format("[merged]")
|
||||
} else if pr.State == gitea.StateClosed {
|
||||
state = color.New(color.FgRed).Format("[closed]")
|
||||
}
|
||||
lbls := make([]string, len(pr.Labels))
|
||||
for idx, label := range pr.Labels {
|
||||
lbls[idx] = label.Name
|
||||
}
|
||||
fmt.Println(index, title, state)
|
||||
fmt.Println(color.New(color.FgCyan).Format(fmt.Sprintf("%d comments", pr.Comments)))
|
||||
fmt.Println(color.New(color.FgYellow).Format(pr.HTMLURL))
|
||||
|
||||
return nil
|
||||
}
|
1
go.mod
1
go.mod
@ -8,6 +8,7 @@ require (
|
||||
github.com/AlecAivazis/survey/v2 v2.0.5
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/charmbracelet/glamour v0.1.0
|
||||
github.com/huandu/xstrings v1.3.0
|
||||
github.com/kr/pretty v0.2.0 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
github.com/kyokomi/emoji v2.1.0+incompatible
|
||||
|
2
go.sum
2
go.sum
@ -45,6 +45,8 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||
github.com/huandu/xstrings v1.3.0 h1:gvV6jG9dTgFEncxo+AF7PH6MZXi/vZl25owA/8Dg8Wo=
|
||||
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
|
@ -10,7 +10,7 @@ func GetRepo(remoteName string) []string {
|
||||
cmd := exec.Command("git", "remote", "get-url", remoteName)
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return []string{"", ""}
|
||||
return []string{"https://gitea.com", "jolheiser", "tea"}
|
||||
}
|
||||
|
||||
remote := strings.TrimSpace(string(out))
|
||||
|
Loading…
Reference in New Issue
Block a user