1 Commits

Author SHA1 Message Date
8372dad929 Changelog v0.4.1 (#176)
Changelog v0.4.1

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/176
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: Gary Kim <gary@garykim.dev>
2020-09-13 21:48:36 +00:00
520 changed files with 1177 additions and 71780 deletions

View File

@ -13,7 +13,7 @@ workspace:
steps: steps:
- name: build - name: build
pull: always pull: always
image: golang:1.15 image: golang:1.13
environment: environment:
GOPROXY: https://goproxy.cn GOPROXY: https://goproxy.cn
commands: commands:
@ -32,7 +32,7 @@ steps:
- name: unit-test - name: unit-test
pull: always pull: always
image: golang:1.15 image: golang:1.13
commands: commands:
- make unit-test-coverage - make unit-test-coverage
settings: settings:
@ -46,7 +46,7 @@ steps:
- name: release-test - name: release-test
pull: always pull: always
image: golang:1.15 image: golang:1.13
commands: commands:
- make test - make test
settings: settings:
@ -60,7 +60,7 @@ steps:
- name: tag-test - name: tag-test
pull: always pull: always
image: golang:1.15 image: golang:1.13
commands: commands:
- make test - make test
settings: settings:

View File

@ -1,28 +1,5 @@
# Changelog # Changelog
## [v0.5.0](https://gitea.com/gitea/tea/releases/tag/v0.5.0) - 2020-09-27
* BREAKING
* Add Login Manage Functions (#182)
* FEATURES
* Add Release Subcomands (#195)
* Render Markdown and colorize labels table (#181)
* Add BasicAuth & Interactive for Login (#174)
* Add milestones subcomands (#149)
* BUGFIXES
* Fix Pulls Create (#202)
* Pulls create: detect head branch repo owner (#193)
* Fix Labels Delete (#180)
* ENHANCEMENTS
* Add Pagination Options for List Subcomands (#204)
* Issues/Pulls: Details show State (#196)
* Make issues & pulls subcommands consistent (#188)
* Update SDK to v0.13.0 (#179)
* More Options To Specify Repo (#178)
* Add Repo Create subcomand & enhancements (#173)
* Times: format duration as seconds for machine-readable outputs (#168)
* Add user message to login list view (#166)
## [v0.4.1](https://gitea.com/gitea/tea/releases/tag/v0.4.1) - 2020-09-13 ## [v0.4.1](https://gitea.com/gitea/tea/releases/tag/v0.4.1) - 2020-09-13
* BUGFIXES * BUGFIXES

View File

@ -71,7 +71,7 @@ vet:
# Default vet # Default vet
$(GO) vet -mod=vendor $(PACKAGES) $(GO) vet -mod=vendor $(PACKAGES)
# Custom vet # Custom vet
$(GO) build -mod=vendor code.gitea.io/gitea-vet $(GO) build -mod=vendor gitea.com/jolheiser/gitea-vet
$(GO) vet -vettool=gitea-vet $(PACKAGES) $(GO) vet -vettool=gitea-vet $(PACKAGES)
.PHONY: lint .PHONY: lint

View File

@ -14,7 +14,7 @@ It uses [code.gitea.io/sdk](https://code.gitea.io/sdk) and interacts with the Gi
You can use the prebuilt binaries from [dl.gitea.io](https://dl.gitea.io/tea/) You can use the prebuilt binaries from [dl.gitea.io](https://dl.gitea.io/tea/)
To install from source, go 1.13 or newer is required: To install from source, go 1.12 or newer is required:
```sh ```sh
go get code.gitea.io/tea go get code.gitea.io/tea
go install code.gitea.io/tea go install code.gitea.io/tea
@ -46,14 +46,12 @@ Detailed usage information is available via `tea <command> --help`.
login Log in to a Gitea server login Log in to a Gitea server
logout Log out from a Gitea server logout Log out from a Gitea server
issues List, create and update issues issues List, create and update issues
pulls List, create, checkout and clean pull requests pulls List, checkout and clean pull requests
releases List, create, update and delete releases releases Create releases
repos Operate with repositories repos Operate with repositories
labels Manage issue labels labels Manage issue labels
times Operate on tracked times of a repositorys issues and pulls times Operate on tracked times of a repositorys issues and pulls
open Open something of the repository on web browser open Open something of the repository on web browser
notifications Show notifications
milestones List and create milestones
``` ```
To fetch issues from different repos, use the `--remote` flag (when inside a gitea repository directory) or `--login` & `--repo` flags. To fetch issues from different repos, use the `--remote` flag (when inside a gitea repository directory) or `--login` & `--repo` flags.

View File

@ -10,5 +10,5 @@ package main
import ( import (
// for vet // for vet
_ "code.gitea.io/gitea-vet" _ "gitea.com/jolheiser/gitea-vet"
) )

View File

@ -21,8 +21,6 @@ import (
"code.gitea.io/tea/modules/git" "code.gitea.io/tea/modules/git"
"code.gitea.io/tea/modules/utils" "code.gitea.io/tea/modules/utils"
"github.com/muesli/termenv"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
@ -31,7 +29,7 @@ type Login struct {
Name string `yaml:"name"` Name string `yaml:"name"`
URL string `yaml:"url"` URL string `yaml:"url"`
Token string `yaml:"token"` Token string `yaml:"token"`
Default bool `yaml:"default"` Active bool `yaml:"active"`
SSHHost string `yaml:"ssh_host"` SSHHost string `yaml:"ssh_host"`
// optional path to the private key // optional path to the private key
SSHKey string `yaml:"ssh_key"` SSHKey string `yaml:"ssh_key"`
@ -42,23 +40,16 @@ type Login struct {
// Client returns a client to operate Gitea API // Client returns a client to operate Gitea API
func (l *Login) Client() *gitea.Client { func (l *Login) Client() *gitea.Client {
httpClient := &http.Client{} client := gitea.NewClient(l.URL, l.Token)
if l.Insecure { if l.Insecure {
cookieJar, _ := cookiejar.New(nil) cookieJar, _ := cookiejar.New(nil)
httpClient = &http.Client{ client.SetHTTPClient(&http.Client{
Jar: cookieJar, Jar: cookieJar,
Transport: &http.Transport{ Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}} },
} })
client, err := gitea.NewClient(l.URL,
gitea.SetToken(l.Token),
gitea.SetHTTPClient(httpClient),
)
if err != nil {
log.Fatal(err)
} }
return client return client
} }
@ -102,30 +93,20 @@ func init() {
yamlConfigPath = filepath.Join(dir, "tea.yml") yamlConfigPath = filepath.Join(dir, "tea.yml")
} }
func getGlamourTheme() string { func splitRepo(repoPath string) (string, string) {
if termenv.HasDarkBackground() {
return "dark"
}
return "light"
}
func getOwnerAndRepo(repoPath, user string) (string, string) {
if len(repoPath) == 0 {
return "", ""
}
p := strings.Split(repoPath, "/") p := strings.Split(repoPath, "/")
if len(p) >= 2 { if len(p) >= 2 {
return p[0], p[1] return p[0], p[1]
} }
return user, repoPath return repoPath, ""
} }
func getDefaultLogin() (*Login, error) { func getActiveLogin() (*Login, error) {
if len(config.Logins) == 0 { if len(config.Logins) == 0 {
return nil, errors.New("No available login") return nil, errors.New("No available login")
} }
for _, l := range config.Logins { for _, l := range config.Logins {
if l.Default { if l.Active {
return &l, nil return &l, nil
} }
} }
@ -272,15 +253,3 @@ func curGitRepoPath(path string) (*Login, string, error) {
return nil, "", errors.New("No Gitea login found. You might want to specify --repo (and --login) to work outside of a repository") return nil, "", errors.New("No Gitea login found. You might want to specify --repo (and --login) to work outside of a repository")
} }
func getListOptions(ctx *cli.Context) gitea.ListOptions {
page := ctx.Int("page")
limit := ctx.Int("limit")
if limit != 0 && page == 0 {
page = 1
}
return gitea.ListOptions{
Page: page,
PageSize: limit,
}
}

View File

@ -7,8 +7,6 @@ package cmd
import ( import (
"log" "log"
"code.gitea.io/tea/modules/utils"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -53,27 +51,6 @@ var OutputFlag = cli.StringFlag{
Destination: &outputValue, Destination: &outputValue,
} }
// StateFlag provides flag to specify issue/pr state, defaulting to "open"
var StateFlag = cli.StringFlag{
Name: "state",
Usage: "Filter by state (all|open|closed)",
DefaultText: "open",
}
// PaginationPageFlag provides flag for pagination options
var PaginationPageFlag = cli.StringFlag{
Name: "page",
Aliases: []string{"p"},
Usage: "specify page, default is 1",
}
// PaginationLimitFlag provides flag for pagination options
var PaginationLimitFlag = cli.StringFlag{
Name: "limit",
Aliases: []string{"lm"},
Usage: "specify limit of items per page",
}
// LoginOutputFlags defines login and output flags that should // LoginOutputFlags defines login and output flags that should
// added to all subcommands and appended to the flags of the // added to all subcommands and appended to the flags of the
// subcommand to work around issue and provide --login and --output: // subcommand to work around issue and provide --login and --output:
@ -102,38 +79,18 @@ var AllDefaultFlags = append([]cli.Flag{
&RemoteFlag, &RemoteFlag,
}, LoginOutputFlags...) }, LoginOutputFlags...)
// IssuePRFlags defines flags that should be available on issue & pr listing flags.
var IssuePRFlags = append([]cli.Flag{
&StateFlag,
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...)
// initCommand returns repository and *Login based on flags // initCommand returns repository and *Login based on flags
func initCommand() (*Login, string, string) { func initCommand() (*Login, string, string) {
var login *Login
err := loadConfig(yamlConfigPath) err := loadConfig(yamlConfigPath)
if err != nil { if err != nil {
log.Fatal("load config file failed ", yamlConfigPath) log.Fatal("load config file failed ", yamlConfigPath)
} }
if login, err = getDefaultLogin(); err != nil { login, repoPath, err := curGitRepoPath(repoValue)
log.Fatal(err.Error())
}
exist, err := utils.PathExists(repoValue)
if err != nil { if err != nil {
log.Fatal(err.Error()) log.Fatal(err.Error())
} }
if exist || len(repoValue) == 0 {
login, repoValue, err = curGitRepoPath(repoValue)
if err != nil {
log.Fatal(err.Error())
}
}
if loginValue != "" { if loginValue != "" {
login = getLoginByName(loginValue) login = getLoginByName(loginValue)
if login == nil { if login == nil {
@ -141,7 +98,7 @@ func initCommand() (*Login, string, string) {
} }
} }
owner, repo := getOwnerAndRepo(repoValue, login.User) owner, repo := splitRepo(repoPath)
return login, owner, repo return login, owner, repo
} }
@ -154,7 +111,7 @@ func initCommandLoginOnly() *Login {
var login *Login var login *Login
if loginValue == "" { if loginValue == "" {
login, err = getDefaultLogin() login, err = getActiveLogin()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -10,15 +10,15 @@ import (
"strconv" "strconv"
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/charmbracelet/glamour"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
// CmdIssues represents to login a gitea server. // CmdIssues represents to login a gitea server.
var CmdIssues = cli.Command{ var CmdIssues = cli.Command{
Name: "issues", Name: "issues",
Usage: "List, create and update issues", Usage: "List and create issues",
Description: "List, create and update issues", Description: `List and create issues`,
ArgsUsage: "[<issue index>]", ArgsUsage: "[<issue index>]",
Action: runIssues, Action: runIssues,
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
@ -27,7 +27,7 @@ var CmdIssues = cli.Command{
&CmdIssuesReopen, &CmdIssuesReopen,
&CmdIssuesClose, &CmdIssuesClose,
}, },
Flags: IssuePRFlags, Flags: AllDefaultFlags,
} }
// CmdIssuesList represents a sub command of issues to list issues // CmdIssuesList represents a sub command of issues to list issues
@ -36,7 +36,13 @@ var CmdIssuesList = cli.Command{
Usage: "List issues of the repository", Usage: "List issues of the repository",
Description: `List issues of the repository`, Description: `List issues of the repository`,
Action: runIssuesList, Action: runIssuesList,
Flags: IssuePRFlags, Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "state",
Usage: "Filter by issue state (all|open|closed)",
DefaultText: "open",
},
}, AllDefaultFlags...),
} }
func runIssues(ctx *cli.Context) error { func runIssues(ctx *cli.Context) error {
@ -53,20 +59,17 @@ func runIssueDetail(ctx *cli.Context, index string) error {
if err != nil { if err != nil {
return err return err
} }
issue, _, err := login.Client().GetIssue(owner, repo, idx) issue, err := login.Client().GetIssue(owner, repo, idx)
if err != nil { if err != nil {
return err return err
} }
in := fmt.Sprintf("# #%d %s (%s)\n%s created %s\n\n%s\n", issue.Index, fmt.Printf("#%d %s\n%s created %s\n\n%s\n", issue.Index,
issue.Title, issue.Title,
issue.State,
issue.Poster.UserName, issue.Poster.UserName,
issue.Created.Format("2006-01-02 15:04:05"), issue.Created.Format("2006-01-02 15:04:05"),
issue.Body, issue.Body,
) )
out, err := glamour.Render(in, getGlamourTheme())
fmt.Print(out)
return nil return nil
} }
@ -83,8 +86,7 @@ func runIssuesList(ctx *cli.Context) error {
state = gitea.StateClosed state = gitea.StateClosed
} }
issues, _, err := login.Client().ListRepoIssues(owner, repo, gitea.ListIssueOption{ issues, err := login.Client().ListRepoIssues(owner, repo, gitea.ListIssueOption{
ListOptions: getListOptions(ctx),
State: state, State: state,
Type: gitea.IssueTypeIssue, Type: gitea.IssueTypeIssue,
}) })
@ -95,11 +97,10 @@ func runIssuesList(ctx *cli.Context) error {
headers := []string{ headers := []string{
"Index", "Index",
"Title",
"State", "State",
"Author", "Author",
"Milestone",
"Updated", "Updated",
"Title",
} }
var values [][]string var values [][]string
@ -110,23 +111,18 @@ func runIssuesList(ctx *cli.Context) error {
} }
for _, issue := range issues { for _, issue := range issues {
author := issue.Poster.FullName name := issue.Poster.FullName
if len(author) == 0 { if len(name) == 0 {
author = issue.Poster.UserName name = issue.Poster.UserName
}
mile := ""
if issue.Milestone != nil {
mile = issue.Milestone.Title
} }
values = append( values = append(
values, values,
[]string{ []string{
strconv.FormatInt(issue.Index, 10), strconv.FormatInt(issue.Index, 10),
issue.Title,
string(issue.State), string(issue.State),
author, name,
mile,
issue.Updated.Format("2006-01-02 15:04:05"), issue.Updated.Format("2006-01-02 15:04:05"),
issue.Title,
}, },
) )
} }
@ -158,7 +154,7 @@ var CmdIssuesCreate = cli.Command{
func runIssuesCreate(ctx *cli.Context) error { func runIssuesCreate(ctx *cli.Context) error {
login, owner, repo := initCommand() login, owner, repo := initCommand()
_, _, err := login.Client().CreateIssue(owner, repo, gitea.CreateIssueOption{ _, err := login.Client().CreateIssue(owner, repo, gitea.CreateIssueOption{
Title: ctx.String("title"), Title: ctx.String("title"),
Body: ctx.String("body"), Body: ctx.String("body"),
// TODO: // TODO:
@ -216,6 +212,6 @@ func editIssueState(ctx *cli.Context, opts gitea.EditIssueOption) error {
return err return err
} }
_, _, err = login.Client().EditIssue(owner, repo, index, opts) _, err = login.Client().EditIssue(owner, repo, index, opts)
return err return err
} }

View File

@ -14,7 +14,6 @@ import (
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/muesli/termenv"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -35,8 +34,6 @@ var CmdLabels = cli.Command{
Aliases: []string{"s"}, Aliases: []string{"s"},
Usage: "Save all the labels as a file", Usage: "Save all the labels as a file",
}, },
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...), }, AllDefaultFlags...),
} }
@ -52,7 +49,7 @@ func runLabels(ctx *cli.Context) error {
var values [][]string var values [][]string
labels, _, err := login.Client().ListRepoLabels(owner, repo, gitea.ListLabelsOptions{ListOptions: getListOptions(ctx)}) labels, err := login.Client().ListRepoLabels(owner, repo, gitea.ListLabelsOptions{})
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -62,8 +59,6 @@ func runLabels(ctx *cli.Context) error {
return nil return nil
} }
p := termenv.ColorProfile()
fPath := ctx.String("save") fPath := ctx.String("save")
if len(fPath) > 0 { if len(fPath) > 0 {
f, err := os.Create(fPath) f, err := os.Create(fPath)
@ -77,13 +72,11 @@ func runLabels(ctx *cli.Context) error {
} }
} else { } else {
for _, label := range labels { for _, label := range labels {
color := termenv.String(label.Color)
values = append( values = append(
values, values,
[]string{ []string{
strconv.FormatInt(label.ID, 10), strconv.FormatInt(label.ID, 10),
fmt.Sprint(color.Background(p.Color("#" + label.Color))), label.Color,
label.Name, label.Name,
label.Description, label.Description,
}, },
@ -148,7 +141,7 @@ func runLabelCreate(ctx *cli.Context) error {
labelFile := ctx.String("file") labelFile := ctx.String("file")
var err error var err error
if len(labelFile) == 0 { if len(labelFile) == 0 {
_, _, err = login.Client().CreateLabel(owner, repo, gitea.CreateLabelOption{ _, err = login.Client().CreateLabel(owner, repo, gitea.CreateLabelOption{
Name: ctx.String("name"), Name: ctx.String("name"),
Color: ctx.String("color"), Color: ctx.String("color"),
Description: ctx.String("description"), Description: ctx.String("description"),
@ -169,7 +162,7 @@ func runLabelCreate(ctx *cli.Context) error {
if color == "" || name == "" { if color == "" || name == "" {
log.Printf("Line %d ignored because lack of enough fields: %s\n", i, line) log.Printf("Line %d ignored because lack of enough fields: %s\n", i, line)
} else { } else {
_, _, err = login.Client().CreateLabel(owner, repo, gitea.CreateLabelOption{ _, err = login.Client().CreateLabel(owner, repo, gitea.CreateLabelOption{
Name: name, Name: name,
Color: color, Color: color,
Description: description, Description: description,
@ -234,7 +227,7 @@ func runLabelUpdate(ctx *cli.Context) error {
} }
var err error var err error
_, _, err = login.Client().EditLabel(owner, repo, id, gitea.EditLabelOption{ _, err = login.Client().EditLabel(owner, repo, id, gitea.EditLabelOption{
Name: pName, Name: pName,
Color: pColor, Color: pColor,
Description: pDescription, Description: pDescription,
@ -252,7 +245,7 @@ var CmdLabelDelete = cli.Command{
Name: "delete", Name: "delete",
Usage: "Delete a label", Usage: "Delete a label",
Description: `Delete a label`, Description: `Delete a label`,
Action: runLabelDelete, Action: runLabelCreate,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.IntFlag{ &cli.IntFlag{
Name: "id", Name: "id",
@ -264,7 +257,7 @@ var CmdLabelDelete = cli.Command{
func runLabelDelete(ctx *cli.Context) error { func runLabelDelete(ctx *cli.Context) error {
login, owner, repo := initCommand() login, owner, repo := initCommand()
_, err := login.Client().DeleteLabel(owner, repo, ctx.Int64("id")) err := login.Client().DeleteLabel(owner, repo, ctx.Int64("id"))
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -10,14 +10,9 @@ import (
"log" "log"
"net/http" "net/http"
"net/http/cookiejar" "net/http/cookiejar"
"net/url"
"os"
"strings"
"time"
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/skratchdot/open-golang/open"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -26,66 +21,13 @@ var CmdLogin = cli.Command{
Name: "login", Name: "login",
Usage: "Log in to a Gitea server", Usage: "Log in to a Gitea server",
Description: `Log in to a Gitea server`, Description: `Log in to a Gitea server`,
Action: runLoginAddInteractive, Action: runLoginList,
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
&cmdLoginList, &cmdLoginList,
&cmdLoginAdd, &cmdLoginAdd,
&cmdLoginEdit,
&cmdLoginSetDefault,
}, },
} }
// cmdLoginEdit represents to login a gitea server.
var cmdLoginEdit = cli.Command{
Name: "edit",
Usage: "Edit Gitea logins",
Description: `Edit Gitea logins`,
Action: runLoginEdit,
Flags: []cli.Flag{&OutputFlag},
}
func runLoginEdit(ctx *cli.Context) error {
return open.Start(yamlConfigPath)
}
// cmdLoginSetDefault represents to login a gitea server.
var cmdLoginSetDefault = cli.Command{
Name: "default",
Usage: "Get or Set Default Login",
Description: `Get or Set Default Login`,
ArgsUsage: "<Login>",
Action: runLoginSetDefault,
Flags: []cli.Flag{&OutputFlag},
}
func runLoginSetDefault(ctx *cli.Context) error {
if err := loadConfig(yamlConfigPath); err != nil {
return err
}
if ctx.Args().Len() == 0 {
l, err := getDefaultLogin()
if err != nil {
return err
}
fmt.Printf("Default Login: %s\n", l.Name)
return nil
}
loginExist := false
for i := range config.Logins {
config.Logins[i].Default = false
if config.Logins[i].Name == ctx.Args().First() {
config.Logins[i].Default = true
loginExist = true
}
}
if !loginExist {
return fmt.Errorf("login '%s' not found", ctx.Args().First())
}
return saveConfig(yamlConfigPath)
}
// CmdLogin represents to login a gitea server. // CmdLogin represents to login a gitea server.
var cmdLoginAdd = cli.Command{ var cmdLoginAdd = cli.Command{
Name: "add", Name: "add",
@ -96,6 +38,7 @@ var cmdLoginAdd = cli.Command{
Name: "name", Name: "name",
Aliases: []string{"n"}, Aliases: []string{"n"},
Usage: "Login name", Usage: "Login name",
Required: true,
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "url", Name: "url",
@ -111,19 +54,7 @@ var cmdLoginAdd = cli.Command{
Value: "", Value: "",
EnvVars: []string{"GITEA_SERVER_TOKEN"}, EnvVars: []string{"GITEA_SERVER_TOKEN"},
Usage: "Access token. Can be obtained from Settings > Applications", Usage: "Access token. Can be obtained from Settings > Applications",
}, Required: true,
&cli.StringFlag{
Name: "user",
Value: "",
EnvVars: []string{"GITEA_SERVER_USER"},
Usage: "User for basic auth (will create token)",
},
&cli.StringFlag{
Name: "password",
Aliases: []string{"pwd"},
Value: "",
EnvVars: []string{"GITEA_SERVER_PASSWORD"},
Usage: "Password for basic auth (will create token)",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "ssh-key", Name: "ssh-key",
@ -140,100 +71,14 @@ var cmdLoginAdd = cli.Command{
} }
func runLoginAdd(ctx *cli.Context) error { func runLoginAdd(ctx *cli.Context) error {
return runLoginAddMain( if !ctx.IsSet("url") {
ctx.String("name"),
ctx.String("token"),
ctx.String("user"),
ctx.String("password"),
ctx.String("ssh-key"),
ctx.String("url"),
ctx.Bool("insecure"))
}
func runLoginAddInteractive(ctx *cli.Context) error {
var stdin, name, token, user, passwd, sshKey, giteaURL string
var insecure = false
fmt.Print("URL of Gitea instance: ")
if _, err := fmt.Scanln(&stdin); err != nil {
stdin = ""
}
giteaURL = strings.TrimSpace(stdin)
if len(giteaURL) == 0 {
fmt.Println("URL is required!")
return nil
}
parsedURL, err := url.Parse(giteaURL)
if err != nil {
return err
}
name = strings.ReplaceAll(strings.Title(parsedURL.Host), ".", "")
fmt.Print("Name of new Login [" + name + "]: ")
if _, err := fmt.Scanln(&stdin); err != nil {
stdin = ""
}
if len(strings.TrimSpace(stdin)) != 0 {
name = strings.TrimSpace(stdin)
}
fmt.Print("Do you have a token [Yes/no]: ")
if _, err := fmt.Scanln(&stdin); err != nil {
stdin = ""
}
if len(stdin) != 0 && strings.ToLower(stdin[:1]) == "n" {
fmt.Print("Username: ")
if _, err := fmt.Scanln(&stdin); err != nil {
stdin = ""
}
user = strings.TrimSpace(stdin)
fmt.Print("Password: ")
if _, err := fmt.Scanln(&stdin); err != nil {
stdin = ""
}
passwd = strings.TrimSpace(stdin)
} else {
fmt.Print("Token: ")
if _, err := fmt.Scanln(&stdin); err != nil {
stdin = ""
}
token = strings.TrimSpace(stdin)
}
fmt.Print("Set Optional settings [yes/No]: ")
if _, err := fmt.Scanln(&stdin); err != nil {
stdin = ""
}
if len(stdin) != 0 && strings.ToLower(stdin[:1]) == "y" {
fmt.Print("SSH Key Path: ")
if _, err := fmt.Scanln(&stdin); err != nil {
stdin = ""
}
sshKey = strings.TrimSpace(stdin)
fmt.Print("Allow Insecure connections [yes/No]: ")
if _, err := fmt.Scanln(&stdin); err != nil {
stdin = ""
}
insecure = len(stdin) != 0 && strings.ToLower(stdin[:1]) == "y"
}
return runLoginAddMain(name, token, user, passwd, sshKey, giteaURL, insecure)
}
func runLoginAddMain(name, token, user, passwd, sshKey, giteaURL string, insecure bool) error {
if len(giteaURL) == 0 {
log.Fatal("You have to input Gitea server URL") log.Fatal("You have to input Gitea server URL")
} }
if len(token) == 0 && (len(user)+len(passwd)) == 0 { if !ctx.IsSet("token") {
log.Fatal("No token set") log.Fatal("No token found")
} else if len(user) != 0 && len(passwd) == 0 { }
log.Fatal("No password set") if !ctx.IsSet("name") {
} else if len(user) == 0 && len(passwd) != 0 { log.Fatal("You have to set a name for the login")
log.Fatal("No user set")
} }
err := loadConfig(yamlConfigPath) err := loadConfig(yamlConfigPath)
@ -241,72 +86,30 @@ func runLoginAddMain(name, token, user, passwd, sshKey, giteaURL string, insecur
log.Fatal("Unable to load config file " + yamlConfigPath) log.Fatal("Unable to load config file " + yamlConfigPath)
} }
httpClient := &http.Client{} client := gitea.NewClient(ctx.String("url"), ctx.String("token"))
if insecure { if ctx.Bool("insecure") {
cookieJar, _ := cookiejar.New(nil) cookieJar, _ := cookiejar.New(nil)
httpClient = &http.Client{
client.SetHTTPClient(&http.Client{
Jar: cookieJar, Jar: cookieJar,
Transport: &http.Transport{ Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}} },
})
} }
client, err := gitea.NewClient(giteaURL, u, err := client.GetMyUserInfo()
gitea.SetToken(token),
gitea.SetBasicAuth(user, passwd),
gitea.SetHTTPClient(httpClient),
)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
u, _, err := client.GetMyUserInfo()
if err != nil {
log.Fatal(err)
}
if len(token) == 0 {
// create token
host, _ := os.Hostname()
tl, _, err := client.ListAccessTokens(gitea.ListAccessTokensOptions{})
if err != nil {
return err
}
tokenName := host + "-tea"
for i := range tl {
if tl[i].Name == tokenName {
tokenName += time.Now().Format("2006-01-02_15-04-05")
break
}
}
t, _, err := client.CreateAccessToken(gitea.CreateAccessTokenOption{Name: tokenName})
if err != nil {
return err
}
token = t.Token
}
fmt.Println("Login successful! Login name " + u.UserName) fmt.Println("Login successful! Login name " + u.UserName)
if len(name) == 0 {
parsedURL, err := url.Parse(giteaURL)
if err != nil {
return err
}
name = strings.ReplaceAll(strings.Title(parsedURL.Host), ".", "")
for _, l := range config.Logins {
if l.Name == name {
name += "_" + u.UserName
break
}
}
}
err = addLogin(Login{ err = addLogin(Login{
Name: name, Name: ctx.String("name"),
URL: giteaURL, URL: ctx.String("url"),
Token: token, Token: ctx.String("token"),
Insecure: insecure, Insecure: ctx.Bool("insecure"),
SSHKey: sshKey, SSHKey: ctx.String("ssh-key"),
User: u.UserName, User: u.UserName,
}) })
if err != nil { if err != nil {
@ -340,8 +143,6 @@ func runLoginList(ctx *cli.Context) error {
"Name", "Name",
"URL", "URL",
"SSHHost", "SSHHost",
"User",
"Default",
} }
var values [][]string var values [][]string
@ -351,8 +152,6 @@ func runLoginList(ctx *cli.Context) error {
l.Name, l.Name,
l.URL, l.URL,
l.GetSSHHost(), l.GetSSHHost(),
l.User,
fmt.Sprint(l.Default),
}) })
} }

View File

@ -1,202 +0,0 @@
// 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"
"strconv"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2"
)
// CmdMilestonesIssues represents a sub command of milestones to manage issue/pull of an milestone
var CmdMilestonesIssues = cli.Command{
Name: "issues",
Aliases: []string{"i"},
Usage: "manage issue/pull of an milestone",
Description: "manage issue/pull of an milestone",
ArgsUsage: "<milestone name>",
Action: runMilestoneIssueList,
Subcommands: []*cli.Command{
&CmdMilestoneAddIssue,
&CmdMilestoneRemoveIssue,
},
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "state",
Usage: "Filter by issue state (all|open|closed)",
DefaultText: "open",
},
&cli.StringFlag{
Name: "kind",
Usage: "Filter by kind (issue|pull)",
},
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...),
}
// CmdMilestoneAddIssue represents a sub command of milestone issues to add an issue/pull to an milestone
var CmdMilestoneAddIssue = cli.Command{
Name: "add",
Aliases: []string{"a"},
Usage: "Add an issue/pull to an milestone",
Description: "Add an issue/pull to an milestone",
ArgsUsage: "<milestone name> <issue/pull index>",
Action: runMilestoneIssueAdd,
Flags: AllDefaultFlags,
}
// CmdMilestoneRemoveIssue represents a sub command of milestones to remove an issue/pull from an milestone
var CmdMilestoneRemoveIssue = cli.Command{
Name: "remove",
Aliases: []string{"r"},
Usage: "Remove an issue/pull to an milestone",
Description: "Remove an issue/pull to an milestone",
ArgsUsage: "<milestone name> <issue/pull index>",
Action: runMilestoneIssueRemove,
Flags: AllDefaultFlags,
}
func runMilestoneIssueList(ctx *cli.Context) error {
login, owner, repo := initCommand()
client := login.Client()
state := gitea.StateOpen
switch ctx.String("state") {
case "all":
state = gitea.StateAll
case "closed":
state = gitea.StateClosed
}
kind := gitea.IssueTypeAll
switch ctx.String("kind") {
case "issue":
kind = gitea.IssueTypeIssue
case "pull":
kind = gitea.IssueTypePull
}
fmt.Println(state)
milestone := ctx.Args().First()
// make sure milestone exist
_, _, err := client.GetMilestoneByName(owner, repo, milestone)
if err != nil {
return err
}
issues, _, err := client.ListRepoIssues(owner, repo, gitea.ListIssueOption{
ListOptions: getListOptions(ctx),
Milestones: []string{milestone},
Type: kind,
State: state,
})
if err != nil {
return err
}
headers := []string{
"Index",
"State",
"Kind",
"Author",
"Updated",
"Title",
}
var values [][]string
if len(issues) == 0 {
Output(outputValue, headers, values)
return nil
}
for _, issue := range issues {
name := issue.Poster.FullName
if len(name) == 0 {
name = issue.Poster.UserName
}
kind := "Issue"
if issue.PullRequest != nil {
kind = "Pull"
}
values = append(
values,
[]string{
strconv.FormatInt(issue.Index, 10),
string(issue.State),
kind,
name,
issue.Updated.Format("2006-01-02 15:04:05"),
issue.Title,
},
)
}
Output(outputValue, headers, values)
return nil
}
func runMilestoneIssueAdd(ctx *cli.Context) error {
login, owner, repo := initCommand()
client := login.Client()
if ctx.Args().Len() == 0 {
return fmt.Errorf("need two arguments")
}
mileName := ctx.Args().Get(0)
issueIndex := ctx.Args().Get(1)
idx, err := argToIndex(issueIndex)
if err != nil {
return err
}
// make sure milestone exist
mile, _, err := client.GetMilestoneByName(owner, repo, mileName)
if err != nil {
return err
}
_, _, err = client.EditIssue(owner, repo, idx, gitea.EditIssueOption{
Milestone: &mile.ID,
})
return err
}
func runMilestoneIssueRemove(ctx *cli.Context) error {
login, owner, repo := initCommand()
client := login.Client()
if ctx.Args().Len() == 0 {
return fmt.Errorf("need two arguments")
}
mileName := ctx.Args().Get(0)
issueIndex := ctx.Args().Get(1)
idx, err := argToIndex(issueIndex)
if err != nil {
return err
}
issue, _, err := client.GetIssue(owner, repo, idx)
if err != nil {
return err
}
if issue.Milestone == nil {
return fmt.Errorf("issue is not assigned to a milestone")
}
if issue.Milestone.Title != mileName {
return fmt.Errorf("issue is not assigned to this milestone")
}
zero := int64(0)
_, _, err = client.EditIssue(owner, repo, idx, gitea.EditIssueOption{
Milestone: &zero,
})
return err
}

View File

@ -1,255 +0,0 @@
// 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"
"log"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2"
)
// CmdMilestones represents to operate repositories milestones.
var CmdMilestones = cli.Command{
Name: "milestones",
Aliases: []string{"ms", "mile"},
Usage: "List and create milestones",
Description: `List and create milestones`,
ArgsUsage: "[<milestone name>]",
Action: runMilestones,
Subcommands: []*cli.Command{
&CmdMilestonesList,
&CmdMilestonesCreate,
&CmdMilestonesClose,
&CmdMilestonesDelete,
&CmdMilestonesReopen,
&CmdMilestonesIssues,
},
Flags: AllDefaultFlags,
}
// CmdMilestonesList represents a sub command of milestones to list milestones
var CmdMilestonesList = cli.Command{
Name: "ls",
Usage: "List milestones of the repository",
Description: `List milestones of the repository`,
Action: runMilestonesList,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "state",
Usage: "Filter by milestone state (all|open|closed)",
DefaultText: "open",
},
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...),
}
func runMilestones(ctx *cli.Context) error {
if ctx.Args().Len() == 1 {
return runMilestoneDetail(ctx, ctx.Args().First())
}
return runMilestonesList(ctx)
}
func runMilestoneDetail(ctx *cli.Context, name string) error {
login, owner, repo := initCommand()
client := login.Client()
milestone, _, err := client.GetMilestoneByName(owner, repo, name)
if err != nil {
return err
}
fmt.Printf("%s\n",
milestone.Title,
)
if len(milestone.Description) != 0 {
fmt.Printf("\n%s\n", milestone.Description)
}
if milestone.Deadline != nil && !milestone.Deadline.IsZero() {
fmt.Printf("\nDeadline: %s\n", milestone.Deadline.Format("2006-01-02 15:04:05"))
}
return nil
}
func runMilestonesList(ctx *cli.Context) error {
login, owner, repo := initCommand()
state := gitea.StateOpen
switch ctx.String("state") {
case "all":
state = gitea.StateAll
case "closed":
state = gitea.StateClosed
}
milestones, _, err := login.Client().ListRepoMilestones(owner, repo, gitea.ListMilestoneOption{
ListOptions: getListOptions(ctx),
State: state,
})
if err != nil {
log.Fatal(err)
}
headers := []string{
"Title",
}
if state == gitea.StateAll {
headers = append(headers, "State")
}
headers = append(headers,
"Open/Closed Issues",
"DueDate",
)
var values [][]string
for _, m := range milestones {
var deadline = ""
if m.Deadline != nil && !m.Deadline.IsZero() {
deadline = m.Deadline.Format("2006-01-02 15:04:05")
}
item := []string{
m.Title,
}
if state == gitea.StateAll {
item = append(item, string(m.State))
}
item = append(item,
fmt.Sprintf("%d/%d", m.OpenIssues, m.ClosedIssues),
deadline,
)
values = append(values, item)
}
Output(outputValue, headers, values)
return nil
}
// CmdMilestonesCreate represents a sub command of milestones to create milestone
var CmdMilestonesCreate = cli.Command{
Name: "create",
Usage: "Create an milestone on repository",
Description: `Create an milestone on repository`,
Action: runMilestonesCreate,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "title",
Aliases: []string{"t"},
Usage: "milestone title to create",
},
&cli.StringFlag{
Name: "description",
Aliases: []string{"d"},
Usage: "milestone description to create",
},
&cli.StringFlag{
Name: "state",
Usage: "set milestone state (default is open)",
DefaultText: "open",
},
}, AllDefaultFlags...),
}
func runMilestonesCreate(ctx *cli.Context) error {
login, owner, repo := initCommand()
title := ctx.String("title")
if len(title) == 0 {
fmt.Printf("Title is required\n")
return nil
}
state := gitea.StateOpen
if ctx.String("state") == "closed" {
state = gitea.StateClosed
}
mile, _, err := login.Client().CreateMilestone(owner, repo, gitea.CreateMilestoneOption{
Title: title,
Description: ctx.String("description"),
State: state,
})
if err != nil {
log.Fatal(err)
}
return runMilestoneDetail(ctx, mile.Title)
}
// CmdMilestonesClose represents a sub command of milestones to close an milestone
var CmdMilestonesClose = cli.Command{
Name: "close",
Usage: "Change state of an milestone to 'closed'",
Description: `Change state of an milestone to 'closed'`,
ArgsUsage: "<milestone name>",
Action: func(ctx *cli.Context) error {
if ctx.Bool("force") {
return deleteMilestone(ctx)
}
return editMilestoneStatus(ctx, true)
},
Flags: append([]cli.Flag{
&cli.BoolFlag{
Name: "force",
Aliases: []string{"f"},
Usage: "delete milestone",
},
}, AllDefaultFlags...),
}
func editMilestoneStatus(ctx *cli.Context, close bool) error {
login, owner, repo := initCommand()
client := login.Client()
state := gitea.StateOpen
if close {
state = gitea.StateClosed
}
_, _, err := client.EditMilestoneByName(owner, repo, ctx.Args().First(), gitea.EditMilestoneOption{
State: &state,
Title: ctx.Args().First(),
})
return err
}
// CmdMilestonesDelete represents a sub command of milestones to delete an milestone
var CmdMilestonesDelete = cli.Command{
Name: "delete",
Aliases: []string{"rm"},
Usage: "delete a milestone",
Description: "delete a milestone",
ArgsUsage: "<milestone name>",
Action: deleteMilestone,
Flags: AllDefaultFlags,
}
func deleteMilestone(ctx *cli.Context) error {
login, owner, repo := initCommand()
client := login.Client()
_, err := client.DeleteMilestoneByName(owner, repo, ctx.Args().First())
return err
}
// CmdMilestonesReopen represents a sub command of milestones to open an milestone
var CmdMilestonesReopen = cli.Command{
Name: "reopen",
Aliases: []string{"open"},
Usage: "Change state of an milestone to 'open'",
Description: `Change state of an milestone to 'open'`,
ArgsUsage: "<milestone name>",
Action: func(ctx *cli.Context) error {
return editMilestoneStatus(ctx, false)
},
Flags: AllDefaultFlags,
}

View File

@ -15,8 +15,8 @@ import (
// CmdNotifications is the main command to operate with notifications // CmdNotifications is the main command to operate with notifications
var CmdNotifications = cli.Command{ var CmdNotifications = cli.Command{
Name: "notifications", Name: "notifications",
Usage: "Show notifications", Usage: "show notifications",
Description: "Show notifications, by default based of the current repo and unread one", Description: "show notifications, by default based of the current repo and unread one",
Action: runNotifications, Action: runNotifications,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
&cli.BoolFlag{ &cli.BoolFlag{
@ -24,18 +24,24 @@ var CmdNotifications = cli.Command{
Aliases: []string{"a"}, Aliases: []string{"a"},
Usage: "show all notifications of related gitea instance", Usage: "show all notifications of related gitea instance",
}, },
/* // not supported jet
&cli.BoolFlag{ &cli.BoolFlag{
Name: "read", Name: "read",
Aliases: []string{"rd"}, Aliases: []string{"rd"},
Usage: "show read notifications instead unread", Usage: "show read notifications instead unread",
}, },
&cli.BoolFlag{ */
Name: "pinned", &cli.IntFlag{
Aliases: []string{"pd"}, Name: "page",
Usage: "show pinned notifications instead unread", Aliases: []string{"p"},
Usage: "specify page, default is 1",
Value: 1,
},
&cli.IntFlag{
Name: "limit",
Aliases: []string{"lm"},
Usage: "specify limit of items per page",
}, },
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...), }, AllDefaultFlags...),
} }
@ -43,30 +49,20 @@ func runNotifications(ctx *cli.Context) error {
var news []*gitea.NotificationThread var news []*gitea.NotificationThread
var err error var err error
listOpts := getListOptions(ctx) listOpts := gitea.ListOptions{
if listOpts.Page == 0 { Page: ctx.Int("page"),
listOpts.Page = 1 PageSize: ctx.Int("limit"),
}
var status []gitea.NotifyStatus
if ctx.Bool("read") {
status = []gitea.NotifyStatus{gitea.NotifyStatusRead}
}
if ctx.Bool("pinned") {
status = append(status, gitea.NotifyStatusPinned)
} }
if ctx.Bool("all") { if ctx.Bool("all") {
login := initCommandLoginOnly() login := initCommandLoginOnly()
news, _, err = login.Client().ListNotifications(gitea.ListNotificationOptions{ news, err = login.Client().ListNotifications(gitea.ListNotificationOptions{
ListOptions: listOpts, ListOptions: listOpts,
Status: status,
}) })
} else { } else {
login, owner, repo := initCommand() login, owner, repo := initCommand()
news, _, err = login.Client().ListRepoNotifications(owner, repo, gitea.ListNotificationOptions{ news, err = login.Client().ListRepoNotifications(owner, repo, gitea.ListNotificationOptions{
ListOptions: listOpts, ListOptions: listOpts,
Status: status,
}) })
} }
if err != nil { if err != nil {

View File

@ -13,7 +13,6 @@ import (
local_git "code.gitea.io/tea/modules/git" local_git "code.gitea.io/tea/modules/git"
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/charmbracelet/glamour"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
git_config "github.com/go-git/go-git/v5/config" git_config "github.com/go-git/go-git/v5/config"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -23,13 +22,17 @@ import (
var CmdPulls = cli.Command{ var CmdPulls = cli.Command{
Name: "pulls", Name: "pulls",
Aliases: []string{"pull", "pr"}, Aliases: []string{"pull", "pr"},
Usage: "List, create, checkout and clean pull requests", Usage: "List open pull requests",
Description: `List, create, checkout and clean pull requests`, Description: `List open pull requests`,
ArgsUsage: "[<pull index>]",
Action: runPulls, Action: runPulls,
Flags: IssuePRFlags, Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "state",
Usage: "Filter by PR state (all|open|closed)",
DefaultText: "open",
},
}, AllDefaultFlags...),
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
&CmdPullsList,
&CmdPullsCheckout, &CmdPullsCheckout,
&CmdPullsClean, &CmdPullsClean,
&CmdPullsCreate, &CmdPullsCreate,
@ -37,44 +40,6 @@ var CmdPulls = cli.Command{
} }
func runPulls(ctx *cli.Context) error { func runPulls(ctx *cli.Context) error {
if ctx.Args().Len() == 1 {
return runPullDetail(ctx, ctx.Args().First())
}
return runPullsList(ctx)
}
// CmdPullsList represents a sub command of issues to list pulls
var CmdPullsList = cli.Command{
Name: "ls",
Usage: "List pull requests of the repository",
Description: `List pull requests of the repository`,
Action: runPullsList,
Flags: IssuePRFlags,
}
func runPullDetail(ctx *cli.Context, index string) error {
login, owner, repo := initCommand()
idx, err := argToIndex(index)
if err != nil {
return err
}
pr, _, err := login.Client().GetPullRequest(owner, repo, idx)
if err != nil {
return err
}
// TODO: use glamour once #181 is merged
fmt.Printf("#%d %s\n%s created %s\n\n%s\n", pr.Index,
pr.Title,
pr.Poster.UserName,
pr.Created.Format("2006-01-02 15:04:05"),
pr.Body,
)
return nil
}
func runPullsList(ctx *cli.Context) error {
login, owner, repo := initCommand() login, owner, repo := initCommand()
state := gitea.StateOpen state := gitea.StateOpen
@ -87,7 +52,7 @@ func runPullsList(ctx *cli.Context) error {
state = gitea.StateClosed state = gitea.StateClosed
} }
prs, _, err := login.Client().ListRepoPullRequests(owner, repo, gitea.ListPullRequestsOptions{ prs, err := login.Client().ListRepoPullRequests(owner, repo, gitea.ListPullRequestsOptions{
State: state, State: state,
}) })
@ -97,11 +62,10 @@ func runPullsList(ctx *cli.Context) error {
headers := []string{ headers := []string{
"Index", "Index",
"Title",
"State", "State",
"Author", "Author",
"Milestone",
"Updated", "Updated",
"Title",
} }
var values [][]string var values [][]string
@ -115,23 +79,18 @@ func runPullsList(ctx *cli.Context) error {
if pr == nil { if pr == nil {
continue continue
} }
author := pr.Poster.FullName name := pr.Poster.FullName
if len(author) == 0 { if len(name) == 0 {
author = pr.Poster.UserName name = pr.Poster.UserName
}
mile := ""
if pr.Milestone != nil {
mile = pr.Milestone.Title
} }
values = append( values = append(
values, values,
[]string{ []string{
strconv.FormatInt(pr.Index, 10), strconv.FormatInt(pr.Index, 10),
pr.Title,
string(pr.State), string(pr.State),
author, name,
mile,
pr.Updated.Format("2006-01-02 15:04:05"), pr.Updated.Format("2006-01-02 15:04:05"),
pr.Title,
}, },
) )
} }
@ -161,7 +120,7 @@ func runPullsCheckout(ctx *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
pr, _, err := login.Client().GetPullRequest(owner, repo, idx) pr, err := login.Client().GetPullRequest(owner, repo, idx)
if err != nil { if err != nil {
return err return err
} }
@ -245,7 +204,7 @@ func runPullsClean(ctx *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
pr, _, err := login.Client().GetPullRequest(owner, repo, idx) pr, err := login.Client().GetPullRequest(owner, repo, idx)
if err != nil { if err != nil {
return err return err
} }
@ -339,22 +298,15 @@ func runPullsCreate(ctx *cli.Context) error {
login, ownerArg, repoArg := initCommand() login, ownerArg, repoArg := initCommand()
client := login.Client() client := login.Client()
repo, _, err := client.GetRepo(ownerArg, repoArg) repo, err := login.Client().GetRepo(ownerArg, repoArg)
if err != nil { if err != nil {
log.Fatal("could not fetch repo meta: ", err) log.Fatal(err)
} }
// open local git repo // open local git repo
localRepo, err := local_git.RepoForWorkdir() localRepo, err := local_git.RepoForWorkdir()
if err != nil { if err != nil {
log.Fatal("could not open local repo: ", err) log.Fatal(err)
}
// push if possible
log.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())
} }
base := ctx.String("base") base := ctx.String("base")
@ -366,35 +318,10 @@ func runPullsCreate(ctx *cli.Context) error {
head := ctx.String("head") head := ctx.String("head")
// default is current one // default is current one
if len(head) == 0 { if len(head) == 0 {
headBranch, err := localRepo.Head() head, err = localRepo.TeaGetCurrentBranchName()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
sha := headBranch.Hash().String()
remote, err := localRepo.TeaFindBranchRemote("", sha)
if err != nil {
log.Fatal("could not determine remote for current branch: ", err)
}
if remote == nil {
// if no remote branch is found for the local hash, we abort:
// user has probably not configured a remote for the local branch,
// or local branch does not represent remote state.
log.Fatal("no matching remote found for this branch. try git push -u <remote> <branch>")
}
branchName, err := localRepo.TeaGetCurrentBranchName()
if err != nil {
log.Fatal(err)
}
url, err := local_git.ParseURL(remote.Config().URLs[0])
if err != nil {
log.Fatal(err)
}
owner, _ := getOwnerAndRepo(strings.TrimLeft(url.Path, "/"), "")
head = fmt.Sprintf("%s:%s", owner, branchName)
} }
title := ctx.String("title") title := ctx.String("title")
@ -414,7 +341,13 @@ func runPullsCreate(ctx *cli.Context) error {
return nil return nil
} }
pr, _, err := client.CreatePullRequest(ownerArg, repoArg, gitea.CreatePullRequestOption{ // push if possible
err = localRepo.Push(&git.PushOptions{})
if err != nil {
fmt.Printf("Error occurred during 'git push':\n%s\n", err.Error())
}
pr, err := client.CreatePullRequest(ownerArg, repoArg, gitea.CreatePullRequestOption{
Head: head, Head: head,
Base: base, Base: base,
Title: title, Title: title,
@ -422,21 +355,19 @@ func runPullsCreate(ctx *cli.Context) error {
}) })
if err != nil { if err != nil {
log.Fatalf("could not create PR from %s to %s:%s: %s", head, ownerArg, base, err) log.Fatal(err)
} }
in := fmt.Sprintf("# #%d %s (%s)\n%s created %s\n\n%s\n", pr.Index, fmt.Printf("#%d %s\n%s created %s\n", pr.Index,
pr.Title, pr.Title,
pr.State,
pr.Poster.UserName, pr.Poster.UserName,
pr.Created.Format("2006-01-02 15:04:05"), pr.Created.Format("2006-01-02 15:04:05"),
pr.Body,
) )
out, err := glamour.Render(in, getGlamourTheme()) if len(pr.Body) != 0 {
fmt.Print(out) fmt.Printf("\n%s\n", pr.Body)
}
fmt.Println(pr.HTMLURL) fmt.Println(pr.HTMLURL)
return err return nil
} }
func argToIndex(arg string) (int64, error) { func argToIndex(arg string) (int64, error) {

View File

@ -5,12 +5,9 @@
package cmd package cmd
import ( import (
"fmt"
"log" "log"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
@ -19,36 +16,20 @@ import (
// CmdReleases represents to login a gitea server. // CmdReleases represents to login a gitea server.
var CmdReleases = cli.Command{ var CmdReleases = cli.Command{
Name: "release", Name: "releases",
Aliases: []string{"releases"}, Usage: "Create releases",
Usage: "Manage releases", Description: `Create releases`,
Description: "Manage releases",
Action: runReleases, Action: runReleases,
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
&CmdReleaseList,
&CmdReleaseCreate, &CmdReleaseCreate,
&CmdReleaseDelete,
&CmdReleaseEdit,
}, },
Flags: AllDefaultFlags, Flags: AllDefaultFlags,
} }
// CmdReleaseList represents a sub command of Release to list releases
var CmdReleaseList = cli.Command{
Name: "ls",
Usage: "List Releases",
Description: "List Releases",
Action: runReleases,
Flags: append([]cli.Flag{
&PaginationPageFlag,
&PaginationLimitFlag,
}, AllDefaultFlags...),
}
func runReleases(ctx *cli.Context) error { func runReleases(ctx *cli.Context) error {
login, owner, repo := initCommand() login, owner, repo := initCommand()
releases, _, err := login.Client().ListReleases(owner, repo, gitea.ListReleasesOptions{ListOptions: getListOptions(ctx)}) releases, err := login.Client().ListReleases(owner, repo, gitea.ListReleasesOptions{})
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -57,7 +38,6 @@ func runReleases(ctx *cli.Context) error {
"Tag-Name", "Tag-Name",
"Title", "Title",
"Published At", "Published At",
"Status",
"Tar URL", "Tar URL",
} }
@ -69,19 +49,12 @@ func runReleases(ctx *cli.Context) error {
} }
for _, release := range releases { for _, release := range releases {
status := "released"
if release.IsDraft {
status = "draft"
} else if release.IsPrerelease {
status = "prerelease"
}
values = append( values = append(
values, values,
[]string{ []string{
release.TagName, release.TagName,
release.Title, release.Title,
release.PublishedAt.Format("2006-01-02 15:04:05"), release.PublishedAt.Format("2006-01-02 15:04:05"),
status,
release.TarURL, release.TarURL,
}, },
) )
@ -91,7 +64,7 @@ func runReleases(ctx *cli.Context) error {
return nil return nil
} }
// CmdReleaseCreate represents a sub command of Release to create release // CmdReleaseCreate represents a sub command of Release to create release.
var CmdReleaseCreate = cli.Command{ var CmdReleaseCreate = cli.Command{
Name: "create", Name: "create",
Usage: "Create a release", Usage: "Create a release",
@ -131,13 +104,13 @@ var CmdReleaseCreate = cli.Command{
Aliases: []string{"a"}, Aliases: []string{"a"},
Usage: "List of files to attach", Usage: "List of files to attach",
}, },
}, AllDefaultFlags...), }, LoginRepoFlags...),
} }
func runReleaseCreate(ctx *cli.Context) error { func runReleaseCreate(ctx *cli.Context) error {
login, owner, repo := initCommand() login, owner, repo := initCommand()
release, resp, err := login.Client().CreateRelease(owner, repo, gitea.CreateReleaseOption{ release, err := login.Client().CreateRelease(owner, repo, gitea.CreateReleaseOption{
TagName: ctx.String("tag"), TagName: ctx.String("tag"),
Target: ctx.String("target"), Target: ctx.String("target"),
Title: ctx.String("title"), Title: ctx.String("title"),
@ -147,10 +120,10 @@ func runReleaseCreate(ctx *cli.Context) error {
}) })
if err != nil { if err != nil {
if resp != nil && resp.StatusCode == http.StatusConflict { if err.Error() == "409 Conflict" {
fmt.Println("error: There already is a release for this tag") log.Fatal("error: There already is a release for this tag")
return nil
} }
log.Fatal(err) log.Fatal(err)
} }
@ -163,7 +136,7 @@ func runReleaseCreate(ctx *cli.Context) error {
filePath := filepath.Base(asset) filePath := filepath.Base(asset)
if _, _, err = login.Client().CreateReleaseAttachment(owner, repo, release.ID, file, filePath); err != nil { if _, err = login.Client().CreateReleaseAttachment(owner, repo, release.ID, file, filePath); err != nil {
file.Close() file.Close()
log.Fatal(err) log.Fatal(err)
} }
@ -173,139 +146,3 @@ func runReleaseCreate(ctx *cli.Context) error {
return nil return nil
} }
// CmdReleaseDelete represents a sub command of Release to delete a release
var CmdReleaseDelete = cli.Command{
Name: "delete",
Usage: "Delete a release",
Description: `Delete a release`,
ArgsUsage: "<release tag>",
Action: runReleaseDelete,
Flags: AllDefaultFlags,
}
func runReleaseDelete(ctx *cli.Context) error {
login, owner, repo := initCommand()
client := login.Client()
tag := ctx.Args().First()
if len(tag) == 0 {
fmt.Println("Release tag needed to delete")
return nil
}
release, err := getReleaseByTag(owner, repo, tag, client)
if err != nil {
return err
}
if release == nil {
return nil
}
_, err = client.DeleteRelease(owner, repo, release.ID)
return err
}
func getReleaseByTag(owner, repo, tag string, client *gitea.Client) (*gitea.Release, error) {
rl, _, err := client.ListReleases(owner, repo, gitea.ListReleasesOptions{})
if err != nil {
return nil, err
}
if len(rl) == 0 {
fmt.Println("Repo does not have any release")
return nil, nil
}
for _, r := range rl {
if r.TagName == tag {
return r, nil
}
}
fmt.Println("Release tag does not exist")
return nil, nil
}
// CmdReleaseEdit represents a sub command of Release to edit releases
var CmdReleaseEdit = cli.Command{
Name: "edit",
Usage: "Edit a release",
Description: `Edit a release`,
ArgsUsage: "<release tag>",
Action: runReleaseEdit,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "tag",
Usage: "Change Tag",
},
&cli.StringFlag{
Name: "target",
Usage: "Change Target",
},
&cli.StringFlag{
Name: "title",
Aliases: []string{"t"},
Usage: "Change Title",
},
&cli.StringFlag{
Name: "note",
Aliases: []string{"n"},
Usage: "Change Notes",
},
&cli.StringFlag{
Name: "draft",
Aliases: []string{"d"},
Usage: "Mark as Draft [True/false]",
DefaultText: "true",
},
&cli.StringFlag{
Name: "prerelease",
Aliases: []string{"p"},
Usage: "Mark as Pre-Release [True/false]",
DefaultText: "true",
},
}, AllDefaultFlags...),
}
func runReleaseEdit(ctx *cli.Context) error {
login, owner, repo := initCommand()
client := login.Client()
tag := ctx.Args().First()
if len(tag) == 0 {
fmt.Println("Release tag needed to edit")
return nil
}
release, err := getReleaseByTag(owner, repo, tag, client)
if err != nil {
return err
}
if release == nil {
return nil
}
var isDraft, isPre *bool
bTrue := true
bFalse := false
if ctx.IsSet("draft") {
isDraft = &bFalse
if strings.ToLower(ctx.String("draft"))[:1] == "t" {
isDraft = &bTrue
}
}
if ctx.IsSet("prerelease") {
isPre = &bFalse
if strings.ToLower(ctx.String("prerelease"))[:1] == "t" {
isPre = &bTrue
}
}
_, _, err = client.EditRelease(owner, repo, release.ID, gitea.EditReleaseOption{
TagName: ctx.String("tag"),
Target: ctx.String("target"),
Title: ctx.String("title"),
Note: ctx.String("note"),
IsDraft: isDraft,
IsPrerelease: isPre,
})
return err
}

View File

@ -5,32 +5,26 @@
package cmd package cmd
import ( import (
"fmt"
"log" "log"
"net/http"
"strings"
"code.gitea.io/tea/modules/utils"
"code.gitea.io/sdk/gitea" "code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
// CmdRepos represents to login a gitea server. // CmdRepos represents to login a gitea server.
var CmdRepos = cli.Command{ var CmdRepos = cli.Command{
Name: "repos", Name: "repos",
Usage: "Show repositories details", Usage: "Operate with repositories",
Description: "Show repositories details", Description: `Operate with repositories`,
ArgsUsage: "[<repo owner>/<repo name>]", Action: runReposList,
Action: runRepos,
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
&CmdReposList, &CmdReposList,
&CmdRepoCreate,
}, },
Flags: LoginOutputFlags, Flags: LoginOutputFlags,
} }
// CmdReposList represents a sub command of repos to list them // CmdReposList represents a sub command of issues to list issues
var CmdReposList = cli.Command{ var CmdReposList = cli.Command{
Name: "ls", Name: "ls",
Usage: "List available repositories", Usage: "List available repositories",
@ -39,166 +33,65 @@ var CmdReposList = cli.Command{
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "mode", Name: "mode",
Aliases: []string{"m"}, Usage: "Filter listed repositories based on mode, optional - fork, mirror, source",
Required: false,
Usage: "Filter by mode: fork, mirror, source",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "owner", Name: "org",
Aliases: []string{"O"}, Usage: "Filter listed repositories based on organization, optional",
Required: false,
Usage: "Filter by owner",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "private", Name: "user",
Required: false, Usage: "Filter listed repositories absed on user, optional",
Usage: "Filter private repos (true|false)",
},
&cli.StringFlag{
Name: "archived",
Required: false,
Usage: "Filter archived repos (true|false)",
},
&PaginationPageFlag,
&PaginationLimitFlag,
}, LoginOutputFlags...),
}
// CmdRepoCreate represents a sub command of repos to create one
var CmdRepoCreate = cli.Command{
Name: "create",
Aliases: []string{"c"},
Usage: "Create a repository",
Description: "Create a repository",
Action: runRepoCreate,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{""},
Required: true,
Usage: "name of new repo",
},
&cli.StringFlag{
Name: "owner",
Aliases: []string{"O"},
Required: false,
Usage: "name of repo owner",
},
&cli.BoolFlag{
Name: "private",
Required: false,
Value: false,
Usage: "make repo private",
},
&cli.StringFlag{
Name: "description",
Aliases: []string{"desc"},
Required: false,
Usage: "add description to repo",
},
&cli.BoolFlag{
Name: "init",
Required: false,
Value: false,
Usage: "initialize repo",
},
&cli.StringFlag{
Name: "labels",
Required: false,
Usage: "name of label set to add",
},
&cli.StringFlag{
Name: "gitignores",
Aliases: []string{"git"},
Required: false,
Usage: "list of gitignore templates (need --init)",
},
&cli.StringFlag{
Name: "license",
Required: false,
Usage: "add license (need --init)",
},
&cli.StringFlag{
Name: "readme",
Required: false,
Usage: "use readme template (need --init)",
},
&cli.StringFlag{
Name: "branch",
Required: false,
Usage: "use custom default branch (need --init)",
}, },
}, LoginOutputFlags...), }, LoginOutputFlags...),
} }
func runRepos(ctx *cli.Context) error {
if ctx.Args().Len() == 1 {
return runRepoDetail(ctx, ctx.Args().First())
}
return runReposList(ctx)
}
// runReposList list repositories // runReposList list repositories
func runReposList(ctx *cli.Context) error { func runReposList(ctx *cli.Context) error {
login := initCommandLoginOnly() login := initCommandLoginOnly()
client := login.Client()
var ownerID int64 mode := ctx.String("mode")
if ctx.IsSet("owner") { org := ctx.String("org")
// test if owner is a organisation user := ctx.String("user")
org, resp, err := client.GetOrg(ctx.String("owner"))
if err != nil { var rps []*gitea.Repository
if resp == nil || resp.StatusCode != http.StatusNotFound { var err error
return err
} if org != "" {
// if owner is no org, its a user rps, err = login.Client().ListOrgRepos(org, gitea.ListOrgReposOptions{})
user, _, err := client.GetUserInfo(ctx.String("owner")) } else if user != "" {
if err != nil { rps, err = login.Client().ListUserRepos(user, gitea.ListReposOptions{})
return err
}
ownerID = user.ID
} else { } else {
ownerID = org.ID rps, err = login.Client().ListMyRepos(gitea.ListReposOptions{})
}
if err != nil {
log.Fatal(err)
}
var repos []*gitea.Repository
if mode == "" {
repos = rps
} else if mode == "fork" {
for _, rp := range rps {
if rp.Fork == true {
repos = append(repos, rp)
}
}
} else if mode == "mirror" {
for _, rp := range rps {
if rp.Mirror == true {
repos = append(repos, rp)
}
}
} else if mode == "source" {
for _, rp := range rps {
if rp.Mirror != true && rp.Fork != true {
repos = append(repos, rp)
}
} }
} else { } else {
me, _, err := client.GetMyUserInfo() log.Fatal("Unknown mode: ", mode, "\nUse one of the following:\n- fork\n- mirror\n- source\n")
if err != nil { return nil
return err
}
ownerID = me.ID
}
var isArchived *bool
if ctx.IsSet("archived") {
archived := strings.ToLower(ctx.String("archived"))[:1] == "t"
isArchived = &archived
}
var isPrivate *bool
if ctx.IsSet("private") {
private := strings.ToLower(ctx.String("private"))[:1] == "t"
isArchived = &private
}
mode := gitea.RepoTypeNone
switch ctx.String("mode") {
case "fork":
mode = gitea.RepoTypeFork
case "mirror":
mode = gitea.RepoTypeMirror
case "source":
mode = gitea.RepoTypeSource
}
rps, _, err := client.SearchRepos(gitea.SearchRepoOptions{
ListOptions: getListOptions(ctx),
OwnerID: ownerID,
IsPrivate: isPrivate,
IsArchived: isArchived,
Type: mode,
})
if err != nil {
return err
} }
if len(rps) == 0 { if len(rps) == 0 {
@ -214,7 +107,7 @@ func runReposList(ctx *cli.Context) error {
} }
var values [][]string var values [][]string
for _, rp := range rps { for _, rp := range repos {
var mode = "source" var mode = "source"
if rp.Fork { if rp.Fork {
mode = "fork" mode = "fork"
@ -237,80 +130,3 @@ func runReposList(ctx *cli.Context) error {
return nil return nil
} }
func runRepoDetail(_ *cli.Context, path string) error {
login := initCommandLoginOnly()
client := login.Client()
repoOwner, repoName := getOwnerAndRepo(path, login.User)
repo, _, err := client.GetRepo(repoOwner, repoName)
if err != nil {
return err
}
topics, _, err := client.ListRepoTopics(repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
if err != nil {
return err
}
output := repo.FullName
if repo.Mirror {
output += " (mirror)"
}
if repo.Fork {
output += " (fork)"
}
if repo.Archived {
output += " (archived)"
}
if repo.Empty {
output += " (empty)"
}
output += "\n"
if len(topics) != 0 {
output += "Topics: " + strings.Join(topics, ", ") + "\n"
}
output += "\n"
output += repo.Description + "\n\n"
output += fmt.Sprintf(
"Open Issues: %d, Stars: %d, Forks: %d, Size: %s\n\n",
repo.OpenIssues,
repo.Stars,
repo.Forks,
utils.FormatSize(int64(repo.Size)),
)
fmt.Print(output)
return nil
}
func runRepoCreate(ctx *cli.Context) error {
login := initCommandLoginOnly()
client := login.Client()
var (
repo *gitea.Repository
err error
)
opts := gitea.CreateRepoOption{
Name: ctx.String("name"),
Description: ctx.String("description"),
Private: ctx.Bool("private"),
AutoInit: ctx.Bool("init"),
IssueLabels: ctx.String("labels"),
Gitignores: ctx.String("gitignores"),
License: ctx.String("license"),
Readme: ctx.String("readme"),
DefaultBranch: ctx.String("branch"),
}
if len(ctx.String("owner")) != 0 {
repo, _, err = client.CreateOrgRepo(ctx.String("owner"), opts)
} else {
repo, _, err = client.CreateRepo(opts)
}
if err != nil {
return err
}
if err = runRepoDetail(ctx, repo.FullName); err != nil {
return err
}
fmt.Printf("%s\n", repo.HTMLURL)
return nil
}

View File

@ -66,17 +66,17 @@ func runTrackedTimes(ctx *cli.Context) error {
fmt.Println(ctx.Command.ArgsUsage) fmt.Println(ctx.Command.ArgsUsage)
if user == "" { if user == "" {
// get all tracked times on the repo // get all tracked times on the repo
times, _, err = client.GetRepoTrackedTimes(owner, repo) times, err = client.GetRepoTrackedTimes(owner, repo)
} else if strings.HasPrefix(user, "#") { } else if strings.HasPrefix(user, "#") {
// get all tracked times on the specified issue // get all tracked times on the specified issue
issue, err := argToIndex(user) issue, err := argToIndex(user)
if err != nil { if err != nil {
return err return err
} }
times, _, err = client.ListTrackedTimes(owner, repo, issue, gitea.ListTrackedTimesOptions{}) times, err = client.ListTrackedTimes(owner, repo, issue, gitea.ListTrackedTimesOptions{})
} else { } else {
// get all tracked times by the specified user // get all tracked times by the specified user
times, _, err = client.GetUserTrackedTimes(owner, repo, user) times, err = client.GetUserTrackedTimes(owner, repo, user)
} }
if err != nil { if err != nil {
@ -101,15 +101,6 @@ func runTrackedTimes(ctx *cli.Context) error {
return nil return nil
} }
func formatDuration(seconds int64, outputType string) string {
switch outputType {
case "yaml":
case "csv":
return fmt.Sprint(seconds)
}
return time.Duration(1e9 * seconds).String()
}
func printTrackedTimes(times []*gitea.TrackedTime, outputType string, from, until time.Time, printTotal bool) { func printTrackedTimes(times []*gitea.TrackedTime, outputType string, from, until time.Time, printTotal bool) {
var outputValues [][]string var outputValues [][]string
var totalDuration int64 var totalDuration int64
@ -135,14 +126,14 @@ func printTrackedTimes(times []*gitea.TrackedTime, outputType string, from, unti
t.Created.In(localLoc).Format("2006-01-02 15:04:05"), t.Created.In(localLoc).Format("2006-01-02 15:04:05"),
"#" + strconv.FormatInt(t.Issue.Index, 10), "#" + strconv.FormatInt(t.Issue.Index, 10),
t.UserName, t.UserName,
formatDuration(t.Time, outputType), time.Duration(1e9 * t.Time).String(),
}, },
) )
} }
if printTotal { if printTotal {
outputValues = append(outputValues, []string{ outputValues = append(outputValues, []string{
"TOTAL", "", "", formatDuration(totalDuration, outputType), "TOTAL", "", "", time.Duration(1e9 * totalDuration).String(),
}) })
} }
@ -185,7 +176,7 @@ func runTrackedTimesAdd(ctx *cli.Context) error {
log.Fatal(err) log.Fatal(err)
} }
_, _, err = login.Client().AddTime(owner, repo, issue, gitea.AddTimeOption{ _, err = login.Client().AddTime(owner, repo, issue, gitea.AddTimeOption{
Time: int64(duration.Seconds()), Time: int64(duration.Seconds()),
}) })
if err != nil { if err != nil {
@ -227,7 +218,7 @@ func runTrackedTimesDelete(ctx *cli.Context) error {
log.Fatal(err) log.Fatal(err)
} }
_, err = client.DeleteTime(owner, repo, issue, timeID) err = client.DeleteTime(owner, repo, issue, timeID)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -262,7 +253,7 @@ func runTrackedTimesReset(ctx *cli.Context) error {
log.Fatal(err) log.Fatal(err)
} }
_, err = client.ResetIssueTime(owner, repo, issue) err = client.ResetIssueTime(owner, repo, issue)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

9
go.mod
View File

@ -3,14 +3,13 @@ module code.gitea.io/tea
go 1.12 go 1.12
require ( require (
code.gitea.io/gitea-vet v0.2.0 code.gitea.io/sdk/gitea v0.12.1
code.gitea.io/sdk/gitea v0.13.0 gitea.com/jolheiser/gitea-vet v0.1.0
github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1 github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1
github.com/charmbracelet/glamour v0.2.0
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/go-git/go-git/v5 v5.1.0 github.com/go-git/go-git/v5 v5.1.0
github.com/hashicorp/go-version v1.2.1 // indirect github.com/hashicorp/go-version v1.2.1 // indirect
github.com/muesli/termenv v0.7.2 github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/olekukonko/tablewriter v0.0.4 github.com/olekukonko/tablewriter v0.0.4
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/stretchr/testify v1.5.1 github.com/stretchr/testify v1.5.1
@ -18,6 +17,6 @@ require (
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect
golang.org/x/tools v0.0.0-20200721032237-77f530d86f9a // indirect golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed // indirect
gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v2 v2.3.0
) )

53
go.sum
View File

@ -1,39 +1,24 @@
code.gitea.io/gitea-vet v0.2.0 h1:xkUePzbHI8e0qp4Aly4GBSd0+6cqEMVTrdZq57fPozo= code.gitea.io/sdk/gitea v0.12.1 h1:bMgjEqPnNX/i6TpVwXwpjJtFOnUSuC9P6yy/jjy8sjY=
code.gitea.io/gitea-vet v0.2.0/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/sdk/gitea v0.12.1/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
code.gitea.io/sdk/gitea v0.13.0 h1:iHognp8ZMhMFLooUUNZFpm8IHaC9qoHJDvAE5vTm5aw= gitea.com/jolheiser/gitea-vet v0.1.0 h1:gJEms9YWbIcrPOEmDOJ+5JZXCYFxNpwxlI73uRulAi4=
code.gitea.io/sdk/gitea v0.13.0/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= gitea.com/jolheiser/gitea-vet v0.1.0/go.mod h1:2Oa6TAdEp1N/38oBNh3ZeiSEER60D/CeDaBFv2sdH58=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
github.com/alecthomas/chroma v0.7.3 h1:NfdAERMy+esYQs8OXk0I868/qDxxCEo7FMz1WIqMAeI=
github.com/alecthomas/chroma v0.7.3/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1 h1:TEBmxO80TM04L8IuMWk77SGL1HomBmKTdzdJLLWznxI= github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1 h1:TEBmxO80TM04L8IuMWk77SGL1HomBmKTdzdJLLWznxI=
github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/charmbracelet/glamour v0.2.0 h1:mTgaiNiumpqTZp3qVM6DH9UB0NlbY17wejoMf1kM8Pg=
github.com/charmbracelet/glamour v0.2.0/go.mod h1:UA27Kwj3QHialP74iU6C+Gpc8Y7IOAKupeKMLLBURWM=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
@ -50,8 +35,6 @@ github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEss
github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f h1:5CjVwnuUcp5adK4gmY6i72gpVFVnZDP2h5TmPScB6u4=
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
@ -70,38 +53,22 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/muesli/reflow v0.1.0 h1:oQdpLfO56lr5pgLvqD0TcjW85rDjSYSBVdiG1Ch1ddM=
github.com/muesli/reflow v0.1.0/go.mod h1:I9bWAt7QTg/que/qmUCJBGlj7wEq8OAFBjPNjc6xK4I=
github.com/muesli/termenv v0.6.0 h1:zxvzTBmo4ZcxhNGGWeMz+Tttm51eF5bmPjfy4MCRYlk=
github.com/muesli/termenv v0.6.0/go.mod h1:SohX91w6swWA4AYU+QmPx+aSgXhWO0juiyID9UZmbpA=
github.com/muesli/termenv v0.7.2 h1:r1raklL3uKE7rOvWgSenmEm2px+dnc33OTisZ8YR1fw=
github.com/muesli/termenv v0.7.2/go.mod h1:ct2L5N2lmix82RaY3bMWwVu/jUFc9Ule0KGDCiKYPh8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
@ -110,8 +77,6 @@ github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EE
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
@ -122,8 +87,6 @@ github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.0 h1:WOOcyaJPlzb8fZ8TloxFe8QZkhOOJx87leDa9MIT9dc=
github.com/yuin/goldmark v1.2.0/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -136,7 +99,6 @@ golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -151,12 +113,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -166,8 +125,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI=
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200721032237-77f530d86f9a h1:kVMPw4f6EVqYdfGQTedjrpw1dbE2PEMfw4jwXsNdn9s= golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed h1:+qzWo37K31KxduIYaBeMqJ8MUOyTayOQKpH9aDPLMSY=
golang.org/x/tools v0.0.0-20200721032237-77f530d86f9a/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

View File

@ -44,7 +44,6 @@ func main() {
&cmd.CmdTrackedTimes, &cmd.CmdTrackedTimes,
&cmd.CmdOpen, &cmd.CmdOpen,
&cmd.CmdNotifications, &cmd.CmdNotifications,
&cmd.CmdMilestones,
} }
app.EnableBashCompletion = true app.EnableBashCompletion = true
err := app.Run(os.Args) err := app.Run(os.Args)

View File

@ -176,48 +176,6 @@ func (r TeaRepo) TeaFindBranchByName(branchName, repoURL string) (b *git_config.
return b, b.Validate() return b, b.Validate()
} }
// TeaFindBranchRemote gives the first remote that has a branch with the same name or sha,
// depending on what is passed in.
// This function is needed, as git does not always define branches in .git/config with remote entries.
func (r TeaRepo) TeaFindBranchRemote(branchName, hash string) (*git.Remote, error) {
remotes, err := r.Remotes()
if err != nil {
return nil, err
}
switch {
case len(remotes) == 0:
return nil, nil
case len(remotes) == 1:
return remotes[0], nil
}
// check if the given remote has our branch (.git/refs/remotes/<remoteName>/*)
iter, err := r.References()
if err != nil {
return nil, err
}
defer iter.Close()
var match *git.Remote
err = iter.ForEach(func(ref *git_plumbing.Reference) error {
if ref.Name().IsRemote() {
names := strings.SplitN(ref.Name().Short(), "/", 2)
remote := names[0]
branch := names[1]
hashMatch := hash != "" && hash == ref.Hash().String()
nameMatch := branchName != "" && branchName == branch
if hashMatch || nameMatch {
match, err = r.Remote(remote)
return err
}
}
return nil
})
return match, err
}
// TeaGetCurrentBranchName return the name of the branch witch is currently active // TeaGetCurrentBranchName return the name of the branch witch is currently active
func (r TeaRepo) TeaGetCurrentBranchName() (string, error) { func (r TeaRepo) TeaGetCurrentBranchName() (string, error) {
localHead, err := r.Head() localHead, err := r.Head()
@ -229,5 +187,5 @@ func (r TeaRepo) TeaGetCurrentBranchName() (string, error) {
return "", fmt.Errorf("active ref is no branch") return "", fmt.Errorf("active ref is no branch")
} }
return strings.TrimPrefix(localHead.Name().String(), "refs/heads/"), nil return strings.TrimLeft(localHead.Name().String(), "refs/heads/"), nil
} }

View File

@ -1,23 +0,0 @@
// 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 utils
import "fmt"
// FormatSize get kb in int and return string
func FormatSize(kb int64) string {
if kb < 1024 {
return fmt.Sprintf("%d Kb", kb)
}
mb := kb / 1024
if mb < 1024 {
return fmt.Sprintf("%d Mb", mb)
}
gb := mb / 1024
if gb < 1024 {
return fmt.Sprintf("%d Gb", gb)
}
return fmt.Sprintf("%d Tb", gb/1024)
}

View File

@ -1,21 +0,0 @@
// 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 utils
import (
"os"
)
// PathExists returns whether the given file or directory exists or not
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return true, err
}

View File

@ -1,30 +0,0 @@
# The full repository name
repo: gitea/gitea-vet
# Service type (gitea or github)
service: gitea
# Base URL for Gitea instance if using gitea service type (optional)
base-url: https://gitea.com
# Changelog groups and which labeled PRs to add to each group
groups:
-
name: BREAKING
labels:
- breaking
-
name: FEATURES
labels:
- feature
-
name: BUGFIXES
labels:
- bug
-
name: ENHANCEMENTS
labels:
- enhancement
# regex indicating which labels to skip for the changelog
skip-labels: skip-changelog|backport\/.+

View File

@ -1,45 +0,0 @@
---
kind: pipeline
name: compliance
platform:
os: linux
arch: arm64
trigger:
event:
- pull_request
steps:
- name: check
pull: always
image: golang:1.14
environment:
GOPROXY: https://goproxy.cn
commands:
- make build
- make lint
- make vet
---
kind: pipeline
name: build-master
platform:
os: linux
arch: amd64
trigger:
branch:
- master
event:
- push
steps:
- name: build
pull: always
image: techknowlogick/xgo:latest
environment:
GOPROXY: https://goproxy.cn
commands:
- make build

View File

@ -1,23 +0,0 @@
linters:
enable:
- deadcode
- dogsled
- dupl
- errcheck
- gocognit
- goconst
- gocritic
- gocyclo
- gofmt
- golint
- gosimple
- govet
- maligned
- misspell
- prealloc
- staticcheck
- structcheck
- typecheck
- unparam
- unused
- varcheck

View File

@ -1,6 +0,0 @@
## [0.2.0](https://gitea.com/gitea/gitea-vet/pulls?q=&type=all&state=closed&milestone=1272) - 2020-07-20
* FEATURES
* Add migrations check (#5)
* BUGFIXES
* Correct Import Paths (#6)

View File

@ -1,22 +0,0 @@
GO ?= go
.PHONY: build
build:
$(GO) build
.PHONY: fmt
fmt:
$(GO) fmt ./...
.PHONY: vet
vet: build
$(GO) vet ./...
$(GO) vet -vettool=gitea-vet ./...
.PHONY: lint
lint:
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
export BINARY="golangci-lint"; \
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(shell $(GO) env GOPATH)/bin v1.24.0; \
fi
golangci-lint run --timeout 5m

View File

@ -1,11 +0,0 @@
# gitea-vet
[![Build Status](https://drone.gitea.com/api/badges/gitea/gitea-vet/status.svg)](https://drone.gitea.com/gitea/gitea-vet)
`go vet` tool for Gitea
| Analyzer | Description |
|------------|-----------------------------------------------------------------------------|
| Imports | Checks for import sorting. stdlib->code.gitea.io->other |
| License | Checks file headers for some form of `Copyright...YYYY...Gitea/Gogs` |
| Migrations | Checks for black-listed packages in `code.gitea.io/gitea/models/migrations` |

View File

@ -1,59 +0,0 @@
// 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 checks
import (
"errors"
"os/exec"
"strings"
"golang.org/x/tools/go/analysis"
)
var Migrations = &analysis.Analyzer{
Name: "migrations",
Doc: "check migrations for black-listed packages.",
Run: checkMigrations,
}
var migrationBlacklist = []string{
"code.gitea.io/gitea/models",
"code.gitea.io/gitea/modules/structs",
}
func checkMigrations(pass *analysis.Pass) (interface{}, error) {
if !strings.EqualFold(pass.Pkg.Path(), "code.gitea.io/gitea/models/migrations") {
return nil, nil
}
if _, err := exec.LookPath("go"); err != nil {
return nil, errors.New("go was not found in the PATH")
}
depsCmd := exec.Command("go", "list", "-f", `{{join .Deps "\n"}}`, "code.gitea.io/gitea/models/migrations")
depsOut, err := depsCmd.Output()
if err != nil {
return nil, err
}
deps := strings.Split(string(depsOut), "\n")
for _, dep := range deps {
if stringInSlice(dep, migrationBlacklist) {
pass.Reportf(0, "code.gitea.io/gitea/models/migrations cannot depend on the following packages: %s", migrationBlacklist)
return nil, nil
}
}
return nil, nil
}
func stringInSlice(needle string, haystack []string) bool {
for _, h := range haystack {
if strings.EqualFold(needle, h) {
return true
}
}
return false
}

View File

@ -1,44 +0,0 @@
// 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 gitea
import (
"fmt"
"time"
)
// CronTask represents a Cron task
type CronTask struct {
Name string `json:"name"`
Schedule string `json:"schedule"`
Next time.Time `json:"next"`
Prev time.Time `json:"prev"`
ExecTimes int64 `json:"exec_times"`
}
// ListCronTaskOptions list options for ListCronTasks
type ListCronTaskOptions struct {
ListOptions
}
// ListCronTasks list available cron tasks
func (c *Client) ListCronTasks(opt ListCronTaskOptions) ([]*CronTask, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil {
return nil, nil, err
}
opt.setDefaults()
ct := make([]*CronTask, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/admin/cron?%s", opt.getURLQuery().Encode()), jsonHeader, nil, &ct)
return ct, resp, err
}
// RunCronTasks run a cron task
func (c *Client) RunCronTasks(task string) (*Response, error) {
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil {
return nil, err
}
_, resp, err := c.getResponse("POST", fmt.Sprintf("/admin/cron/%s", task), jsonHeader, nil)
return resp, err
}

View File

@ -17,20 +17,19 @@ type AdminListOrgsOptions struct {
} }
// AdminListOrgs lists all orgs // AdminListOrgs lists all orgs
func (c *Client) AdminListOrgs(opt AdminListOrgsOptions) ([]*Organization, *Response, error) { func (c *Client) AdminListOrgs(opt AdminListOrgsOptions) ([]*Organization, error) {
opt.setDefaults() opt.setDefaults()
orgs := make([]*Organization, 0, opt.PageSize) orgs := make([]*Organization, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/admin/orgs?%s", opt.getURLQuery().Encode()), nil, nil, &orgs) return orgs, c.getParsedResponse("GET", fmt.Sprintf("/admin/orgs?%s", opt.getURLQuery().Encode()), nil, nil, &orgs)
return orgs, resp, err
} }
// AdminCreateOrg create an organization // AdminCreateOrg create an organization
func (c *Client) AdminCreateOrg(user string, opt CreateOrgOption) (*Organization, *Response, error) { func (c *Client) AdminCreateOrg(user string, opt CreateOrgOption) (*Organization, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
org := new(Organization) org := new(Organization)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/orgs", user), jsonHeader, bytes.NewReader(body), org) return org, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/orgs", user),
return org, resp, err jsonHeader, bytes.NewReader(body), org)
} }

View File

@ -11,12 +11,12 @@ import (
) )
// AdminCreateRepo create a repo // AdminCreateRepo create a repo
func (c *Client) AdminCreateRepo(user string, opt CreateRepoOption) (*Repository, *Response, error) { func (c *Client) AdminCreateRepo(user string, opt CreateRepoOption) (*Repository, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
repo := new(Repository) repo := new(Repository)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/repos", user), jsonHeader, bytes.NewReader(body), repo) return repo, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/repos", user),
return repo, resp, err jsonHeader, bytes.NewReader(body), repo)
} }

View File

@ -17,11 +17,10 @@ type AdminListUsersOptions struct {
} }
// AdminListUsers lists all users // AdminListUsers lists all users
func (c *Client) AdminListUsers(opt AdminListUsersOptions) ([]*User, *Response, error) { func (c *Client) AdminListUsers(opt AdminListUsersOptions) ([]*User, error) {
opt.setDefaults() opt.setDefaults()
users := make([]*User, 0, opt.PageSize) users := make([]*User, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/admin/users?%s", opt.getURLQuery().Encode()), nil, nil, &users) return users, c.getParsedResponse("GET", fmt.Sprintf("/admin/users?%s", opt.getURLQuery().Encode()), nil, nil, &users)
return users, resp, err
} }
// CreateUserOption create user options // CreateUserOption create user options
@ -36,29 +35,14 @@ type CreateUserOption struct {
SendNotify bool `json:"send_notify"` SendNotify bool `json:"send_notify"`
} }
// Validate the CreateUserOption struct
func (opt CreateUserOption) Validate() error {
if len(opt.Email) == 0 {
return fmt.Errorf("email is empty")
}
if len(opt.Username) == 0 {
return fmt.Errorf("username is empty")
}
return nil
}
// AdminCreateUser create a user // AdminCreateUser create a user
func (c *Client) AdminCreateUser(opt CreateUserOption) (*User, *Response, error) { func (c *Client) AdminCreateUser(opt CreateUserOption) (*User, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
user := new(User) user := new(User)
resp, err := c.getParsedResponse("POST", "/admin/users", jsonHeader, bytes.NewReader(body), user) return user, c.getParsedResponse("POST", "/admin/users", jsonHeader, bytes.NewReader(body), user)
return user, resp, err
} }
// EditUserOption edit user options // EditUserOption edit user options
@ -81,34 +65,33 @@ type EditUserOption struct {
} }
// AdminEditUser modify user informations // AdminEditUser modify user informations
func (c *Client) AdminEditUser(user string, opt EditUserOption) (*Response, error) { func (c *Client) AdminEditUser(user string, opt EditUserOption) error {
body, err := json.Marshal(&opt)
if err != nil {
return err
}
_, err = c.getResponse("PATCH", fmt.Sprintf("/admin/users/%s", user), jsonHeader, bytes.NewReader(body))
return err
}
// AdminDeleteUser delete one user according name
func (c *Client) AdminDeleteUser(user string) error {
_, err := c.getResponse("DELETE", fmt.Sprintf("/admin/users/%s", user), nil, nil)
return err
}
// AdminCreateUserPublicKey adds a public key for the user
func (c *Client) AdminCreateUserPublicKey(user string, opt CreateKeyOption) (*PublicKey, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, resp, err := c.getResponse("PATCH", fmt.Sprintf("/admin/users/%s", user), jsonHeader, bytes.NewReader(body))
return resp, err
}
// AdminDeleteUser delete one user according name
func (c *Client) AdminDeleteUser(user string) (*Response, error) {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/admin/users/%s", user), nil, nil)
return resp, err
}
// AdminCreateUserPublicKey adds a public key for the user
func (c *Client) AdminCreateUserPublicKey(user string, opt CreateKeyOption) (*PublicKey, *Response, error) {
body, err := json.Marshal(&opt)
if err != nil {
return nil, nil, err
}
key := new(PublicKey) key := new(PublicKey)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/keys", user), jsonHeader, bytes.NewReader(body), key) return key, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/keys", user), jsonHeader, bytes.NewReader(body), key)
return key, resp, err
} }
// AdminDeleteUserPublicKey deletes a user's public key // AdminDeleteUserPublicKey deletes a user's public key
func (c *Client) AdminDeleteUserPublicKey(user string, keyID int) (*Response, error) { func (c *Client) AdminDeleteUserPublicKey(user string, keyID int) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/admin/users/%s/keys/%d", user, keyID), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/admin/users/%s/keys/%d", user, keyID), nil, nil)
return resp, err return err
} }

View File

@ -30,47 +30,47 @@ type ListReleaseAttachmentsOptions struct {
} }
// ListReleaseAttachments list release's attachments // ListReleaseAttachments list release's attachments
func (c *Client) ListReleaseAttachments(user, repo string, release int64, opt ListReleaseAttachmentsOptions) ([]*Attachment, *Response, error) { func (c *Client) ListReleaseAttachments(user, repo string, release int64, opt ListReleaseAttachmentsOptions) ([]*Attachment, error) {
opt.setDefaults() opt.setDefaults()
attachments := make([]*Attachment, 0, opt.PageSize) attachments := make([]*Attachment, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", err := c.getParsedResponse("GET",
fmt.Sprintf("/repos/%s/%s/releases/%d/assets?%s", user, repo, release, opt.getURLQuery().Encode()), fmt.Sprintf("/repos/%s/%s/releases/%d/assets?%s", user, repo, release, opt.getURLQuery().Encode()),
nil, nil, &attachments) nil, nil, &attachments)
return attachments, resp, err return attachments, err
} }
// GetReleaseAttachment returns the requested attachment // GetReleaseAttachment returns the requested attachment
func (c *Client) GetReleaseAttachment(user, repo string, release int64, id int64) (*Attachment, *Response, error) { func (c *Client) GetReleaseAttachment(user, repo string, release int64, id int64) (*Attachment, error) {
a := new(Attachment) a := new(Attachment)
resp, err := c.getParsedResponse("GET", err := c.getParsedResponse("GET",
fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, id), fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, id),
nil, nil, &a) nil, nil, &a)
return a, resp, err return a, err
} }
// CreateReleaseAttachment creates an attachment for the given release // CreateReleaseAttachment creates an attachment for the given release
func (c *Client) CreateReleaseAttachment(user, repo string, release int64, file io.Reader, filename string) (*Attachment, *Response, error) { func (c *Client) CreateReleaseAttachment(user, repo string, release int64, file io.Reader, filename string) (*Attachment, error) {
// Write file to body // Write file to body
body := new(bytes.Buffer) body := new(bytes.Buffer)
writer := multipart.NewWriter(body) writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("attachment", filename) part, err := writer.CreateFormFile("attachment", filename)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
if _, err = io.Copy(part, file); err != nil { if _, err = io.Copy(part, file); err != nil {
return nil, nil, err return nil, err
} }
if err = writer.Close(); err != nil { if err = writer.Close(); err != nil {
return nil, nil, err return nil, err
} }
// Send request // Send request
attachment := new(Attachment) attachment := new(Attachment)
resp, err := c.getParsedResponse("POST", err = c.getParsedResponse("POST",
fmt.Sprintf("/repos/%s/%s/releases/%d/assets", user, repo, release), fmt.Sprintf("/repos/%s/%s/releases/%d/assets", user, repo, release),
http.Header{"Content-Type": {writer.FormDataContentType()}}, body, &attachment) http.Header{"Content-Type": {writer.FormDataContentType()}}, body, &attachment)
return attachment, resp, err return attachment, err
} }
// EditAttachmentOptions options for editing attachments // EditAttachmentOptions options for editing attachments
@ -79,18 +79,17 @@ type EditAttachmentOptions struct {
} }
// EditReleaseAttachment updates the given attachment with the given options // EditReleaseAttachment updates the given attachment with the given options
func (c *Client) EditReleaseAttachment(user, repo string, release int64, attachment int64, form EditAttachmentOptions) (*Attachment, *Response, error) { func (c *Client) EditReleaseAttachment(user, repo string, release int64, attachment int64, form EditAttachmentOptions) (*Attachment, error) {
body, err := json.Marshal(&form) body, err := json.Marshal(&form)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
attach := new(Attachment) attach := new(Attachment)
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, attachment), jsonHeader, bytes.NewReader(body), attach) return attach, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, attachment), jsonHeader, bytes.NewReader(body), attach)
return attach, resp, err
} }
// DeleteReleaseAttachment deletes the given attachment including the uploaded file // DeleteReleaseAttachment deletes the given attachment including the uploaded file
func (c *Client) DeleteReleaseAttachment(user, repo string, release int64, id int64) (*Response, error) { func (c *Client) DeleteReleaseAttachment(user, repo string, release int64, id int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, id), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, id), nil, nil)
return resp, err return err
} }

View File

@ -6,7 +6,6 @@
package gitea package gitea
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -23,7 +22,7 @@ var jsonHeader = http.Header{"content-type": []string{"application/json"}}
// Version return the library version // Version return the library version
func Version() string { func Version() string {
return "0.13.0" return "0.12.0"
} }
// Client represents a Gitea API client. // Client represents a Gitea API client.
@ -35,123 +34,48 @@ type Client struct {
otp string otp string
sudo string sudo string
client *http.Client client *http.Client
ctx context.Context
serverVersion *version.Version serverVersion *version.Version
versionLock sync.RWMutex versionLock sync.RWMutex
} }
// Response represents the gitea response
type Response struct {
*http.Response
}
// NewClient initializes and returns a API client. // NewClient initializes and returns a API client.
func NewClient(url string, options ...func(*Client)) (*Client, error) { func NewClient(url, token string) *Client {
client := &Client{ return &Client{
url: strings.TrimSuffix(url, "/"), url: strings.TrimSuffix(url, "/"),
accessToken: token,
client: &http.Client{}, client: &http.Client{},
ctx: context.Background(),
} }
for _, opt := range options {
opt(client)
}
if err := client.CheckServerVersionConstraint(">=1.10"); err != nil {
return nil, err
}
return client, nil
} }
// NewClientWithHTTP creates an API client with a custom http client // NewClientWithHTTP creates an API client with a custom http client
// Deprecated use SetHTTPClient option
func NewClientWithHTTP(url string, httpClient *http.Client) *Client { func NewClientWithHTTP(url string, httpClient *http.Client) *Client {
client, _ := NewClient(url, SetHTTPClient(httpClient)) client := NewClient(url, "")
client.client = httpClient
return client return client
} }
// SetHTTPClient is an option for NewClient to set custom http client // SetBasicAuth sets basicauth
func SetHTTPClient(httpClient *http.Client) func(client *Client) {
return func(client *Client) {
client.client = httpClient
}
}
// SetToken is an option for NewClient to set token
func SetToken(token string) func(client *Client) {
return func(client *Client) {
client.accessToken = token
}
}
// SetBasicAuth is an option for NewClient to set username and password
func SetBasicAuth(username, password string) func(client *Client) {
return func(client *Client) {
client.SetBasicAuth(username, password)
}
}
// SetBasicAuth sets username and password
func (c *Client) SetBasicAuth(username, password string) { func (c *Client) SetBasicAuth(username, password string) {
c.username, c.password = username, password c.username, c.password = username, password
} }
// SetOTP is an option for NewClient to set OTP for 2FA
func SetOTP(otp string) func(client *Client) {
return func(client *Client) {
client.SetOTP(otp)
}
}
// SetOTP sets OTP for 2FA // SetOTP sets OTP for 2FA
func (c *Client) SetOTP(otp string) { func (c *Client) SetOTP(otp string) {
c.otp = otp c.otp = otp
} }
// SetContext is an option for NewClient to set context
func SetContext(ctx context.Context) func(client *Client) {
return func(client *Client) {
client.SetContext(ctx)
}
}
// SetContext set context witch is used for http requests
func (c *Client) SetContext(ctx context.Context) {
c.ctx = ctx
}
// SetHTTPClient replaces default http.Client with user given one. // SetHTTPClient replaces default http.Client with user given one.
func (c *Client) SetHTTPClient(client *http.Client) { func (c *Client) SetHTTPClient(client *http.Client) {
c.client = client c.client = client
} }
// SetSudo is an option for NewClient to set sudo header
func SetSudo(sudo string) func(client *Client) {
return func(client *Client) {
client.SetSudo(sudo)
}
}
// SetSudo sets username to impersonate. // SetSudo sets username to impersonate.
func (c *Client) SetSudo(sudo string) { func (c *Client) SetSudo(sudo string) {
c.sudo = sudo c.sudo = sudo
} }
func (c *Client) getWebResponse(method, path string, body io.Reader) ([]byte, *Response, error) { func (c *Client) doRequest(method, path string, header http.Header, body io.Reader) (*http.Response, error) {
req, err := http.NewRequestWithContext(c.ctx, method, c.url+path, body) req, err := http.NewRequest(method, c.url+"/api/v1"+path, body)
if err != nil {
return nil, nil, err
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, err
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
return data, &Response{resp}, nil
}
func (c *Client) doRequest(method, path string, header http.Header, body io.Reader) (*Response, error) {
req, err := http.NewRequestWithContext(c.ctx, method, c.url+"/api/v1"+path, body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -171,34 +95,30 @@ func (c *Client) doRequest(method, path string, header http.Header, body io.Read
req.Header[k] = v req.Header[k] = v
} }
resp, err := c.client.Do(req) return c.client.Do(req)
if err != nil {
return nil, err
}
return &Response{resp}, nil
} }
func (c *Client) getResponse(method, path string, header http.Header, body io.Reader) ([]byte, *Response, error) { func (c *Client) getResponse(method, path string, header http.Header, body io.Reader) ([]byte, error) {
resp, err := c.doRequest(method, path, header, body) resp, err := c.doRequest(method, path, header, body)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
defer resp.Body.Close() defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, resp, err return nil, err
} }
switch resp.StatusCode { switch resp.StatusCode {
case 403: case 403:
return data, resp, errors.New("403 Forbidden") return nil, errors.New("403 Forbidden")
case 404: case 404:
return data, resp, errors.New("404 Not Found") return nil, errors.New("404 Not Found")
case 409: case 409:
return data, resp, errors.New("409 Conflict") return nil, errors.New("409 Conflict")
case 422: case 422:
return data, resp, fmt.Errorf("422 Unprocessable Entity: %s", string(data)) return nil, fmt.Errorf("422 Unprocessable Entity: %s", string(data))
} }
if resp.StatusCode/100 != 2 { if resp.StatusCode/100 != 2 {
@ -206,28 +126,28 @@ func (c *Client) getResponse(method, path string, header http.Header, body io.Re
if err = json.Unmarshal(data, &errMap); err != nil { if err = json.Unmarshal(data, &errMap); err != nil {
// when the JSON can't be parsed, data was probably empty or a plain string, // when the JSON can't be parsed, data was probably empty or a plain string,
// so we try to return a helpful error anyway // so we try to return a helpful error anyway
return data, resp, fmt.Errorf("Unknown API Error: %d\nRequest: '%s' with '%s' method '%s' header and '%s' body", resp.StatusCode, path, method, header, string(data)) return nil, fmt.Errorf("Unknown API Error: %d\nRequest: '%s' with '%s' method '%s' header and '%s' body", resp.StatusCode, path, method, header, string(data))
} }
return data, resp, errors.New(errMap["message"].(string)) return nil, errors.New(errMap["message"].(string))
} }
return data, resp, nil return data, nil
} }
func (c *Client) getParsedResponse(method, path string, header http.Header, body io.Reader, obj interface{}) (*Response, error) { func (c *Client) getParsedResponse(method, path string, header http.Header, body io.Reader, obj interface{}) error {
data, resp, err := c.getResponse(method, path, header, body) data, err := c.getResponse(method, path, header, body)
if err != nil { if err != nil {
return nil, err return err
} }
return resp, json.Unmarshal(data, obj) return json.Unmarshal(data, obj)
} }
func (c *Client) getStatusCode(method, path string, header http.Header, body io.Reader) (int, *Response, error) { func (c *Client) getStatusCode(method, path string, header http.Header, body io.Reader) (int, error) {
resp, err := c.doRequest(method, path, header, body) resp, err := c.doRequest(method, path, header, body)
if err != nil { if err != nil {
return -1, resp, err return -1, err
} }
defer resp.Body.Close() defer resp.Body.Close()
return resp.StatusCode, resp, nil return resp.StatusCode, nil
} }

View File

@ -16,13 +16,12 @@ type ListForksOptions struct {
} }
// ListForks list a repository's forks // ListForks list a repository's forks
func (c *Client) ListForks(user string, repo string, opt ListForksOptions) ([]*Repository, *Response, error) { func (c *Client) ListForks(user string, repo string, opt ListForksOptions) ([]*Repository, error) {
opt.setDefaults() opt.setDefaults()
forks := make([]*Repository, opt.PageSize) forks := make([]*Repository, opt.PageSize)
resp, err := c.getParsedResponse("GET", return forks, c.getParsedResponse("GET",
fmt.Sprintf("/repos/%s/%s/forks?%s", user, repo, opt.getURLQuery().Encode()), fmt.Sprintf("/repos/%s/%s/forks?%s", user, repo, opt.getURLQuery().Encode()),
nil, nil, &forks) nil, nil, &forks)
return forks, resp, err
} }
// CreateForkOption options for creating a fork // CreateForkOption options for creating a fork
@ -32,12 +31,11 @@ type CreateForkOption struct {
} }
// CreateFork create a fork of a repository // CreateFork create a fork of a repository
func (c *Client) CreateFork(user, repo string, form CreateForkOption) (*Repository, *Response, error) { func (c *Client) CreateFork(user, repo string, form CreateForkOption) (*Repository, error) {
body, err := json.Marshal(form) body, err := json.Marshal(form)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
fork := new(Repository) fork := new(Repository)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/forks", user, repo), jsonHeader, bytes.NewReader(body), &fork) return fork, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/forks", user, repo), jsonHeader, bytes.NewReader(body), &fork)
return fork, resp, err
} }

View File

@ -18,8 +18,7 @@ type GitBlobResponse struct {
} }
// GetBlob get the blob of a repository file // GetBlob get the blob of a repository file
func (c *Client) GetBlob(user, repo, sha string) (*GitBlobResponse, *Response, error) { func (c *Client) GetBlob(user, repo, sha string) (*GitBlobResponse, error) {
blob := new(GitBlobResponse) blob := new(GitBlobResponse)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/blobs/%s", user, repo, sha), nil, nil, blob) return blob, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/blobs/%s", user, repo, sha), nil, nil, blob)
return blob, resp, err
} }

View File

@ -23,18 +23,16 @@ type ListRepoGitHooksOptions struct {
} }
// ListRepoGitHooks list all the Git hooks of one repository // ListRepoGitHooks list all the Git hooks of one repository
func (c *Client) ListRepoGitHooks(user, repo string, opt ListRepoGitHooksOptions) ([]*GitHook, *Response, error) { func (c *Client) ListRepoGitHooks(user, repo string, opt ListRepoGitHooksOptions) ([]*GitHook, error) {
opt.setDefaults() opt.setDefaults()
hooks := make([]*GitHook, 0, opt.PageSize) hooks := make([]*GitHook, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/git?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &hooks) return hooks, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/git?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &hooks)
return hooks, resp, err
} }
// GetRepoGitHook get a Git hook of a repository // GetRepoGitHook get a Git hook of a repository
func (c *Client) GetRepoGitHook(user, repo, id string) (*GitHook, *Response, error) { func (c *Client) GetRepoGitHook(user, repo, id string) (*GitHook, error) {
h := new(GitHook) h := new(GitHook)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/git/%s", user, repo, id), nil, nil, h) return h, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/git/%s", user, repo, id), nil, nil, h)
return h, resp, err
} }
// EditGitHookOption options when modifying one Git hook // EditGitHookOption options when modifying one Git hook
@ -43,17 +41,17 @@ type EditGitHookOption struct {
} }
// EditRepoGitHook modify one Git hook of a repository // EditRepoGitHook modify one Git hook of a repository
func (c *Client) EditRepoGitHook(user, repo, id string, opt EditGitHookOption) (*Response, error) { func (c *Client) EditRepoGitHook(user, repo, id string, opt EditGitHookOption) error {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/hooks/git/%s", user, repo, id), jsonHeader, bytes.NewReader(body)) _, err = c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/hooks/git/%s", user, repo, id), jsonHeader, bytes.NewReader(body))
return resp, err return err
} }
// DeleteRepoGitHook delete one Git hook from a repository // DeleteRepoGitHook delete one Git hook from a repository
func (c *Client) DeleteRepoGitHook(user, repo, id string) (*Response, error) { func (c *Client) DeleteRepoGitHook(user, repo, id string) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/git/%s", user, repo, id), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/git/%s", user, repo, id), nil, nil)
return resp, err return err
} }

