Proper help text & new README structure #311
21
README.md
21
README.md
|
@ -8,7 +8,7 @@
|
|||
|
||||
```
|
||||
tea - command line tool to interact with Gitea
|
||||
version 0.6.0+9-g75d415b
|
||||
version 0.6.0+17-g1c10f33
|
||||
noerw marked this conversation as resolved
Outdated
|
||||
|
||||
USAGE
|
||||
tea command [subcommand] [command options] [arguments...]
|
||||
|
@ -22,20 +22,21 @@
|
|||
COMMANDS
|
||||
help, h Shows a list of commands or help for one command
|
||||
ENTITIES:
|
||||
issues, issue List, create and update issues
|
||||
pulls, pull, pr List, create, checkout and clean pull requests
|
||||
issues, issue, i List, create and update issues
|
||||
pulls, pull, pr Manage and checkout pull requests
|
||||
labels, label Manage issue labels
|
||||
milestones, milestone, ms List and create milestones
|
||||
releases, release Manage releases
|
||||
times, time Operate on tracked times of a repository's issues & pulls
|
||||
releases, release, r Manage releases
|
||||
times, time, t Operate on tracked times of a repository's issues & pulls
|
||||
organizations, organization, org List, create, delete organizations
|
||||
repos, repo Show repository details
|
||||
HELPERS:
|
||||
open Open something of the repository on web browser
|
||||
notifications, notification, notif Show notifications
|
||||
open, o Open something of the repository in web browser
|
||||
notifications, notification, n Show notifications
|
||||
SETUP:
|
||||
logins, login Log in to a Gitea server
|
||||
logout Log out from a Gitea server
|
||||
logins, login Log in to a Gitea server
|
||||
logout Log out from a Gitea server
|
||||
shellcompletion, autocomplete Install shell completion for tea
|
||||
|
||||
OPTIONS
|
||||
--help, -h show help (default: false)
|
||||
|
@ -73,7 +74,7 @@
|
|||
You can use the prebuilt binaries from [dl.gitea.io](https://dl.gitea.io/tea/)
|
||||
|
||||
Distribution packages exist for:
|
||||
- **alpinelinux ([tea](https://pkgs.alpinelinux.org/packages?name=tea&branch=edge))**
|
||||
- **alpinelinux ([tea](https://pkgs.alpinelinux.org/packages?name=tea&branch=edge))**
|
||||
- **archlinux ([gitea-tea](https://aur.archlinux.org/packages/gitea-tea))**
|
||||
|
||||
To install from source, go 1.13 or newer is required:
|
||||
|
|
106
cmd/autocomplete.go
Normal file
106
cmd/autocomplete.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// CmdAutocomplete manages autocompletion
|
||||
var CmdAutocomplete = cli.Command{
|
||||
Name: "shellcompletion",
|
||||
Aliases: []string{"autocomplete"},
|
||||
Category: catSetup,
|
||||
Usage: "Install shell completion for tea",
|
||||
Description: "Install shell completion for tea",
|
||||
ArgsUsage: "<shell type> (bash, zsh, powershell)",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "install",
|
||||
Usage: "Persist in shell config instead of printing commands",
|
||||
},
|
||||
},
|
||||
Action: runAutocompleteAdd,
|
||||
}
|
||||
|
||||
func runAutocompleteAdd(ctx *cli.Context) error {
|
||||
var remoteFile, localFile, cmds string
|
||||
shell := ctx.Args().First()
|
||||
|
||||
switch shell {
|
||||
case "zsh":
|
||||
remoteFile = "contrib/autocomplete.zsh"
|
||||
localFile = "autocomplete.zsh"
|
||||
cmds = "echo 'PROG=tea _CLI_ZSH_AUTOCOMPLETE_HACK=1 source %s' >> ~/.zshrc && source ~/.zshrc"
|
||||
|
||||
case "bash":
|
||||
remoteFile = "contrib/autocomplete.sh"
|
||||
localFile = "autocomplete.sh"
|
||||
cmds = "echo 'PROG=tea source %s' >> ~/.bashrc && source ~/.bashrc"
|
||||
|
||||
case "powershell":
|
||||
remoteFile = "contrib/autocomplete.ps1"
|
||||
localFile = "tea.ps1"
|
||||
cmds = "\"& %s\" >> $profile"
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Must specify valid shell type")
|
||||
}
|
||||
|
||||
localPath, err := xdg.ConfigFile("tea/" + localFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmds = fmt.Sprintf(cmds, localPath)
|
||||
|
||||
if err := saveAutoCompleteFile(remoteFile, localPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx.Bool("install") {
|
||||
fmt.Println("Installing in your shellrc")
|
||||
installer := exec.Command(shell, "-c", cmds)
|
||||
if shell == "powershell" {
|
||||
installer = exec.Command("powershell.exe", "-Command", cmds)
|
||||
}
|
||||
out, err := installer.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't run the commands: %s %s", err, out)
|
||||
}
|
||||
} else {
|
||||
fmt.Println("\n# Run the following commands to install autocompletion (or use --install)")
|
||||
fmt.Println(cmds)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveAutoCompleteFile(file, destPath string) error {
|
||||
url := fmt.Sprintf("https://gitea.com/gitea/tea/raw/branch/master/%s", file)
|
||||
fmt.Println("Fetching " + url)
|
||||
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
writer, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer writer.Close()
|
||||
|
||||
_, err = io.Copy(writer, res.Body)
|
||||
return err
|
||||
}
|
|
@ -17,7 +17,7 @@ import (
|
|||
// CmdIssues represents to login a gitea server.
|
||||
var CmdIssues = cli.Command{
|
||||
Name: "issues",
|
||||
Aliases: []string{"issue"},
|
||||
Aliases: []string{"issue", "i"},
|
||||
Category: catEntities,
|
||||
Usage: "List, create and update issues",
|
||||
Description: "List, create and update issues",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
package issues
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
@ -34,7 +34,7 @@ func editIssueState(cmd *cli.Context, opts gitea.EditIssueOption) error {
|
|||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
if ctx.Args().Len() == 0 {
|
||||
log.Fatal(ctx.Command.ArgsUsage)
|
||||
return fmt.Errorf(ctx.Command.ArgsUsage)
|
||||
}
|
||||
|
||||
index, err := utils.ArgToIndex(ctx.Args().First())
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
// CmdIssuesCreate represents a sub command of issues to create issue
|
||||
var CmdIssuesCreate = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create an issue on repository",
|
||||
Description: `Create an issue on repository`,
|
||||
Action: runIssuesCreate,
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package issues
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
@ -17,8 +15,8 @@ import (
|
|||
|
||||
// CmdIssuesList represents a sub command of issues to list issues
|
||||
var CmdIssuesList = cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List issues of the repository",
|
||||
Description: `List issues of the repository`,
|
||||
Action: RunIssuesList,
|
||||
|
@ -47,7 +45,7 @@ func RunIssuesList(cmd *cli.Context) error {
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
print.IssuesList(issues, ctx.Output)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/labels"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
@ -35,6 +35,5 @@ func runLabels(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
func runLabelsDetails(ctx *cli.Context) error {
|
||||
log.Fatal("Not yet implemented.")
|
||||
return nil
|
||||
return fmt.Errorf("Not yet implemented")
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
// CmdLabelCreate represents a sub command of labels to create label.
|
||||
var CmdLabelCreate = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create a label",
|
||||
Description: `Create a label`,
|
||||
Action: runLabelCreate,
|
||||
|
@ -80,11 +81,7 @@ func runLabelCreate(cmd *cli.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func splitLabelLine(line string) (string, string, string) {
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package labels
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
@ -15,6 +13,7 @@ import (
|
|||
// CmdLabelDelete represents a sub command of labels to delete label.
|
||||
var CmdLabelDelete = cli.Command{
|
||||
Name: "delete",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "Delete a label",
|
||||
Description: `Delete a label`,
|
||||
Action: runLabelDelete,
|
||||
|
@ -31,9 +30,5 @@ func runLabelDelete(cmd *cli.Context) error {
|
|||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
|
||||
_, err := ctx.Login.Client().DeleteLabel(ctx.Owner, ctx.Repo, ctx.Int64("id"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package labels
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
@ -18,8 +16,8 @@ import (
|
|||
|
||||
// CmdLabelsList represents a sub command of labels to list labels
|
||||
var CmdLabelsList = cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List labels",
|
||||
Description: "List labels",
|
||||
Action: RunLabelsList,
|
||||
|
@ -44,7 +42,7 @@ func RunLabelsList(cmd *cli.Context) error {
|
|||
ListOptions: ctx.GetListOptions(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx.IsSet("save") {
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package labels
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
|
@ -68,7 +66,7 @@ func runLabelUpdate(cmd *cli.Context) error {
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
// CmdLoginEdit represents to login a gitea server.
|
||||
var CmdLoginEdit = cli.Command{
|
||||
Name: "edit",
|
||||
Aliases: []string{"e"},
|
||||
Usage: "Edit Gitea logins",
|
||||
Description: `Edit Gitea logins`,
|
||||
Action: runLoginEdit,
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package login
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/config"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
@ -16,8 +14,8 @@ import (
|
|||
|
||||
// CmdLoginList represents to login a gitea server.
|
||||
var CmdLoginList = cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List Gitea logins",
|
||||
Description: `List Gitea logins`,
|
||||
Action: RunLoginList,
|
||||
|
@ -28,7 +26,7 @@ var CmdLoginList = cli.Command{
|
|||
func RunLoginList(cmd *cli.Context) error {
|
||||
logins, err := config.GetLogins()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
print.LoginsList(logins, cmd.String("output"))
|
||||
return nil
|
||||
|
|
|
@ -6,7 +6,6 @@ package milestones
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
@ -19,6 +18,7 @@ import (
|
|||
// CmdMilestonesCreate represents a sub command of milestones to create milestone
|
||||
var CmdMilestonesCreate = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create an milestone on repository",
|
||||
Description: `Create an milestone on repository`,
|
||||
Action: runMilestonesCreate,
|
||||
|
@ -62,7 +62,7 @@ func runMilestonesCreate(cmd *cli.Context) error {
|
|||
State: state,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
print.MilestoneDetails(mile)
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package milestones
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
@ -17,8 +15,8 @@ import (
|
|||
|
||||
// CmdMilestonesList represents a sub command of milestones to list milestones
|
||||
var CmdMilestonesList = cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List milestones of the repository",
|
||||
Description: `List milestones of the repository`,
|
||||
Action: RunMilestonesList,
|
||||
|
@ -53,7 +51,7 @@ func RunMilestonesList(cmd *cli.Context) error {
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
print.MilestonesList(milestones, ctx.Output, state)
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
@ -18,7 +16,7 @@ import (
|
|||
// CmdNotifications is the main command to operate with notifications
|
||||
var CmdNotifications = cli.Command{
|
||||
Name: "notifications",
|
||||
Aliases: []string{"notification", "notif"},
|
||||
Aliases: []string{"notification", "n"},
|
||||
Category: catHelpers,
|
||||
Usage: "Show notifications",
|
||||
Description: "Show notifications, by default based of the current repo and unread one",
|
||||
|
@ -77,7 +75,7 @@ func runNotifications(cmd *cli.Context) error {
|
|||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
print.NotificationsList(news, ctx.Output, ctx.Bool("all"))
|
||||
|
|
20
cmd/open.go
20
cmd/open.go
|
@ -5,7 +5,6 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
|
@ -20,9 +19,10 @@ import (
|
|||
// CmdOpen represents a sub command of issues to open issue on the web browser
|
||||
var CmdOpen = cli.Command{
|
||||
Name: "open",
|
||||
Aliases: []string{"o"},
|
||||
Category: catHelpers,
|
||||
Usage: "Open something of the repository on web browser",
|
||||
Description: `Open something of the repository on web browser`,
|
||||
Usage: "Open something of the repository in web browser",
|
||||
Description: `Open something of the repository in web browser`,
|
||||
Action: runOpen,
|
||||
Flags: append([]cli.Flag{}, flags.LoginRepoFlags...),
|
||||
}
|
||||
|
@ -43,12 +43,11 @@ func runOpen(cmd *cli.Context) error {
|
|||
case strings.EqualFold(number, "commits"):
|
||||
repo, err := local_git.RepoForWorkdir()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
b, err := repo.Head()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
name := b.Name()
|
||||
switch {
|
||||
|
@ -75,11 +74,6 @@ func runOpen(cmd *cli.Context) error {
|
|||
suffix = number
|
||||
}
|
||||
|
||||
u := path.Join(ctx.Login.URL, ctx.RepoSlug, suffix)
|
||||
err := open.Run(u)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
u := path.Join(ctx.Login.URL, ctx.Owner, ctx.Repo, suffix)
|
||||
return open.Run(u)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/organizations"
|
||||
|
||||
|
@ -35,7 +35,5 @@ func runOrganizations(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
func runOrganizationDetail(path string) error {
|
||||
|
||||
log.Fatal("Not yet implemented.")
|
||||
return nil
|
||||
return fmt.Errorf("Not yet implemented")
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
package organizations
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
@ -28,14 +28,12 @@ func RunOrganizationDelete(cmd *cli.Context) error {
|
|||
client := ctx.Login.Client()
|
||||
|
||||
if ctx.Args().Len() < 1 {
|
||||
log.Fatal("You have to specify the organization name you want to delete.")
|
||||
return nil
|
||||
return fmt.Errorf("You have to specify the organization name you want to delete")
|
||||
}
|
||||
|
||||
response, err := client.DeleteOrg(ctx.Args().First())
|
||||
if response != nil && response.StatusCode == 404 {
|
||||
log.Fatal("The given organization does not exist.")
|
||||
return nil
|
||||
return fmt.Errorf("The given organization does not exist")
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package organizations
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
@ -17,8 +15,8 @@ import (
|
|||
|
||||
// CmdOrganizationList represents a sub command of organizations to list users organizations
|
||||
var CmdOrganizationList = cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List Organizations",
|
||||
Description: "List users organizations",
|
||||
Action: RunOrganizationList,
|
||||
|
@ -37,7 +35,7 @@ func RunOrganizationList(cmd *cli.Context) error {
|
|||
ListOptions: ctx.GetListOptions(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
print.OrganizationsList(userOrganizations, ctx.Output)
|
||||
|
|
13
cmd/pulls.go
13
cmd/pulls.go
|
@ -22,8 +22,8 @@ var CmdPulls = cli.Command{
|
|||
Name: "pulls",
|
||||
Aliases: []string{"pull", "pr"},
|
||||
Category: catEntities,
|
||||
Usage: "List, create, checkout and clean pull requests",
|
||||
Description: `List, create, checkout and clean pull requests`,
|
||||
Usage: "Manage and checkout pull requests",
|
||||
Description: `Manage and checkout pull requests`,
|
||||
ArgsUsage: "[<pull index>]",
|
||||
Action: runPulls,
|
||||
Flags: flags.IssuePRFlags,
|
||||
|
@ -32,6 +32,8 @@ var CmdPulls = cli.Command{
|
|||
&pulls.CmdPullsCheckout,
|
||||
&pulls.CmdPullsClean,
|
||||
&pulls.CmdPullsCreate,
|
||||
&pulls.CmdPullsClose,
|
||||
&pulls.CmdPullsReopen,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -61,6 +63,11 @@ func runPullDetail(cmd *cli.Context, index string) error {
|
|||
fmt.Printf("error while loading reviews: %v\n", err)
|
||||
}
|
||||
|
||||
print.PullDetails(pr, reviews)
|
||||
ci, _, err := client.GetCombinedStatus(ctx.Owner, ctx.Repo, pr.Head.Sha)
|
||||
if err != nil {
|
||||
fmt.Printf("error while loading CI: %v\n", err)
|
||||
}
|
||||
|
||||
print.PullDetails(pr, reviews, ci)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
package pulls
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
@ -19,6 +19,7 @@ import (
|
|||
// CmdPullsCheckout is a command to locally checkout the given PR
|
||||
var CmdPullsCheckout = cli.Command{
|
||||
Name: "checkout",
|
||||
Aliases: []string{"co"},
|
||||
Usage: "Locally check out the given PR",
|
||||
Description: `Locally check out the given PR`,
|
||||
Action: runPullsCheckout,
|
||||
|
@ -30,7 +31,7 @@ func runPullsCheckout(cmd *cli.Context) error {
|
|||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{LocalRepo: true})
|
||||
if ctx.Args().Len() != 1 {
|
||||
log.Fatal("Must specify a PR index")
|
||||
return fmt.Errorf("Must specify a PR index")
|
||||
}
|
||||
idx, err := utils.ArgToIndex(ctx.Args().First())
|
||||
if err != nil {
|
||||
|
|
25
cmd/pulls/close.go
Normal file
25
cmd/pulls/close.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// CmdPullsClose closes a given open pull request
|
||||
var CmdPullsClose = cli.Command{
|
||||
Name: "close",
|
||||
Usage: "Change state of a pull request to 'closed'",
|
||||
Description: `Change state of a pull request to 'closed'`,
|
||||
ArgsUsage: "<pull index>",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
var s = gitea.StateClosed
|
||||
return editPullState(ctx, gitea.EditPullRequestOption{State: &s})
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
|
@ -16,6 +16,7 @@ import (
|
|||
// CmdPullsCreate creates a pull request
|
||||
var CmdPullsCreate = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create a pull-request",
|
||||
Description: "Create a pull-request",
|
||||
Action: runPullsCreate,
|
||||
|
|
38
cmd/pulls/edit.go
Normal file
38
cmd/pulls/edit.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// editPullState abstracts the arg parsing to edit the given pull request
|
||||
func editPullState(cmd *cli.Context, opts gitea.EditPullRequestOption) error {
|
||||
ctx := context.InitCommand(cmd)
|
||||
ctx.Ensure(context.CtxRequirement{RemoteRepo: true})
|
||||
if ctx.Args().Len() == 0 {
|
||||
return fmt.Errorf("Please provide a Pull Request index")
|
||||
}
|
||||
|
||||
index, err := utils.ArgToIndex(ctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pr, _, err := ctx.Login.Client().EditPullRequest(ctx.Owner, ctx.Repo, index, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
print.PullDetails(pr, nil, nil)
|
||||
return nil
|
||||
}
|
|
@ -5,8 +5,6 @@
|
|||
package pulls
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
"code.gitea.io/tea/modules/print"
|
||||
|
@ -17,8 +15,8 @@ import (
|
|||
|
||||
// CmdPullsList represents a sub command of issues to list pulls
|
||||
var CmdPullsList = cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List pull requests of the repository",
|
||||
Description: `List pull requests of the repository`,
|
||||
Action: RunPullsList,
|
||||
|
@ -45,7 +43,7 @@ func RunPullsList(cmd *cli.Context) error {
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
print.PullsList(prs, ctx.Output)
|
||||
|
|
26
cmd/pulls/reopen.go
Normal file
26
cmd/pulls/reopen.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package pulls
|
||||
|
||||
import (
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// CmdPullsReopen reopens a given closed pull request
|
||||
var CmdPullsReopen = cli.Command{
|
||||
Name: "reopen",
|
||||
Aliases: []string{"open"},
|
||||
Usage: "Change state of a pull request to 'open'",
|
||||
Description: `Change state of a pull request to 'open'`,
|
||||
ArgsUsage: "<pull index>",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
var s = gitea.StateOpen
|
||||
return editPullState(ctx, gitea.EditPullRequestOption{State: &s})
|
||||
},
|
||||
Flags: flags.AllDefaultFlags,
|
||||
}
|
|
@ -15,7 +15,7 @@ import (
|
|||
// ToDo: ReleaseDetails
|
||||
var CmdReleases = cli.Command{
|
||||
Name: "releases",
|
||||
Aliases: []string{"release"},
|
||||
Aliases: []string{"release", "r"},
|
||||
Category: catEntities,
|
||||
Usage: "Manage releases",
|
||||
Description: "Manage releases",
|
||||
|
|
|
@ -6,7 +6,6 @@ package releases
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -21,6 +20,7 @@ import (
|
|||
// CmdReleaseCreate represents a sub command of Release to create release
|
||||
var CmdReleaseCreate = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Create a release",
|
||||
Description: `Create a release`,
|
||||
Action: runReleaseCreate,
|
||||
|
@ -76,24 +76,23 @@ func runReleaseCreate(cmd *cli.Context) error {
|
|||
|
||||
if err != nil {
|
||||
if resp != nil && resp.StatusCode == http.StatusConflict {
|
||||
fmt.Println("error: There already is a release for this tag")
|
||||
return nil
|
||||
return fmt.Errorf("There already is a release for this tag")
|
||||
}
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, asset := range ctx.StringSlice("asset") {
|
||||
var file *os.File
|
||||
|
||||
if file, err = os.Open(asset); err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
filePath := filepath.Base(asset)
|
||||
|
||||
if _, _, err = ctx.Login.Client().CreateReleaseAttachment(ctx.Owner, ctx.Repo, release.ID, file, filePath); err != nil {
|
||||
file.Close()
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
// CmdReleaseDelete represents a sub command of Release to delete a release
|
||||
var CmdReleaseDelete = cli.Command{
|
||||
Name: "delete",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "Delete a release",
|
||||
Description: `Delete a release`,
|
||||
ArgsUsage: "<release tag>",
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
// CmdReleaseEdit represents a sub command of Release to edit releases
|
||||
var CmdReleaseEdit = cli.Command{
|
||||
Name: "edit",
|
||||
Aliases: []string{"e"},
|
||||
Usage: "Edit a release",
|
||||
Description: `Edit a release`,
|
||||
ArgsUsage: "<release tag>",
|
||||
|
|
|
@ -6,7 +6,6 @@ package releases
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
@ -18,8 +17,8 @@ import (
|
|||
|
||||
// CmdReleaseList represents a sub command of Release to list releases
|
||||
var CmdReleaseList = cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List Releases",
|
||||
Description: "List Releases",
|
||||
Action: RunReleasesList,
|
||||
|
@ -38,7 +37,7 @@ func RunReleasesList(cmd *cli.Context) error {
|
|||
ListOptions: ctx.GetListOptions(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
print.ReleasesList(releases, ctx.Output)
|
||||
|
|
|
@ -35,8 +35,8 @@ var CmdReposListFlags = append([]cli.Flag{
|
|||
|
||||
// CmdReposList represents a sub command of repos to list them
|
||||
var CmdReposList = cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List repositories you have access to",
|
||||
Description: "List repositories you have access to",
|
||||
Action: RunReposList,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
package repos
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
|
@ -67,7 +67,7 @@ func runReposSearch(cmd *cli.Context) error {
|
|||
if err != nil {
|
||||
// HACK: the client does not return a response on 404, so we can't check res.StatusCode
|
||||
if err.Error() != "404 Not Found" {
|
||||
log.Fatal("could not find owner: ", err)
|
||||
return fmt.Errorf("Could not find owner: %s", err)
|
||||
}
|
||||
|
||||
// if owner is no org, its a user
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
// CmdTrackedTimes represents the command to operate repositories' times.
|
||||
var CmdTrackedTimes = cli.Command{
|
||||
Name: "times",
|
||||
Aliases: []string{"time"},
|
||||
Aliases: []string{"time", "t"},
|
||||
Category: catEntities,
|
||||
Usage: "Operate on tracked times of a repository's issues & pulls",
|
||||
Description: `Operate on tracked times of a repository's issues & pulls.
|
||||
|
|
|
@ -6,7 +6,6 @@ package times
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -21,6 +20,7 @@ import (
|
|||
// CmdTrackedTimesAdd represents a sub command of times to add time to an issue
|
||||
var CmdTrackedTimesAdd = cli.Command{
|
||||
Name: "add",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Track spent time on an issue",
|
||||
UsageText: "tea times add <issue> <duration>",
|
||||
Description: `Track spent time on an issue
|
||||
|
@ -41,20 +41,16 @@ func runTrackedTimesAdd(cmd *cli.Context) error {
|
|||
|
||||
issue, err := utils.ArgToIndex(ctx.Args().First())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
duration, err := time.ParseDuration(strings.Join(ctx.Args().Tail(), ""))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
_, _, err = ctx.Login.Client().AddTime(ctx.Owner, ctx.Repo, issue, gitea.AddTimeOption{
|
||||
Time: int64(duration.Seconds()),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ package times
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
|
@ -37,18 +36,14 @@ func runTrackedTimesDelete(cmd *cli.Context) error {
|
|||
|
||||
issue, err := utils.ArgToIndex(ctx.Args().First())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
timeID, err := strconv.ParseInt(ctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.DeleteTime(ctx.Owner, ctx.Repo, issue, timeID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ import (
|
|||
|
||||
// CmdTrackedTimesList represents a sub command of times to list them
|
||||
var CmdTrackedTimesList = cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"list"},
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Action: RunTimesList,
|
||||
Usage: "Operate on tracked times of a repository's issues & pulls",
|
||||
Description: `Operate on tracked times of a repository's issues & pulls.
|
||||
|
|
|
@ -6,7 +6,6 @@ package times
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"code.gitea.io/tea/cmd/flags"
|
||||
"code.gitea.io/tea/modules/context"
|
||||
|
@ -36,13 +35,9 @@ func runTrackedTimesReset(cmd *cli.Context) error {
|
|||
|
||||
issue, err := utils.ArgToIndex(ctx.Args().First())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.ResetIssueTime(ctx.Owner, ctx.Repo, issue)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
|
9
contrib/autocomplete.ps1
Normal file
9
contrib/autocomplete.ps1
Normal file
|
@ -0,0 +1,9 @@
|
|||
$fn = $($MyInvocation.MyCommand.Name)
|
||||
$name = $fn -replace "(.*)\.ps1$", '$1'
|
||||
Register-ArgumentCompleter -Native -CommandName $name -ScriptBlock {
|
||||
param($commandName, $wordToComplete, $cursorPosition)
|
||||
$other = "$wordToComplete --generate-bash-completion"
|
||||
Invoke-Expression $other | ForEach-Object {
|
||||
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
||||
}
|
||||
}
|
21
contrib/autocomplete.sh
Normal file
21
contrib/autocomplete.sh
Normal file
|
@ -0,0 +1,21 @@
|
|||
#! /bin/bash
|
||||
|
||||
: ${PROG:=$(basename ${BASH_SOURCE})}
|
||||
|
||||
_cli_bash_autocomplete() {
|
||||
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
|
||||
local cur opts base
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [[ "$cur" == "-"* ]]; then
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
|
||||
else
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
|
||||
fi
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG
|
||||
unset PROG
|
23
contrib/autocomplete.zsh
Normal file
23
contrib/autocomplete.zsh
Normal file
|
@ -0,0 +1,23 @@
|
|||
#compdef $PROG
|
||||
|
||||
_cli_zsh_autocomplete() {
|
||||
|
||||
local -a opts
|
||||
local cur
|
||||
cur=${words[-1]}
|
||||
if [[ "$cur" == "-"* ]]; then
|
||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
|
||||
else
|
||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
|
||||
fi
|
||||
|
||||
if [[ "${opts[1]}" != "" ]]; then
|
||||
_describe 'values' opts
|
||||
else
|
||||
_files
|
||||
fi
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
compdef _cli_zsh_autocomplete $PROG
|
9
main.go
9
main.go
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -7,7 +7,6 @@ package main // import "code.gitea.io/tea"
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
@ -35,6 +34,7 @@ func main() {
|
|||
app.Commands = []*cli.Command{
|
||||
&cmd.CmdLogin,
|
||||
&cmd.CmdLogout,
|
||||
&cmd.CmdAutocomplete,
|
||||
|
||||
&cmd.CmdIssues,
|
||||
&cmd.CmdPulls,
|
||||
|
@ -51,7 +51,10 @@ func main() {
|
|||
app.EnableBashCompletion = true
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to run app with %s: %v", os.Args, err)
|
||||
// app.Run already exits for errors implementing ErrorCoder,
|
||||
// so we only handle generic errors with code 1 here.
|
||||
fmt.Fprintf(app.ErrWriter, "Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,33 +47,28 @@ func (r TeaRepo) TeaCheckout(branchName string) error {
|
|||
return tree.Checkout(&git.CheckoutOptions{Branch: localBranchRefName})
|
||||
}
|
||||
|
||||
// TeaDeleteBranch removes the given branch locally, and if `remoteBranch` is
|
||||
// not empty deletes it at it's remote repo.
|
||||
func (r TeaRepo) TeaDeleteBranch(branch *git_config.Branch, remoteBranch string, auth git_transport.AuthMethod) error {
|
||||
// TeaDeleteLocalBranch removes the given branch locally
|
||||
func (r TeaRepo) TeaDeleteLocalBranch(branch *git_config.Branch) error {
|
||||
err := r.DeleteBranch(branch.Name)
|
||||
// if the branch is not found that's ok, as .git/config may have no entry if
|
||||
// no remote tracking branch is configured for it (eg push without -u flag)
|
||||
if err != nil && err.Error() != "branch not found" {
|
||||
return err
|
||||
}
|
||||
err = r.Storer.RemoveReference(git_plumbing.NewBranchReferenceName(branch.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.Storer.RemoveReference(git_plumbing.NewBranchReferenceName(branch.Name))
|
||||
}
|
||||
|
||||
if remoteBranch != "" {
|
||||
// delete remote branch via git protocol:
|
||||
// an empty source in the refspec means remote deletion to git 🙃
|
||||
refspec := fmt.Sprintf(":%s", git_plumbing.NewBranchReferenceName(remoteBranch))
|
||||
err = r.Push(&git.PushOptions{
|
||||
RemoteName: branch.Remote,
|
||||
RefSpecs: []git_config.RefSpec{git_config.RefSpec(refspec)},
|
||||
Prune: true,
|
||||
Auth: auth,
|
||||
})
|
||||
}
|
||||
|
||||
return err
|
||||
// TeaDeleteRemoteBranch removes the given branch on the given remote via git protocol
|
||||
func (r TeaRepo) TeaDeleteRemoteBranch(remoteName, remoteBranch string, auth git_transport.AuthMethod) error {
|
||||
// delete remote branch via git protocol:
|
||||
// an empty source in the refspec means remote deletion to git 🙃
|
||||
refspec := fmt.Sprintf(":%s", git_plumbing.NewBranchReferenceName(remoteBranch))
|
||||
return r.Push(&git.PushOptions{
|
||||
RemoteName: remoteName,
|
||||
RefSpecs: []git_config.RefSpec{git_config.RefSpec(refspec)},
|
||||
Prune: true,
|
||||
Auth: auth,
|
||||
})
|
||||
}
|
||||
|
||||
// TeaFindBranchBySha returns a branch that is at the the given SHA and syncs to the
|
||||
|
|
|
@ -7,12 +7,21 @@ package print
|
|||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
var ciStatusSymbols = map[gitea.StatusState]string{
|
||||
gitea.StatusSuccess: "✓ ",
|
||||
gitea.StatusPending: "⭮ ",
|
||||
gitea.StatusWarning: "⚠ ",
|
||||
gitea.StatusError: "✘ ",
|
||||
gitea.StatusFailure: "❌ ",
|
||||
}
|
||||
|
||||
// PullDetails print an pull rendered to stdout
|
||||
func PullDetails(pr *gitea.PullRequest, reviews []*gitea.PullReview) {
|
||||
func PullDetails(pr *gitea.PullRequest, reviews []*gitea.PullReview, ciStatus *gitea.CombinedStatus) {
|
||||
base := pr.Base.Name
|
||||
head := pr.Head.Name
|
||||
if pr.Head.RepoID != pr.Base.RepoID {
|
||||
|
@ -23,11 +32,16 @@ func PullDetails(pr *gitea.PullRequest, reviews []*gitea.PullReview) {
|
|||
}
|
||||
}
|
||||
|
||||
state := pr.State
|
||||
if pr.Merged != nil {
|
||||
state = "merged"
|
||||
}
|
||||
|
||||
out := fmt.Sprintf(
|
||||
"# #%d %s (%s)\n@%s created %s\t**%s** <- **%s**\n\n%s\n",
|
||||
"# #%d %s (%s)\n@%s created %s\t**%s** <- **%s**\n\n%s\n\n",
|
||||
pr.Index,
|
||||
pr.Title,
|
||||
pr.State,
|
||||
state,
|
||||
pr.Poster.UserName,
|
||||
FormatTime(*pr.Created),
|
||||
base,
|
||||
|
@ -35,29 +49,70 @@ func PullDetails(pr *gitea.PullRequest, reviews []*gitea.PullReview) {
|
|||
pr.Body,
|
||||
)
|
||||
|
||||
if len(reviews) != 0 {
|
||||
out += "\n"
|
||||
revMap := make(map[string]gitea.ReviewStateType)
|
||||
for _, review := range reviews {
|
||||
switch review.State {
|
||||
case gitea.ReviewStateApproved,
|
||||
gitea.ReviewStateRequestChanges,
|
||||
gitea.ReviewStateRequestReview:
|
||||
revMap[review.Reviewer.UserName] = review.State
|
||||
if ciStatus != nil || len(reviews) != 0 || pr.State == gitea.StateOpen {
|
||||
out += "---\n"
|
||||
}
|
||||
|
||||
out += formatReviews(reviews)
|
||||
|
||||
if ciStatus != nil {
|
||||
var summary, errors string
|
||||
for _, s := range ciStatus.Statuses {
|
||||
summary += ciStatusSymbols[s.State]
|
||||
if s.State != gitea.StatusSuccess {
|
||||
errors += fmt.Sprintf(" - [**%s**:\t%s](%s)\n", s.Context, s.Description, s.TargetURL)
|
||||
}
|
||||
}
|
||||
for k, v := range revMap {
|
||||
out += fmt.Sprintf("\n @%s: %s", k, v)
|
||||
if len(ciStatus.Statuses) != 0 {
|
||||
out += fmt.Sprintf("- CI: %s\n%s", summary, errors)
|
||||
}
|
||||
}
|
||||
|
||||
if pr.State == gitea.StateOpen && pr.Mergeable {
|
||||
out += "\nNo Conflicts"
|
||||
if pr.State == gitea.StateOpen {
|
||||
if pr.Mergeable {
|
||||
out += "- No Conflicts\n"
|
||||
} else {
|
||||
out += "- **Conflicting files**\n"
|
||||
}
|
||||
}
|
||||
|
||||
outputMarkdown(out)
|
||||
}
|
||||
|
||||
func formatReviews(reviews []*gitea.PullReview) string {
|
||||
result := ""
|
||||
if len(reviews) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
// deduplicate reviews by user (via review time & userID),
|
||||
reviewByUser := make(map[int64]*gitea.PullReview)
|
||||
for _, review := range reviews {
|
||||
switch review.State {
|
||||
case gitea.ReviewStateApproved,
|
||||
gitea.ReviewStateRequestChanges,
|
||||
gitea.ReviewStateRequestReview:
|
||||
if r, ok := reviewByUser[review.Reviewer.ID]; !ok || review.Submitted.After(r.Submitted) {
|
||||
reviewByUser[review.Reviewer.ID] = review
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// group reviews by type
|
||||
usersByState := make(map[gitea.ReviewStateType][]string)
|
||||
for _, r := range reviewByUser {
|
||||
u := r.Reviewer.UserName
|
||||
users := usersByState[r.State]
|
||||
usersByState[r.State] = append(users, u)
|
||||
}
|
||||
|
||||
// stringify
|
||||
for state, user := range usersByState {
|
||||
result += fmt.Sprintf("- %s by @%s\n", state, strings.Join(user, ", @"))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// PullsList prints a listing of pulls
|
||||
func PullsList(prs []*gitea.PullRequest, output string) {
|
||||
t := tableWithHeader(
|
||||
|
|
|
@ -6,7 +6,6 @@ package task
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.gitea.io/tea/modules/config"
|
||||
|
@ -34,12 +33,12 @@ func CreateIssue(login *config.Login, repoOwner, repoName, title, description st
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("could not create issue: %s", err)
|
||||
return fmt.Errorf("could not create issue: %s", err)
|
||||
}
|
||||
|
||||
print.IssueDetails(issue)
|
||||
|
||||
fmt.Println(issue.HTMLURL)
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ package task
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
|
@ -16,7 +15,7 @@ import (
|
|||
func LabelsExport(labels []*gitea.Label, path string) error {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ package task
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
|
@ -21,7 +20,7 @@ func CreateLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bo
|
|||
// checks ...
|
||||
// ... if we have a url
|
||||
if len(giteaURL) == 0 {
|
||||
log.Fatal("You have to input Gitea server URL")
|
||||
return fmt.Errorf("You have to input Gitea server URL")
|
||||
}
|
||||
|
||||
// ... if there already exist a login with same name
|
||||
|
@ -35,17 +34,17 @@ func CreateLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bo
|
|||
|
||||
// .. if we have enough information to authenticate
|
||||
if len(token) == 0 && (len(user)+len(passwd)) == 0 {
|
||||
log.Fatal("No token set")
|
||||
return fmt.Errorf("No token set")
|
||||
} else if len(user) != 0 && len(passwd) == 0 {
|
||||
log.Fatal("No password set")
|
||||
return fmt.Errorf("No password set")
|
||||
} else if len(user) == 0 && len(passwd) != 0 {
|
||||
log.Fatal("No user set")
|
||||
return fmt.Errorf("No user set")
|
||||
}
|
||||
|
||||
// Normalize URL
|
||||
serverURL, err := utils.NormalizeURL(giteaURL)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to parse URL", err)
|
||||
return fmt.Errorf("Unable to parse URL: %s", err)
|
||||
}
|
||||
|
||||
login := config.Login{
|
||||
|
@ -60,23 +59,21 @@ func CreateLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bo
|
|||
client := login.Client()
|
||||
|
||||
if len(token) == 0 {
|
||||
login.Token, err = generateToken(client, user, passwd)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
if login.Token, err = generateToken(client, user, passwd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Verify if authentication works and get user info
|
||||
u, _, err := client.GetMyUserInfo()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
login.User = u.UserName
|
||||
|
||||
if len(login.Name) == 0 {
|
||||
login.Name, err = GenerateLoginName(giteaURL, login.User)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
if login.Name, err = GenerateLoginName(giteaURL, login.User); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,9 +88,8 @@ func CreateLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bo
|
|||
}
|
||||
}
|
||||
|
||||
err = config.AddLogin(&login)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
if err = config.AddLogin(&login); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Login as %s on %s successful. Added this login as %s\n", login.User, login.URL, login.Name)
|
||||
|
|
|
@ -27,6 +27,10 @@ func PullCheckout(login *config.Login, repoOwner, repoName string, index int64,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remoteDeleted := pr.Head.Ref == fmt.Sprintf("refs/pull/%d/head", pr.Index)
|
||||
if remoteDeleted {
|
||||
return fmt.Errorf("Can't checkout: remote head branch was already deleted")
|
||||
}
|
||||
|
||||
remoteURL := pr.Head.Repository.CloneURL
|
||||
if len(login.SSHKey) != 0 {
|
||||
|
|
|
@ -19,6 +19,9 @@ func PullClean(login *config.Login, repoOwner, repoName string, index int64, ign
|
|||
client := login.Client()
|
||||
|
||||
repo, _, err := client.GetRepo(repoOwner, repoName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defaultBranch := repo.DefaultBranch
|
||||
if len(defaultBranch) == 0 {
|
||||
defaultBranch = "master"
|
||||
|
@ -33,7 +36,13 @@ func PullClean(login *config.Login, repoOwner, repoName string, index int64, ign
|
|||
return fmt.Errorf("PR is still open, won't delete branches")
|
||||
}
|
||||
|
||||
// IDEA: abort if PR.Head.Repository.CloneURL does not match login.URL?
|
||||
// if remote head branch is already deleted, pr.Head.Ref points to "pulls/<idx>/head"
|
||||
remoteBranch := pr.Head.Ref
|
||||
remoteDeleted := remoteBranch == fmt.Sprintf("refs/pull/%d/head", pr.Index)
|
||||
if remoteDeleted {
|
||||
remoteBranch = pr.Head.Name // this still holds the original branch name
|
||||
fmt.Printf("Remote branch '%s' already deleted.\n", remoteBranch)
|
||||
}
|
||||
|
||||
r, err := local_git.RepoForWorkdir()
|
||||
if err != nil {
|
||||
|
@ -43,7 +52,7 @@ func PullClean(login *config.Login, repoOwner, repoName string, index int64, ign
|
|||
// find a branch with matching sha or name, that has a remote matching the repo url
|
||||
var branch *git_config.Branch
|
||||
if ignoreSHA {
|
||||
branch, err = r.TeaFindBranchByName(pr.Head.Ref, pr.Head.Repository.CloneURL)
|
||||
branch, err = r.TeaFindBranchByName(remoteBranch, pr.Head.Repository.CloneURL)
|
||||
} else {
|
||||
branch, err = r.TeaFindBranchBySha(pr.Head.Sha, pr.Head.Repository.CloneURL)
|
||||
}
|
||||
|
@ -52,12 +61,12 @@ func PullClean(login *config.Login, repoOwner, repoName string, index int64, ign
|
|||
}
|
||||
if branch == nil {
|
||||
if ignoreSHA {
|
||||
return fmt.Errorf("Remote branch %s not found in local repo", pr.Head.Ref)
|
||||
return fmt.Errorf("Remote branch %s not found in local repo", remoteBranch)
|
||||
}
|
||||
return fmt.Errorf(`Remote branch %s not found in local repo.
|
||||
Either you don't track this PR, or the local branch has diverged from the remote.
|
||||
If you still want to continue & are sure you don't loose any important commits,
|
||||
call me again with the --ignore-sha flag`, pr.Head.Ref)
|
||||
call me again with the --ignore-sha flag`, remoteBranch)
|
||||
}
|
||||
|
||||
// prepare deletion of local branch:
|
||||
|
@ -73,14 +82,23 @@ call me again with the --ignore-sha flag`, pr.Head.Ref)
|
|||
}
|
||||
|
||||
// remove local & remote branch
|
||||
fmt.Printf("Deleting local branch %s and remote branch %s\n", branch.Name, pr.Head.Ref)
|
||||
url, err := r.TeaRemoteURL(branch.Remote)
|
||||
fmt.Printf("Deleting local branch %s\n", branch.Name)
|
||||
err = r.TeaDeleteLocalBranch(branch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
auth, err := local_git.GetAuthForURL(url, login.Token, login.SSHKey, callback)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
if !remoteDeleted && pr.Head.Repository.Permissions.Push {
|
||||
fmt.Printf("Deleting remote branch %s\n", remoteBranch)
|
||||
url, err := r.TeaRemoteURL(branch.Remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
auth, err := local_git.GetAuthForURL(url, login.Token, login.SSHKey, callback)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = r.TeaDeleteRemoteBranch(branch.Remote, remoteBranch, auth)
|
||||
}
|
||||
return r.TeaDeleteBranch(branch, pr.Head.Ref, auth)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ package task
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
|
@ -24,14 +23,14 @@ func CreatePull(login *config.Login, repoOwner, repoName, base, head, title, des
|
|||
// open local git repo
|
||||
localRepo, err := local_git.RepoForWorkdir()
|
||||
if err != nil {
|
||||
log.Fatal("could not open local repo: ", err)
|
||||
return fmt.Errorf("Could not open local repo: %s", err)
|
||||
}
|
||||
|
||||
// push if possible
|
||||
log.Println("git push")
|
||||
fmt.Println("git push")
|
||||
err = localRepo.Push(&git.PushOptions{})
|
||||
if err != nil && err != git.NoErrAlreadyUpToDate {
|
||||
log.Printf("Error occurred during 'git push':\n%s\n", err.Error())
|
||||
fmt.Printf("Error occurred during 'git push':\n%s\n", err.Error())
|
||||
}
|
||||
|
||||
// default is default branch
|
||||
|
@ -74,10 +73,10 @@ func CreatePull(login *config.Login, repoOwner, repoName, base, head, title, des
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("could not create PR from %s to %s:%s: %s", head, repoOwner, base, err)
|
||||
return fmt.Errorf("Could not create PR from %s to %s:%s: %s", head, repoOwner, base, err)
|
||||
}
|
||||
|
||||
print.PullDetails(pr, nil)
|
||||
print.PullDetails(pr, nil, nil)
|
||||
|
||||
fmt.Println(pr.HTMLURL)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user
version 0.7.0 preview ... or so (should be changed on release)