View File

@ -30,33 +30,29 @@ type ListHooksOptions struct {
} }
// ListOrgHooks list all the hooks of one organization // ListOrgHooks list all the hooks of one organization
func (c *Client) ListOrgHooks(org string, opt ListHooksOptions) ([]*Hook, *Response, error) { func (c *Client) ListOrgHooks(org string, opt ListHooksOptions) ([]*Hook, error) {
opt.setDefaults() opt.setDefaults()
hooks := make([]*Hook, 0, opt.PageSize) hooks := make([]*Hook, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/hooks?%s", org, opt.getURLQuery().Encode()), nil, nil, &hooks) return hooks, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/hooks?%s", org, opt.getURLQuery().Encode()), nil, nil, &hooks)
return hooks, resp, err
} }
// ListRepoHooks list all the hooks of one repository // ListRepoHooks list all the hooks of one repository
func (c *Client) ListRepoHooks(user, repo string, opt ListHooksOptions) ([]*Hook, *Response, error) { func (c *Client) ListRepoHooks(user, repo string, opt ListHooksOptions) ([]*Hook, error) {
opt.setDefaults() opt.setDefaults()
hooks := make([]*Hook, 0, opt.PageSize) hooks := make([]*Hook, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &hooks) return hooks, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &hooks)
return hooks, resp, err
} }
// GetOrgHook get a hook of an organization // GetOrgHook get a hook of an organization
func (c *Client) GetOrgHook(org string, id int64) (*Hook, *Response, error) { func (c *Client) GetOrgHook(org string, id int64) (*Hook, error) {
h := new(Hook) h := new(Hook)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), nil, nil, h) return h, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), nil, nil, h)
return h, resp, err
} }
// GetRepoHook get a hook of a repository // GetRepoHook get a hook of a repository
func (c *Client) GetRepoHook(user, repo string, id int64) (*Hook, *Response, error) { func (c *Client) GetRepoHook(user, repo string, id int64) (*Hook, error) {
h := new(Hook) h := new(Hook)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil, h) return h, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil, h)
return h, resp, err
} }
// CreateHookOption options when create a hook // CreateHookOption options when create a hook
@ -68,37 +64,24 @@ type CreateHookOption struct {
Active bool `json:"active"` Active bool `json:"active"`
} }
// Validate the CreateHookOption struct
func (opt CreateHookOption) Validate() error {
if len(opt.Type) == 0 {
return fmt.Errorf("hook type needed")
}
return nil
}
// CreateOrgHook create one hook for an organization, with options // CreateOrgHook create one hook for an organization, with options
func (c *Client) CreateOrgHook(org string, opt CreateHookOption) (*Hook, *Response, error) { func (c *Client) CreateOrgHook(org string, opt CreateHookOption) (*Hook, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
h := new(Hook) h := new(Hook)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/orgs/%s/hooks", org), jsonHeader, bytes.NewReader(body), h) return h, c.getParsedResponse("POST", fmt.Sprintf("/orgs/%s/hooks", org), jsonHeader, bytes.NewReader(body), h)
return h, resp, err
} }
// CreateRepoHook create one hook for a repository, with options // CreateRepoHook create one hook for a repository, with options
func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook, *Response, error) { func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
h := new(Hook) h := new(Hook)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), jsonHeader, bytes.NewReader(body), h) return h, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), jsonHeader, bytes.NewReader(body), h)
return h, resp, err
} }
// EditHookOption options when modify one hook // EditHookOption options when modify one hook
@ -110,33 +93,33 @@ type EditHookOption struct {
} }
// EditOrgHook modify one hook of an organization, with hook id and options // EditOrgHook modify one hook of an organization, with hook id and options
func (c *Client) EditOrgHook(org string, id int64, opt EditHookOption) (*Response, error) { func (c *Client) EditOrgHook(org string, id int64, opt EditHookOption) error {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("PATCH", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), jsonHeader, bytes.NewReader(body)) _, err = c.getResponse("PATCH", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), jsonHeader, bytes.NewReader(body))
return resp, err return err
} }
// EditRepoHook modify one hook of a repository, with hook id and options // EditRepoHook modify one hook of a repository, with hook id and options
func (c *Client) EditRepoHook(user, repo string, id int64, opt EditHookOption) (*Response, error) { func (c *Client) EditRepoHook(user, repo string, id int64, opt EditHookOption) error {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), jsonHeader, bytes.NewReader(body)) _, err = c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), jsonHeader, bytes.NewReader(body))
return resp, err return err
} }
// DeleteOrgHook delete one hook from an organization, with hook id // DeleteOrgHook delete one hook from an organization, with hook id
func (c *Client) DeleteOrgHook(org string, id int64) (*Response, error) { func (c *Client) DeleteOrgHook(org string, id int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s/hooks/%d", org, id), nil, nil)
return resp, err return err
} }
// DeleteRepoHook delete one hook from a repository, with hook id // DeleteRepoHook delete one hook from a repository, with hook id
func (c *Client) DeleteRepoHook(user, repo string, id int64) (*Response, error) { func (c *Client) DeleteRepoHook(user, repo string, id int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil)
return resp, err return err
} }

View File

@ -44,7 +44,6 @@ type Issue struct {
Assignees []*User `json:"assignees"` Assignees []*User `json:"assignees"`
// Whether the issue is open or closed // Whether the issue is open or closed
State StateType `json:"state"` State StateType `json:"state"`
IsLocked bool `json:"is_locked"`
Comments int `json:"comments"` Comments int `json:"comments"`
Created time.Time `json:"created_at"` Created time.Time `json:"created_at"`
Updated time.Time `json:"updated_at"` Updated time.Time `json:"updated_at"`
@ -114,13 +113,13 @@ func (opt *ListIssueOption) QueryEncode() string {
} }
// ListIssues returns all issues assigned the authenticated user // ListIssues returns all issues assigned the authenticated user
func (c *Client) ListIssues(opt ListIssueOption) ([]*Issue, *Response, error) { func (c *Client) ListIssues(opt ListIssueOption) ([]*Issue, error) {
opt.setDefaults() opt.setDefaults()
issues := make([]*Issue, 0, opt.PageSize) issues := make([]*Issue, 0, opt.PageSize)
link, _ := url.Parse("/repos/issues/search") link, _ := url.Parse("/repos/issues/search")
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &issues) err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &issues)
if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil { if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil {
for i := 0; i < len(issues); i++ { for i := 0; i < len(issues); i++ {
if issues[i].Repository != nil { if issues[i].Repository != nil {
@ -128,17 +127,17 @@ func (c *Client) ListIssues(opt ListIssueOption) ([]*Issue, *Response, error) {
} }
} }
} }
return issues, resp, err return issues, err
} }
// ListRepoIssues returns all issues for a given repository // ListRepoIssues returns all issues for a given repository
func (c *Client) ListRepoIssues(owner, repo string, opt ListIssueOption) ([]*Issue, *Response, error) { func (c *Client) ListRepoIssues(owner, repo string, opt ListIssueOption) ([]*Issue, error) {
opt.setDefaults() opt.setDefaults()
issues := make([]*Issue, 0, opt.PageSize) issues := make([]*Issue, 0, opt.PageSize)
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues", owner, repo)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues", owner, repo))
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &issues) err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &issues)
if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil { if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil {
for i := 0; i < len(issues); i++ { for i := 0; i < len(issues); i++ {
if issues[i].Repository != nil { if issues[i].Repository != nil {
@ -146,17 +145,17 @@ func (c *Client) ListRepoIssues(owner, repo string, opt ListIssueOption) ([]*Iss
} }
} }
} }
return issues, resp, err return issues, err
} }
// GetIssue returns a single issue for a given repository // GetIssue returns a single issue for a given repository
func (c *Client) GetIssue(owner, repo string, index int64) (*Issue, *Response, error) { func (c *Client) GetIssue(owner, repo string, index int64) (*Issue, error) {
issue := new(Issue) issue := new(Issue)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index), nil, nil, issue) err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index), nil, nil, issue)
if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil && issue.Repository != nil { if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil && issue.Repository != nil {
issue.Repository.Owner = strings.Split(issue.Repository.FullName, "/")[0] issue.Repository.Owner = strings.Split(issue.Repository.FullName, "/")[0]
} }
return issue, resp, err return issue, err
} }
// CreateIssueOption options to create one issue // CreateIssueOption options to create one issue
@ -174,27 +173,15 @@ type CreateIssueOption struct {
Closed bool `json:"closed"` Closed bool `json:"closed"`
} }
// Validate the CreateIssueOption struct
func (opt CreateIssueOption) Validate() error {
if len(strings.TrimSpace(opt.Title)) == 0 {
return fmt.Errorf("title is empty")
}
return nil
}
// CreateIssue create a new issue for a given repository // CreateIssue create a new issue for a given repository
func (c *Client) CreateIssue(owner, repo string, opt CreateIssueOption) (*Issue, *Response, error) { func (c *Client) CreateIssue(owner, repo string, opt CreateIssueOption) (*Issue, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
issue := new(Issue) issue := new(Issue)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues", owner, repo), return issue, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues", owner, repo),
jsonHeader, bytes.NewReader(body), issue) jsonHeader, bytes.NewReader(body), issue)
return issue, resp, err
} }
// EditIssueOption options for editing an issue // EditIssueOption options for editing an issue
@ -208,26 +195,13 @@ type EditIssueOption struct {
Deadline *time.Time `json:"due_date"` Deadline *time.Time `json:"due_date"`
} }
// Validate the EditIssueOption struct
func (opt EditIssueOption) Validate() error {
if len(opt.Title) != 0 && len(strings.TrimSpace(opt.Title)) == 0 {
return fmt.Errorf("title is empty")
}
return nil
}
// EditIssue modify an existing issue for a given repository // EditIssue modify an existing issue for a given repository
func (c *Client) EditIssue(owner, repo string, index int64, opt EditIssueOption) (*Issue, *Response, error) { func (c *Client) EditIssue(owner, repo string, index int64, opt EditIssueOption) (*Issue, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
issue := new(Issue) issue := new(Issue)
resp, err := c.getParsedResponse("PATCH", return issue, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index),
fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index),
jsonHeader, bytes.NewReader(body), issue) jsonHeader, bytes.NewReader(body), issue)
return issue, resp, err
} }

View File

@ -46,33 +46,30 @@ func (opt *ListIssueCommentOptions) QueryEncode() string {
} }
// ListIssueComments list comments on an issue. // ListIssueComments list comments on an issue.
func (c *Client) ListIssueComments(owner, repo string, index int64, opt ListIssueCommentOptions) ([]*Comment, *Response, error) { func (c *Client) ListIssueComments(owner, repo string, index int64, opt ListIssueCommentOptions) ([]*Comment, error) {
opt.setDefaults() opt.setDefaults()
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues/%d/comments", owner, repo, index)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues/%d/comments", owner, repo, index))
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
comments := make([]*Comment, 0, opt.PageSize) comments := make([]*Comment, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &comments) return comments, c.getParsedResponse("GET", link.String(), nil, nil, &comments)
return comments, resp, err
} }
// ListRepoIssueComments list comments for a given repo. // ListRepoIssueComments list comments for a given repo.
func (c *Client) ListRepoIssueComments(owner, repo string, opt ListIssueCommentOptions) ([]*Comment, *Response, error) { func (c *Client) ListRepoIssueComments(owner, repo string, opt ListIssueCommentOptions) ([]*Comment, error) {
opt.setDefaults() opt.setDefaults()
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues/comments", owner, repo)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues/comments", owner, repo))
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
comments := make([]*Comment, 0, opt.PageSize) comments := make([]*Comment, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &comments) return comments, c.getParsedResponse("GET", link.String(), nil, nil, &comments)
return comments, resp, err
} }
// GetIssueComment get a comment for a given repo by id. // GetIssueComment get a comment for a given repo by id.
func (c *Client) GetIssueComment(owner, repo string, id int64) (*Comment, *Response, error) { func (c *Client) GetIssueComment(owner, repo string, id int64) (*Comment, error) {
comment := new(Comment) comment := new(Comment)
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return comment, nil, err return comment, err
} }
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/comments/%d", owner, repo, id), nil, nil, &comment) return comment, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/comments/%d", owner, repo, id), nil, nil, &comment)
return comment, resp, err
} }
// CreateIssueCommentOption options for creating a comment on an issue // CreateIssueCommentOption options for creating a comment on an issue
@ -80,26 +77,14 @@ type CreateIssueCommentOption struct {
Body string `json:"body"` Body string `json:"body"`
} }
// Validate the CreateIssueCommentOption struct
func (opt CreateIssueCommentOption) Validate() error {
if len(opt.Body) == 0 {
return fmt.Errorf("body is empty")
}
return nil
}
// CreateIssueComment create comment on an issue. // CreateIssueComment create comment on an issue.
func (c *Client) CreateIssueComment(owner, repo string, index int64, opt CreateIssueCommentOption) (*Comment, *Response, error) { func (c *Client) CreateIssueComment(owner, repo string, index int64, opt CreateIssueCommentOption) (*Comment, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
comment := new(Comment) comment := new(Comment)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/comments", owner, repo, index), jsonHeader, bytes.NewReader(body), comment) return comment, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/comments", owner, repo, index), jsonHeader, bytes.NewReader(body), comment)
return comment, resp, err
} }
// EditIssueCommentOption options for editing a comment // EditIssueCommentOption options for editing a comment
@ -107,30 +92,18 @@ type EditIssueCommentOption struct {
Body string `json:"body"` Body string `json:"body"`
} }
// Validate the EditIssueCommentOption struct
func (opt EditIssueCommentOption) Validate() error {
if len(opt.Body) == 0 {
return fmt.Errorf("body is empty")
}
return nil
}
// EditIssueComment edits an issue comment. // EditIssueComment edits an issue comment.
func (c *Client) EditIssueComment(owner, repo string, commentID int64, opt EditIssueCommentOption) (*Comment, *Response, error) { func (c *Client) EditIssueComment(owner, repo string, commentID int64, opt EditIssueCommentOption) (*Comment, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
comment := new(Comment) comment := new(Comment)
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/issues/comments/%d", owner, repo, commentID), jsonHeader, bytes.NewReader(body), comment) return comment, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/issues/comments/%d", owner, repo, commentID), jsonHeader, bytes.NewReader(body), comment)
return comment, resp, err
} }
// DeleteIssueComment deletes an issue comment. // DeleteIssueComment deletes an issue comment.
func (c *Client) DeleteIssueComment(owner, repo string, commentID int64) (*Response, error) { func (c *Client) DeleteIssueComment(owner, repo string, commentID int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/comments/%d", owner, repo, commentID), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/comments/%d", owner, repo, commentID), nil, nil)
return resp, err return err
} }

View File

@ -8,8 +8,6 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"regexp"
"strings"
) )
// Label a label to an issue or a pr // Label a label to an issue or a pr
@ -28,18 +26,17 @@ type ListLabelsOptions struct {
} }
// ListRepoLabels list labels of one repository // ListRepoLabels list labels of one repository
func (c *Client) ListRepoLabels(owner, repo string, opt ListLabelsOptions) ([]*Label, *Response, error) { func (c *Client) ListRepoLabels(owner, repo string, opt ListLabelsOptions) ([]*Label, error) {
opt.setDefaults() opt.setDefaults()
labels := make([]*Label, 0, opt.PageSize) labels := make([]*Label, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels?%s", owner, repo, opt.getURLQuery().Encode()), nil, nil, &labels) return labels, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels?%s", owner, repo, opt.getURLQuery().Encode()), nil, nil, &labels)
return labels, resp, err
} }
// GetRepoLabel get one label of repository by repo it // GetRepoLabel get one label of repository by repo it
func (c *Client) GetRepoLabel(owner, repo string, id int64) (*Label, *Response, error) { // TODO: maybe we need get a label by name
func (c *Client) GetRepoLabel(owner, repo string, id int64) (*Label, error) {
label := new(Label) label := new(Label)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil, label) return label, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil, label)
return label, resp, err
} }
// CreateLabelOption options for creating a label // CreateLabelOption options for creating a label
@ -50,26 +47,8 @@ type CreateLabelOption struct {
Description string `json:"description"` Description string `json:"description"`
} }
// Validate the CreateLabelOption struct
func (opt CreateLabelOption) Validate() error {
aw, err := regexp.MatchString("^#?[0-9,a-f,A-F]{6}$", opt.Color)
if err != nil {
return err
}
if !aw {
return fmt.Errorf("invalid color format")
}
if len(strings.TrimSpace(opt.Name)) == 0 {
return fmt.Errorf("empty name not allowed")
}
return nil
}
// CreateLabel create one label of repository // CreateLabel create one label of repository
func (c *Client) CreateLabel(owner, repo string, opt CreateLabelOption) (*Label, *Response, error) { func (c *Client) CreateLabel(owner, repo string, opt CreateLabelOption) (*Label, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
if len(opt.Color) == 6 { if len(opt.Color) == 6 {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
opt.Color = "#" + opt.Color opt.Color = "#" + opt.Color
@ -77,13 +56,11 @@ func (c *Client) CreateLabel(owner, repo string, opt CreateLabelOption) (*Label,
} }
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
label := new(Label) label := new(Label)
resp, err := c.getParsedResponse("POST", return label, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/labels", owner, repo),
fmt.Sprintf("/repos/%s/%s/labels", owner, repo),
jsonHeader, bytes.NewReader(body), label) jsonHeader, bytes.NewReader(body), label)
return label, resp, err
} }
// EditLabelOption options for editing a label // EditLabelOption options for editing a label
@ -93,50 +70,27 @@ type EditLabelOption struct {
Description *string `json:"description"` Description *string `json:"description"`
} }
// Validate the EditLabelOption struct
func (opt EditLabelOption) Validate() error {
if opt.Color != nil {
aw, err := regexp.MatchString("^#?[0-9,a-f,A-F]{6}$", *opt.Color)
if err != nil {
return err
}
if !aw {
return fmt.Errorf("invalid color format")
}
}
if opt.Name != nil {
if len(strings.TrimSpace(*opt.Name)) == 0 {
return fmt.Errorf("empty name not allowed")
}
}
return nil
}
// EditLabel modify one label with options // EditLabel modify one label with options
func (c *Client) EditLabel(owner, repo string, id int64, opt EditLabelOption) (*Label, *Response, error) { func (c *Client) EditLabel(owner, repo string, id int64, opt EditLabelOption) (*Label, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
label := new(Label) label := new(Label)
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), label) return label, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), label)
return label, resp, err
} }
// DeleteLabel delete one label of repository by id // DeleteLabel delete one label of repository by id
func (c *Client) DeleteLabel(owner, repo string, id int64) (*Response, error) { // TODO: maybe we need delete by name
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil) func (c *Client) DeleteLabel(owner, repo string, id int64) error {
return resp, err _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil)
return err
} }
// GetIssueLabels get labels of one issue via issue id // GetIssueLabels get labels of one issue via issue id
func (c *Client) GetIssueLabels(owner, repo string, index int64, opts ListLabelsOptions) ([]*Label, *Response, error) { func (c *Client) GetIssueLabels(owner, repo string, index int64, opts ListLabelsOptions) ([]*Label, error) {
labels := make([]*Label, 0, 5) labels := make([]*Label, 0, 5)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/labels?%s", owner, repo, index, opts.getURLQuery().Encode()), nil, nil, &labels) return labels, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/labels?%s", owner, repo, index, opts.getURLQuery().Encode()), nil, nil, &labels)
return labels, resp, err
} }
// IssueLabelsOption a collection of labels // IssueLabelsOption a collection of labels
@ -146,36 +100,34 @@ type IssueLabelsOption struct {
} }
// AddIssueLabels add one or more labels to one issue // AddIssueLabels add one or more labels to one issue
func (c *Client) AddIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, *Response, error) { func (c *Client) AddIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
var labels []*Label var labels []*Label
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), jsonHeader, bytes.NewReader(body), &labels) return labels, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), jsonHeader, bytes.NewReader(body), &labels)
return labels, resp, err
} }
// ReplaceIssueLabels replace old labels of issue with new labels // ReplaceIssueLabels replace old labels of issue with new labels
func (c *Client) ReplaceIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, *Response, error) { func (c *Client) ReplaceIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
var labels []*Label var labels []*Label
resp, err := c.getParsedResponse("PUT", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), jsonHeader, bytes.NewReader(body), &labels) return labels, c.getParsedResponse("PUT", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), jsonHeader, bytes.NewReader(body), &labels)
return labels, resp, err
} }
// DeleteIssueLabel delete one label of one issue by issue id and label id // DeleteIssueLabel delete one label of one issue by issue id and label id
// TODO: maybe we need delete by label name and issue id // TODO: maybe we need delete by label name and issue id
func (c *Client) DeleteIssueLabel(owner, repo string, index, label int64) (*Response, error) { func (c *Client) DeleteIssueLabel(owner, repo string, index, label int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels/%d", owner, repo, index, label), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels/%d", owner, repo, index, label), nil, nil)
return resp, err return err
} }
// ClearIssueLabels delete all the labels of one issue. // ClearIssueLabels delete all the labels of one issue.
func (c *Client) ClearIssueLabels(owner, repo string, index int64) (*Response, error) { func (c *Client) ClearIssueLabels(owner, repo string, index int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), nil, nil)
return resp, err return err
} }

View File

@ -9,7 +9,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"strings"
"time" "time"
) )
@ -21,8 +20,6 @@ type Milestone struct {
State StateType `json:"state"` State StateType `json:"state"`
OpenIssues int `json:"open_issues"` OpenIssues int `json:"open_issues"`
ClosedIssues int `json:"closed_issues"` ClosedIssues int `json:"closed_issues"`
Created time.Time `json:"created_at"`
Updated *time.Time `json:"updated_at"`
Closed *time.Time `json:"closed_at"` Closed *time.Time `json:"closed_at"`
Deadline *time.Time `json:"due_on"` Deadline *time.Time `json:"due_on"`
} }
@ -32,7 +29,6 @@ type ListMilestoneOption struct {
ListOptions ListOptions
// open, closed, all // open, closed, all
State StateType State StateType
Name string
} }
// QueryEncode turns options into querystring argument // QueryEncode turns options into querystring argument
@ -41,40 +37,23 @@ func (opt *ListMilestoneOption) QueryEncode() string {
if opt.State != "" { if opt.State != "" {
query.Add("state", string(opt.State)) query.Add("state", string(opt.State))
} }
if len(opt.Name) != 0 {
query.Add("name", opt.Name)
}
return query.Encode() return query.Encode()
} }
// ListRepoMilestones list all the milestones of one repository // ListRepoMilestones list all the milestones of one repository
func (c *Client) ListRepoMilestones(owner, repo string, opt ListMilestoneOption) ([]*Milestone, *Response, error) { func (c *Client) ListRepoMilestones(owner, repo string, opt ListMilestoneOption) ([]*Milestone, error) {
opt.setDefaults() opt.setDefaults()
milestones := make([]*Milestone, 0, opt.PageSize) milestones := make([]*Milestone, 0, opt.PageSize)
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/milestones", owner, repo)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/milestones", owner, repo))
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &milestones) return milestones, c.getParsedResponse("GET", link.String(), nil, nil, &milestones)
return milestones, resp, err
} }
// GetMilestone get one milestone by repo name and milestone id // GetMilestone get one milestone by repo name and milestone id
func (c *Client) GetMilestone(owner, repo string, id int64) (*Milestone, *Response, error) { func (c *Client) GetMilestone(owner, repo string, id int64) (*Milestone, error) {
milestone := new(Milestone) milestone := new(Milestone)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil, milestone) return milestone, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil, milestone)
return milestone, resp, err
}
// GetMilestoneByName get one milestone by repo and milestone name
func (c *Client) GetMilestoneByName(owner, repo string, name string) (*Milestone, *Response, error) {
if c.CheckServerVersionConstraint(">=1.13") != nil {
// backwards compatibility mode
m, resp, err := c.resolveMilestoneByName(owner, repo, name)
return m, resp, err
}
milestone := new(Milestone)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/milestones/%s", owner, repo, name), nil, nil, milestone)
return milestone, resp, err
} }
// CreateMilestoneOption options for creating a milestone // CreateMilestoneOption options for creating a milestone
@ -85,129 +64,47 @@ type CreateMilestoneOption struct {
Deadline *time.Time `json:"due_on"` Deadline *time.Time `json:"due_on"`
} }
// Validate the CreateMilestoneOption struct
func (opt CreateMilestoneOption) Validate() error {
if len(strings.TrimSpace(opt.Title)) == 0 {
return fmt.Errorf("title is empty")
}
return nil
}
// CreateMilestone create one milestone with options // CreateMilestone create one milestone with options
func (c *Client) CreateMilestone(owner, repo string, opt CreateMilestoneOption) (*Milestone, *Response, error) { func (c *Client) CreateMilestone(owner, repo string, opt CreateMilestoneOption) (*Milestone, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
milestone := new(Milestone) milestone := new(Milestone)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/milestones", owner, repo), jsonHeader, bytes.NewReader(body), milestone) err = c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/milestones", owner, repo), jsonHeader, bytes.NewReader(body), milestone)
// make creating closed milestones need gitea >= v1.13.0 // make creating closed milestones need gitea >= v1.13.0
// this make it backwards compatible // this make it backwards compatible
if err == nil && opt.State == StateClosed && milestone.State != StateClosed { if err == nil && opt.State == StateClosed && milestone.State != StateClosed {
closed := StateClosed closed := "closed"
return c.EditMilestone(owner, repo, milestone.ID, EditMilestoneOption{ return c.EditMilestone(owner, repo, milestone.ID, EditMilestoneOption{
State: &closed, State: &closed,
}) })
} }
return milestone, resp, err return milestone, err
} }
// EditMilestoneOption options for editing a milestone // EditMilestoneOption options for editing a milestone
type EditMilestoneOption struct { type EditMilestoneOption struct {
Title string `json:"title"` Title string `json:"title"`
Description *string `json:"description"` Description *string `json:"description"`
State *StateType `json:"state"` State *string `json:"state"`
Deadline *time.Time `json:"due_on"` Deadline *time.Time `json:"due_on"`
} }
// Validate the EditMilestoneOption struct
func (opt EditMilestoneOption) Validate() error {
if len(opt.Title) != 0 && len(strings.TrimSpace(opt.Title)) == 0 {
return fmt.Errorf("title is empty")
}
return nil
}
// EditMilestone modify milestone with options // EditMilestone modify milestone with options
func (c *Client) EditMilestone(owner, repo string, id int64, opt EditMilestoneOption) (*Milestone, *Response, error) { func (c *Client) EditMilestone(owner, repo string, id int64, opt EditMilestoneOption) (*Milestone, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil {
return nil, nil, err
}
milestone := new(Milestone)
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), milestone)
return milestone, resp, err
}
// EditMilestoneByName modify milestone with options
func (c *Client) EditMilestoneByName(owner, repo string, name string, opt EditMilestoneOption) (*Milestone, *Response, error) {
if c.CheckServerVersionConstraint(">=1.13") != nil {
// backwards compatibility mode
m, _, err := c.resolveMilestoneByName(owner, repo, name)
if err != nil {
return nil, nil, err
}
return c.EditMilestone(owner, repo, m.ID, opt)
}
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt)
if err != nil {
return nil, nil, err
}
milestone := new(Milestone)
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/milestones/%s", owner, repo, name), jsonHeader, bytes.NewReader(body), milestone)
return milestone, resp, err
}
// DeleteMilestone delete one milestone by id
func (c *Client) DeleteMilestone(owner, repo string, id int64) (*Response, error) {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil)
return resp, err
}
// DeleteMilestoneByName delete one milestone by name
func (c *Client) DeleteMilestoneByName(owner, repo string, name string) (*Response, error) {
if c.CheckServerVersionConstraint(">=1.13") != nil {
// backwards compatibility mode
m, _, err := c.resolveMilestoneByName(owner, repo, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return c.DeleteMilestone(owner, repo, m.ID) milestone := new(Milestone)
} return milestone, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), milestone)
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/milestones/%s", owner, repo, name), nil, nil)
return resp, err
} }
// resolveMilestoneByName is a fallback method to find milestone id by name // DeleteMilestone delete one milestone by milestone id
func (c *Client) resolveMilestoneByName(owner, repo, name string) (*Milestone, *Response, error) { func (c *Client) DeleteMilestone(owner, repo string, id int64) error {
for i := 1; ; i++ { _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil)
miles, resp, err := c.ListRepoMilestones(owner, repo, ListMilestoneOption{ return err
ListOptions: ListOptions{
Page: i,
},
State: "all",
})
if err != nil {
return nil, nil, err
}
if len(miles) == 0 {
return nil, nil, fmt.Errorf("milestone '%s' do not exist", name)
}
for _, m := range miles {
if strings.ToLower(strings.TrimSpace(m.Title)) == strings.ToLower(strings.TrimSpace(name)) {
return m, resp, nil
}
}
}
} }

View File

@ -19,23 +19,21 @@ type Reaction struct {
} }
// GetIssueReactions get a list reactions of an issue // GetIssueReactions get a list reactions of an issue
func (c *Client) GetIssueReactions(owner, repo string, index int64) ([]*Reaction, *Response, error) { func (c *Client) GetIssueReactions(owner, repo string, index int64) ([]*Reaction, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err return nil, err
} }
reactions := make([]*Reaction, 0, 10) reactions := make([]*Reaction, 0, 10)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/reactions", owner, repo, index), nil, nil, &reactions) return reactions, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/reactions", owner, repo, index), nil, nil, &reactions)
return reactions, resp, err
} }
// GetIssueCommentReactions get a list of reactions from a comment of an issue // GetIssueCommentReactions get a list of reactions from a comment of an issue
func (c *Client) GetIssueCommentReactions(owner, repo string, commentID int64) ([]*Reaction, *Response, error) { func (c *Client) GetIssueCommentReactions(owner, repo string, commentID int64) ([]*Reaction, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err return nil, err
} }
reactions := make([]*Reaction, 0, 10) reactions := make([]*Reaction, 0, 10)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/comments/%d/reactions", owner, repo, commentID), nil, nil, &reactions) return reactions, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/comments/%d/reactions", owner, repo, commentID), nil, nil, &reactions)
return reactions, resp, err
} }
// editReactionOption contain the reaction type // editReactionOption contain the reaction type
@ -44,61 +42,57 @@ type editReactionOption struct {
} }
// PostIssueReaction add a reaction to an issue // PostIssueReaction add a reaction to an issue
func (c *Client) PostIssueReaction(owner, repo string, index int64, reaction string) (*Reaction, *Response, error) { func (c *Client) PostIssueReaction(owner, repo string, index int64, reaction string) (*Reaction, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err return nil, err
} }
reactionResponse := new(Reaction) reactionResponse := new(Reaction)
body, err := json.Marshal(&editReactionOption{Reaction: reaction}) body, err := json.Marshal(&editReactionOption{Reaction: reaction})
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
resp, err := c.getParsedResponse("POST", return reactionResponse, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/reactions", owner, repo, index),
fmt.Sprintf("/repos/%s/%s/issues/%d/reactions", owner, repo, index),
jsonHeader, bytes.NewReader(body), reactionResponse) jsonHeader, bytes.NewReader(body), reactionResponse)
return reactionResponse, resp, err
} }
// DeleteIssueReaction remove a reaction from an issue // DeleteIssueReaction remove a reaction from an issue
func (c *Client) DeleteIssueReaction(owner, repo string, index int64, reaction string) (*Response, error) { func (c *Client) DeleteIssueReaction(owner, repo string, index int64, reaction string) error {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, err return err
} }
body, err := json.Marshal(&editReactionOption{Reaction: reaction}) body, err := json.Marshal(&editReactionOption{Reaction: reaction})
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/reactions", owner, repo, index), jsonHeader, bytes.NewReader(body)) _, err = c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/reactions", owner, repo, index), jsonHeader, bytes.NewReader(body))
return resp, err return err
} }
// PostIssueCommentReaction add a reaction to a comment of an issue // PostIssueCommentReaction add a reaction to a comment of an issue
func (c *Client) PostIssueCommentReaction(owner, repo string, commentID int64, reaction string) (*Reaction, *Response, error) { func (c *Client) PostIssueCommentReaction(owner, repo string, commentID int64, reaction string) (*Reaction, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err return nil, err
} }
reactionResponse := new(Reaction) reactionResponse := new(Reaction)
body, err := json.Marshal(&editReactionOption{Reaction: reaction}) body, err := json.Marshal(&editReactionOption{Reaction: reaction})
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
resp, err := c.getParsedResponse("POST", return reactionResponse, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/comments/%d/reactions", owner, repo, commentID),
fmt.Sprintf("/repos/%s/%s/issues/comments/%d/reactions", owner, repo, commentID),
jsonHeader, bytes.NewReader(body), reactionResponse) jsonHeader, bytes.NewReader(body), reactionResponse)
return reactionResponse, resp, err
} }
// DeleteIssueCommentReaction remove a reaction from a comment of an issue // DeleteIssueCommentReaction remove a reaction from a comment of an issue
func (c *Client) DeleteIssueCommentReaction(owner, repo string, commentID int64, reaction string) (*Response, error) { func (c *Client) DeleteIssueCommentReaction(owner, repo string, commentID int64, reaction string) error {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, err return err
} }
// swagger:operation DELETE /repos/{owner}/{repo}/issues/comments/{id}/reactions issue issueDeleteCommentReaction
body, err := json.Marshal(&editReactionOption{Reaction: reaction}) body, err := json.Marshal(&editReactionOption{Reaction: reaction})
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("DELETE", _, err = c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/comments/%d/reactions", owner, repo, commentID),
fmt.Sprintf("/repos/%s/%s/issues/comments/%d/reactions", owner, repo, commentID),
jsonHeader, bytes.NewReader(body)) jsonHeader, bytes.NewReader(body))
return resp, err return err
} }

View File

@ -16,28 +16,27 @@ type StopWatch struct {
} }
// GetMyStopwatches list all stopwatches // GetMyStopwatches list all stopwatches
func (c *Client) GetMyStopwatches() ([]*StopWatch, *Response, error) { func (c *Client) GetMyStopwatches() ([]*StopWatch, error) {
stopwatches := make([]*StopWatch, 0, 1) stopwatches := make([]*StopWatch, 0, 1)
resp, err := c.getParsedResponse("GET", "/user/stopwatches", nil, nil, &stopwatches) return stopwatches, c.getParsedResponse("GET", "/user/stopwatches", nil, nil, &stopwatches)
return stopwatches, resp, err
} }
// DeleteIssueStopwatch delete / cancel a specific stopwatch // DeleteIssueStopwatch delete / cancel a specific stopwatch
func (c *Client) DeleteIssueStopwatch(owner, repo string, index int64) (*Response, error) { func (c *Client) DeleteIssueStopwatch(owner, repo string, index int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/stopwatch/delete", owner, repo, index), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/stopwatch/delete", owner, repo, index), nil, nil)
return resp, err return err
} }
// StartIssueStopWatch starts a stopwatch for an existing issue for a given // StartIssueStopWatch starts a stopwatch for an existing issue for a given
// repository // repository
func (c *Client) StartIssueStopWatch(owner, repo string, index int64) (*Response, error) { func (c *Client) StartIssueStopWatch(owner, repo string, index int64) error {
_, resp, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/stopwatch/start", owner, repo, index), nil, nil) _, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/stopwatch/start", owner, repo, index), nil, nil)
return resp, err return err
} }
// StopIssueStopWatch stops an existing stopwatch for an issue in a given // StopIssueStopWatch stops an existing stopwatch for an issue in a given
// repository // repository
func (c *Client) StopIssueStopWatch(owner, repo string, index int64) (*Response, error) { func (c *Client) StopIssueStopWatch(owner, repo string, index int64) error {
_, resp, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/stopwatch/stop", owner, repo, index), nil, nil) _, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/stopwatch/stop", owner, repo, index), nil, nil)
return resp, err return err
} }

View File

@ -10,75 +10,73 @@ import (
) )
// GetIssueSubscribers get list of users who subscribed on an issue // GetIssueSubscribers get list of users who subscribed on an issue
func (c *Client) GetIssueSubscribers(owner, repo string, index int64) ([]*User, *Response, error) { func (c *Client) GetIssueSubscribers(owner, repo string, index int64) ([]*User, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err return nil, err
} }
subscribers := make([]*User, 0, 10) subscribers := make([]*User, 0, 10)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions", owner, repo, index), nil, nil, &subscribers) return subscribers, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions", owner, repo, index), nil, nil, &subscribers)
return subscribers, resp, err
} }
// AddIssueSubscription Subscribe user to issue // AddIssueSubscription Subscribe user to issue
func (c *Client) AddIssueSubscription(owner, repo string, index int64, user string) (*Response, error) { func (c *Client) AddIssueSubscription(owner, repo string, index int64, user string) error {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, err return err
} }
status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil) status, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil)
if err != nil { if err != nil {
return resp, err return err
} }
if status == http.StatusCreated { if status == http.StatusCreated {
return resp, nil return nil
} }
if status == http.StatusOK { if status == http.StatusOK {
return resp, fmt.Errorf("already subscribed") return fmt.Errorf("already subscribed")
} }
return resp, fmt.Errorf("unexpected Status: %d", status) return fmt.Errorf("unexpected Status: %d", status)
} }
// DeleteIssueSubscription unsubscribe user from issue // DeleteIssueSubscription unsubscribe user from issue
func (c *Client) DeleteIssueSubscription(owner, repo string, index int64, user string) (*Response, error) { func (c *Client) DeleteIssueSubscription(owner, repo string, index int64, user string) error {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, err return err
} }
status, resp, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil) status, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil)
if err != nil { if err != nil {
return resp, err return err
} }
if status == http.StatusCreated { if status == http.StatusCreated {
return resp, nil return nil
} }
if status == http.StatusOK { if status == http.StatusOK {
return resp, fmt.Errorf("already unsubscribed") return fmt.Errorf("already unsubscribed")
} }
return resp, fmt.Errorf("unexpected Status: %d", status) return fmt.Errorf("unexpected Status: %d", status)
} }
// CheckIssueSubscription check if current user is subscribed to an issue // CheckIssueSubscription check if current user is subscribed to an issue
func (c *Client) CheckIssueSubscription(owner, repo string, index int64) (*WatchInfo, *Response, error) { func (c *Client) CheckIssueSubscription(owner, repo string, index int64) (*WatchInfo, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err return nil, err
} }
wi := new(WatchInfo) wi := new(WatchInfo)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/check", owner, repo, index), nil, nil, wi) return wi, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/check", owner, repo, index), nil, nil, wi)
return wi, resp, err
} }
// IssueSubscribe subscribe current user to an issue // IssueSubscribe subscribe current user to an issue
func (c *Client) IssueSubscribe(owner, repo string, index int64) (*Response, error) { func (c *Client) IssueSubscribe(owner, repo string, index int64) error {
u, _, err := c.GetMyUserInfo() u, err := c.GetMyUserInfo()
if err != nil { if err != nil {
return nil, err return err
} }
return c.AddIssueSubscription(owner, repo, index, u.UserName) return c.AddIssueSubscription(owner, repo, index, u.UserName)
} }
// IssueUnSubscribe unsubscribe current user from an issue // IssueUnSubscribe unsubscribe current user from an issue
func (c *Client) IssueUnSubscribe(owner, repo string, index int64) (*Response, error) { func (c *Client) IssueUnSubscribe(owner, repo string, index int64) error {
u, _, err := c.GetMyUserInfo() u, err := c.GetMyUserInfo()
if err != nil { if err != nil {
return nil, err return err
} }
return c.DeleteIssueSubscription(owner, repo, index, u.UserName) return c.DeleteIssueSubscription(owner, repo, index, u.UserName)
} }

View File

@ -26,70 +26,42 @@ type TrackedTime struct {
} }
// GetUserTrackedTimes list tracked times of a user // GetUserTrackedTimes list tracked times of a user
func (c *Client) GetUserTrackedTimes(owner, repo, user string) ([]*TrackedTime, *Response, error) { func (c *Client) GetUserTrackedTimes(owner, repo, user string) ([]*TrackedTime, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err
}
times := make([]*TrackedTime, 0, 10) times := make([]*TrackedTime, 0, 10)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/times/%s", owner, repo, user), nil, nil, &times) return times, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/times/%s", owner, repo, user), nil, nil, &times)
return times, resp, err
} }
// GetRepoTrackedTimes list tracked times of a repository // GetRepoTrackedTimes list tracked times of a repository
func (c *Client) GetRepoTrackedTimes(owner, repo string) ([]*TrackedTime, *Response, error) { func (c *Client) GetRepoTrackedTimes(owner, repo string) ([]*TrackedTime, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err
}
times := make([]*TrackedTime, 0, 10) times := make([]*TrackedTime, 0, 10)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/times", owner, repo), nil, nil, &times) return times, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/times", owner, repo), nil, nil, &times)
return times, resp, err
} }
// GetMyTrackedTimes list tracked times of the current user // GetMyTrackedTimes list tracked times of the current user
func (c *Client) GetMyTrackedTimes() ([]*TrackedTime, *Response, error) { func (c *Client) GetMyTrackedTimes() ([]*TrackedTime, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err
}
times := make([]*TrackedTime, 0, 10) times := make([]*TrackedTime, 0, 10)
resp, err := c.getParsedResponse("GET", "/user/times", nil, nil, &times) return times, c.getParsedResponse("GET", "/user/times", nil, nil, &times)
return times, resp, err
} }
// AddTimeOption options for adding time to an issue // AddTimeOption options for adding time to an issue
type AddTimeOption struct { type AddTimeOption struct {
// time in seconds // time in seconds
Time int64 `json:"time"` Time int64 `json:"time" binding:"Required"`
// optional // optional
Created time.Time `json:"created"` Created time.Time `json:"created"`
// optional // optional
User string `json:"user_name"` User string `json:"user_name"`
} }
// Validate the AddTimeOption struct
func (opt AddTimeOption) Validate() error {
if opt.Time == 0 {
return fmt.Errorf("no time to add")
}
return nil
}
// AddTime adds time to issue with the given index // AddTime adds time to issue with the given index
func (c *Client) AddTime(owner, repo string, index int64, opt AddTimeOption) (*TrackedTime, *Response, error) { func (c *Client) AddTime(owner, repo string, index int64, opt AddTimeOption) (*TrackedTime, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err
}
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
t := new(TrackedTime) t := new(TrackedTime)
resp, err := c.getParsedResponse("POST", return t, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/times", owner, repo, index),
fmt.Sprintf("/repos/%s/%s/issues/%d/times", owner, repo, index),
jsonHeader, bytes.NewReader(body), t) jsonHeader, bytes.NewReader(body), t)
return t, resp, err
} }
// ListTrackedTimesOptions options for listing repository's tracked times // ListTrackedTimesOptions options for listing repository's tracked times
@ -98,30 +70,20 @@ type ListTrackedTimesOptions struct {
} }
// ListTrackedTimes list tracked times of a single issue for a given repository // ListTrackedTimes list tracked times of a single issue for a given repository
func (c *Client) ListTrackedTimes(owner, repo string, index int64, opt ListTrackedTimesOptions) ([]*TrackedTime, *Response, error) { func (c *Client) ListTrackedTimes(owner, repo string, index int64, opt ListTrackedTimesOptions) ([]*TrackedTime, error) {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil {
return nil, nil, err
}
opt.setDefaults() opt.setDefaults()
times := make([]*TrackedTime, 0, opt.PageSize) times := make([]*TrackedTime, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/times?%s", owner, repo, index, opt.getURLQuery().Encode()), nil, nil, &times) return times, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/times?%s", owner, repo, index, opt.getURLQuery().Encode()), nil, nil, &times)
return times, resp, err
} }
// ResetIssueTime reset tracked time of a single issue for a given repository // ResetIssueTime reset tracked time of a single issue for a given repository
func (c *Client) ResetIssueTime(owner, repo string, index int64) (*Response, error) { func (c *Client) ResetIssueTime(owner, repo string, index int64) error {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/times", owner, repo, index), nil, nil)
return nil, err return err
}
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/times", owner, repo, index), nil, nil)
return resp, err
} }
// DeleteTime delete a specific tracked time by id of a single issue for a given repository // DeleteTime delete a specific tracked time by id of a single issue for a given repository
func (c *Client) DeleteTime(owner, repo string, index, timeID int64) (*Response, error) { func (c *Client) DeleteTime(owner, repo string, index, timeID int64) error {
if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/times/%d", owner, repo, index, timeID), nil, nil)
return nil, err return err
}
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/times/%d", owner, repo, index, timeID), nil, nil)
return resp, err
} }

View File

@ -29,31 +29,16 @@ type NotificationSubject struct {
Type string `json:"type" binding:"In(Issue,Pull,Commit)"` Type string `json:"type" binding:"In(Issue,Pull,Commit)"`
} }
// NotifyStatus notification status type
type NotifyStatus string
const (
// NotifyStatusUnread was not read
NotifyStatusUnread NotifyStatus = "unread"
// NotifyStatusRead was already read by user
NotifyStatusRead NotifyStatus = "read"
// NotifyStatusPinned notification is pinned by user
NotifyStatusPinned NotifyStatus = "pinned"
)
// ListNotificationOptions represents the filter options // ListNotificationOptions represents the filter options
type ListNotificationOptions struct { type ListNotificationOptions struct {
ListOptions ListOptions
Since time.Time Since time.Time
Before time.Time Before time.Time
Status []NotifyStatus
} }
// MarkNotificationOptions represents the filter & modify options // MarkNotificationOptions represents the filter options
type MarkNotificationOptions struct { type MarkNotificationOptions struct {
LastReadAt time.Time LastReadAt time.Time
Status []NotifyStatus
ToStatus NotifyStatus
} }
// QueryEncode encode options to url query // QueryEncode encode options to url query
@ -65,134 +50,88 @@ func (opt *ListNotificationOptions) QueryEncode() string {
if !opt.Before.IsZero() { if !opt.Before.IsZero() {
query.Add("before", opt.Before.Format(time.RFC3339)) query.Add("before", opt.Before.Format(time.RFC3339))
} }
for _, s := range opt.Status {
query.Add("status-types", string(s))
}
return query.Encode() return query.Encode()
} }
// Validate the CreateUserOption struct
func (opt ListNotificationOptions) Validate(c *Client) error {
if len(opt.Status) != 0 {
return c.CheckServerVersionConstraint(">=1.12.3")
}
return nil
}
// QueryEncode encode options to url query // QueryEncode encode options to url query
func (opt *MarkNotificationOptions) QueryEncode() string { func (opt *MarkNotificationOptions) QueryEncode() string {
query := make(url.Values) query := make(url.Values)
if !opt.LastReadAt.IsZero() { if !opt.LastReadAt.IsZero() {
query.Add("last_read_at", opt.LastReadAt.Format(time.RFC3339)) query.Add("last_read_at", opt.LastReadAt.Format(time.RFC3339))
} }
for _, s := range opt.Status {
query.Add("status-types", string(s))
}
if len(opt.ToStatus) != 0 {
query.Add("to-status", string(opt.ToStatus))
}
return query.Encode() return query.Encode()
} }
// Validate the CreateUserOption struct
func (opt MarkNotificationOptions) Validate(c *Client) error {
if len(opt.Status) != 0 || len(opt.ToStatus) != 0 {
return c.CheckServerVersionConstraint(">=1.12.3")
}
return nil
}
// CheckNotifications list users's notification threads // CheckNotifications list users's notification threads
func (c *Client) CheckNotifications() (int64, *Response, error) { func (c *Client) CheckNotifications() (int64, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return 0, nil, err return 0, err
} }
new := struct { new := struct {
New int64 `json:"new"` New int64 `json:"new"`
}{} }{}
resp, err := c.getParsedResponse("GET", "/notifications/new", jsonHeader, nil, &new) return new.New, c.getParsedResponse("GET", "/notifications/new", jsonHeader, nil, &new)
return new.New, resp, err
} }
// GetNotification get notification thread by ID // GetNotification get notification thread by ID
func (c *Client) GetNotification(id int64) (*NotificationThread, *Response, error) { func (c *Client) GetNotification(id int64) (*NotificationThread, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err return nil, err
} }
thread := new(NotificationThread) thread := new(NotificationThread)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/notifications/threads/%d", id), nil, nil, thread) return thread, c.getParsedResponse("GET", fmt.Sprintf("/notifications/threads/%d", id), nil, nil, thread)
return thread, resp, err
} }
// ReadNotification mark notification thread as read by ID // ReadNotification mark notification thread as read by ID
// It optionally takes a second argument if status has to be set other than 'read' func (c *Client) ReadNotification(id int64) error {
func (c *Client) ReadNotification(id int64, status ...NotifyStatus) (*Response, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, err return err
} }
link := fmt.Sprintf("/notifications/threads/%d", id) _, err := c.getResponse("PATCH", fmt.Sprintf("/notifications/threads/%d", id), nil, nil)
if len(status) != 0 { return err
link += fmt.Sprintf("?to-status=%s", status[0])
}
_, resp, err := c.getResponse("PATCH", link, nil, nil)
return resp, err
} }
// ListNotifications list users's notification threads // ListNotifications list users's notification threads
func (c *Client) ListNotifications(opt ListNotificationOptions) ([]*NotificationThread, *Response, error) { func (c *Client) ListNotifications(opt ListNotificationOptions) ([]*NotificationThread, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err return nil, err
}
if err := opt.Validate(c); err != nil {
return nil, nil, err
} }
link, _ := url.Parse("/notifications") link, _ := url.Parse("/notifications")
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
threads := make([]*NotificationThread, 0, 10) threads := make([]*NotificationThread, 0, 10)
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &threads) return threads, c.getParsedResponse("GET", link.String(), nil, nil, &threads)
return threads, resp, err
} }
// ReadNotifications mark notification threads as read // ReadNotifications mark notification threads as read
func (c *Client) ReadNotifications(opt MarkNotificationOptions) (*Response, error) { func (c *Client) ReadNotifications(opt MarkNotificationOptions) error {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, err return err
}
if err := opt.Validate(c); err != nil {
return nil, err
} }
link, _ := url.Parse("/notifications") link, _ := url.Parse("/notifications")
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
_, resp, err := c.getResponse("PUT", link.String(), nil, nil) _, err := c.getResponse("PUT", link.String(), nil, nil)
return resp, err return err
} }
// ListRepoNotifications list users's notification threads on a specific repo // ListRepoNotifications list users's notification threads on a specific repo
func (c *Client) ListRepoNotifications(owner, reponame string, opt ListNotificationOptions) ([]*NotificationThread, *Response, error) { func (c *Client) ListRepoNotifications(owner, reponame string, opt ListNotificationOptions) ([]*NotificationThread, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err return nil, err
}
if err := opt.Validate(c); err != nil {
return nil, nil, err
} }
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/notifications", owner, reponame)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/notifications", owner, reponame))
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
threads := make([]*NotificationThread, 0, 10) threads := make([]*NotificationThread, 0, 10)
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &threads) return threads, c.getParsedResponse("GET", link.String(), nil, nil, &threads)
return threads, resp, err
} }
// ReadRepoNotifications mark notification threads as read on a specific repo // ReadRepoNotifications mark notification threads as read on a specific repo
func (c *Client) ReadRepoNotifications(owner, reponame string, opt MarkNotificationOptions) (*Response, error) { func (c *Client) ReadRepoNotifications(owner, reponame string, opt MarkNotificationOptions) error {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, err return err
}
if err := opt.Validate(c); err != nil {
return nil, err
} }
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/notifications", owner, reponame)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/notifications", owner, reponame))
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
_, resp, err := c.getResponse("PUT", link.String(), nil, nil) _, err := c.getResponse("PUT", link.String(), nil, nil)
return resp, err return err
} }

View File

@ -33,59 +33,55 @@ type CreateOauth2Option struct {
} }
// CreateOauth2 create an Oauth2 Application and returns a completed Oauth2 object. // CreateOauth2 create an Oauth2 Application and returns a completed Oauth2 object.
func (c *Client) CreateOauth2(opt CreateOauth2Option) (*Oauth2, *Response, error) { func (c *Client) CreateOauth2(opt CreateOauth2Option) (*Oauth2, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil {
return nil, nil, err return nil, e
} }
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
oauth := new(Oauth2) oauth := new(Oauth2)
resp, err := c.getParsedResponse("POST", "/user/applications/oauth2", jsonHeader, bytes.NewReader(body), oauth) return oauth, c.getParsedResponse("POST", "/user/applications/oauth2", jsonHeader, bytes.NewReader(body), oauth)
return oauth, resp, err
} }
// UpdateOauth2 a specific Oauth2 Application by ID and return a completed Oauth2 object. // UpdateOauth2 a specific Oauth2 Application by ID and return a completed Oauth2 object.
func (c *Client) UpdateOauth2(oauth2id int64, opt CreateOauth2Option) (*Oauth2, *Response, error) { func (c *Client) UpdateOauth2(oauth2id int64, opt CreateOauth2Option) (*Oauth2, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil {
return nil, nil, err return nil, e
} }
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
oauth := new(Oauth2) oauth := new(Oauth2)
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/user/applications/oauth2/%d", oauth2id), jsonHeader, bytes.NewReader(body), oauth) return oauth, c.getParsedResponse("PATCH", fmt.Sprintf("/user/applications/oauth2/%d", oauth2id), jsonHeader, bytes.NewReader(body), oauth)
return oauth, resp, err
} }
// GetOauth2 a specific Oauth2 Application by ID. // GetOauth2 a specific Oauth2 Application by ID.
func (c *Client) GetOauth2(oauth2id int64) (*Oauth2, *Response, error) { func (c *Client) GetOauth2(oauth2id int64) (*Oauth2, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil {
return nil, nil, err return nil, e
} }
oauth2s := &Oauth2{} oauth2s := &Oauth2{}
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/applications/oauth2/%d", oauth2id), nil, nil, &oauth2s) return oauth2s, c.getParsedResponse("GET", fmt.Sprintf("/user/applications/oauth2/%d", oauth2id), nil, nil, &oauth2s)
return oauth2s, resp, err
} }
// ListOauth2 all of your Oauth2 Applications. // ListOauth2 all of your Oauth2 Applications.
func (c *Client) ListOauth2(opt ListOauth2Option) ([]*Oauth2, *Response, error) { func (c *Client) ListOauth2(opt ListOauth2Option) ([]*Oauth2, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil {
return nil, nil, err return nil, e
} }
opt.setDefaults() opt.setDefaults()
oauth2s := make([]*Oauth2, 0, opt.PageSize) oauth2s := make([]*Oauth2, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/applications/oauth2?%s", opt.getURLQuery().Encode()), nil, nil, &oauth2s) return oauth2s, c.getParsedResponse("GET", fmt.Sprintf("/user/applications/oauth2?%s", opt.getURLQuery().Encode()), nil, nil, &oauth2s)
return oauth2s, resp, err
} }
// DeleteOauth2 delete an Oauth2 application by ID // DeleteOauth2 delete an Oauth2 application by ID
func (c *Client) DeleteOauth2(oauth2id int64) (*Response, error) { func (c *Client) DeleteOauth2(oauth2id int64) error {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil {
return nil, err return e
} }
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/user/applications/oauth2/%d", oauth2id), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/user/applications/oauth2/%d", oauth2id), nil, nil)
return resp, err return err
} }

View File

@ -23,86 +23,51 @@ type Organization struct {
Visibility string `json:"visibility"` Visibility string `json:"visibility"`
} }
// VisibleType defines the visibility
type VisibleType string
const (
// VisibleTypePublic Visible for everyone
VisibleTypePublic VisibleType = "public"
// VisibleTypeLimited Visible for every connected user
VisibleTypeLimited VisibleType = "limited"
// VisibleTypePrivate Visible only for organization's members
VisibleTypePrivate VisibleType = "private"
)
// ListOrgsOptions options for listing organizations // ListOrgsOptions options for listing organizations
type ListOrgsOptions struct { type ListOrgsOptions struct {
ListOptions ListOptions
} }
// ListMyOrgs list all of current user's organizations // ListMyOrgs list all of current user's organizations
func (c *Client) ListMyOrgs(opt ListOrgsOptions) ([]*Organization, *Response, error) { func (c *Client) ListMyOrgs(opt ListOrgsOptions) ([]*Organization, error) {
opt.setDefaults() opt.setDefaults()
orgs := make([]*Organization, 0, opt.PageSize) orgs := make([]*Organization, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/orgs?%s", opt.getURLQuery().Encode()), nil, nil, &orgs) return orgs, c.getParsedResponse("GET", fmt.Sprintf("/user/orgs?%s", opt.getURLQuery().Encode()), nil, nil, &orgs)
return orgs, resp, err
} }
// ListUserOrgs list all of some user's organizations // ListUserOrgs list all of some user's organizations
func (c *Client) ListUserOrgs(user string, opt ListOrgsOptions) ([]*Organization, *Response, error) { func (c *Client) ListUserOrgs(user string, opt ListOrgsOptions) ([]*Organization, error) {
opt.setDefaults() opt.setDefaults()
orgs := make([]*Organization, 0, opt.PageSize) orgs := make([]*Organization, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/orgs?%s", user, opt.getURLQuery().Encode()), nil, nil, &orgs) return orgs, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/orgs?%s", user, opt.getURLQuery().Encode()), nil, nil, &orgs)
return orgs, resp, err
} }
// GetOrg get one organization by name // GetOrg get one organization by name
func (c *Client) GetOrg(orgname string) (*Organization, *Response, error) { func (c *Client) GetOrg(orgname string) (*Organization, error) {
org := new(Organization) org := new(Organization)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s", orgname), nil, nil, org) return org, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s", orgname), nil, nil, org)
return org, resp, err
} }
// CreateOrgOption options for creating an organization // CreateOrgOption options for creating an organization
type CreateOrgOption struct { type CreateOrgOption struct {
Name string `json:"username"` UserName string `json:"username"`
FullName string `json:"full_name"` FullName string `json:"full_name"`
Description string `json:"description"` Description string `json:"description"`
Website string `json:"website"` Website string `json:"website"`
Location string `json:"location"` Location string `json:"location"`
Visibility VisibleType `json:"visibility"` // possible values are `public` (default), `limited` or `private`
} // enum: public,limited,private
Visibility string `json:"visibility"`
// checkVisibilityOpt check if mode exist
func checkVisibilityOpt(v VisibleType) bool {
return v == VisibleTypePublic || v == VisibleTypeLimited || v == VisibleTypePrivate
}
// Validate the CreateOrgOption struct
func (opt CreateOrgOption) Validate() error {
if len(opt.Name) == 0 {
return fmt.Errorf("empty org name")
}
if len(opt.Visibility) != 0 && !checkVisibilityOpt(opt.Visibility) {
return fmt.Errorf("infalid bisibility option")
}
return nil
} }
// CreateOrg creates an organization // CreateOrg creates an organization
func (c *Client) CreateOrg(opt CreateOrgOption) (*Organization, *Response, error) { func (c *Client) CreateOrg(opt CreateOrgOption) (*Organization, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
org := new(Organization) org := new(Organization)
resp, err := c.getParsedResponse("POST", "/orgs", jsonHeader, bytes.NewReader(body), org) return org, c.getParsedResponse("POST", "/orgs", jsonHeader, bytes.NewReader(body), org)
return org, resp, err
} }
// EditOrgOption options for editing an organization // EditOrgOption options for editing an organization
@ -111,32 +76,23 @@ type EditOrgOption struct {
Description string `json:"description"` Description string `json:"description"`
Website string `json:"website"` Website string `json:"website"`
Location string `json:"location"` Location string `json:"location"`
Visibility VisibleType `json:"visibility"` // possible values are `public`, `limited` or `private`
} // enum: public,limited,private
Visibility string `json:"visibility"`
// Validate the EditOrgOption struct
func (opt EditOrgOption) Validate() error {
if len(opt.Visibility) != 0 && !checkVisibilityOpt(opt.Visibility) {
return fmt.Errorf("infalid bisibility option")
}
return nil
} }
// EditOrg modify one organization via options // EditOrg modify one organization via options
func (c *Client) EditOrg(orgname string, opt EditOrgOption) (*Response, error) { func (c *Client) EditOrg(orgname string, opt EditOrgOption) error {
if err := opt.Validate(); err != nil {
return nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("PATCH", fmt.Sprintf("/orgs/%s", orgname), jsonHeader, bytes.NewReader(body)) _, err = c.getResponse("PATCH", fmt.Sprintf("/orgs/%s", orgname), jsonHeader, bytes.NewReader(body))
return resp, err return err
} }
// DeleteOrg deletes an organization // DeleteOrg deletes an organization
func (c *Client) DeleteOrg(orgname string) (*Response, error) { func (c *Client) DeleteOrg(orgname string) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s", orgname), jsonHeader, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s", orgname), nil, nil)
return resp, err return err
} }

View File

@ -11,9 +11,9 @@ import (
) )
// DeleteOrgMembership remove a member from an organization // DeleteOrgMembership remove a member from an organization
func (c *Client) DeleteOrgMembership(org, user string) (*Response, error) { func (c *Client) DeleteOrgMembership(org, user string) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s/members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/orgs/%s/members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil)
return resp, err return err
} }
// ListOrgMembershipOption list OrgMembership options // ListOrgMembershipOption list OrgMembership options
@ -22,80 +22,77 @@ type ListOrgMembershipOption struct {
} }
// ListOrgMembership list an organization's members // ListOrgMembership list an organization's members
func (c *Client) ListOrgMembership(org string, opt ListOrgMembershipOption) ([]*User, *Response, error) { func (c *Client) ListOrgMembership(org string, opt ListOrgMembershipOption) ([]*User, error) {
opt.setDefaults() opt.setDefaults()
users := make([]*User, 0, opt.PageSize) users := make([]*User, 0, opt.PageSize)
link, _ := url.Parse(fmt.Sprintf("/orgs/%s/members", url.PathEscape(org))) link, _ := url.Parse(fmt.Sprintf("/orgs/%s/members", url.PathEscape(org)))
link.RawQuery = opt.getURLQuery().Encode() link.RawQuery = opt.getURLQuery().Encode()
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &users) return users, c.getParsedResponse("GET", link.String(), jsonHeader, nil, &users)
return users, resp, err
} }
// ListPublicOrgMembership list an organization's members // ListPublicOrgMembership list an organization's members
func (c *Client) ListPublicOrgMembership(org string, opt ListOrgMembershipOption) ([]*User, *Response, error) { func (c *Client) ListPublicOrgMembership(org string, opt ListOrgMembershipOption) ([]*User, error) {
opt.setDefaults() opt.setDefaults()
users := make([]*User, 0, opt.PageSize) users := make([]*User, 0, opt.PageSize)
link, _ := url.Parse(fmt.Sprintf("/orgs/%s/public_members", url.PathEscape(org))) link, _ := url.Parse(fmt.Sprintf("/orgs/%s/public_members", url.PathEscape(org)))
link.RawQuery = opt.getURLQuery().Encode() link.RawQuery = opt.getURLQuery().Encode()
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &users) return users, c.getParsedResponse("GET", link.String(), jsonHeader, nil, &users)
return users, resp, err
} }
// CheckOrgMembership Check if a user is a member of an organization // CheckOrgMembership Check if a user is a member of an organization
func (c *Client) CheckOrgMembership(org, user string) (bool, *Response, error) { func (c *Client) CheckOrgMembership(org, user string) (bool, error) {
status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/orgs/%s/members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) status, err := c.getStatusCode("GET", fmt.Sprintf("/orgs/%s/members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil)
if err != nil { if err != nil {
return false, resp, err return false, err
} }
switch status { switch status {
case http.StatusNoContent: case http.StatusNoContent:
return true, resp, nil return true, nil
case http.StatusNotFound: case http.StatusNotFound:
return false, resp, nil return false, nil
default: default:
return false, resp, fmt.Errorf("unexpected Status: %d", status) return false, fmt.Errorf("unexpected Status: %d", status)
} }
} }
// CheckPublicOrgMembership Check if a user is a member of an organization // CheckPublicOrgMembership Check if a user is a member of an organization
func (c *Client) CheckPublicOrgMembership(org, user string) (bool, *Response, error) { func (c *Client) CheckPublicOrgMembership(org, user string) (bool, error) {
status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/orgs/%s/public_members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) status, err := c.getStatusCode("GET", fmt.Sprintf("/orgs/%s/public_members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil)
if err != nil { if err != nil {
return false, resp, err return false, err
} }
switch status { switch status {
case http.StatusNoContent: case http.StatusNoContent:
return true, resp, nil return true, nil
case http.StatusNotFound: case http.StatusNotFound:
return false, resp, nil return false, nil
default: default:
return false, resp, fmt.Errorf("unexpected Status: %d", status) return false, fmt.Errorf("unexpected Status: %d", status)
} }
} }
// SetPublicOrgMembership publicize/conceal a user's membership // SetPublicOrgMembership publicize/conceal a user's membership
func (c *Client) SetPublicOrgMembership(org, user string, visible bool) (*Response, error) { func (c *Client) SetPublicOrgMembership(org, user string, visible bool) error {
var ( var (
status int status int
err error err error
resp *Response
) )
if visible { if visible {
status, resp, err = c.getStatusCode("PUT", fmt.Sprintf("/orgs/%s/public_members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) status, err = c.getStatusCode("PUT", fmt.Sprintf("/orgs/%s/public_members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil)
} else { } else {
status, resp, err = c.getStatusCode("DELETE", fmt.Sprintf("/orgs/%s/public_members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil) status, err = c.getStatusCode("DELETE", fmt.Sprintf("/orgs/%s/public_members/%s", url.PathEscape(org), url.PathEscape(user)), nil, nil)
} }
if err != nil { if err != nil {
return resp, err return err
} }
switch status { switch status {
case http.StatusNoContent: case http.StatusNoContent:
return resp, nil return nil
case http.StatusNotFound: case http.StatusNotFound:
return resp, fmt.Errorf("forbidden") return fmt.Errorf("forbidden")
default: default:
return resp, fmt.Errorf("unexpected Status: %d", status) return fmt.Errorf("unexpected Status: %d", status)
} }
} }

View File

@ -16,9 +16,8 @@ type Team struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Organization *Organization `json:"organization"` Organization *Organization `json:"organization"`
Permission AccessMode `json:"permission"` // enum: none,read,write,admin,owner
CanCreateOrgRepo bool `json:"can_create_org_repo"` Permission string `json:"permission"`
IncludesAllRepositories bool `json:"includes_all_repositories"`
// example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.ext_wiki"] // example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.ext_wiki"]
Units []string `json:"units"` Units []string `json:"units"`
} }
@ -29,119 +28,69 @@ type ListTeamsOptions struct {
} }
// ListOrgTeams lists all teams of an organization // ListOrgTeams lists all teams of an organization
func (c *Client) ListOrgTeams(org string, opt ListTeamsOptions) ([]*Team, *Response, error) { func (c *Client) ListOrgTeams(org string, opt ListTeamsOptions) ([]*Team, error) {
opt.setDefaults() opt.setDefaults()
teams := make([]*Team, 0, opt.PageSize) teams := make([]*Team, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/teams?%s", org, opt.getURLQuery().Encode()), nil, nil, &teams) return teams, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/teams?%s", org, opt.getURLQuery().Encode()), nil, nil, &teams)
return teams, resp, err
} }
// ListMyTeams lists all the teams of the current user // ListMyTeams lists all the teams of the current user
func (c *Client) ListMyTeams(opt *ListTeamsOptions) ([]*Team, *Response, error) { func (c *Client) ListMyTeams(opt *ListTeamsOptions) ([]*Team, error) {
opt.setDefaults() opt.setDefaults()
teams := make([]*Team, 0, opt.PageSize) teams := make([]*Team, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/teams?%s", opt.getURLQuery().Encode()), nil, nil, &teams) return teams, c.getParsedResponse("GET", fmt.Sprintf("/user/teams?%s", opt.getURLQuery().Encode()), nil, nil, &teams)
return teams, resp, err
} }
// GetTeam gets a team by ID // GetTeam gets a team by ID
func (c *Client) GetTeam(id int64) (*Team, *Response, error) { func (c *Client) GetTeam(id int64) (*Team, error) {
t := new(Team) t := new(Team)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/teams/%d", id), nil, nil, t) return t, c.getParsedResponse("GET", fmt.Sprintf("/teams/%d", id), nil, nil, t)
return t, resp, err
} }
// CreateTeamOption options for creating a team // CreateTeamOption options for creating a team
type CreateTeamOption struct { type CreateTeamOption struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Permission AccessMode `json:"permission"` // enum: read,write,admin
CanCreateOrgRepo bool `json:"can_create_org_repo"` Permission string `json:"permission"`
IncludesAllRepositories bool `json:"includes_all_repositories"`
// example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.ext_wiki"] // example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.ext_wiki"]
Units []string `json:"units"` Units []string `json:"units"`
} }
// Validate the CreateTeamOption struct
func (opt CreateTeamOption) Validate() error {
if opt.Permission == AccessModeOwner {
opt.Permission = AccessModeAdmin
} else if opt.Permission != AccessModeRead && opt.Permission != AccessModeWrite && opt.Permission != AccessModeAdmin {
return fmt.Errorf("permission mode invalid")
}
if len(opt.Name) == 0 {
return fmt.Errorf("name required")
}
if len(opt.Name) > 30 {
return fmt.Errorf("name to long")
}
if len(opt.Description) > 255 {
return fmt.Errorf("description to long")
}
return nil
}
// CreateTeam creates a team for an organization // CreateTeam creates a team for an organization
func (c *Client) CreateTeam(org string, opt CreateTeamOption) (*Team, *Response, error) { func (c *Client) CreateTeam(org string, opt CreateTeamOption) (*Team, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
t := new(Team) t := new(Team)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/orgs/%s/teams", org), jsonHeader, bytes.NewReader(body), t) return t, c.getParsedResponse("POST", fmt.Sprintf("/orgs/%s/teams", org), jsonHeader, bytes.NewReader(body), t)
return t, resp, err
} }
// EditTeamOption options for editing a team // EditTeamOption options for editing a team
type EditTeamOption struct { type EditTeamOption struct {
Name string `json:"name"` Name string `json:"name"`
Description *string `json:"description"` Description string `json:"description"`
Permission AccessMode `json:"permission"` // enum: read,write,admin
CanCreateOrgRepo *bool `json:"can_create_org_repo"` Permission string `json:"permission"`
IncludesAllRepositories *bool `json:"includes_all_repositories"`
// example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.ext_wiki"] // example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.ext_wiki"]
Units []string `json:"units"` Units []string `json:"units"`
} }
// Validate the EditTeamOption struct
func (opt EditTeamOption) Validate() error {
if opt.Permission == AccessModeOwner {
opt.Permission = AccessModeAdmin
} else if opt.Permission != AccessModeRead && opt.Permission != AccessModeWrite && opt.Permission != AccessModeAdmin {
return fmt.Errorf("permission mode invalid")
}
if len(opt.Name) == 0 {
return fmt.Errorf("name required")
}
if len(opt.Name) > 30 {
return fmt.Errorf("name to long")
}
if opt.Description != nil && len(*opt.Description) > 255 {
return fmt.Errorf("description to long")
}
return nil
}
// EditTeam edits a team of an organization // EditTeam edits a team of an organization
func (c *Client) EditTeam(id int64, opt EditTeamOption) (*Response, error) { func (c *Client) EditTeam(id int64, opt EditTeamOption) error {
if err := opt.Validate(); err != nil {
return nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("PATCH", fmt.Sprintf("/teams/%d", id), jsonHeader, bytes.NewReader(body)) _, err = c.getResponse("PATCH", fmt.Sprintf("/teams/%d", id), jsonHeader, bytes.NewReader(body))
return resp, err return err
} }
// DeleteTeam deletes a team of an organization // DeleteTeam deletes a team of an organization
func (c *Client) DeleteTeam(id int64) (*Response, error) { func (c *Client) DeleteTeam(id int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/teams/%d", id), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/teams/%d", id), nil, nil)
return resp, err return err
} }
// ListTeamMembersOptions options for listing team's members // ListTeamMembersOptions options for listing team's members
@ -150,30 +99,28 @@ type ListTeamMembersOptions struct {
} }
// ListTeamMembers lists all members of a team // ListTeamMembers lists all members of a team
func (c *Client) ListTeamMembers(id int64, opt ListTeamMembersOptions) ([]*User, *Response, error) { func (c *Client) ListTeamMembers(id int64, opt ListTeamMembersOptions) ([]*User, error) {
opt.setDefaults() opt.setDefaults()
members := make([]*User, 0, opt.PageSize) members := make([]*User, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/teams/%d/members?%s", id, opt.getURLQuery().Encode()), nil, nil, &members) return members, c.getParsedResponse("GET", fmt.Sprintf("/teams/%d/members?%s", id, opt.getURLQuery().Encode()), nil, nil, &members)
return members, resp, err
} }
// GetTeamMember gets a member of a team // GetTeamMember gets a member of a team
func (c *Client) GetTeamMember(id int64, user string) (*User, *Response, error) { func (c *Client) GetTeamMember(id int64, user string) (*User, error) {
m := new(User) m := new(User)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/teams/%d/members/%s", id, user), nil, nil, m) return m, c.getParsedResponse("GET", fmt.Sprintf("/teams/%d/members/%s", id, user), nil, nil, m)
return m, resp, err
} }
// AddTeamMember adds a member to a team // AddTeamMember adds a member to a team
func (c *Client) AddTeamMember(id int64, user string) (*Response, error) { func (c *Client) AddTeamMember(id int64, user string) error {
_, resp, err := c.getResponse("PUT", fmt.Sprintf("/teams/%d/members/%s", id, user), nil, nil) _, err := c.getResponse("PUT", fmt.Sprintf("/teams/%d/members/%s", id, user), nil, nil)
return resp, err return err
} }
// RemoveTeamMember removes a member from a team // RemoveTeamMember removes a member from a team
func (c *Client) RemoveTeamMember(id int64, user string) (*Response, error) { func (c *Client) RemoveTeamMember(id int64, user string) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/teams/%d/members/%s", id, user), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/teams/%d/members/%s", id, user), nil, nil)
return resp, err return err
} }
// ListTeamRepositoriesOptions options for listing team's repositories // ListTeamRepositoriesOptions options for listing team's repositories
@ -182,21 +129,20 @@ type ListTeamRepositoriesOptions struct {
} }
// ListTeamRepositories lists all repositories of a team // ListTeamRepositories lists all repositories of a team
func (c *Client) ListTeamRepositories(id int64, opt ListTeamRepositoriesOptions) ([]*Repository, *Response, error) { func (c *Client) ListTeamRepositories(id int64, opt ListTeamRepositoriesOptions) ([]*Repository, error) {
opt.setDefaults() opt.setDefaults()
repos := make([]*Repository, 0, opt.PageSize) repos := make([]*Repository, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/teams/%d/repos?%s", id, opt.getURLQuery().Encode()), nil, nil, &repos) return repos, c.getParsedResponse("GET", fmt.Sprintf("/teams/%d/repos?%s", id, opt.getURLQuery().Encode()), nil, nil, &repos)
return repos, resp, err
} }
// AddTeamRepository adds a repository to a team // AddTeamRepository adds a repository to a team
func (c *Client) AddTeamRepository(id int64, org, repo string) (*Response, error) { func (c *Client) AddTeamRepository(id int64, org, repo string) error {
_, resp, err := c.getResponse("PUT", fmt.Sprintf("/teams/%d/repos/%s/%s", id, org, repo), nil, nil) _, err := c.getResponse("PUT", fmt.Sprintf("/teams/%d/repos/%s/%s", id, org, repo), nil, nil)
return resp, err return err
} }
// RemoveTeamRepository removes a repository from a team // RemoveTeamRepository removes a repository from a team
func (c *Client) RemoveTeamRepository(id int64, org, repo string) (*Response, error) { func (c *Client) RemoveTeamRepository(id int64, org, repo string) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/teams/%d/repos/%s/%s", id, org, repo), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/teams/%d/repos/%s/%s", id, org, repo), nil, nil)
return resp, err return err
} }

27
vendor/code.gitea.io/sdk/gitea/org_type.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2019 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 gitea
// VisibleType defines the visibility (Organization only)
type VisibleType int
const (
// VisibleTypePublic Visible for everyone
VisibleTypePublic VisibleType = iota
// VisibleTypeLimited Visible for every connected user
VisibleTypeLimited
// VisibleTypePrivate Visible only for organization's members
VisibleTypePrivate
)
// ExtractKeysFromMapString provides a slice of keys from map
func ExtractKeysFromMapString(in map[string]VisibleType) (keys []string) {
for k := range in {
keys = append(keys, k)
}
return
}

View File

@ -10,7 +10,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"strings"
"time" "time"
) )
@ -36,7 +35,6 @@ type PullRequest struct {
Assignee *User `json:"assignee"` Assignee *User `json:"assignee"`
Assignees []*User `json:"assignees"` Assignees []*User `json:"assignees"`
State StateType `json:"state"` State StateType `json:"state"`
IsLocked bool `json:"is_locked"`
Comments int `json:"comments"` Comments int `json:"comments"`
HTMLURL string `json:"html_url"` HTMLURL string `json:"html_url"`
@ -98,21 +96,19 @@ func (opt *ListPullRequestsOptions) QueryEncode() string {
} }
// ListRepoPullRequests list PRs of one repository // ListRepoPullRequests list PRs of one repository
func (c *Client) ListRepoPullRequests(owner, repo string, opt ListPullRequestsOptions) ([]*PullRequest, *Response, error) { func (c *Client) ListRepoPullRequests(owner, repo string, opt ListPullRequestsOptions) ([]*PullRequest, error) {
opt.setDefaults() opt.setDefaults()
prs := make([]*PullRequest, 0, opt.PageSize) prs := make([]*PullRequest, 0, opt.PageSize)
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/pulls", owner, repo)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/pulls", owner, repo))
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &prs) return prs, c.getParsedResponse("GET", link.String(), jsonHeader, nil, &prs)
return prs, resp, err
} }
// GetPullRequest get information of one PR // GetPullRequest get information of one PR
func (c *Client) GetPullRequest(owner, repo string, index int64) (*PullRequest, *Response, error) { func (c *Client) GetPullRequest(owner, repo string, index int64) (*PullRequest, error) {
pr := new(PullRequest) pr := new(PullRequest)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d", owner, repo, index), nil, nil, pr) return pr, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d", owner, repo, index), nil, nil, pr)
return pr, resp, err
} }
// CreatePullRequestOption options when creating a pull request // CreatePullRequestOption options when creating a pull request
@ -129,16 +125,14 @@ type CreatePullRequestOption struct {
} }
// CreatePullRequest create pull request with options // CreatePullRequest create pull request with options
func (c *Client) CreatePullRequest(owner, repo string, opt CreatePullRequestOption) (*PullRequest, *Response, error) { func (c *Client) CreatePullRequest(owner, repo string, opt CreatePullRequestOption) (*PullRequest, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
pr := new(PullRequest) pr := new(PullRequest)
resp, err := c.getParsedResponse("POST", return pr, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/pulls", owner, repo),
fmt.Sprintf("/repos/%s/%s/pulls", owner, repo),
jsonHeader, bytes.NewReader(body), pr) jsonHeader, bytes.NewReader(body), pr)
return pr, resp, err
} }
// EditPullRequestOption options when modify pull request // EditPullRequestOption options when modify pull request
@ -154,33 +148,15 @@ type EditPullRequestOption struct {
Deadline *time.Time `json:"due_date"` Deadline *time.Time `json:"due_date"`
} }
// Validate the EditPullRequestOption struct
func (opt EditPullRequestOption) Validate(c *Client) error {
if len(opt.Title) != 0 && len(strings.TrimSpace(opt.Title)) == 0 {
return fmt.Errorf("title is empty")
}
if len(opt.Base) != 0 {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return fmt.Errorf("can not change base gitea to old")
}
}
return nil
}
// EditPullRequest modify pull request with PR id and options // EditPullRequest modify pull request with PR id and options
func (c *Client) EditPullRequest(owner, repo string, index int64, opt EditPullRequestOption) (*PullRequest, *Response, error) { func (c *Client) EditPullRequest(owner, repo string, index int64, opt EditPullRequestOption) (*PullRequest, error) {
if err := opt.Validate(c); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
pr := new(PullRequest) pr := new(PullRequest)
resp, err := c.getParsedResponse("PATCH", return pr, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/pulls/%d", owner, repo, index),
fmt.Sprintf("/repos/%s/%s/pulls/%d", owner, repo, index),
jsonHeader, bytes.NewReader(body), pr) jsonHeader, bytes.NewReader(body), pr)
return pr, resp, err
} }
// MergePullRequestOption options when merging a pull request // MergePullRequestOption options when merging a pull request
@ -190,64 +166,31 @@ type MergePullRequestOption struct {
Message string `json:"MergeMessageField"` Message string `json:"MergeMessageField"`
} }
// Validate the MergePullRequestOption struct // MergePullRequest merge a PR to repository by PR id
func (opt MergePullRequestOption) Validate(c *Client) error { func (c *Client) MergePullRequest(owner, repo string, index int64, opt MergePullRequestOption) (bool, error) {
if opt.Style == MergeStyleSquash { if opt.Style == MergeStyleSquash {
if err := c.CheckServerVersionConstraint(">=1.11.5"); err != nil { if err := c.CheckServerVersionConstraint(">=1.11.5"); err != nil {
return err return false, err
} }
} }
return nil
}
// MergePullRequest merge a PR to repository by PR id
func (c *Client) MergePullRequest(owner, repo string, index int64, opt MergePullRequestOption) (bool, *Response, error) {
if err := opt.Validate(c); err != nil {
return false, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return false, nil, err return false, err
} }
status, resp, err := c.getStatusCode("POST", fmt.Sprintf("/repos/%s/%s/pulls/%d/merge", owner, repo, index), jsonHeader, bytes.NewReader(body)) status, err := c.getStatusCode("POST", fmt.Sprintf("/repos/%s/%s/pulls/%d/merge", owner, repo, index), jsonHeader, bytes.NewReader(body))
if err != nil { if err != nil {
return false, resp, err return false, err
} }
return status == 200, resp, nil return status == 200, nil
} }
// IsPullRequestMerged test if one PR is merged to one repository // IsPullRequestMerged test if one PR is merged to one repository
func (c *Client) IsPullRequestMerged(owner, repo string, index int64) (bool, *Response, error) { func (c *Client) IsPullRequestMerged(owner, repo string, index int64) (bool, error) {
status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d/merge", owner, repo, index), nil, nil) statusCode, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d/merge", owner, repo, index), nil, nil)
if err != nil { if err != nil {
return false, resp, err return false, err
} }
return status == 204, resp, nil return statusCode == 204, nil
}
// getPullRequestDiffOrPatch gets the patch or diff file as bytes for a PR
func (c *Client) getPullRequestDiffOrPatch(owner, repo, kind string, index int64) ([]byte, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil {
r, _, err2 := c.GetRepo(owner, repo)
if err2 != nil {
return nil, nil, err
}
if r.Private {
return nil, nil, err
}
return c.getWebResponse("GET", fmt.Sprintf("/%s/%s/pulls/%d.%s", owner, repo, index, kind), nil)
}
return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d.%s", owner, repo, index, kind), nil, nil)
}
// GetPullRequestPatch gets the .patch file as bytes for a PR
func (c *Client) GetPullRequestPatch(owner, repo string, index int64) ([]byte, *Response, error) {
return c.getPullRequestDiffOrPatch(owner, repo, "patch", index)
}
// GetPullRequestDiff gets the .diff file as bytes for a PR
func (c *Client) GetPullRequestDiff(owner, repo string, index int64) ([]byte, *Response, error) {
return c.getPullRequestDiffOrPatch(owner, repo, "diff", index)
} }

View File

@ -9,7 +9,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"strings"
"time" "time"
) )
@ -41,6 +40,7 @@ type PullReview struct {
Stale bool `json:"stale"` Stale bool `json:"stale"`
Official bool `json:"official"` Official bool `json:"official"`
CodeCommentsCount int `json:"comments_count"` CodeCommentsCount int `json:"comments_count"`
// swagger:strfmt date-time
Submitted time.Time `json:"submitted_at"` Submitted time.Time `json:"submitted_at"`
HTMLURL string `json:"html_url"` HTMLURL string `json:"html_url"`
@ -54,7 +54,9 @@ type PullReviewComment struct {
Reviewer *User `json:"user"` Reviewer *User `json:"user"`
ReviewID int64 `json:"pull_request_review_id"` ReviewID int64 `json:"pull_request_review_id"`
// swagger:strfmt date-time
Created time.Time `json:"created_at"` Created time.Time `json:"created_at"`
// swagger:strfmt date-time
Updated time.Time `json:"updated_at"` Updated time.Time `json:"updated_at"`
Path string `json:"path"` Path string `json:"path"`
@ -98,42 +100,10 @@ type ListPullReviewsOptions struct {
ListOptions ListOptions
} }
// Validate the CreatePullReviewOptions struct
func (opt CreatePullReviewOptions) Validate() error {
if opt.State != ReviewStateApproved && len(strings.TrimSpace(opt.Body)) == 0 {
return fmt.Errorf("body is empty")
}
for i := range opt.Comments {
if err := opt.Comments[i].Validate(); err != nil {
return err
}
}
return nil
}
// Validate the SubmitPullReviewOptions struct
func (opt SubmitPullReviewOptions) Validate() error {
if opt.State != ReviewStateApproved && len(strings.TrimSpace(opt.Body)) == 0 {
return fmt.Errorf("body is empty")
}
return nil
}
// Validate the CreatePullReviewComment struct
func (opt CreatePullReviewComment) Validate() error {
if len(strings.TrimSpace(opt.Body)) == 0 {
return fmt.Errorf("body is empty")
}
if opt.NewLineNum != 0 && opt.OldLineNum != 0 {
return fmt.Errorf("old and new line num are set, cant identify the code comment position")
}
return nil
}
// ListPullReviews lists all reviews of a pull request // ListPullReviews lists all reviews of a pull request
func (c *Client) ListPullReviews(owner, repo string, index int64, opt ListPullReviewsOptions) ([]*PullReview, *Response, error) { func (c *Client) ListPullReviews(owner, repo string, index int64, opt ListPullReviewsOptions) ([]*PullReview, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err return nil, err
} }
opt.setDefaults() opt.setDefaults()
rs := make([]*PullReview, 0, opt.PageSize) rs := make([]*PullReview, 0, opt.PageSize)
@ -141,79 +111,74 @@ func (c *Client) ListPullReviews(owner, repo string, index int64, opt ListPullRe
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews", owner, repo, index)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews", owner, repo, index))
link.RawQuery = opt.ListOptions.getURLQuery().Encode() link.RawQuery = opt.ListOptions.getURLQuery().Encode()
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &rs) return rs, c.getParsedResponse("GET", link.String(), jsonHeader, nil, &rs)
return rs, resp, err
} }
// GetPullReview gets a specific review of a pull request // GetPullReview gets a specific review of a pull request
func (c *Client) GetPullReview(owner, repo string, index, id int64) (*PullReview, *Response, error) { func (c *Client) GetPullReview(owner, repo string, index, id int64) (*PullReview, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err
}
r := new(PullReview)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews/%d", owner, repo, index, id), jsonHeader, nil, &r)
return r, resp, err
}
// ListPullReviewComments lists all comments of a pull request review
func (c *Client) ListPullReviewComments(owner, repo string, index, id int64) ([]*PullReviewComment, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err
}
rcl := make([]*PullReviewComment, 0, 4)
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews/%d/comments", owner, repo, index, id))
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &rcl)
return rcl, resp, err
}
// DeletePullReview delete a specific review from a pull request
func (c *Client) DeletePullReview(owner, repo string, index, id int64) (*Response, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, err return nil, err
} }
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews/%d", owner, repo, index, id), jsonHeader, nil) r := new(PullReview)
return resp, err return r, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews/%d", owner, repo, index, id), jsonHeader, nil, &r)
}
// ListPullReviewsCommentsOptions options for listing PullReviewsComments
type ListPullReviewsCommentsOptions struct {
ListOptions
}
// ListPullReviewComments lists all comments of a pull request review
func (c *Client) ListPullReviewComments(owner, repo string, index, id int64, opt ListPullReviewsCommentsOptions) ([]*PullReviewComment, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, err
}
opt.setDefaults()
rcl := make([]*PullReviewComment, 0, opt.PageSize)
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews/%d/comments", owner, repo, index, id))
link.RawQuery = opt.ListOptions.getURLQuery().Encode()
return rcl, c.getParsedResponse("GET", link.String(), jsonHeader, nil, &rcl)
}
// DeletePullReview delete a specific review from a pull request
func (c *Client) DeletePullReview(owner, repo string, index, id int64) error {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return err
}
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews/%d", owner, repo, index, id), jsonHeader, nil)
return err
} }
// CreatePullReview create a review to an pull request // CreatePullReview create a review to an pull request
func (c *Client) CreatePullReview(owner, repo string, index int64, opt CreatePullReviewOptions) (*PullReview, *Response, error) { func (c *Client) CreatePullReview(owner, repo string, index int64, opt CreatePullReviewOptions) (*PullReview, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err return nil, err
}
if err := opt.Validate(); err != nil {
return nil, nil, err
} }
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
r := new(PullReview) r := new(PullReview)
resp, err := c.getParsedResponse("POST", return r, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews", owner, repo, index),
fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews", owner, repo, index),
jsonHeader, bytes.NewReader(body), r) jsonHeader, bytes.NewReader(body), r)
return r, resp, err
} }
// SubmitPullReview submit a pending review to an pull request // SubmitPullReview submit a pending review to an pull request
func (c *Client) SubmitPullReview(owner, repo string, index, id int64, opt SubmitPullReviewOptions) (*PullReview, *Response, error) { func (c *Client) SubmitPullReview(owner, repo string, index, id int64, opt SubmitPullReviewOptions) (*PullReview, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err return nil, err
}
if err := opt.Validate(); err != nil {
return nil, nil, err
} }
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
r := new(PullReview) r := new(PullReview)
resp, err := c.getParsedResponse("POST", return r, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews/%d", owner, repo, index, id),
fmt.Sprintf("/repos/%s/%s/pulls/%d/reviews/%d", owner, repo, index, id),
jsonHeader, bytes.NewReader(body), r) jsonHeader, bytes.NewReader(body), r)
return r, resp, err
} }

View File

@ -8,7 +8,6 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings"
"time" "time"
) )
@ -36,22 +35,22 @@ type ListReleasesOptions struct {
} }
// ListReleases list releases of a repository // ListReleases list releases of a repository
func (c *Client) ListReleases(user, repo string, opt ListReleasesOptions) ([]*Release, *Response, error) { func (c *Client) ListReleases(user, repo string, opt ListReleasesOptions) ([]*Release, error) {
opt.setDefaults() opt.setDefaults()
releases := make([]*Release, 0, opt.PageSize) releases := make([]*Release, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", err := c.getParsedResponse("GET",
fmt.Sprintf("/repos/%s/%s/releases?%s", user, repo, opt.getURLQuery().Encode()), fmt.Sprintf("/repos/%s/%s/releases?%s", user, repo, opt.getURLQuery().Encode()),
nil, nil, &releases) nil, nil, &releases)
return releases, resp, err return releases, err
} }
// GetRelease get a release of a repository // GetRelease get a release of a repository
func (c *Client) GetRelease(user, repo string, id int64) (*Release, *Response, error) { func (c *Client) GetRelease(user, repo string, id int64) (*Release, error) {
r := new(Release) r := new(Release)
resp, err := c.getParsedResponse("GET", err := c.getParsedResponse("GET",
fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id), fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id),
nil, nil, &r) nil, nil, &r)
return r, resp, err return r, err
} }
// CreateReleaseOption options when creating a release // CreateReleaseOption options when creating a release
@ -64,28 +63,17 @@ type CreateReleaseOption struct {
IsPrerelease bool `json:"prerelease"` IsPrerelease bool `json:"prerelease"`
} }
// Validate the CreateReleaseOption struct
func (opt CreateReleaseOption) Validate() error {
if len(strings.TrimSpace(opt.Title)) == 0 {
return fmt.Errorf("title is empty")
}
return nil
}
// CreateRelease create a release // CreateRelease create a release
func (c *Client) CreateRelease(user, repo string, opt CreateReleaseOption) (*Release, *Response, error) { func (c *Client) CreateRelease(user, repo string, form CreateReleaseOption) (*Release, error) {
if err := opt.Validate(); err != nil { body, err := json.Marshal(form)
return nil, nil, err
}
body, err := json.Marshal(opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
r := new(Release) r := new(Release)
resp, err := c.getParsedResponse("POST", err = c.getParsedResponse("POST",
fmt.Sprintf("/repos/%s/%s/releases", user, repo), fmt.Sprintf("/repos/%s/%s/releases", user, repo),
jsonHeader, bytes.NewReader(body), r) jsonHeader, bytes.NewReader(body), r)
return r, resp, err return r, err
} }
// EditReleaseOption options when editing a release // EditReleaseOption options when editing a release
@ -99,22 +87,22 @@ type EditReleaseOption struct {
} }
// EditRelease edit a release // EditRelease edit a release
func (c *Client) EditRelease(user, repo string, id int64, form EditReleaseOption) (*Release, *Response, error) { func (c *Client) EditRelease(user, repo string, id int64, form EditReleaseOption) (*Release, error) {
body, err := json.Marshal(form) body, err := json.Marshal(form)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
r := new(Release) r := new(Release)
resp, err := c.getParsedResponse("PATCH", err = c.getParsedResponse("PATCH",
fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id), fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id),
jsonHeader, bytes.NewReader(body), r) jsonHeader, bytes.NewReader(body), r)
return r, resp, err return r, err
} }
// DeleteRelease delete a release from a repository // DeleteRelease delete a release from a repository
func (c *Client) DeleteRelease(user, repo string, id int64) (*Response, error) { func (c *Client) DeleteRelease(user, repo string, id int64) error {
_, resp, err := c.getResponse("DELETE", _, err := c.getResponse("DELETE",
fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id), fmt.Sprintf("/repos/%s/%s/releases/%d", user, repo, id),
nil, nil) nil, nil)
return resp, err return err
} }

View File

@ -1,5 +1,4 @@
// Copyright 2014 The Gogs Authors. All rights reserved. // Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -10,7 +9,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"strings"
"time" "time"
) )
@ -59,39 +57,23 @@ type Repository struct {
AvatarURL string `json:"avatar_url"` AvatarURL string `json:"avatar_url"`
} }
// RepoType represent repo type
type RepoType string
const (
// RepoTypeNone dont specify a type
RepoTypeNone RepoType = ""
// RepoTypeSource is the default repo type
RepoTypeSource RepoType = "source"
// RepoTypeFork is a repo witch was forked from an other one
RepoTypeFork RepoType = "fork"
// RepoTypeMirror represents an mirror repo
RepoTypeMirror RepoType = "mirror"
)
// ListReposOptions options for listing repositories // ListReposOptions options for listing repositories
type ListReposOptions struct { type ListReposOptions struct {
ListOptions ListOptions
} }
// ListMyRepos lists all repositories for the authenticated user that has access to. // ListMyRepos lists all repositories for the authenticated user that has access to.
func (c *Client) ListMyRepos(opt ListReposOptions) ([]*Repository, *Response, error) { func (c *Client) ListMyRepos(opt ListReposOptions) ([]*Repository, error) {
opt.setDefaults() opt.setDefaults()
repos := make([]*Repository, 0, opt.PageSize) repos := make([]*Repository, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/repos?%s", opt.getURLQuery().Encode()), nil, nil, &repos) return repos, c.getParsedResponse("GET", fmt.Sprintf("/user/repos?%s", opt.getURLQuery().Encode()), nil, nil, &repos)
return repos, resp, err
} }
// ListUserRepos list all repositories of one user by user's name // ListUserRepos list all repositories of one user by user's name
func (c *Client) ListUserRepos(user string, opt ListReposOptions) ([]*Repository, *Response, error) { func (c *Client) ListUserRepos(user string, opt ListReposOptions) ([]*Repository, error) {
opt.setDefaults() opt.setDefaults()
repos := make([]*Repository, 0, opt.PageSize) repos := make([]*Repository, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/repos?%s", user, opt.getURLQuery().Encode()), nil, nil, &repos) return repos, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/repos?%s", user, opt.getURLQuery().Encode()), nil, nil, &repos)
return repos, resp, err
} }
// ListOrgReposOptions options for a organization's repositories // ListOrgReposOptions options for a organization's repositories
@ -100,62 +82,26 @@ type ListOrgReposOptions struct {
} }
// ListOrgRepos list all repositories of one organization by organization's name // ListOrgRepos list all repositories of one organization by organization's name
func (c *Client) ListOrgRepos(org string, opt ListOrgReposOptions) ([]*Repository, *Response, error) { func (c *Client) ListOrgRepos(org string, opt ListOrgReposOptions) ([]*Repository, error) {
opt.setDefaults() opt.setDefaults()
repos := make([]*Repository, 0, opt.PageSize) repos := make([]*Repository, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/repos?%s", org, opt.getURLQuery().Encode()), nil, nil, &repos) return repos, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/repos?%s", org, opt.getURLQuery().Encode()), nil, nil, &repos)
return repos, resp, err
} }
// SearchRepoOptions options for searching repositories // SearchRepoOptions options for searching repositories
type SearchRepoOptions struct { type SearchRepoOptions struct {
ListOptions ListOptions
// The keyword to query
Keyword string Keyword string
// Limit search to repositories with keyword as topic Topic bool
KeywordIsTopic bool IncludeDesc bool
// Include search of keyword within repository description UID int64
KeywordInDescription bool PriorityOwnerID int64
StarredBy int64
/* Private bool
User Filter Template bool
*/ Mode string
Exclusive bool
// Repo Owner
OwnerID int64
// Stared By UserID
StarredByUserID int64
/*
Repo Attributes
*/
// pubic, private or all repositories (defaults to all)
IsPrivate *bool
// archived, non-archived or all repositories (defaults to all)
IsArchived *bool
// Exclude template repos from search
ExcludeTemplate bool
// Filter by "fork", "source", "mirror"
Type RepoType
/*
Sort Filters
*/
// sort repos by attribute. Supported values are "alpha", "created", "updated", "size", and "id". Default is "alpha"
Sort string Sort string
// sort order, either "asc" (ascending) or "desc" (descending). Default is "asc", ignored if "sort" is not specified.
Order string
// Repo owner to prioritize in the results
PrioritizedByOwnerID int64
/*
Cover EdgeCases
*/
// if set all other options are ignored and this string is used as query
RawQuery string
} }
// QueryEncode turns options into querystring argument // QueryEncode turns options into querystring argument
@ -164,46 +110,34 @@ func (opt *SearchRepoOptions) QueryEncode() string {
if opt.Keyword != "" { if opt.Keyword != "" {
query.Add("q", opt.Keyword) query.Add("q", opt.Keyword)
} }
if opt.KeywordIsTopic {
query.Add("topic", "true") query.Add("topic", fmt.Sprintf("%t", opt.Topic))
} query.Add("includeDesc", fmt.Sprintf("%t", opt.IncludeDesc))
if opt.KeywordInDescription {
query.Add("includeDesc", "true") if opt.UID > 0 {
query.Add("uid", fmt.Sprintf("%d", opt.UID))
} }
// User Filter if opt.PriorityOwnerID > 0 {
if opt.OwnerID > 0 { query.Add("priority_owner_id", fmt.Sprintf("%d", opt.PriorityOwnerID))
query.Add("uid", fmt.Sprintf("%d", opt.OwnerID))
query.Add("exclusive", "true")
}
if opt.StarredByUserID > 0 {
query.Add("starredBy", fmt.Sprintf("%d", opt.StarredByUserID))
} }
// Repo Attributes if opt.StarredBy > 0 {
if opt.IsPrivate != nil { query.Add("starredBy", fmt.Sprintf("%d", opt.StarredBy))
query.Add("is_private", fmt.Sprintf("%v", opt.IsPrivate))
}
if opt.IsArchived != nil {
query.Add("archived", fmt.Sprintf("%v", opt.IsArchived))
}
if opt.ExcludeTemplate {
query.Add("template", "false")
}
if len(opt.Type) != 0 {
query.Add("mode", string(opt.Type))
} }
// Sort Filters query.Add("private", fmt.Sprintf("%t", opt.Private))
query.Add("template", fmt.Sprintf("%t", opt.Template))
if opt.Mode != "" {
query.Add("mode", opt.Mode)
}
query.Add("exclusive", fmt.Sprintf("%t", opt.Exclusive))
if opt.Sort != "" { if opt.Sort != "" {
query.Add("sort", opt.Sort) query.Add("sort", opt.Sort)
} }
if opt.PrioritizedByOwnerID > 0 {
query.Add("priority_owner_id", fmt.Sprintf("%d", opt.PrioritizedByOwnerID))
}
if opt.Order != "" {
query.Add("order", opt.Order)
}
return query.Encode() return query.Encode()
} }
@ -213,33 +147,21 @@ type searchRepoResponse struct {
} }
// SearchRepos searches for repositories matching the given filters // SearchRepos searches for repositories matching the given filters
func (c *Client) SearchRepos(opt SearchRepoOptions) ([]*Repository, *Response, error) { func (c *Client) SearchRepos(opt SearchRepoOptions) ([]*Repository, error) {
opt.setDefaults() opt.setDefaults()
repos := new(searchRepoResponse) resp := new(searchRepoResponse)
link, _ := url.Parse("/repos/search") link, _ := url.Parse("/repos/search")
if len(opt.RawQuery) != 0 {
link.RawQuery = opt.RawQuery
} else {
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
// IsPrivate only works on gitea >= 1.12.0
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil && opt.IsPrivate != nil {
if *opt.IsPrivate {
// private repos only not supported on gitea <= 1.11.x
return nil, nil, err
}
link.Query().Add("private", "false")
}
}
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &repos) err := c.getParsedResponse("GET", link.String(), nil, nil, &resp)
return repos.Repos, resp, err return resp.Repos, err
} }
// CreateRepoOption options when creating repository // CreateRepoOption options when creating repository
type CreateRepoOption struct { type CreateRepoOption struct {
// Name of the repository to create // Name of the repository to create
//
Name string `json:"name"` Name string `json:"name"`
// Description of the repository to create // Description of the repository to create
Description string `json:"description"` Description string `json:"description"`
@ -259,47 +181,30 @@ type CreateRepoOption struct {
DefaultBranch string `json:"default_branch"` DefaultBranch string `json:"default_branch"`
} }
// Validate the CreateRepoOption struct
func (opt CreateRepoOption) Validate() error {
if len(strings.TrimSpace(opt.Name)) == 0 {
return fmt.Errorf("name is empty")
}
return nil
}
// CreateRepo creates a repository for authenticated user. // CreateRepo creates a repository for authenticated user.
func (c *Client) CreateRepo(opt CreateRepoOption) (*Repository, *Response, error) { func (c *Client) CreateRepo(opt CreateRepoOption) (*Repository, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
repo := new(Repository) repo := new(Repository)
resp, err := c.getParsedResponse("POST", "/user/repos", jsonHeader, bytes.NewReader(body), repo) return repo, c.getParsedResponse("POST", "/user/repos", jsonHeader, bytes.NewReader(body), repo)
return repo, resp, err
} }
// CreateOrgRepo creates an organization repository for authenticated user. // CreateOrgRepo creates an organization repository for authenticated user.
func (c *Client) CreateOrgRepo(org string, opt CreateRepoOption) (*Repository, *Response, error) { func (c *Client) CreateOrgRepo(org string, opt CreateRepoOption) (*Repository, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
repo := new(Repository) repo := new(Repository)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/org/%s/repos", org), jsonHeader, bytes.NewReader(body), repo) return repo, c.getParsedResponse("POST", fmt.Sprintf("/org/%s/repos", org), jsonHeader, bytes.NewReader(body), repo)
return repo, resp, err
} }
// GetRepo returns information of a repository of given owner. // GetRepo returns information of a repository of given owner.
func (c *Client) GetRepo(owner, reponame string) (*Repository, *Response, error) { func (c *Client) GetRepo(owner, reponame string) (*Repository, error) {
repo := new(Repository) repo := new(Repository)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s", owner, reponame), nil, nil, repo) return repo, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s", owner, reponame), nil, nil, repo)
return repo, resp, err
} }
// EditRepoOption options when editing a repository's properties // EditRepoOption options when editing a repository's properties
@ -337,54 +242,49 @@ type EditRepoOption struct {
} }
// EditRepo edit the properties of a repository // EditRepo edit the properties of a repository
func (c *Client) EditRepo(owner, reponame string, opt EditRepoOption) (*Repository, *Response, error) { func (c *Client) EditRepo(owner, reponame string, opt EditRepoOption) (*Repository, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
repo := new(Repository) repo := new(Repository)
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s", owner, reponame), jsonHeader, bytes.NewReader(body), repo) return repo, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s", owner, reponame), jsonHeader, bytes.NewReader(body), repo)
return repo, resp, err
} }
// DeleteRepo deletes a repository of user or organization. // DeleteRepo deletes a repository of user or organization.
func (c *Client) DeleteRepo(owner, repo string) (*Response, error) { func (c *Client) DeleteRepo(owner, repo string) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s", owner, repo), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s", owner, repo), nil, nil)
return resp, err return err
}
// MigrateRepoOption options for migrating a repository from an external service
type MigrateRepoOption struct {
CloneAddr string `json:"clone_addr"`
AuthUsername string `json:"auth_username"`
AuthPassword string `json:"auth_password"`
UID int `json:"uid"`
RepoName string `json:"repo_name"`
Mirror bool `json:"mirror"`
Private bool `json:"private"`
Description string `json:"description"`
}
// MigrateRepo migrates a repository from other Git hosting sources for the
// authenticated user.
//
// To migrate a repository for a organization, the authenticated user must be a
// owner of the specified organization.
func (c *Client) MigrateRepo(opt MigrateRepoOption) (*Repository, error) {
body, err := json.Marshal(&opt)
if err != nil {
return nil, err
}
repo := new(Repository)
return repo, c.getParsedResponse("POST", "/repos/migrate", jsonHeader, bytes.NewReader(body), repo)
} }
// MirrorSync adds a mirrored repository to the mirror sync queue. // MirrorSync adds a mirrored repository to the mirror sync queue.
func (c *Client) MirrorSync(owner, repo string) (*Response, error) { func (c *Client) MirrorSync(owner, repo string) error {
_, resp, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/mirror-sync", owner, repo), nil, nil) _, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/mirror-sync", owner, repo), nil, nil)
return resp, err return err
}
// GetRepoLanguages return language stats of a repo
func (c *Client) GetRepoLanguages(owner, repo string) (map[string]int64, *Response, error) {
langMap := make(map[string]int64)
data, resp, err := c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/languages", owner, repo), jsonHeader, nil)
if err != nil {
return nil, resp, err
}
if err = json.Unmarshal(data, &langMap); err != nil {
return nil, resp, err
}
return langMap, resp, nil
}
// ArchiveType represent supported archive formats by gitea
type ArchiveType string
const (
// ZipArchive represent zip format
ZipArchive ArchiveType = ".zip"
// TarGZArchive represent tar.gz format
TarGZArchive ArchiveType = ".tar.gz"
)
// GetArchive get an archive of a repository by git reference
// e.g.: ref -> master, 70b7c74b33, v1.2.1, ...
func (c *Client) GetArchive(owner, repo, ref string, ext ArchiveType) ([]byte, *Response, error) {
return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/archive/%s%s", owner, repo, url.PathEscape(ref), ext), nil, nil)
} }

View File

@ -6,8 +6,6 @@
package gitea package gitea
import ( import (
"bytes"
"encoding/json"
"fmt" "fmt"
"time" "time"
) )
@ -65,70 +63,29 @@ type ListRepoBranchesOptions struct {
} }
// ListRepoBranches list all the branches of one repository // ListRepoBranches list all the branches of one repository
func (c *Client) ListRepoBranches(user, repo string, opt ListRepoBranchesOptions) ([]*Branch, *Response, error) { func (c *Client) ListRepoBranches(user, repo string, opt ListRepoBranchesOptions) ([]*Branch, error) {
opt.setDefaults() opt.setDefaults()
branches := make([]*Branch, 0, opt.PageSize) branches := make([]*Branch, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &branches) return branches, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &branches)
return branches, resp, err
} }
// GetRepoBranch get one branch's information of one repository // GetRepoBranch get one branch's information of one repository
func (c *Client) GetRepoBranch(user, repo, branch string) (*Branch, *Response, error) { func (c *Client) GetRepoBranch(user, repo, branch string) (*Branch, error) {
b := new(Branch) b := new(Branch)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil, &b) if err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil, &b); err != nil {
if err != nil { return nil, err
return nil, resp, err
} }
return b, resp, nil return b, nil
} }
// DeleteRepoBranch delete a branch in a repository // DeleteRepoBranch delete a branch in a repository
func (c *Client) DeleteRepoBranch(user, repo, branch string) (bool, *Response, error) { func (c *Client) DeleteRepoBranch(user, repo, branch string) (bool, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return false, nil, err return false, err
} }
status, resp, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil) status, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil)
if err != nil { if err != nil {
return false, resp, err return false, err
} }
return status == 204, resp, nil return status == 204, nil
}
// CreateBranchOption options when creating a branch in a repository
type CreateBranchOption struct {
// Name of the branch to create
BranchName string `json:"new_branch_name"`
// Name of the old branch to create from (optional)
OldBranchName string `json:"old_branch_name"`
}
// Validate the CreateBranchOption struct
func (opt CreateBranchOption) Validate() error {
if len(opt.BranchName) == 0 {
return fmt.Errorf("BranchName is empty")
}
if len(opt.BranchName) > 100 {
return fmt.Errorf("BranchName to long")
}
if len(opt.OldBranchName) > 100 {
return fmt.Errorf("OldBranchName to long")
}
return nil
}
// CreateBranch creates a branch for a user's repository
func (c *Client) CreateBranch(owner, repo string, opt CreateBranchOption) (*Branch, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil {
return nil, nil, err
}
if err := opt.Validate(); err != nil {
return nil, nil, err
}
body, err := json.Marshal(&opt)
if err != nil {
return nil, nil, err
}
branch := new(Branch)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/branches", owner, repo), jsonHeader, bytes.NewReader(body), branch)
return branch, resp, err
} }

View File

@ -34,7 +34,9 @@ type BranchProtection struct {
DismissStaleApprovals bool `json:"dismiss_stale_approvals"` DismissStaleApprovals bool `json:"dismiss_stale_approvals"`
RequireSignedCommits bool `json:"require_signed_commits"` RequireSignedCommits bool `json:"require_signed_commits"`
ProtectedFilePatterns string `json:"protected_file_patterns"` ProtectedFilePatterns string `json:"protected_file_patterns"`
// swagger:strfmt date-time
Created time.Time `json:"created_at"` Created time.Time `json:"created_at"`
// swagger:strfmt date-time
Updated time.Time `json:"updated_at"` Updated time.Time `json:"updated_at"`
} }
@ -91,60 +93,56 @@ type ListBranchProtectionsOptions struct {
} }
// ListBranchProtections list branch protections for a repo // ListBranchProtections list branch protections for a repo
func (c *Client) ListBranchProtections(owner, repo string, opt ListBranchProtectionsOptions) ([]*BranchProtection, *Response, error) { func (c *Client) ListBranchProtections(owner, repo string, opt ListBranchProtectionsOptions) ([]*BranchProtection, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err
}
bps := make([]*BranchProtection, 0, opt.PageSize)
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/branch_protections", owner, repo))
link.RawQuery = opt.getURLQuery().Encode()
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &bps)
return bps, resp, err
}
// GetBranchProtection gets a branch protection
func (c *Client) GetBranchProtection(owner, repo, name string) (*BranchProtection, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err
}
bp := new(BranchProtection)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branch_protections/%s", owner, repo, name), jsonHeader, nil, bp)
return bp, resp, err
}
// CreateBranchProtection creates a branch protection for a repo
func (c *Client) CreateBranchProtection(owner, repo string, opt CreateBranchProtectionOption) (*BranchProtection, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err
}
bp := new(BranchProtection)
body, err := json.Marshal(&opt)
if err != nil {
return nil, nil, err
}
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/branch_protections", owner, repo), jsonHeader, bytes.NewReader(body), bp)
return bp, resp, err
}
// EditBranchProtection edits a branch protection for a repo
func (c *Client) EditBranchProtection(owner, repo, name string, opt EditBranchProtectionOption) (*BranchProtection, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err
}
bp := new(BranchProtection)
body, err := json.Marshal(&opt)
if err != nil {
return nil, nil, err
}
resp, err := c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/branch_protections/%s", owner, repo, name), jsonHeader, bytes.NewReader(body), bp)
return bp, resp, err
}
// DeleteBranchProtection deletes a branch protection for a repo
func (c *Client) DeleteBranchProtection(owner, repo, name string) (*Response, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, err return nil, err
} }
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/branch_protections/%s", owner, repo, name), jsonHeader, nil) bps := make([]*BranchProtection, 0, 5)
return resp, err link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/branch_protections", owner, repo))
link.RawQuery = opt.getURLQuery().Encode()
return bps, c.getParsedResponse("GET", link.String(), jsonHeader, nil, &bps)
}
// GetBranchProtection gets a branch protection
func (c *Client) GetBranchProtection(owner, repo, name string) (*BranchProtection, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, err
}
bp := new(BranchProtection)
return bp, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branch_protections/%s", owner, repo, name), jsonHeader, nil, bp)
}
// CreateBranchProtection creates a branch protection for a repo
func (c *Client) CreateBranchProtection(owner, repo string, opt CreateBranchProtectionOption) (*BranchProtection, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, err
}
bp := new(BranchProtection)
body, err := json.Marshal(&opt)
if err != nil {
return nil, err
}
return bp, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/branch_protections", owner, repo), jsonHeader, bytes.NewReader(body), bp)
}
// EditBranchProtection edits a branch protection for a repo
func (c *Client) EditBranchProtection(owner, repo, name string, opt EditBranchProtectionOption) (*BranchProtection, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, err
}
bp := new(BranchProtection)
body, err := json.Marshal(&opt)
if err != nil {
return nil, err
}
return bp, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/branch_protections/%s", owner, repo, name), jsonHeader, bytes.NewReader(body), bp)
}
// DeleteBranchProtection deletes a branch protection for a repo
func (c *Client) DeleteBranchProtection(owner, repo, name string) error {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return err
}
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/branch_protections/%s", owner, repo, name), jsonHeader, nil)
return err
} }

View File

@ -16,82 +16,44 @@ type ListCollaboratorsOptions struct {
} }
// ListCollaborators list a repository's collaborators // ListCollaborators list a repository's collaborators
func (c *Client) ListCollaborators(user, repo string, opt ListCollaboratorsOptions) ([]*User, *Response, error) { func (c *Client) ListCollaborators(user, repo string, opt ListCollaboratorsOptions) ([]*User, error) {
opt.setDefaults() opt.setDefaults()
collaborators := make([]*User, 0, opt.PageSize) collaborators := make([]*User, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", return collaborators, c.getParsedResponse("GET",
fmt.Sprintf("/repos/%s/%s/collaborators?%s", user, repo, opt.getURLQuery().Encode()), fmt.Sprintf("/repos/%s/%s/collaborators?%s", user, repo, opt.getURLQuery().Encode()),
nil, nil, &collaborators) nil, nil, &collaborators)
return collaborators, resp, err
} }
// IsCollaborator check if a user is a collaborator of a repository // IsCollaborator check if a user is a collaborator of a repository
func (c *Client) IsCollaborator(user, repo, collaborator string) (bool, *Response, error) { func (c *Client) IsCollaborator(user, repo, collaborator string) (bool, error) {
status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, nil) status, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, nil)
if err != nil { if err != nil {
return false, resp, err return false, err
} }
if status == 204 { if status == 204 {
return true, resp, nil return true, nil
} }
return false, resp, nil return false, nil
} }
// AddCollaboratorOption options when adding a user as a collaborator of a repository // AddCollaboratorOption options when adding a user as a collaborator of a repository
type AddCollaboratorOption struct { type AddCollaboratorOption struct {
Permission *AccessMode `json:"permission"` Permission *string `json:"permission"`
}
// AccessMode represent the grade of access you have to something
type AccessMode string
const (
// AccessModeNone no access
AccessModeNone AccessMode = "none"
// AccessModeRead read access
AccessModeRead AccessMode = "read"
// AccessModeWrite write access
AccessModeWrite AccessMode = "write"
// AccessModeAdmin admin access
AccessModeAdmin AccessMode = "admin"
// AccessModeOwner owner
AccessModeOwner AccessMode = "owner"
)
// Validate the AddCollaboratorOption struct
func (opt AddCollaboratorOption) Validate() error {
if opt.Permission != nil {
if *opt.Permission == AccessModeOwner {
*opt.Permission = AccessModeAdmin
return nil
}
if *opt.Permission == AccessModeNone {
opt.Permission = nil
return nil
}
if *opt.Permission != AccessModeRead && *opt.Permission != AccessModeWrite && *opt.Permission != AccessModeAdmin {
return fmt.Errorf("permission mode invalid")
}
}
return nil
} }
// AddCollaborator add some user as a collaborator of a repository // AddCollaborator add some user as a collaborator of a repository
func (c *Client) AddCollaborator(user, repo, collaborator string, opt AddCollaboratorOption) (*Response, error) { func (c *Client) AddCollaborator(user, repo, collaborator string, opt AddCollaboratorOption) error {
if err := opt.Validate(); err != nil {
return nil, err
}
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), jsonHeader, bytes.NewReader(body)) _, err = c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), jsonHeader, bytes.NewReader(body))
return resp, err return err
} }
// DeleteCollaborator remove a collaborator from a repository // DeleteCollaborator remove a collaborator from a repository
func (c *Client) DeleteCollaborator(user, repo, collaborator string) (*Response, error) { func (c *Client) DeleteCollaborator(user, repo, collaborator string) error {
_, resp, err := c.getResponse("DELETE", _, err := c.getResponse("DELETE",
fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, nil) fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, nil)
return resp, err return err
} }

View File

@ -55,10 +55,9 @@ type CommitDateOptions struct {
} }
// GetSingleCommit returns a single commit // GetSingleCommit returns a single commit
func (c *Client) GetSingleCommit(user, repo, commitID string) (*Commit, *Response, error) { func (c *Client) GetSingleCommit(user, repo, commitID string) (*Commit, error) {
commit := new(Commit) commit := new(Commit)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/commits/%s", user, repo, commitID), nil, nil, &commit) return commit, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/commits/%s", user, repo, commitID), nil, nil, &commit)
return commit, resp, err
} }
// ListCommitOptions list commit options // ListCommitOptions list commit options
@ -78,11 +77,10 @@ func (opt *ListCommitOptions) QueryEncode() string {
} }
// ListRepoCommits return list of commits from a repo // ListRepoCommits return list of commits from a repo
func (c *Client) ListRepoCommits(user, repo string, opt ListCommitOptions) ([]*Commit, *Response, error) { func (c *Client) ListRepoCommits(user, repo string, opt ListCommitOptions) ([]*Commit, error) {
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/commits", user, repo)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/commits", user, repo))
opt.setDefaults() opt.setDefaults()
commits := make([]*Commit, 0, opt.PageSize) commits := make([]*Commit, 0, opt.PageSize)
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &commits) return commits, c.getParsedResponse("GET", link.String(), nil, nil, &commits)
return commits, resp, err
} }

View File

@ -114,76 +114,74 @@ type FileDeleteResponse struct {
// GetFile downloads a file of repository, ref can be branch/tag/commit. // GetFile downloads a file of repository, ref can be branch/tag/commit.
// e.g.: ref -> master, tree -> macaron.go(no leading slash) // e.g.: ref -> master, tree -> macaron.go(no leading slash)
func (c *Client) GetFile(user, repo, ref, tree string) ([]byte, *Response, error) { func (c *Client) GetFile(user, repo, ref, tree string) ([]byte, error) {
return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/raw/%s/%s", user, repo, ref, tree), nil, nil) return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/raw/%s/%s", user, repo, ref, tree), nil, nil)
} }
// GetContents get the metadata and contents (if a file) of an entry in a repository, or a list of entries if a dir // GetContents get the metadata and contents (if a file) of an entry in a repository, or a list of entries if a dir
// ref is optional // ref is optional
func (c *Client) GetContents(owner, repo, ref, filepath string) (*ContentsResponse, *Response, error) { func (c *Client) GetContents(owner, repo, ref, filepath string) (*ContentsResponse, error) {
cr := new(ContentsResponse) cr := new(ContentsResponse)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/contents/%s?ref=%s", owner, repo, filepath, ref), jsonHeader, nil, cr) return cr, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/contents/%s?ref=%s", owner, repo, filepath, ref), jsonHeader, nil, cr)
return cr, resp, err
} }
// CreateFile create a file in a repository // CreateFile create a file in a repository
func (c *Client) CreateFile(owner, repo, filepath string, opt CreateFileOptions) (*FileResponse, *Response, error) { func (c *Client) CreateFile(owner, repo, filepath string, opt CreateFileOptions) (*FileResponse, error) {
var err error var err error
if opt.BranchName, err = c.setDefaultBranchForOldVersions(owner, repo, opt.BranchName); err != nil { if opt.BranchName, err = c.setDefaultBranchForOldVersions(owner, repo, opt.BranchName); err != nil {
return nil, nil, err return nil, err
} }
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
fr := new(FileResponse) fr := new(FileResponse)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/contents/%s", owner, repo, filepath), jsonHeader, bytes.NewReader(body), fr) return fr, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/contents/%s", owner, repo, filepath), jsonHeader, bytes.NewReader(body), fr)
return fr, resp, err
} }
// UpdateFile update a file in a repository // UpdateFile update a file in a repository
func (c *Client) UpdateFile(owner, repo, filepath string, opt UpdateFileOptions) (*FileResponse, *Response, error) { func (c *Client) UpdateFile(owner, repo, filepath string, opt UpdateFileOptions) (*FileResponse, error) {
var err error var err error
if opt.BranchName, err = c.setDefaultBranchForOldVersions(owner, repo, opt.BranchName); err != nil { if opt.BranchName, err = c.setDefaultBranchForOldVersions(owner, repo, opt.BranchName); err != nil {
return nil, nil, err return nil, err
} }
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
fr := new(FileResponse) fr := new(FileResponse)
resp, err := c.getParsedResponse("PUT", fmt.Sprintf("/repos/%s/%s/contents/%s", owner, repo, filepath), jsonHeader, bytes.NewReader(body), fr) return fr, c.getParsedResponse("PUT", fmt.Sprintf("/repos/%s/%s/contents/%s", owner, repo, filepath), jsonHeader, bytes.NewReader(body), fr)
return fr, resp, err
} }
// DeleteFile delete a file from repository // DeleteFile delete a file from repository
func (c *Client) DeleteFile(owner, repo, filepath string, opt DeleteFileOptions) (*Response, error) { func (c *Client) DeleteFile(owner, repo, filepath string, opt DeleteFileOptions) error {
var err error var err error
if opt.BranchName, err = c.setDefaultBranchForOldVersions(owner, repo, opt.BranchName); err != nil { if opt.BranchName, err = c.setDefaultBranchForOldVersions(owner, repo, opt.BranchName); err != nil {
return nil, err return err
} }
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, err return err
} }
status, resp, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/contents/%s", owner, repo, filepath), jsonHeader, bytes.NewReader(body)) status, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/contents/%s", owner, repo, filepath), jsonHeader, bytes.NewReader(body))
if err != nil { if err != nil {
return resp, err return err
} }
if status != 200 && status != 204 { if status != 200 && status != 204 {
return resp, fmt.Errorf("unexpected Status: %d", status) return fmt.Errorf("unexpected Status: %d", status)
} }
return resp, nil return nil
} }
func (c *Client) setDefaultBranchForOldVersions(owner, repo, branch string) (string, error) { func (c *Client) setDefaultBranchForOldVersions(owner, repo, branch string) (string, error) {
if len(branch) == 0 { if len(branch) == 0 {
// Gitea >= 1.12.0 Use DefaultBranch on "", mimic this for older versions // Gitea >= 1.12.0 Use DefaultBranch on "", mimic this for older versions
if c.CheckServerVersionConstraint(">=1.12.0") != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
r, _, err := c.GetRepo(owner, repo) r, err := c.GetRepo(owner, repo)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -45,35 +45,32 @@ func (opt *ListDeployKeysOptions) QueryEncode() string {
} }
// ListDeployKeys list all the deploy keys of one repository // ListDeployKeys list all the deploy keys of one repository
func (c *Client) ListDeployKeys(user, repo string, opt ListDeployKeysOptions) ([]*DeployKey, *Response, error) { func (c *Client) ListDeployKeys(user, repo string, opt ListDeployKeysOptions) ([]*DeployKey, error) {
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/keys", user, repo)) link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/keys", user, repo))
opt.setDefaults() opt.setDefaults()
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
keys := make([]*DeployKey, 0, opt.PageSize) keys := make([]*DeployKey, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &keys) return keys, c.getParsedResponse("GET", link.String(), nil, nil, &keys)
return keys, resp, err
} }
// GetDeployKey get one deploy key with key id // GetDeployKey get one deploy key with key id
func (c *Client) GetDeployKey(user, repo string, keyID int64) (*DeployKey, *Response, error) { func (c *Client) GetDeployKey(user, repo string, keyID int64) (*DeployKey, error) {
key := new(DeployKey) key := new(DeployKey)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/keys/%d", user, repo, keyID), nil, nil, &key) return key, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/keys/%d", user, repo, keyID), nil, nil, &key)
return key, resp, err
} }
// CreateDeployKey options when create one deploy key // CreateDeployKey options when create one deploy key
func (c *Client) CreateDeployKey(user, repo string, opt CreateKeyOption) (*DeployKey, *Response, error) { func (c *Client) CreateDeployKey(user, repo string, opt CreateKeyOption) (*DeployKey, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
key := new(DeployKey) key := new(DeployKey)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/keys", user, repo), jsonHeader, bytes.NewReader(body), key) return key, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/keys", user, repo), jsonHeader, bytes.NewReader(body), key)
return key, resp, err
} }
// DeleteDeployKey delete deploy key with key id // DeleteDeployKey delete deploy key with key id
func (c *Client) DeleteDeployKey(owner, repo string, keyID int64) (*Response, error) { func (c *Client) DeleteDeployKey(owner, repo string, keyID int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/keys/%d", owner, repo, keyID), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/keys/%d", owner, repo, keyID), nil, nil)
return resp, err return err
} }

View File

@ -1,115 +0,0 @@
// 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 gitea
import (
"bytes"
"encoding/json"
"fmt"
)
// GitServiceType represents a git service
type GitServiceType string
const (
// GitServicePlain represents a plain git service
GitServicePlain GitServiceType = "git"
//GitServiceGithub represents github.com
GitServiceGithub GitServiceType = "github"
// GitServiceGitlab represents a gitlab service
GitServiceGitlab GitServiceType = "gitlab"
// Not supported jet
// // GitServiceGitea represents a gitea service
// GitServiceGitea GitServiceType = "gitea"
// // GitServiceGogs represents a gogs service
// GitServiceGogs GitServiceType = "gogs"
)
// MigrateRepoOption options for migrating a repository from an external service
type MigrateRepoOption struct {
RepoName string `json:"repo_name"`
RepoOwner string `json:"repo_owner"`
// deprecated use RepoOwner
RepoOwnerID int64 `json:"uid"`
CloneAddr string `json:"clone_addr"`
Service GitServiceType `json:"service"`
AuthUsername string `json:"auth_username"`
AuthPassword string `json:"auth_password"`
AuthToken string `json:"auth_token"`
Mirror bool `json:"mirror"`
Private bool `json:"private"`
Description string `json:"description"`
Wiki bool `json:"wiki"`
Milestones bool `json:"milestones"`
Labels bool `json:"labels"`
Issues bool `json:"issues"`
PullRequests bool `json:"pull_requests"`
Releases bool `json:"releases"`
}
// Validate the MigrateRepoOption struct
func (opt *MigrateRepoOption) Validate() error {
// check user options
if len(opt.CloneAddr) == 0 {
return fmt.Errorf("CloneAddr required")
}
if len(opt.RepoName) == 0 {
return fmt.Errorf("RepoName required")
} else if len(opt.RepoName) > 100 {
return fmt.Errorf("RepoName to long")
}
if len(opt.Description) > 255 {
return fmt.Errorf("Description to long")
}
switch opt.Service {
case GitServiceGithub:
if len(opt.AuthToken) == 0 {
return fmt.Errorf("github require token authentication")
}
}
return nil
}
// MigrateRepo migrates a repository from other Git hosting sources for the authenticated user.
//
// To migrate a repository for a organization, the authenticated user must be a
// owner of the specified organization.
func (c *Client) MigrateRepo(opt MigrateRepoOption) (*Repository, *Response, error) {
if err := opt.Validate(); err != nil {
return nil, nil, err
}
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil {
if len(opt.AuthToken) != 0 {
// gitea <= 1.12 dont understand AuthToken
opt.AuthUsername = opt.AuthToken
opt.AuthPassword, opt.AuthToken = "", ""
}
if len(opt.RepoOwner) != 0 {
// gitea <= 1.12 dont understand RepoOwner
u, _, err := c.GetUserInfo(opt.RepoOwner)
if err != nil {
return nil, nil, err
}
opt.RepoOwnerID = u.ID
} else if opt.RepoOwnerID == 0 {
// gitea <= 1.12 require RepoOwnerID
u, _, err := c.GetMyUserInfo()
if err != nil {
return nil, nil, err
}
opt.RepoOwnerID = u.ID
}
}
body, err := json.Marshal(&opt)
if err != nil {
return nil, nil, err
}
repo := new(Repository)
resp, err := c.getParsedResponse("POST", "/repos/migrate", jsonHeader, bytes.NewReader(body), repo)
return repo, resp, err
}

View File

@ -26,44 +26,44 @@ type GitObject struct {
} }
// GetRepoRef get one ref's information of one repository // GetRepoRef get one ref's information of one repository
func (c *Client) GetRepoRef(user, repo, ref string) (*Reference, *Response, error) { func (c *Client) GetRepoRef(user, repo, ref string) (*Reference, error) {
ref = strings.TrimPrefix(ref, "refs/") ref = strings.TrimPrefix(ref, "refs/")
r := new(Reference) r := new(Reference)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/refs/%s", user, repo, ref), nil, nil, &r) err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/refs/%s", user, repo, ref), nil, nil, &r)
if _, ok := err.(*json.UnmarshalTypeError); ok { if _, ok := err.(*json.UnmarshalTypeError); ok {
// Multiple refs // Multiple refs
return nil, resp, errors.New("no exact match found for this ref") return nil, errors.New("no exact match found for this ref")
} else if err != nil { } else if err != nil {
return nil, resp, err return nil, err
} }
return r, resp, nil return r, nil
} }
// GetRepoRefs get list of ref's information of one repository // GetRepoRefs get list of ref's information of one repository
func (c *Client) GetRepoRefs(user, repo, ref string) ([]*Reference, *Response, error) { func (c *Client) GetRepoRefs(user, repo, ref string) ([]*Reference, error) {
ref = strings.TrimPrefix(ref, "refs/") ref = strings.TrimPrefix(ref, "refs/")
data, resp, err := c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/git/refs/%s", user, repo, ref), nil, nil) resp, err := c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/git/refs/%s", user, repo, ref), nil, nil)
if err != nil { if err != nil {
return nil, resp, err return nil, err
} }
// Attempt to unmarshal single returned ref. // Attempt to unmarshal single returned ref.
r := new(Reference) r := new(Reference)
refErr := json.Unmarshal(data, r) refErr := json.Unmarshal(resp, r)
if refErr == nil { if refErr == nil {
return []*Reference{r}, resp, nil return []*Reference{r}, nil
} }
// Attempt to unmarshal multiple refs. // Attempt to unmarshal multiple refs.
var rs []*Reference var rs []*Reference
refsErr := json.Unmarshal(data, &rs) refsErr := json.Unmarshal(resp, &rs)
if refsErr == nil { if refsErr == nil {
if len(rs) == 0 { if len(rs) == 0 {
return nil, resp, errors.New("unexpected response: an array of refs with length 0") return nil, errors.New("unexpected response: an array of refs with length 0")
} }
return rs, resp, nil return rs, nil
} }
return nil, resp, fmt.Errorf("unmarshalling failed for both single and multiple refs: %s and %s", refErr, refsErr) return nil, fmt.Errorf("unmarshalling failed for both single and multiple refs: %s and %s", refErr, refsErr)
} }

View File

@ -23,9 +23,8 @@ type ListRepoTagsOptions struct {
} }
// ListRepoTags list all the branches of one repository // ListRepoTags list all the branches of one repository
func (c *Client) ListRepoTags(user, repo string, opt ListRepoTagsOptions) ([]*Tag, *Response, error) { func (c *Client) ListRepoTags(user, repo string, opt ListRepoTagsOptions) ([]*Tag, error) {
opt.setDefaults() opt.setDefaults()
tags := make([]*Tag, 0, opt.PageSize) tags := make([]*Tag, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/tags?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &tags) return tags, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/tags?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, &tags)
return tags, resp, err
} }

View File

@ -21,38 +21,38 @@ type topicsList struct {
} }
// ListRepoTopics list all repository's topics // ListRepoTopics list all repository's topics
func (c *Client) ListRepoTopics(user, repo string, opt ListRepoTopicsOptions) ([]string, *Response, error) { func (c *Client) ListRepoTopics(user, repo string, opt ListRepoTopicsOptions) ([]string, error) {
opt.setDefaults() opt.setDefaults()
list := new(topicsList) list := new(topicsList)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/topics?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, list) err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/topics?%s", user, repo, opt.getURLQuery().Encode()), nil, nil, list)
if err != nil { if err != nil {
return nil, resp, err return nil, err
} }
return list.Topics, resp, nil return list.Topics, nil
} }
// SetRepoTopics replaces the list of repo's topics // SetRepoTopics replaces the list of repo's topics
func (c *Client) SetRepoTopics(user, repo string, list []string) (*Response, error) { func (c *Client) SetRepoTopics(user, repo string, list []string) error {
l := topicsList{Topics: list} l := topicsList{Topics: list}
body, err := json.Marshal(&l) body, err := json.Marshal(&l)
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/topics", user, repo), jsonHeader, bytes.NewReader(body)) _, err = c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/topics", user, repo), jsonHeader, bytes.NewReader(body))
return resp, err return err
} }
// AddRepoTopic adds a topic to a repo's topics list // AddRepoTopic adds a topic to a repo's topics list
func (c *Client) AddRepoTopic(user, repo, topic string) (*Response, error) { func (c *Client) AddRepoTopic(user, repo, topic string) error {
_, resp, err := c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/topics/%s", user, repo, topic), nil, nil) _, err := c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/topics/%s", user, repo, topic), nil, nil)
return resp, err return err
} }
// DeleteRepoTopic deletes a topic from repo's topics list // DeleteRepoTopic deletes a topic from repo's topics list
func (c *Client) DeleteRepoTopic(user, repo, topic string) (*Response, error) { func (c *Client) DeleteRepoTopic(user, repo, topic string) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/topics/%s", user, repo, topic), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/topics/%s", user, repo, topic), nil, nil)
return resp, err return err
} }

View File

@ -19,15 +19,14 @@ type TransferRepoOption struct {
} }
// TransferRepo transfers the ownership of a repository // TransferRepo transfers the ownership of a repository
func (c *Client) TransferRepo(owner, reponame string, opt TransferRepoOption) (*Repository, *Response, error) { func (c *Client) TransferRepo(owner, reponame string, opt TransferRepoOption) (*Repository, error) {
if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil {
return nil, nil, err return nil, err
} }
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
repo := new(Repository) repo := new(Repository)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/transfer", owner, reponame), jsonHeader, bytes.NewReader(body), repo) return repo, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/transfer", owner, reponame), jsonHeader, bytes.NewReader(body), repo)
return repo, resp, err
} }

View File

@ -30,12 +30,11 @@ type GitTreeResponse struct {
// GetTrees downloads a file of repository, ref can be branch/tag/commit. // GetTrees downloads a file of repository, ref can be branch/tag/commit.
// e.g.: ref -> master, tree -> macaron.go(no leading slash) // e.g.: ref -> master, tree -> macaron.go(no leading slash)
func (c *Client) GetTrees(user, repo, ref string, recursive bool) (*GitTreeResponse, *Response, error) { func (c *Client) GetTrees(user, repo, ref string, recursive bool) (*GitTreeResponse, error) {
trees := new(GitTreeResponse) trees := new(GitTreeResponse)
var path = fmt.Sprintf("/repos/%s/%s/git/trees/%s", user, repo, ref) var path = fmt.Sprintf("/repos/%s/%s/git/trees/%s", user, repo, ref)
if recursive { if recursive {
path += "?recursive=1" path += "?recursive=1"
} }
resp, err := c.getParsedResponse("GET", path, nil, nil, trees) return trees, c.getParsedResponse("GET", path, nil, nil, trees)
return trees, resp, err
} }

View File

@ -21,55 +21,53 @@ type WatchInfo struct {
} }
// GetWatchedRepos list all the watched repos of user // GetWatchedRepos list all the watched repos of user
func (c *Client) GetWatchedRepos(user string) ([]*Repository, *Response, error) { func (c *Client) GetWatchedRepos(user string) ([]*Repository, error) {
repos := make([]*Repository, 0, 10) repos := make([]*Repository, 0, 10)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/subscriptions", user), nil, nil, &repos) return repos, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/subscriptions", user), nil, nil, &repos)
return repos, resp, err
} }
// GetMyWatchedRepos list repositories watched by the authenticated user // GetMyWatchedRepos list repositories watched by the authenticated user
func (c *Client) GetMyWatchedRepos() ([]*Repository, *Response, error) { func (c *Client) GetMyWatchedRepos() ([]*Repository, error) {
repos := make([]*Repository, 0, 10) repos := make([]*Repository, 0, 10)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/subscriptions"), nil, nil, &repos) return repos, c.getParsedResponse("GET", fmt.Sprintf("/user/subscriptions"), nil, nil, &repos)
return repos, resp, err
} }
// CheckRepoWatch check if the current user is watching a repo // CheckRepoWatch check if the current user is watching a repo
func (c *Client) CheckRepoWatch(repoUser, repoName string) (bool, *Response, error) { func (c *Client) CheckRepoWatch(repoUser, repoName string) (bool, error) {
status, resp, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/subscription", repoUser, repoName), nil, nil) status, err := c.getStatusCode("GET", fmt.Sprintf("/repos/%s/%s/subscription", repoUser, repoName), nil, nil)
if err != nil { if err != nil {
return false, resp, err return false, err
} }
switch status { switch status {
case http.StatusNotFound: case http.StatusNotFound:
return false, resp, nil return false, nil
case http.StatusOK: case http.StatusOK:
return true, resp, nil return true, nil
default: default:
return false, resp, fmt.Errorf("unexpected Status: %d", status) return false, fmt.Errorf("unexpected Status: %d", status)
} }
} }
// WatchRepo start to watch a repository // WatchRepo start to watch a repository
func (c *Client) WatchRepo(repoUser, repoName string) (*Response, error) { func (c *Client) WatchRepo(repoUser, repoName string) error {
status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/subscription", repoUser, repoName), nil, nil) status, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/subscription", repoUser, repoName), nil, nil)
if err != nil { if err != nil {
return resp, err return err
} }
if status == http.StatusOK { if status == http.StatusOK {
return resp, nil return nil
} }
return resp, fmt.Errorf("unexpected Status: %d", status) return fmt.Errorf("unexpected Status: %d", status)
} }
// UnWatchRepo stop to watch a repository // UnWatchRepo stop to watch a repository
func (c *Client) UnWatchRepo(repoUser, repoName string) (*Response, error) { func (c *Client) UnWatchRepo(repoUser, repoName string) error {
status, resp, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/subscription", repoUser, repoName), nil, nil) status, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/subscription", repoUser, repoName), nil, nil)
if err != nil { if err != nil {
return resp, err return err
} }
if status == http.StatusNoContent { if status == http.StatusNoContent {
return resp, nil return nil
} }
return resp, fmt.Errorf("unexpected Status: %d", status) return fmt.Errorf("unexpected Status: %d", status)
} }

View File

@ -1,72 +0,0 @@
// 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 gitea
// GlobalUISettings represent the global ui settings of a gitea instance witch is exposed by API
type GlobalUISettings struct {
AllowedReactions []string `json:"allowed_reactions"`
}
// GlobalRepoSettings represent the global repository settings of a gitea instance witch is exposed by API
type GlobalRepoSettings struct {
MirrorsDisabled bool `json:"mirrors_disabled"`
HTTPGitDisabled bool `json:"http_git_disabled"`
}
// GlobalAPISettings contains global api settings exposed by it
type GlobalAPISettings struct {
MaxResponseItems int `json:"max_response_items"`
DefaultPagingNum int `json:"default_paging_num"`
DefaultGitTreesPerPage int `json:"default_git_trees_per_page"`
DefaultMaxBlobSize int64 `json:"default_max_blob_size"`
}
// GlobalAttachmentSettings contains global Attachment settings exposed by API
type GlobalAttachmentSettings struct {
Enabled bool `json:"enabled"`
AllowedTypes string `json:"allowed_types"`
MaxSize int64 `json:"max_size"`
MaxFiles int `json:"max_files"`
}
// GetGlobalUISettings get global ui settings witch are exposed by API
func (c *Client) GetGlobalUISettings() (*GlobalUISettings, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil {
return nil, nil, err
}
conf := new(GlobalUISettings)
resp, err := c.getParsedResponse("GET", "/settings/ui", jsonHeader, nil, &conf)
return conf, resp, err
}
// GetGlobalRepoSettings get global repository settings witch are exposed by API
func (c *Client) GetGlobalRepoSettings() (*GlobalRepoSettings, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil {
return nil, nil, err
}
conf := new(GlobalRepoSettings)
resp, err := c.getParsedResponse("GET", "/settings/repository", jsonHeader, nil, &conf)
return conf, resp, err
}
// GetGlobalAPISettings get global api settings witch are exposed by it
func (c *Client) GetGlobalAPISettings() (*GlobalAPISettings, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil {
return nil, nil, err
}
conf := new(GlobalAPISettings)
resp, err := c.getParsedResponse("GET", "/settings/api", jsonHeader, nil, &conf)
return conf, resp, err
}
// GetGlobalAttachmentSettings get global repository settings witch are exposed by API
func (c *Client) GetGlobalAttachmentSettings() (*GlobalAttachmentSettings, *Response, error) {
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil {
return nil, nil, err
}
conf := new(GlobalAttachmentSettings)
resp, err := c.getParsedResponse("GET", "/settings/attachment", jsonHeader, nil, &conf)
return conf, resp, err
}

View File

@ -50,14 +50,13 @@ type CreateStatusOption struct {
} }
// CreateStatus creates a new Status for a given Commit // CreateStatus creates a new Status for a given Commit
func (c *Client) CreateStatus(owner, repo, sha string, opts CreateStatusOption) (*Status, *Response, error) { func (c *Client) CreateStatus(owner, repo, sha string, opts CreateStatusOption) (*Status, error) {
body, err := json.Marshal(&opts) body, err := json.Marshal(&opts)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
status := new(Status) status := new(Status)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/statuses/%s", owner, repo, sha), jsonHeader, bytes.NewReader(body), status) return status, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/statuses/%s", owner, repo, sha), jsonHeader, bytes.NewReader(body), status)
return status, resp, err
} }
// ListStatusesOption options for listing a repository's commit's statuses // ListStatusesOption options for listing a repository's commit's statuses
@ -66,11 +65,10 @@ type ListStatusesOption struct {
} }
// ListStatuses returns all statuses for a given Commit // ListStatuses returns all statuses for a given Commit
func (c *Client) ListStatuses(owner, repo, sha string, opt ListStatusesOption) ([]*Status, *Response, error) { func (c *Client) ListStatuses(owner, repo, sha string, opt ListStatusesOption) ([]*Status, error) {
opt.setDefaults() opt.setDefaults()
statuses := make([]*Status, 0, opt.PageSize) statuses := make([]*Status, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/commits/%s/statuses?%s", owner, repo, sha, opt.getURLQuery().Encode()), nil, nil, &statuses) return statuses, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/commits/%s/statuses?%s", owner, repo, sha, opt.getURLQuery().Encode()), nil, nil, &statuses)
return statuses, resp, err
} }
// CombinedStatus holds the combined state of several statuses for a single commit // CombinedStatus holds the combined state of several statuses for a single commit
@ -85,8 +83,7 @@ type CombinedStatus struct {
} }
// GetCombinedStatus returns the CombinedStatus for a given Commit // GetCombinedStatus returns the CombinedStatus for a given Commit
func (c *Client) GetCombinedStatus(owner, repo, sha string) (*CombinedStatus, *Response, error) { func (c *Client) GetCombinedStatus(owner, repo, sha string) (*CombinedStatus, error) {
status := new(CombinedStatus) status := new(CombinedStatus)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/commits/%s/status", owner, repo, sha), nil, nil, status) return status, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/commits/%s/status", owner, repo, sha), nil, nil, status)
return status, resp, err
} }

View File

@ -29,15 +29,15 @@ type User struct {
} }
// GetUserInfo get user info by user's name // GetUserInfo get user info by user's name
func (c *Client) GetUserInfo(user string) (*User, *Response, error) { func (c *Client) GetUserInfo(user string) (*User, error) {
u := new(User) u := new(User)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s", user), nil, nil, u) err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s", user), nil, nil, u)
return u, resp, err return u, err
} }
// GetMyUserInfo get user info of current user // GetMyUserInfo get user info of current user
func (c *Client) GetMyUserInfo() (*User, *Response, error) { func (c *Client) GetMyUserInfo() (*User, error) {
u := new(User) u := new(User)
resp, err := c.getParsedResponse("GET", "/user", nil, nil, u) err := c.getParsedResponse("GET", "/user", nil, nil, u)
return u, resp, err return u, err
} }

View File

@ -9,7 +9,6 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect"
) )
// AccessToken represents an API access token. // AccessToken represents an API access token.
@ -26,14 +25,13 @@ type ListAccessTokensOptions struct {
} }
// ListAccessTokens lists all the access tokens of user // ListAccessTokens lists all the access tokens of user
func (c *Client) ListAccessTokens(opts ListAccessTokensOptions) ([]*AccessToken, *Response, error) { func (c *Client) ListAccessTokens(opts ListAccessTokensOptions) ([]*AccessToken, error) {
if len(c.username) == 0 { if len(c.username) == 0 {
return nil, nil, fmt.Errorf("\"username\" not set: only BasicAuth allowed") return nil, fmt.Errorf("\"username\" not set: only BasicAuth allowed")
} }
opts.setDefaults() opts.setDefaults()
tokens := make([]*AccessToken, 0, opts.PageSize) tokens := make([]*AccessToken, 0, opts.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/tokens?%s", c.username, opts.getURLQuery().Encode()), jsonHeader, nil, &tokens) return tokens, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/tokens?%s", c.username, opts.getURLQuery().Encode()), jsonHeader, nil, &tokens)
return tokens, resp, err
} }
// CreateAccessTokenOption options when create access token // CreateAccessTokenOption options when create access token
@ -42,39 +40,23 @@ type CreateAccessTokenOption struct {
} }
// CreateAccessToken create one access token with options // CreateAccessToken create one access token with options
func (c *Client) CreateAccessToken(opt CreateAccessTokenOption) (*AccessToken, *Response, error) { func (c *Client) CreateAccessToken(opt CreateAccessTokenOption) (*AccessToken, error) {
if len(c.username) == 0 {
return nil, nil, fmt.Errorf("\"username\" not set: only BasicAuth allowed")
}
body, err := json.Marshal(&opt)
if err != nil {
return nil, nil, err
}
t := new(AccessToken)
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/users/%s/tokens", c.username), jsonHeader, bytes.NewReader(body), t)
return t, resp, err
}
// DeleteAccessToken delete token, identified by ID and if not available by name
func (c *Client) DeleteAccessToken(value interface{}) (*Response, error) {
if len(c.username) == 0 { if len(c.username) == 0 {
return nil, fmt.Errorf("\"username\" not set: only BasicAuth allowed") return nil, fmt.Errorf("\"username\" not set: only BasicAuth allowed")
} }
body, err := json.Marshal(&opt)
var token = "" if err != nil {
switch reflect.ValueOf(value).Kind() {
case reflect.Int64:
token = fmt.Sprintf("%d", value.(int64))
case reflect.String:
if err := c.CheckServerVersionConstraint(">= 1.13.0"); err != nil {
return nil, err return nil, err
} }
token = value.(string) t := new(AccessToken)
default: return t, c.getParsedResponse("POST", fmt.Sprintf("/users/%s/tokens", c.username), jsonHeader, bytes.NewReader(body), t)
return nil, fmt.Errorf("only string and int64 supported") }
}
// DeleteAccessToken delete token with key id
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/users/%s/tokens/%s", c.username, token), jsonHeader, nil) func (c *Client) DeleteAccessToken(keyID int64) error {
return resp, err if len(c.username) == 0 {
return fmt.Errorf("\"username\" not set: only BasicAuth allowed")
}
_, err := c.getResponse("DELETE", fmt.Sprintf("/users/%s/tokens/%d", c.username, keyID), jsonHeader, nil)
return err
} }

View File

@ -23,11 +23,10 @@ type ListEmailsOptions struct {
} }
// ListEmails all the email addresses of user // ListEmails all the email addresses of user
func (c *Client) ListEmails(opt ListEmailsOptions) ([]*Email, *Response, error) { func (c *Client) ListEmails(opt ListEmailsOptions) ([]*Email, error) {
opt.setDefaults() opt.setDefaults()
emails := make([]*Email, 0, opt.PageSize) emails := make([]*Email, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/emails?%s", opt.getURLQuery().Encode()), nil, nil, &emails) return emails, c.getParsedResponse("GET", fmt.Sprintf("/user/emails?%s", opt.getURLQuery().Encode()), nil, nil, &emails)
return emails, resp, err
} }
// CreateEmailOption options when creating email addresses // CreateEmailOption options when creating email addresses
@ -37,14 +36,13 @@ type CreateEmailOption struct {
} }
// AddEmail add one email to current user with options // AddEmail add one email to current user with options
func (c *Client) AddEmail(opt CreateEmailOption) ([]*Email, *Response, error) { func (c *Client) AddEmail(opt CreateEmailOption) ([]*Email, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
emails := make([]*Email, 0, 3) emails := make([]*Email, 0, 3)
resp, err := c.getParsedResponse("POST", "/user/emails", jsonHeader, bytes.NewReader(body), &emails) return emails, c.getParsedResponse("POST", "/user/emails", jsonHeader, bytes.NewReader(body), &emails)
return emails, resp, err
} }
// DeleteEmailOption options when deleting email addresses // DeleteEmailOption options when deleting email addresses
@ -54,11 +52,11 @@ type DeleteEmailOption struct {
} }
// DeleteEmail delete one email of current users' // DeleteEmail delete one email of current users'
func (c *Client) DeleteEmail(opt DeleteEmailOption) (*Response, error) { func (c *Client) DeleteEmail(opt DeleteEmailOption) error {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, err return err
} }
_, resp, err := c.getResponse("DELETE", "/user/emails", jsonHeader, bytes.NewReader(body)) _, err = c.getResponse("DELETE", "/user/emails", jsonHeader, bytes.NewReader(body))
return resp, err return err
} }

View File

@ -12,19 +12,17 @@ type ListFollowersOptions struct {
} }
// ListMyFollowers list all the followers of current user // ListMyFollowers list all the followers of current user
func (c *Client) ListMyFollowers(opt ListFollowersOptions) ([]*User, *Response, error) { func (c *Client) ListMyFollowers(opt ListFollowersOptions) ([]*User, error) {
opt.setDefaults() opt.setDefaults()
users := make([]*User, 0, opt.PageSize) users := make([]*User, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/followers?%s", opt.getURLQuery().Encode()), nil, nil, &users) return users, c.getParsedResponse("GET", fmt.Sprintf("/user/followers?%s", opt.getURLQuery().Encode()), nil, nil, &users)
return users, resp, err
} }
// ListFollowers list all the followers of one user // ListFollowers list all the followers of one user
func (c *Client) ListFollowers(user string, opt ListFollowersOptions) ([]*User, *Response, error) { func (c *Client) ListFollowers(user string, opt ListFollowersOptions) ([]*User, error) {
opt.setDefaults() opt.setDefaults()
users := make([]*User, 0, opt.PageSize) users := make([]*User, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/followers?%s", user, opt.getURLQuery().Encode()), nil, nil, &users) return users, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/followers?%s", user, opt.getURLQuery().Encode()), nil, nil, &users)
return users, resp, err
} }
// ListFollowingOptions options for listing a user's users being followed // ListFollowingOptions options for listing a user's users being followed
@ -33,41 +31,39 @@ type ListFollowingOptions struct {
} }
// ListMyFollowing list all the users current user followed // ListMyFollowing list all the users current user followed
func (c *Client) ListMyFollowing(opt ListFollowingOptions) ([]*User, *Response, error) { func (c *Client) ListMyFollowing(opt ListFollowingOptions) ([]*User, error) {
opt.setDefaults() opt.setDefaults()
users := make([]*User, 0, opt.PageSize) users := make([]*User, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/following?%s", opt.getURLQuery().Encode()), nil, nil, &users) return users, c.getParsedResponse("GET", fmt.Sprintf("/user/following?%s", opt.getURLQuery().Encode()), nil, nil, &users)
return users, resp, err
} }
// ListFollowing list all the users the user followed // ListFollowing list all the users the user followed
func (c *Client) ListFollowing(user string, opt ListFollowingOptions) ([]*User, *Response, error) { func (c *Client) ListFollowing(user string, opt ListFollowingOptions) ([]*User, error) {
opt.setDefaults() opt.setDefaults()
users := make([]*User, 0, opt.PageSize) users := make([]*User, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/following?%s", user, opt.getURLQuery().Encode()), nil, nil, &users) return users, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/following?%s", user, opt.getURLQuery().Encode()), nil, nil, &users)
return users, resp, err
} }
// IsFollowing if current user followed the target // IsFollowing if current user followed the target
func (c *Client) IsFollowing(target string) (bool, *Response) { func (c *Client) IsFollowing(target string) bool {
_, resp, err := c.getResponse("GET", fmt.Sprintf("/user/following/%s", target), nil, nil) _, err := c.getResponse("GET", fmt.Sprintf("/user/following/%s", target), nil, nil)
return err == nil, resp return err == nil
} }
// IsUserFollowing if the user followed the target // IsUserFollowing if the user followed the target
func (c *Client) IsUserFollowing(user, target string) (bool, *Response) { func (c *Client) IsUserFollowing(user, target string) bool {
_, resp, err := c.getResponse("GET", fmt.Sprintf("/users/%s/following/%s", user, target), nil, nil) _, err := c.getResponse("GET", fmt.Sprintf("/users/%s/following/%s", user, target), nil, nil)
return err == nil, resp return err == nil
} }
// Follow set current user follow the target // Follow set current user follow the target
func (c *Client) Follow(target string) (*Response, error) { func (c *Client) Follow(target string) error {
_, resp, err := c.getResponse("PUT", fmt.Sprintf("/user/following/%s", target), nil, nil) _, err := c.getResponse("PUT", fmt.Sprintf("/user/following/%s", target), nil, nil)
return resp, err return err
} }
// Unfollow set current user unfollow the target // Unfollow set current user unfollow the target
func (c *Client) Unfollow(target string) (*Response, error) { func (c *Client) Unfollow(target string) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/user/following/%s", target), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/user/following/%s", target), nil, nil)
return resp, err return err
} }

View File

@ -39,26 +39,23 @@ type ListGPGKeysOptions struct {
} }
// ListGPGKeys list all the GPG keys of the user // ListGPGKeys list all the GPG keys of the user
func (c *Client) ListGPGKeys(user string, opt ListGPGKeysOptions) ([]*GPGKey, *Response, error) { func (c *Client) ListGPGKeys(user string, opt ListGPGKeysOptions) ([]*GPGKey, error) {
opt.setDefaults() opt.setDefaults()
keys := make([]*GPGKey, 0, opt.PageSize) keys := make([]*GPGKey, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/gpg_keys?%s", user, opt.getURLQuery().Encode()), nil, nil, &keys) return keys, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/gpg_keys?%s", user, opt.getURLQuery().Encode()), nil, nil, &keys)
return keys, resp, err
} }
// ListMyGPGKeys list all the GPG keys of current user // ListMyGPGKeys list all the GPG keys of current user
func (c *Client) ListMyGPGKeys(opt *ListGPGKeysOptions) ([]*GPGKey, *Response, error) { func (c *Client) ListMyGPGKeys(opt *ListGPGKeysOptions) ([]*GPGKey, error) {
opt.setDefaults() opt.setDefaults()
keys := make([]*GPGKey, 0, opt.PageSize) keys := make([]*GPGKey, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/gpg_keys?%s", opt.getURLQuery().Encode()), nil, nil, &keys) return keys, c.getParsedResponse("GET", fmt.Sprintf("/user/gpg_keys?%s", opt.getURLQuery().Encode()), nil, nil, &keys)
return keys, resp, err
} }
// GetGPGKey get current user's GPG key by key id // GetGPGKey get current user's GPG key by key id
func (c *Client) GetGPGKey(keyID int64) (*GPGKey, *Response, error) { func (c *Client) GetGPGKey(keyID int64) (*GPGKey, error) {
key := new(GPGKey) key := new(GPGKey)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/gpg_keys/%d", keyID), nil, nil, &key) return key, c.getParsedResponse("GET", fmt.Sprintf("/user/gpg_keys/%d", keyID), nil, nil, &key)
return key, resp, err
} }
// CreateGPGKeyOption options create user GPG key // CreateGPGKeyOption options create user GPG key
@ -69,18 +66,17 @@ type CreateGPGKeyOption struct {
} }
// CreateGPGKey create GPG key with options // CreateGPGKey create GPG key with options
func (c *Client) CreateGPGKey(opt CreateGPGKeyOption) (*GPGKey, *Response, error) { func (c *Client) CreateGPGKey(opt CreateGPGKeyOption) (*GPGKey, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
key := new(GPGKey) key := new(GPGKey)
resp, err := c.getParsedResponse("POST", "/user/gpg_keys", jsonHeader, bytes.NewReader(body), key) return key, c.getParsedResponse("POST", "/user/gpg_keys", jsonHeader, bytes.NewReader(body), key)
return key, resp, err
} }
// DeleteGPGKey delete GPG key with key id // DeleteGPGKey delete GPG key with key id
func (c *Client) DeleteGPGKey(keyID int64) (*Response, error) { func (c *Client) DeleteGPGKey(keyID int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/user/gpg_keys/%d", keyID), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/user/gpg_keys/%d", keyID), nil, nil)
return resp, err return err
} }

View File

@ -30,26 +30,23 @@ type ListPublicKeysOptions struct {
} }
// ListPublicKeys list all the public keys of the user // ListPublicKeys list all the public keys of the user
func (c *Client) ListPublicKeys(user string, opt ListPublicKeysOptions) ([]*PublicKey, *Response, error) { func (c *Client) ListPublicKeys(user string, opt ListPublicKeysOptions) ([]*PublicKey, error) {
opt.setDefaults() opt.setDefaults()
keys := make([]*PublicKey, 0, opt.PageSize) keys := make([]*PublicKey, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s/keys?%s", user, opt.getURLQuery().Encode()), nil, nil, &keys) return keys, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/keys?%s", user, opt.getURLQuery().Encode()), nil, nil, &keys)
return keys, resp, err
} }
// ListMyPublicKeys list all the public keys of current user // ListMyPublicKeys list all the public keys of current user
func (c *Client) ListMyPublicKeys(opt ListPublicKeysOptions) ([]*PublicKey, *Response, error) { func (c *Client) ListMyPublicKeys(opt ListPublicKeysOptions) ([]*PublicKey, error) {
opt.setDefaults() opt.setDefaults()
keys := make([]*PublicKey, 0, opt.PageSize) keys := make([]*PublicKey, 0, opt.PageSize)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/keys?%s", opt.getURLQuery().Encode()), nil, nil, &keys) return keys, c.getParsedResponse("GET", fmt.Sprintf("/user/keys?%s", opt.getURLQuery().Encode()), nil, nil, &keys)
return keys, resp, err
} }
// GetPublicKey get current user's public key by key id // GetPublicKey get current user's public key by key id
func (c *Client) GetPublicKey(keyID int64) (*PublicKey, *Response, error) { func (c *Client) GetPublicKey(keyID int64) (*PublicKey, error) {
key := new(PublicKey) key := new(PublicKey)
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/keys/%d", keyID), nil, nil, &key) return key, c.getParsedResponse("GET", fmt.Sprintf("/user/keys/%d", keyID), nil, nil, &key)
return key, resp, err
} }
// CreateKeyOption options when creating a key // CreateKeyOption options when creating a key
@ -63,18 +60,17 @@ type CreateKeyOption struct {
} }
// CreatePublicKey create public key with options // CreatePublicKey create public key with options
func (c *Client) CreatePublicKey(opt CreateKeyOption) (*PublicKey, *Response, error) { func (c *Client) CreatePublicKey(opt CreateKeyOption) (*PublicKey, error) {
body, err := json.Marshal(&opt) body, err := json.Marshal(&opt)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
key := new(PublicKey) key := new(PublicKey)
resp, err := c.getParsedResponse("POST", "/user/keys", jsonHeader, bytes.NewReader(body), key) return key, c.getParsedResponse("POST", "/user/keys", jsonHeader, bytes.NewReader(body), key)
return key, resp, err
} }
// DeletePublicKey delete public key with key id // DeletePublicKey delete public key with key id
func (c *Client) DeletePublicKey(keyID int64) (*Response, error) { func (c *Client) DeletePublicKey(keyID int64) error {
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/user/keys/%d", keyID), nil, nil) _, err := c.getResponse("DELETE", fmt.Sprintf("/user/keys/%d", keyID), nil, nil)
return resp, err return err
} }

View File

@ -35,10 +35,10 @@ func (opt *SearchUsersOption) QueryEncode() string {
} }
// SearchUsers finds users by query // SearchUsers finds users by query
func (c *Client) SearchUsers(opt SearchUsersOption) ([]*User, *Response, error) { func (c *Client) SearchUsers(opt SearchUsersOption) ([]*User, error) {
link, _ := url.Parse("/users/search") link, _ := url.Parse("/users/search")
link.RawQuery = opt.QueryEncode() link.RawQuery = opt.QueryEncode()
userResp := new(searchUsersResponse) resp := new(searchUsersResponse)
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &userResp) err := c.getParsedResponse("GET", link.String(), nil, nil, &resp)
return userResp.Users, resp, err return resp.Users, err
} }

View File

@ -11,12 +11,11 @@ import (
) )
// ServerVersion returns the version of the server // ServerVersion returns the version of the server
func (c *Client) ServerVersion() (string, *Response, error) { func (c *Client) ServerVersion() (string, error) {
var v = struct { var v = struct {
Version string `json:"version"` Version string `json:"version"`
}{} }{}
resp, err := c.getParsedResponse("GET", "/version", nil, nil, &v) return v.Version, c.getParsedResponse("GET", "/version", nil, nil, &v)
return v.Version, resp, err
} }
// CheckServerVersionConstraint validates that the login's server satisfies a // CheckServerVersionConstraint validates that the login's server satisfies a
@ -47,7 +46,7 @@ func (c *Client) loadClientServerVersion() error {
c.versionLock.Lock() c.versionLock.Lock()
defer c.versionLock.Unlock() defer c.versionLock.Unlock()
raw, _, err := c.ServerVersion() raw, err := c.ServerVersion()
if err != nil { if err != nil {
return err return err
} }

7
vendor/gitea.com/jolheiser/gitea-vet/Makefile generated vendored Normal file
View File

@ -0,0 +1,7 @@
.PHONY: build
build:
go build
.PHONY: fmt
fmt:
go fmt ./...

7
vendor/gitea.com/jolheiser/gitea-vet/README.md generated vendored Normal file
View File

@ -0,0 +1,7 @@
# gitea-vet
`go vet` tool for Gitea
| Analyzer | Description |
|----------|---------------------------------------------------------------------|
| Imports | Checks for import sorting. stdlib->code.gitea.io->other |
| License | Checks file headers for some form of `Copyright...YYYY...Gitea/Gogs`|

View File

@ -12,7 +12,7 @@ import (
var Imports = &analysis.Analyzer{ var Imports = &analysis.Analyzer{
Name: "imports", Name: "imports",
Doc: "check for import order", Doc: "check for import order.",
Run: runImports, Run: runImports,
} }
@ -22,12 +22,11 @@ func runImports(pass *analysis.Pass) (interface{}, error) {
for _, im := range file.Imports { for _, im := range file.Imports {
var lvl int var lvl int
val := im.Path.Value val := im.Path.Value
switch { if importHasPrefix(val, "code.gitea.io") {
case importHasPrefix(val, "code.gitea.io"):
lvl = 2 lvl = 2
case strings.Contains(val, "."): } else if strings.Contains(val, ".") {
lvl = 3 lvl = 3
default: } else {
lvl = 1 lvl = 1
} }
@ -44,3 +43,12 @@ func runImports(pass *analysis.Pass) (interface{}, error) {
func importHasPrefix(s, p string) bool { func importHasPrefix(s, p string) bool {
return strings.HasPrefix(s, "\""+p) return strings.HasPrefix(s, "\""+p)
} }
func sliceHasPrefix(s string, prefixes ...string) bool {
for _, p := range prefixes {
if importHasPrefix(s, p) {
return true
}
}
return false
}

View File

@ -19,7 +19,7 @@ var (
var License = &analysis.Analyzer{ var License = &analysis.Analyzer{
Name: "license", Name: "license",
Doc: "check for a copyright header", Doc: "check for a copyright header.",
Run: runLicense, Run: runLicense,
} }

View File

@ -1,4 +1,4 @@
module code.gitea.io/gitea-vet module gitea.com/jolheiser/gitea-vet
go 1.14 go 1.14

View File

@ -5,8 +5,7 @@
package main package main
import ( import (
"code.gitea.io/gitea-vet/checks" "gitea.com/jolheiser/gitea-vet/checks"
"golang.org/x/tools/go/analysis/unitchecker" "golang.org/x/tools/go/analysis/unitchecker"
) )
@ -14,6 +13,5 @@ func main() {
unitchecker.Main( unitchecker.Main(
checks.Imports, checks.Imports,
checks.License, checks.License,
checks.Migrations,
) )
} }

View File

@ -1,19 +0,0 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
/cmd/chroma/chroma
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
_models/
_examples/

View File

@ -1,55 +0,0 @@
run:
tests: true
skip-dirs:
- _examples
output:
print-issued-lines: false
linters:
enable-all: true
disable:
- maligned
- megacheck
- lll
- gocyclo
- dupl
- gochecknoglobals
- funlen
- godox
- wsl
- gomnd
- gocognit
linters-settings:
govet:
check-shadowing: true
gocyclo:
min-complexity: 10
dupl:
threshold: 100
goconst:
min-len: 8
min-occurrences: 3
issues:
max-per-linter: 0
max-same: 0
exclude-use-default: false
exclude:
# Captured by errcheck.
- '^(G104|G204):'
# Very commonly not checked.
- 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked'
- 'exported method (.*\.MarshalJSON|.*\.UnmarshalJSON|.*\.EntityURN|.*\.GoString|.*\.Pos) should have comment or be unexported'
- 'composite literal uses unkeyed fields'
- 'declaration of "err" shadows declaration'
- 'should not use dot imports'
- 'Potential file inclusion via variable'
- 'should have comment or be unexported'
- 'comment on exported var .* should be of the form'
- 'at least one file in a package should have a package comment'
- 'string literal contains the Unicode'
- 'methods on the same type should have the same receiver name'
- '_TokenType_name should be _TokenTypeName'
- '`_TokenType_map` should be `_TokenTypeMap`'

View File

@ -1,33 +0,0 @@
project_name: chroma
release:
github:
owner: alecthomas
name: chroma
brews:
-
install: bin.install "chroma"
builds:
- goos:
- linux
- darwin
- windows
goarch:
- amd64
- "386"
goarm:
- "6"
main: ./cmd/chroma/main.go
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
binary: chroma
archives:
-
format: tar.gz
name_template: '{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{
.Arm }}{{ end }}'
files:
- COPYING
- README*
snapshot:
name_template: SNAPSHOT-{{ .Commit }}
checksum:
name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt'

View File

@ -1,12 +0,0 @@
sudo: false
language: go
go:
- "1.13.x"
script:
- go test -v ./...
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s v1.22.2
- ./bin/golangci-lint run
- git clean -fdx .
after_success:
curl -sL https://git.io/goreleaser | bash && goreleaser

View File

@ -1,19 +0,0 @@
Copyright (C) 2017 Alec Thomas
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,19 +0,0 @@
.PHONY: chromad upload all
all: README.md tokentype_string.go
README.md: lexers/*/*.go
./table.py
tokentype_string.go: types.go
go generate
chromad:
(cd ./cmd/chromad && go get github.com/GeertJohan/go.rice/rice@master && go install github.com/GeertJohan/go.rice/rice)
rm -f chromad
(export CGOENABLED=0 GOOS=linux ; cd ./cmd/chromad && go build -o ../../chromad .)
rice append -i ./cmd/chromad --exec=./chromad
upload: chromad
scp chromad root@swapoff.org: && \
ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart'

View File

@ -1,267 +0,0 @@
# Chroma — A general purpose syntax highlighter in pure Go [![Golang Documentation](https://godoc.org/github.com/alecthomas/chroma?status.svg)](https://godoc.org/github.com/alecthomas/chroma) [![Build Status](https://travis-ci.org/alecthomas/chroma.svg)](https://travis-ci.org/alecthomas/chroma) [![Gitter chat](https://badges.gitter.im/alecthomas.svg)](https://gitter.im/alecthomas/Lobby)
> **NOTE:** As Chroma has just been released, its API is still in flux. That said, the high-level interface should not change significantly.
Chroma takes source code and other structured text and converts it into syntax
highlighted HTML, ANSI-coloured text, etc.
Chroma is based heavily on [Pygments](http://pygments.org/), and includes
translators for Pygments lexers and styles.
<a id="markdown-table-of-contents" name="table-of-contents"></a>
## Table of Contents
<!-- TOC -->
1. [Table of Contents](#table-of-contents)
2. [Supported languages](#supported-languages)
3. [Try it](#try-it)
4. [Using the library](#using-the-library)
1. [Quick start](#quick-start)
2. [Identifying the language](#identifying-the-language)
3. [Formatting the output](#formatting-the-output)
4. [The HTML formatter](#the-html-formatter)
5. [More detail](#more-detail)
1. [Lexers](#lexers)
2. [Formatters](#formatters)
3. [Styles](#styles)
6. [Command-line interface](#command-line-interface)
7. [What's missing compared to Pygments?](#whats-missing-compared-to-pygments)
<!-- /TOC -->
<a id="markdown-supported-languages" name="supported-languages"></a>
## Supported languages
Prefix | Language
:----: | --------
A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Angular2, ANTLR, ApacheConf, APL, AppleScript, Arduino, Awk
B | Ballerina, Base Makefile, Bash, Batchfile, BlitzBasic, BNF, Brainfuck
C | C, C#, C++, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Crystal, CSS, Cython
D | D, Dart, Diff, Django/Jinja, Docker, DTD
E | EBNF, Elixir, Elm, EmacsLisp, Erlang
F | Factor, Fish, Forth, Fortran, FSharp
G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groovy
H | Handlebars, Haskell, Haxe, HCL, Hexdump, HTML, HTTP, Hy
I | Idris, INI, Io
J | J, Java, JavaScript, JSON, Julia, Jungle
K | Kotlin
L | Lighttpd configuration file, LLVM, Lua
M | Mako, markdown, Mason, Mathematica, Matlab, MiniZinc, MLIR, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL
N | NASM, Newspeak, Nginx configuration file, Nim, Nix
O | Objective-C, OCaml, Octave, OpenSCAD, Org Mode
P | PacmanConf, Perl, PHP, Pig, PkgConfig, PL/pgSQL, plaintext, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, Protocol Buffer, Puppet, Python, Python 3
Q | QBasic
R | R, Racket, Ragel, react, reg, reStructuredText, Rexx, Ruby, Rust
S | Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, SML, Snobol, Solidity, SPARQL, SQL, SquidConf, Swift, SYSTEMD, systemverilog
T | TableGen, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData
V | VB.net, verilog, VHDL, VimL, vue
W | WDTE
X | XML, Xorg
Y | YAML
_I will attempt to keep this section up to date, but an authoritative list can be
displayed with `chroma --list`._
<a id="markdown-try-it" name="try-it"></a>
## Try it
Try out various languages and styles on the [Chroma Playground](https://swapoff.org/chroma/playground/).
<a id="markdown-using-the-library" name="using-the-library"></a>
## Using the library
Chroma, like Pygments, has the concepts of
[lexers](https://github.com/alecthomas/chroma/tree/master/lexers),
[formatters](https://github.com/alecthomas/chroma/tree/master/formatters) and
[styles](https://github.com/alecthomas/chroma/tree/master/styles).
Lexers convert source text into a stream of tokens, styles specify how token
types are mapped to colours, and formatters convert tokens and styles into
formatted output.
A package exists for each of these, containing a global `Registry` variable
with all of the registered implementations. There are also helper functions
for using the registry in each package, such as looking up lexers by name or
matching filenames, etc.
In all cases, if a lexer, formatter or style can not be determined, `nil` will
be returned. In this situation you may want to default to the `Fallback`
value in each respective package, which provides sane defaults.
<a id="markdown-quick-start" name="quick-start"></a>
### Quick start
A convenience function exists that can be used to simply format some source
text, without any effort:
```go
err := quick.Highlight(os.Stdout, someSourceCode, "go", "html", "monokai")
```
<a id="markdown-identifying-the-language" name="identifying-the-language"></a>
### Identifying the language
To highlight code, you'll first have to identify what language the code is
written in. There are three primary ways to do that:
1. Detect the language from its filename.
```go
lexer := lexers.Match("foo.go")
```
3. Explicitly specify the language by its Chroma syntax ID (a full list is available from `lexers.Names()`).
```go
lexer := lexers.Get("go")
```
3. Detect the language from its content.
```go
lexer := lexers.Analyse("package main\n\nfunc main()\n{\n}\n")
```
In all cases, `nil` will be returned if the language can not be identified.
```go
if lexer == nil {
lexer = lexers.Fallback
}
```
At this point, it should be noted that some lexers can be extremely chatty. To
mitigate this, you can use the coalescing lexer to coalesce runs of identical
token types into a single token:
```go
lexer = chroma.Coalesce(lexer)
```
<a id="markdown-formatting-the-output" name="formatting-the-output"></a>
### Formatting the output
Once a language is identified you will need to pick a formatter and a style (theme).
```go
style := styles.Get("swapoff")
if style == nil {
style = styles.Fallback
}
formatter := formatters.Get("html")
if formatter == nil {
formatter = formatters.Fallback
}
```
Then obtain an iterator over the tokens:
```go
contents, err := ioutil.ReadAll(r)
iterator, err := lexer.Tokenise(nil, string(contents))
```
And finally, format the tokens from the iterator:
```go
err := formatter.Format(w, style, iterator)
```
<a id="markdown-the-html-formatter" name="the-html-formatter"></a>
### The HTML formatter
By default the `html` registered formatter generates standalone HTML with
embedded CSS. More flexibility is available through the `formatters/html` package.
Firstly, the output generated by the formatter can be customised with the
following constructor options:
- `Standalone()` - generate standalone HTML with embedded CSS.
- `WithClasses()` - use classes rather than inlined style attributes.
- `ClassPrefix(prefix)` - prefix each generated CSS class.
- `TabWidth(width)` - Set the rendered tab width, in characters.
- `WithLineNumbers()` - Render line numbers (style with `LineNumbers`).
- `LinkableLineNumbers()` - Make the line numbers linkable.
- `HighlightLines(ranges)` - Highlight lines in these ranges (style with `LineHighlight`).
- `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans.
If `WithClasses()` is used, the corresponding CSS can be obtained from the formatter with:
```go
formatter := html.New(html.WithClasses())
err := formatter.WriteCSS(w, style)
```
<a id="markdown-more-detail" name="more-detail"></a>
## More detail
<a id="markdown-lexers" name="lexers"></a>
### Lexers
See the [Pygments documentation](http://pygments.org/docs/lexerdevelopment/)
for details on implementing lexers. Most concepts apply directly to Chroma,
but see existing lexer implementations for real examples.
In many cases lexers can be automatically converted directly from Pygments by
using the included Python 3 script `pygments2chroma.py`. I use something like
the following:
```sh
python3 ~/Projects/chroma/_tools/pygments2chroma.py \
pygments.lexers.jvm.KotlinLexer \
> ~/Projects/chroma/lexers/kotlin.go \
&& gofmt -s -w ~/Projects/chroma/lexers/*.go
```
See notes in [pygments-lexers.go](https://github.com/alecthomas/chroma/blob/master/pygments-lexers.txt)
for a list of lexers, and notes on some of the issues importing them.
<a id="markdown-formatters" name="formatters"></a>
### Formatters
Chroma supports HTML output, as well as terminal output in 8 colour, 256 colour, and true-colour.
A `noop` formatter is included that outputs the token text only, and a `tokens`
formatter outputs raw tokens. The latter is useful for debugging lexers.
<a id="markdown-styles" name="styles"></a>
### Styles
Chroma styles use the [same syntax](http://pygments.org/docs/styles/) as Pygments.
All Pygments styles have been converted to Chroma using the `_tools/style.py` script.
When you work with one of [Chroma's styles](https://github.com/alecthomas/chroma/tree/master/styles), know that the `chroma.Background` token type provides the default style for tokens. It does so by defining a foreground color and background color.
For example, this gives each token name not defined in the style a default color of `#f8f8f8` and uses `#000000` for the highlighted code block's background:
~~~go
chroma.Background: "#f8f8f2 bg:#000000",
~~~
Also, token types in a style file are hierarchical. For instance, when `CommentSpecial` is not defined, Chroma uses the token style from `Comment`. So when several comment tokens use the same color, you'll only need to define `Comment` and override the one that has a different color.
For a quick overview of the available styles and how they look, check out the [Chroma Style Gallery](https://xyproto.github.io/splash/docs/).
<a id="markdown-command-line-interface" name="command-line-interface"></a>
## Command-line interface
A command-line interface to Chroma is included. It can be installed with:
```sh
go get -u github.com/alecthomas/chroma/cmd/chroma
```
<a id="markdown-whats-missing-compared-to-pygments" name="whats-missing-compared-to-pygments"></a>
## What's missing compared to Pygments?
- Quite a few lexers, for various reasons (pull-requests welcome):
- Pygments lexers for complex languages often include custom code to
handle certain aspects, such as Perl6's ability to nest code inside
regular expressions. These require time and effort to convert.
- I mostly only converted languages I had heard of, to reduce the porting cost.
- Some more esoteric features of Pygments are omitted for simplicity.
- Though the Chroma API supports content detection, very few languages support them.
I have plans to implement a statistical analyser at some point, but not enough time.

View File

@ -1,35 +0,0 @@
package chroma
// Coalesce is a Lexer interceptor that collapses runs of common types into a single token.
func Coalesce(lexer Lexer) Lexer { return &coalescer{lexer} }
type coalescer struct{ Lexer }
func (d *coalescer) Tokenise(options *TokeniseOptions, text string) (Iterator, error) {
var prev Token
it, err := d.Lexer.Tokenise(options, text)
if err != nil {
return nil, err
}
return func() Token {
for token := it(); token != (EOF); token = it() {
if len(token.Value) == 0 {
continue
}
if prev == EOF {
prev = token
} else {
if prev.Type == token.Type && len(prev.Value) < 8192 {
prev.Value += token.Value
} else {
out := prev
prev = token
return out
}
}
}
out := prev
prev = EOF
return out
}, nil
}

View File

@ -1,164 +0,0 @@
package chroma
import (
"fmt"
"math"
"strconv"
"strings"
)
// ANSI2RGB maps ANSI colour names, as supported by Chroma, to hex RGB values.
var ANSI2RGB = map[string]string{
"#ansiblack": "000000",
"#ansidarkred": "7f0000",
"#ansidarkgreen": "007f00",
"#ansibrown": "7f7fe0",
"#ansidarkblue": "00007f",
"#ansipurple": "7f007f",
"#ansiteal": "007f7f",
"#ansilightgray": "e5e5e5",
// Normal
"#ansidarkgray": "555555",
"#ansired": "ff0000",
"#ansigreen": "00ff00",
"#ansiyellow": "ffff00",
"#ansiblue": "0000ff",
"#ansifuchsia": "ff00ff",
"#ansiturquoise": "00ffff",
"#ansiwhite": "ffffff",
// Aliases without the "ansi" prefix, because...why?
"#black": "000000",
"#darkred": "7f0000",
"#darkgreen": "007f00",
"#brown": "7f7fe0",
"#darkblue": "00007f",
"#purple": "7f007f",
"#teal": "007f7f",
"#lightgray": "e5e5e5",
// Normal
"#darkgray": "555555",
"#red": "ff0000",
"#green": "00ff00",
"#yellow": "ffff00",
"#blue": "0000ff",
"#fuchsia": "ff00ff",
"#turquoise": "00ffff",
"#white": "ffffff",
}
// Colour represents an RGB colour.
type Colour int32
// NewColour creates a Colour directly from RGB values.
func NewColour(r, g, b uint8) Colour {
return ParseColour(fmt.Sprintf("%02x%02x%02x", r, g, b))
}
// Distance between this colour and another.
//
// This uses the approach described here (https://www.compuphase.com/cmetric.htm).
// This is not as accurate as LAB, et. al. but is *vastly* simpler and sufficient for our needs.
func (c Colour) Distance(e2 Colour) float64 {
ar, ag, ab := int64(c.Red()), int64(c.Green()), int64(c.Blue())
br, bg, bb := int64(e2.Red()), int64(e2.Green()), int64(e2.Blue())
rmean := (ar + br) / 2
r := ar - br
g := ag - bg
b := ab - bb
return math.Sqrt(float64((((512 + rmean) * r * r) >> 8) + 4*g*g + (((767 - rmean) * b * b) >> 8)))
}
// Brighten returns a copy of this colour with its brightness adjusted.
//
// If factor is negative, the colour is darkened.
//
// Uses approach described here (http://www.pvladov.com/2012/09/make-color-lighter-or-darker.html).
func (c Colour) Brighten(factor float64) Colour {
r := float64(c.Red())
g := float64(c.Green())
b := float64(c.Blue())
if factor < 0 {
factor++
r *= factor
g *= factor
b *= factor
} else {
r = (255-r)*factor + r
g = (255-g)*factor + g
b = (255-b)*factor + b
}
return NewColour(uint8(r), uint8(g), uint8(b))
}
// BrightenOrDarken brightens a colour if it is < 0.5 brighteness or darkens if > 0.5 brightness.
func (c Colour) BrightenOrDarken(factor float64) Colour {
if c.Brightness() < 0.5 {
return c.Brighten(factor)
}
return c.Brighten(-factor)
}
// Brightness of the colour (roughly) in the range 0.0 to 1.0
func (c Colour) Brightness() float64 {
return (float64(c.Red()) + float64(c.Green()) + float64(c.Blue())) / 255.0 / 3.0
}
// ParseColour in the forms #rgb, #rrggbb, #ansi<colour>, or #<colour>.
// Will return an "unset" colour if invalid.
func ParseColour(colour string) Colour {
colour = normaliseColour(colour)
n, err := strconv.ParseUint(colour, 16, 32)
if err != nil {
return 0
}
return Colour(n + 1)
}
// MustParseColour is like ParseColour except it panics if the colour is invalid.
//
// Will panic if colour is in an invalid format.
func MustParseColour(colour string) Colour {
parsed := ParseColour(colour)
if !parsed.IsSet() {
panic(fmt.Errorf("invalid colour %q", colour))
}
return parsed
}
// IsSet returns true if the colour is set.
func (c Colour) IsSet() bool { return c != 0 }
func (c Colour) String() string { return fmt.Sprintf("#%06x", int(c-1)) }
func (c Colour) GoString() string { return fmt.Sprintf("Colour(0x%06x)", int(c-1)) }
// Red component of colour.
func (c Colour) Red() uint8 { return uint8(((c - 1) >> 16) & 0xff) }
// Green component of colour.
func (c Colour) Green() uint8 { return uint8(((c - 1) >> 8) & 0xff) }
// Blue component of colour.
func (c Colour) Blue() uint8 { return uint8((c - 1) & 0xff) }
// Colours is an orderable set of colours.
type Colours []Colour
func (c Colours) Len() int { return len(c) }
func (c Colours) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c Colours) Less(i, j int) bool { return c[i] < c[j] }
// Convert colours to #rrggbb.
func normaliseColour(colour string) string {
if ansi, ok := ANSI2RGB[colour]; ok {
return ansi
}
if strings.HasPrefix(colour, "#") {
colour = colour[1:]
if len(colour) == 3 {
return colour[0:1] + colour[0:1] + colour[1:2] + colour[1:2] + colour[2:3] + colour[2:3]
}
}
return colour
}

View File

@ -1,137 +0,0 @@
package chroma
import (
"bytes"
)
type delegatingLexer struct {
root Lexer
language Lexer
}
// DelegatingLexer combines two lexers to handle the common case of a language embedded inside another, such as PHP
// inside HTML or PHP inside plain text.
//
// It takes two lexer as arguments: a root lexer and a language lexer. First everything is scanned using the language
// lexer, which must return "Other" for unrecognised tokens. Then all "Other" tokens are lexed using the root lexer.
// Finally, these two sets of tokens are merged.
//
// The lexers from the template lexer package use this base lexer.
func DelegatingLexer(root Lexer, language Lexer) Lexer {
return &delegatingLexer{
root: root,
language: language,
}
}
func (d *delegatingLexer) Config() *Config {
return d.language.Config()
}
// An insertion is the character range where language tokens should be inserted.
type insertion struct {
start, end int
tokens []Token
}
func (d *delegatingLexer) Tokenise(options *TokeniseOptions, text string) (Iterator, error) { // nolint: gocognit
tokens, err := Tokenise(Coalesce(d.language), options, text)
if err != nil {
return nil, err
}
// Compute insertions and gather "Other" tokens.
others := &bytes.Buffer{}
insertions := []*insertion{}
var insert *insertion
offset := 0
var last Token
for _, t := range tokens {
if t.Type == Other {
if last != EOF && insert != nil && last.Type != Other {
insert.end = offset
}
others.WriteString(t.Value)
} else {
if last == EOF || last.Type == Other {
insert = &insertion{start: offset}
insertions = append(insertions, insert)
}
insert.tokens = append(insert.tokens, t)
}
last = t
offset += len(t.Value)
}
if len(insertions) == 0 {
return d.root.Tokenise(options, text)
}
// Lex the other tokens.
rootTokens, err := Tokenise(Coalesce(d.root), options, others.String())
if err != nil {
return nil, err
}
// Interleave the two sets of tokens.
var out []Token
offset = 0 // Offset into text.
tokenIndex := 0
nextToken := func() Token {
if tokenIndex >= len(rootTokens) {
return EOF
}
t := rootTokens[tokenIndex]
tokenIndex++
return t
}
insertionIndex := 0
nextInsertion := func() *insertion {
if insertionIndex >= len(insertions) {
return nil
}
i := insertions[insertionIndex]
insertionIndex++
return i
}
t := nextToken()
i := nextInsertion()
for t != EOF || i != nil {
// fmt.Printf("%d->%d:%q %d->%d:%q\n", offset, offset+len(t.Value), t.Value, i.start, i.end, Stringify(i.tokens...))
if t == EOF || (i != nil && i.start < offset+len(t.Value)) {
var l Token
l, t = splitToken(t, i.start-offset)
if l != EOF {
out = append(out, l)
offset += len(l.Value)
}
out = append(out, i.tokens...)
offset += i.end - i.start
if t == EOF {
t = nextToken()
}
i = nextInsertion()
} else {
out = append(out, t)
offset += len(t.Value)
t = nextToken()
}
}
return Literator(out...), nil
}
func splitToken(t Token, offset int) (l Token, r Token) {
if t == EOF {
return EOF, EOF
}
if offset == 0 {
return EOF, t
}
if offset == len(t.Value) {
return t, EOF
}
l = t.Clone()
r = t.Clone()
l.Value = l.Value[:offset]
r.Value = r.Value[offset:]
return
}

Some files were not shown because too many files have changed in this diff Show More