mirror of https://gitea.com/gitea/go-sdk.git
Compare commits
23 Commits
gitea/v0.1
...
main
Author | SHA1 | Date |
---|---|---|
appleboy | 8110db1e6d | |
Bo-Yi Wu | 83c73e79a5 | |
Bo-Yi Wu | 6c0938dc15 | |
tobiasbp | 0a99bda0cb | |
Bo-Yi Wu | 36723e11c8 | |
appleboy | a991e370c5 | |
appleboy | bb25c989a0 | |
appleboy | 18e5522f90 | |
Lunny Xiao | bad4de0196 | |
rjhaverkamp | 9ec1b82849 | |
6543 | bf71ec2fd9 | |
Martijn van der Kleijn | 001d5fad51 | |
diogo464 | 5d0143e4e7 | |
Simon Ser | 53f735b911 | |
Christian Groschupp | 98b424a8af | |
Bo-Yi Wu | 2abfdd7ba6 | |
Andreas Wachter | 8f4d3d8916 | |
ysicing | bde56fb9bb | |
ysicing | 228d6931f4 | |
appleboy | c8745e1599 | |
Lauris BH | 0e0a4691b6 | |
crapStone | e23e8aa300 | |
venc0r | d5e174e5b5 |
|
@ -15,10 +15,10 @@ jobs:
|
|||
GITEA_SDK_TEST_USERNAME: "test01"
|
||||
GITEA_SDK_TEST_PASSWORD: "test01"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '>=1.20'
|
||||
go-version: ">=1.21"
|
||||
check-latest: true
|
||||
- run: make clean
|
||||
- run: make vet
|
||||
|
@ -28,7 +28,7 @@ jobs:
|
|||
- run: make test
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:1.18
|
||||
image: gitea/gitea:1.22.0-rc1
|
||||
cmd:
|
||||
- bash
|
||||
- -c
|
||||
|
|
4
Makefile
4
Makefile
|
@ -12,7 +12,7 @@ GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.4.0
|
|||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.0
|
||||
GITEA_VET_PACKAGE ?= code.gitea.io/gitea-vet@v0.2.1
|
||||
|
||||
GITEA_VERSION := 1.18
|
||||
GITEA_VERSION := 1.21.10
|
||||
GITEA_DL := https://dl.gitea.com/gitea/$(GITEA_VERSION)/gitea-$(GITEA_VERSION)-
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
|
@ -72,7 +72,7 @@ vet:
|
|||
cd gitea && $(GO) vet -vettool=gitea-vet $(PACKAGE)
|
||||
|
||||
.PHONY: ci-lint
|
||||
ci-lint:
|
||||
ci-lint:
|
||||
@cd gitea/; echo -n "gofumpt ...";\
|
||||
diff=$$($(GO) run $(GOFUMPT_PACKAGE) -extra -l .); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
|
|
|
@ -12,9 +12,9 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
@ -36,6 +36,7 @@ type Client struct {
|
|||
password string
|
||||
otp string
|
||||
sudo string
|
||||
userAgent string
|
||||
debug bool
|
||||
httpsigner *HTTPSign
|
||||
client *http.Client
|
||||
|
@ -49,6 +50,11 @@ type Client struct {
|
|||
// Response represents the gitea response
|
||||
type Response struct {
|
||||
*http.Response
|
||||
|
||||
FirstPage int
|
||||
PrevPage int
|
||||
NextPage int
|
||||
LastPage int
|
||||
}
|
||||
|
||||
// ClientOption are functions used to init a new client
|
||||
|
@ -215,6 +221,21 @@ func (c *Client) SetSudo(sudo string) {
|
|||
c.mutex.Unlock()
|
||||
}
|
||||
|
||||
// SetUserAgent is an option for NewClient to set user-agent header
|
||||
func SetUserAgent(userAgent string) ClientOption {
|
||||
return func(client *Client) error {
|
||||
client.SetUserAgent(userAgent)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetUserAgent sets the user-agent to send with every request.
|
||||
func (c *Client) SetUserAgent(userAgent string) {
|
||||
c.mutex.Lock()
|
||||
c.userAgent = userAgent
|
||||
c.mutex.Unlock()
|
||||
}
|
||||
|
||||
// SetDebugMode is an option for NewClient to enable debug mode
|
||||
func SetDebugMode() ClientOption {
|
||||
return func(client *Client) error {
|
||||
|
@ -225,6 +246,57 @@ func SetDebugMode() ClientOption {
|
|||
}
|
||||
}
|
||||
|
||||
func newResponse(r *http.Response) *Response {
|
||||
response := &Response{Response: r}
|
||||
response.parseLinkHeader()
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
func (r *Response) parseLinkHeader() {
|
||||
link := r.Header.Get("Link")
|
||||
if link == "" {
|
||||
return
|
||||
}
|
||||
|
||||
links := strings.Split(link, ",")
|
||||
for _, l := range links {
|
||||
u, param, ok := strings.Cut(l, ";")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
u = strings.Trim(u, " <>")
|
||||
|
||||
key, value, ok := strings.Cut(strings.TrimSpace(param), "=")
|
||||
if !ok || key != "rel" {
|
||||
continue
|
||||
}
|
||||
|
||||
value = strings.Trim(value, "\"")
|
||||
|
||||
parsed, err := url.Parse(u)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
page := parsed.Query().Get("page")
|
||||
if page == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
switch value {
|
||||
case "first":
|
||||
r.FirstPage, _ = strconv.Atoi(page)
|
||||
case "prev":
|
||||
r.PrevPage, _ = strconv.Atoi(page)
|
||||
case "next":
|
||||
r.NextPage, _ = strconv.Atoi(page)
|
||||
case "last":
|
||||
r.LastPage, _ = strconv.Atoi(page)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) getWebResponse(method, path string, body io.Reader) ([]byte, *Response, error) {
|
||||
c.mutex.RLock()
|
||||
debug := c.debug
|
||||
|
@ -246,11 +318,12 @@ func (c *Client) getWebResponse(method, path string, body io.Reader) ([]byte, *R
|
|||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if debug {
|
||||
fmt.Printf("Response: %v\n\n", resp)
|
||||
}
|
||||
return data, &Response{resp}, err
|
||||
|
||||
return data, newResponse(resp), err
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(method, path string, header http.Header, body io.Reader) (*Response, error) {
|
||||
|
@ -259,7 +332,7 @@ func (c *Client) doRequest(method, path string, header http.Header, body io.Read
|
|||
if debug {
|
||||
var bodyStr string
|
||||
if body != nil {
|
||||
bs, _ := ioutil.ReadAll(body)
|
||||
bs, _ := io.ReadAll(body)
|
||||
body = bytes.NewReader(bs)
|
||||
bodyStr = string(bs)
|
||||
}
|
||||
|
@ -282,6 +355,9 @@ func (c *Client) doRequest(method, path string, header http.Header, body io.Read
|
|||
if len(c.sudo) != 0 {
|
||||
req.Header.Set("Sudo", c.sudo)
|
||||
}
|
||||
if len(c.userAgent) != 0 {
|
||||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
client := c.client // client ref can change from this point on so safe it
|
||||
c.mutex.RUnlock()
|
||||
|
@ -304,7 +380,8 @@ func (c *Client) doRequest(method, path string, header http.Header, body io.Read
|
|||
if debug {
|
||||
fmt.Printf("Response: %v\n\n", resp)
|
||||
}
|
||||
return &Response{resp}, nil
|
||||
|
||||
return newResponse(resp), nil
|
||||
}
|
||||
|
||||
// Converts a response for a HTTP status code indicating an error condition
|
||||
|
@ -321,7 +398,7 @@ func statusCodeToErr(resp *Response) (body []byte, err error) {
|
|||
// error: body will be read for details
|
||||
//
|
||||
defer resp.Body.Close()
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("body read on HTTP error %d: %v", resp.StatusCode, err)
|
||||
}
|
||||
|
@ -374,7 +451,7 @@ func (c *Client) getResponse(method, path string, header http.Header, body io.Re
|
|||
}
|
||||
|
||||
// success (2XX), read body
|
||||
data, err = ioutil.ReadAll(resp.Body)
|
||||
data, err = io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2023 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 (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParsedPaging(t *testing.T) {
|
||||
resp := newResponse(&http.Response{
|
||||
Header: http.Header{
|
||||
"Link": []string{
|
||||
strings.Join(
|
||||
[]string{
|
||||
`<https://try.gitea.io/api/v1/repos/gitea/go-sdk/issues/1/comments?page=3>; rel="next"`,
|
||||
`<https://try.gitea.io/api/v1/repos/gitea/go-sdk/issues/1/comments?page=4>; rel="last"`,
|
||||
`<https://try.gitea.io/api/v1/repos/gitea/go-sdk/issues/1/comments?page=1>; rel="first"`,
|
||||
`<https://try.gitea.io/api/v1/repos/gitea/go-sdk/issues/1/comments?page=1>; rel="prev"`,
|
||||
}, ",",
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
assert.Equal(t, 1, resp.FirstPage)
|
||||
assert.Equal(t, 1, resp.PrevPage)
|
||||
assert.Equal(t, 3, resp.NextPage)
|
||||
assert.Equal(t, 4, resp.LastPage)
|
||||
}
|
13
gitea/go.mod
13
gitea/go.mod
|
@ -1,11 +1,18 @@
|
|||
module code.gitea.io/sdk/gitea
|
||||
|
||||
go 1.13
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/davidmz/go-pageant v1.0.2
|
||||
github.com/go-fed/httpsig v1.1.0
|
||||
github.com/hashicorp/go-version v1.5.0
|
||||
github.com/hashicorp/go-version v1.6.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
|
||||
golang.org/x/crypto v0.22.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
)
|
||||
|
|
17
gitea/go.sum
17
gitea/go.sum
|
@ -4,8 +4,8 @@ github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454Wv
|
|||
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
|
||||
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
|
||||
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||
github.com/hashicorp/go-version v1.5.0 h1:O293SZ2Eg+AAYijkVK3jR786Am1bhDEh2GHT0tIVE5E=
|
||||
github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
@ -14,22 +14,19 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
@ -62,6 +62,14 @@ func (c *Client) ListOrgHooks(org string, opt ListHooksOptions) ([]*Hook, *Respo
|
|||
return hooks, resp, err
|
||||
}
|
||||
|
||||
// ListMyHooks list all the hooks of the authenticated user
|
||||
func (c *Client) ListMyHooks(opt ListHooksOptions) ([]*Hook, *Response, error) {
|
||||
opt.setDefaults()
|
||||
hooks := make([]*Hook, 0, opt.PageSize)
|
||||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/hooks?%s", opt.getURLQuery().Encode()), nil, nil, &hooks)
|
||||
return hooks, resp, err
|
||||
}
|
||||
|
||||
// ListRepoHooks list all the hooks of one repository
|
||||
func (c *Client) ListRepoHooks(user, repo string, opt ListHooksOptions) ([]*Hook, *Response, error) {
|
||||
if err := escapeValidatePathSegments(&user, &repo); err != nil {
|
||||
|
@ -83,6 +91,13 @@ func (c *Client) GetOrgHook(org string, id int64) (*Hook, *Response, error) {
|
|||
return h, resp, err
|
||||
}
|
||||
|
||||
// GetMyHook get a hook of the authenticated user
|
||||
func (c *Client) GetMyHook(id int64) (*Hook, *Response, error) {
|
||||
h := new(Hook)
|
||||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/user/hooks/%d", id), nil, nil, h)
|
||||
return h, resp, err
|
||||
}
|
||||
|
||||
// GetRepoHook get a hook of a repository
|
||||
func (c *Client) GetRepoHook(user, repo string, id int64) (*Hook, *Response, error) {
|
||||
if err := escapeValidatePathSegments(&user, &repo); err != nil {
|
||||
|
@ -95,11 +110,12 @@ func (c *Client) GetRepoHook(user, repo string, id int64) (*Hook, *Response, err
|
|||
|
||||
// CreateHookOption options when create a hook
|
||||
type CreateHookOption struct {
|
||||
Type HookType `json:"type"`
|
||||
Config map[string]string `json:"config"`
|
||||
Events []string `json:"events"`
|
||||
BranchFilter string `json:"branch_filter"`
|
||||
Active bool `json:"active"`
|
||||
Type HookType `json:"type"`
|
||||
Config map[string]string `json:"config"`
|
||||
Events []string `json:"events"`
|
||||
BranchFilter string `json:"branch_filter"`
|
||||
Active bool `json:"active"`
|
||||
AuthorizationHeader string `json:"authorization_header"`
|
||||
}
|
||||
|
||||
// Validate the CreateHookOption struct
|
||||
|
@ -127,6 +143,20 @@ func (c *Client) CreateOrgHook(org string, opt CreateHookOption) (*Hook, *Respon
|
|||
return h, resp, err
|
||||
}
|
||||
|
||||
// CreateMyHook create one hook for the authenticated user, with options
|
||||
func (c *Client) CreateMyHook(opt CreateHookOption) (*Hook, *Response, error) {
|
||||
if err := opt.Validate(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
body, err := json.Marshal(&opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
h := new(Hook)
|
||||
resp, err := c.getParsedResponse("POST", "/user/hooks", jsonHeader, bytes.NewReader(body), h)
|
||||
return h, resp, err
|
||||
}
|
||||
|
||||
// CreateRepoHook create one hook for a repository, with options
|
||||
func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook, *Response, error) {
|
||||
if err := escapeValidatePathSegments(&user, &repo); err != nil {
|
||||
|
@ -143,10 +173,11 @@ func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook,
|
|||
|
||||
// EditHookOption options when modify one hook
|
||||
type EditHookOption struct {
|
||||
Config map[string]string `json:"config"`
|
||||
Events []string `json:"events"`
|
||||
BranchFilter string `json:"branch_filter"`
|
||||
Active *bool `json:"active"`
|
||||
Config map[string]string `json:"config"`
|
||||
Events []string `json:"events"`
|
||||
BranchFilter string `json:"branch_filter"`
|
||||
Active *bool `json:"active"`
|
||||
AuthorizationHeader string `json:"authorization_header"`
|
||||
}
|
||||
|
||||
// EditOrgHook modify one hook of an organization, with hook id and options
|
||||
|
@ -162,6 +193,16 @@ func (c *Client) EditOrgHook(org string, id int64, opt EditHookOption) (*Respons
|
|||
return resp, err
|
||||
}
|
||||
|
||||
// EditMyHook modify one hook of the authenticated user, with hook id and options
|
||||
func (c *Client) EditMyHook(id int64, opt EditHookOption) (*Response, error) {
|
||||
body, err := json.Marshal(&opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, resp, err := c.getResponse("PATCH", fmt.Sprintf("/user/hooks/%d", id), jsonHeader, bytes.NewReader(body))
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if err := escapeValidatePathSegments(&user, &repo); err != nil {
|
||||
|
@ -184,6 +225,12 @@ func (c *Client) DeleteOrgHook(org string, id int64) (*Response, error) {
|
|||
return resp, err
|
||||
}
|
||||
|
||||
// DeleteMyHook delete one hook from the authenticated user, with hook id
|
||||
func (c *Client) DeleteMyHook(id int64) (*Response, error) {
|
||||
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/user/hooks/%d", id), nil, nil)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// DeleteRepoHook delete one hook from a repository, with hook id
|
||||
func (c *Client) DeleteRepoHook(user, repo string, id int64) (*Response, error) {
|
||||
if err := escapeValidatePathSegments(&user, &repo); err != nil {
|
||||
|
|
|
@ -68,14 +68,14 @@ func TestLabels(t *testing.T) {
|
|||
assert.EqualValues(t, labelTwo, label)
|
||||
|
||||
label, _, err = c.EditLabel(repo.Owner.UserName, repo.Name, labelTwo.ID, EditLabelOption{
|
||||
Color: OptionalString("#0E0175"),
|
||||
Color: OptionalString("#0e0175"),
|
||||
Description: OptionalString("blueish"),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, &Label{
|
||||
ID: labelTwo.ID,
|
||||
Name: labelTwo.Name,
|
||||
Color: "0E0175",
|
||||
Color: "0e0175",
|
||||
Description: "blueish",
|
||||
URL: labelTwo.URL,
|
||||
}, label)
|
||||
|
|
|
@ -43,7 +43,7 @@ func TestMilestones(t *testing.T) {
|
|||
// ListRepoMilestones
|
||||
ml, _, err := c.ListRepoMilestones(repo.Owner.UserName, repo.Name, ListMilestoneOption{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, ml, 2)
|
||||
assert.Len(t, ml, 3)
|
||||
ml, _, err = c.ListRepoMilestones(repo.Owner.UserName, repo.Name, ListMilestoneOption{State: StateClosed})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, ml, 1)
|
||||
|
|
|
@ -19,7 +19,7 @@ func TestIssue(t *testing.T) {
|
|||
|
||||
createIssue(t, c)
|
||||
// Little sleep in order to give some time for gitea to properly store all information on database. Without this sleep, CI is a bit unstable
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
editIssues(t, c)
|
||||
listIssues(t, c)
|
||||
deleteIssue(t, c)
|
||||
|
@ -62,7 +62,7 @@ func deleteIssue(t *testing.T, c *Client) {
|
|||
|
||||
func editIssues(t *testing.T, c *Client) {
|
||||
log.Println("== TestEditIssues ==")
|
||||
il, _, err := c.ListIssues(ListIssueOption{KeyWord: "soon"})
|
||||
il, _, err := c.ListIssues(ListIssueOption{KeyWord: "soon!"})
|
||||
assert.NoError(t, err)
|
||||
issue, _, err := c.GetIssue(il[0].Poster.UserName, il[0].Repository.Name, il[0].Index)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -46,7 +46,7 @@ func TestNotifications(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
issue, _, err := c.CreateIssue(repoB.Owner.UserName, repoB.Name, CreateIssueOption{Title: "B Issue", Closed: false})
|
||||
assert.NoError(t, err)
|
||||
time.Sleep(time.Second * 1)
|
||||
time.Sleep(time.Second * 5)
|
||||
|
||||
// CheckNotifications of user2
|
||||
c.sudo = user2.UserName
|
||||
|
@ -101,7 +101,7 @@ func TestNotifications(t *testing.T) {
|
|||
c.sudo = ""
|
||||
_, _, err = c.EditIssue(repoB.Owner.UserName, repoB.Name, issue.Index, EditIssueOption{State: &iState})
|
||||
assert.NoError(t, err)
|
||||
time.Sleep(time.Second * 1)
|
||||
time.Sleep(time.Second * 5)
|
||||
|
||||
c.sudo = user2.UserName
|
||||
nList, _, err = c.ListNotifications(ListNotificationOptions{})
|
||||
|
@ -120,18 +120,17 @@ func TestNotifications(t *testing.T) {
|
|||
notifications, _, err = c.ReadNotifications(MarkNotificationOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, notifications, 2)
|
||||
_, _ = c.DeleteRepo("test01", "Reviews")
|
||||
nList, _, err = c.ListNotifications(ListNotificationOptions{Status: []NotifyStatus{NotifyStatusRead}})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, nList, 2)
|
||||
if assert.Len(t, nList, 2) {
|
||||
notification, _, err := c.ReadNotification(nList[0].ID, NotifyStatusPinned)
|
||||
assert.EqualValues(t, notification.ID, nList[0].ID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
notification, _, err := c.ReadNotification(nList[0].ID, NotifyStatusPinned)
|
||||
assert.EqualValues(t, notification.ID, nList[0].ID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
notification, _, err = c.ReadNotification(nList[1].ID, NotifyStatusUnread)
|
||||
assert.EqualValues(t, notification.ID, nList[1].ID)
|
||||
assert.NoError(t, err)
|
||||
notification, _, err = c.ReadNotification(nList[1].ID, NotifyStatusUnread)
|
||||
assert.EqualValues(t, notification.ID, nList[1].ID)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
nList, _, err = c.ListNotifications(ListNotificationOptions{Status: []NotifyStatus{NotifyStatusPinned, NotifyStatusUnread}})
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, nList, 2) {
|
||||
|
|
|
@ -93,7 +93,7 @@ func (opt CreateOrgOption) Validate() error {
|
|||
return fmt.Errorf("empty org name")
|
||||
}
|
||||
if len(opt.Visibility) != 0 && !checkVisibilityOpt(opt.Visibility) {
|
||||
return fmt.Errorf("infalid bisibility option")
|
||||
return fmt.Errorf("invalid visibility option")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ type EditOrgOption struct {
|
|||
// Validate the EditOrgOption struct
|
||||
func (opt EditOrgOption) Validate() error {
|
||||
if len(opt.Visibility) != 0 && !checkVisibilityOpt(opt.Visibility) {
|
||||
return fmt.Errorf("infalid bisibility option")
|
||||
return fmt.Errorf("invalid visibility option")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,16 +5,19 @@
|
|||
package gitea
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// ListOrgMembershipOption list OrgMembership options
|
||||
// ListOrgActionSecretOption list OrgActionSecret options
|
||||
type ListOrgActionSecretOption struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
// ListOrgMembership list an organization's members
|
||||
// ListOrgActionSecret list an organization's secrets
|
||||
func (c *Client) ListOrgActionSecret(org string, opt ListOrgActionSecretOption) ([]*Secret, *Response, error) {
|
||||
if err := escapeValidatePathSegments(&org); err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -27,3 +30,58 @@ func (c *Client) ListOrgActionSecret(org string, opt ListOrgActionSecretOption)
|
|||
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &secrets)
|
||||
return secrets, resp, err
|
||||
}
|
||||
|
||||
// CreateSecretOption represents the options for creating a secret.
|
||||
type CreateSecretOption struct {
|
||||
Name string `json:"name"` // Name is the name of the secret.
|
||||
Data string `json:"data"` // Data is the data of the secret.
|
||||
}
|
||||
|
||||
// Validate checks if the CreateSecretOption is valid.
|
||||
// It returns an error if any of the validation checks fail.
|
||||
func (opt *CreateSecretOption) Validate() error {
|
||||
if len(opt.Name) == 0 {
|
||||
return fmt.Errorf("name required")
|
||||
}
|
||||
if len(opt.Name) > 30 {
|
||||
return fmt.Errorf("name to long")
|
||||
}
|
||||
if len(opt.Data) == 0 {
|
||||
return fmt.Errorf("data required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateOrgActionSecret creates a secret for the specified organization in the Gitea Actions.
|
||||
// It takes the organization name and the secret options as parameters.
|
||||
// The function returns the HTTP response and an error, if any.
|
||||
func (c *Client) CreateOrgActionSecret(org string, opt CreateSecretOption) (*Response, error) {
|
||||
if err := escapeValidatePathSegments(&org); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := (&opt).Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body, err := json.Marshal(&opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/orgs/%s/actions/secrets/%s", org, opt.Name), jsonHeader, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch status {
|
||||
case http.StatusCreated:
|
||||
return resp, nil
|
||||
case http.StatusNoContent:
|
||||
return resp, nil
|
||||
case http.StatusNotFound:
|
||||
return resp, fmt.Errorf("forbidden")
|
||||
case http.StatusBadRequest:
|
||||
return resp, fmt.Errorf("bad request")
|
||||
default:
|
||||
return resp, fmt.Errorf("unexpected Status: %d", status)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2024 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 (
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateOrgActionSecret(t *testing.T) {
|
||||
log.Println("== TestCreateOrgActionSecret ==")
|
||||
c := newTestClient()
|
||||
|
||||
user := createTestUser(t, "org_action_user", c)
|
||||
c.SetSudo(user.UserName)
|
||||
newOrg, _, err := c.CreateOrg(CreateOrgOption{Name: "ActionOrg"})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, newOrg)
|
||||
|
||||
// create secret
|
||||
resp, err := c.CreateOrgActionSecret(newOrg.UserName, CreateSecretOption{Name: "test", Data: "test"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
||||
|
||||
// update secret
|
||||
resp, err = c.CreateOrgActionSecret(newOrg.UserName, CreateSecretOption{Name: "test", Data: "test2"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
|
||||
|
||||
// list secrets
|
||||
secrets, _, err := c.ListOrgActionSecret(newOrg.UserName, ListOrgActionSecretOption{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, secrets, 1)
|
||||
}
|
|
@ -45,6 +45,8 @@ const (
|
|||
RepoUnitProjects RepoUnitType = "repo.projects"
|
||||
// RepoUnitPackages represents packages of a repository
|
||||
RepoUnitPackages RepoUnitType = "repo.packages"
|
||||
// RepoUnitActions represents actions of a repository
|
||||
RepoUnitActions RepoUnitType = "repo.actions"
|
||||
)
|
||||
|
||||
// ListTeamsOptions options for listing teams
|
||||
|
|
|
@ -16,7 +16,7 @@ type Package struct {
|
|||
// the package's owner
|
||||
Owner User `json:"owner"`
|
||||
// the repo this package belongs to (if any)
|
||||
Repository *string `json:"repository"`
|
||||
Repository *Repository `json:"repository"`
|
||||
// the package's creator
|
||||
Creator User `json:"creator"`
|
||||
// the type of package:
|
||||
|
|
|
@ -78,6 +78,18 @@ func (c *Client) GetRelease(owner, repo string, id int64) (*Release, *Response,
|
|||
return r, resp, err
|
||||
}
|
||||
|
||||
// GetLatestRelease get the latest release of a repository
|
||||
func (c *Client) GetLatestRelease(owner, repo string) (*Release, *Response, error) {
|
||||
if err := escapeValidatePathSegments(&owner, &repo); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
r := new(Release)
|
||||
resp, err := c.getParsedResponse("GET",
|
||||
fmt.Sprintf("/repos/%s/%s/releases/latest", owner, repo),
|
||||
jsonHeader, nil, &r)
|
||||
return r, resp, err
|
||||
}
|
||||
|
||||
// GetReleaseByTag get a release of a repository by tag
|
||||
func (c *Client) GetReleaseByTag(owner, repo, tag string) (*Release, *Response, error) {
|
||||
if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil {
|
||||
|
@ -190,7 +202,7 @@ func (c *Client) fallbackGetReleaseByTag(owner, repo, tag string) (*Release, *Re
|
|||
}
|
||||
if len(rl) == 0 {
|
||||
return nil,
|
||||
&Response{&http.Response{StatusCode: 404}},
|
||||
newResponse(&http.Response{StatusCode: 404}),
|
||||
fmt.Errorf("release with tag '%s' not found", tag)
|
||||
}
|
||||
for _, r := range rl {
|
||||
|
|
|
@ -76,6 +76,11 @@ func TestRelease(t *testing.T) {
|
|||
assert.EqualValues(t, false, r2.IsPrerelease)
|
||||
assert.EqualValues(t, r.Note, r2.Note)
|
||||
|
||||
// GetLatestRelease
|
||||
r3, _, err := c.GetLatestRelease(repo.Owner.UserName, repo.Name)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, r2, r3)
|
||||
|
||||
// DeleteRelease
|
||||
_, err = c.DeleteRelease(repo.Owner.UserName, repo.Name, r.ID)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -85,6 +85,9 @@ type Repository struct {
|
|||
ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"`
|
||||
HasPullRequests bool `json:"has_pull_requests"`
|
||||
HasProjects bool `json:"has_projects"`
|
||||
HasReleases bool `json:"has_releases,omitempty"`
|
||||
HasPackages bool `json:"has_packages,omitempty"`
|
||||
HasActions bool `json:"has_actions,omitempty"`
|
||||
IgnoreWhitespaceConflicts bool `json:"ignore_whitespace_conflicts"`
|
||||
AllowMerge bool `json:"allow_merge_commits"`
|
||||
AllowRebase bool `json:"allow_rebase"`
|
||||
|
@ -331,8 +334,8 @@ func (opt CreateRepoOption) Validate(c *Client) error {
|
|||
if len(opt.Name) > 100 {
|
||||
return fmt.Errorf("name has more than 100 chars")
|
||||
}
|
||||
if len(opt.Description) > 255 {
|
||||
return fmt.Errorf("description has more than 255 chars")
|
||||
if len(opt.Description) > 2048 {
|
||||
return fmt.Errorf("description has more than 2048 chars")
|
||||
}
|
||||
if len(opt.DefaultBranch) > 100 {
|
||||
return fmt.Errorf("default branch name has more than 100 chars")
|
||||
|
@ -423,6 +426,12 @@ type EditRepoOption struct {
|
|||
HasPullRequests *bool `json:"has_pull_requests,omitempty"`
|
||||
// either `true` to enable project unit, or `false` to disable them.
|
||||
HasProjects *bool `json:"has_projects,omitempty"`
|
||||
// either `true` to enable release, or `false` to disable them.
|
||||
HasReleases *bool `json:"has_releases,omitempty"`
|
||||
// either `true` to enable packages, or `false` to disable them.
|
||||
HasPackages *bool `json:"has_packages,omitempty"`
|
||||
// either `true` to enable actions, or `false` to disable them.
|
||||
HasActions *bool `json:"has_actions,omitempty"`
|
||||
// either `true` to ignore whitespace for conflicts, or `false` to not ignore whitespace. `has_pull_requests` must be `true`.
|
||||
IgnoreWhitespaceConflicts *bool `json:"ignore_whitespace_conflicts,omitempty"`
|
||||
// either `true` to allow merging pull requests with a merge commit, or `false` to prevent merging pull requests with merge commits. `has_pull_requests` must be `true`.
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2024 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"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// ListRepoActionSecretOption list RepoActionSecret options
|
||||
type ListRepoActionSecretOption struct {
|
||||
ListOptions
|
||||
}
|
||||
|
||||
// ListRepoActionSecret list a repository's secrets
|
||||
func (c *Client) ListRepoActionSecret(user, repo string, opt ListRepoActionSecretOption) ([]*Secret, *Response, error) {
|
||||
if err := escapeValidatePathSegments(&user, &repo); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
opt.setDefaults()
|
||||
secrets := make([]*Secret, 0, opt.PageSize)
|
||||
|
||||
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/actions/secrets", user, repo))
|
||||
link.RawQuery = opt.getURLQuery().Encode()
|
||||
resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &secrets)
|
||||
return secrets, resp, err
|
||||
}
|
||||
|
||||
// CreateRepoActionSecret creates a secret for the specified repository in the Gitea Actions.
|
||||
// It takes the organization name and the secret options as parameters.
|
||||
// The function returns the HTTP response and an error, if any.
|
||||
func (c *Client) CreateRepoActionSecret(user, repo string, opt CreateSecretOption) (*Response, error) {
|
||||
if err := escapeValidatePathSegments(&user, &repo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := (&opt).Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body, err := json.Marshal(&opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/actions/secrets/%s", user, repo, opt.Name), jsonHeader, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch status {
|
||||
case http.StatusCreated:
|
||||
return resp, nil
|
||||
case http.StatusNoContent:
|
||||
return resp, nil
|
||||
case http.StatusNotFound:
|
||||
return resp, fmt.Errorf("forbidden")
|
||||
case http.StatusBadRequest:
|
||||
return resp, fmt.Errorf("bad request")
|
||||
default:
|
||||
return resp, fmt.Errorf("unexpected Status: %d", status)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2024 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 (
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateRepoActionSecret(t *testing.T) {
|
||||
log.Println("== TestCreateRepoActionSecret ==")
|
||||
c := newTestClient()
|
||||
|
||||
user := createTestUser(t, "repo_action_user", c)
|
||||
c.SetSudo(user.UserName)
|
||||
newRepo, _, err := c.CreateRepo(CreateRepoOption{
|
||||
Name: "test",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, newRepo)
|
||||
|
||||
// create secret
|
||||
resp, err := c.CreateRepoActionSecret(newRepo.Owner.UserName, newRepo.Name, CreateSecretOption{Name: "test", Data: "test"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
||||
|
||||
// update secret
|
||||
resp, err = c.CreateRepoActionSecret(newRepo.Owner.UserName, newRepo.Name, CreateSecretOption{Name: "test", Data: "test2"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
|
||||
|
||||
// list secrets
|
||||
secrets, _, err := c.ListRepoActionSecret(newRepo.Owner.UserName, newRepo.Name, ListRepoActionSecretOption{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, secrets, 1)
|
||||
}
|
|
@ -6,8 +6,8 @@ package gitea
|
|||
|
||||
import (
|
||||
"log"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -21,22 +21,23 @@ func TestRepoBranches(t *testing.T) {
|
|||
if repo == nil {
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
bl, _, err := c.ListRepoBranches(repo.Owner.UserName, repo.Name, ListRepoBranchesOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, bl, 3)
|
||||
|
||||
sort.Slice(bl, func(i, j int) bool {
|
||||
return bl[i].Name < bl[j].Name
|
||||
})
|
||||
assert.EqualValues(t, "feature", bl[0].Name)
|
||||
assert.EqualValues(t, "main", bl[1].Name)
|
||||
assert.EqualValues(t, "update", bl[2].Name)
|
||||
branchNames := make([]string, len(bl))
|
||||
branches := make(map[string]Branch, len(bl))
|
||||
for index, branch := range bl {
|
||||
branchNames[index] = branch.Name
|
||||
branches[branch.Name] = *branch
|
||||
}
|
||||
assert.ElementsMatch(t, []string{"feature", "main", "update"}, branchNames)
|
||||
|
||||
b, _, err := c.GetRepoBranch(repo.Owner.UserName, repo.Name, "update")
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, bl[2].Commit.ID, b.Commit.ID)
|
||||
assert.EqualValues(t, bl[2].Commit.Added, b.Commit.Added)
|
||||
assert.EqualValues(t, branches["update"].Commit.ID, b.Commit.ID)
|
||||
assert.EqualValues(t, branches["update"].Commit.Added, b.Commit.Added)
|
||||
|
||||
s, _, err := c.DeleteRepoBranch(repo.Owner.UserName, repo.Name, "main")
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2024 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"
|
||||
|
||||
// Compare represents a comparison between two commits.
|
||||
type Compare struct {
|
||||
TotalCommits int `json:"total_commits"` // Total number of commits in the comparison.
|
||||
Commits []*Commit `json:"commits"` // List of commits in the comparison.
|
||||
}
|
||||
|
||||
// CompareCommits compares two commits in a repository.
|
||||
func (c *Client) CompareCommits(user, repo, prev, current string) (*Compare, *Response, error) {
|
||||
if err := c.checkServerVersionGreaterThanOrEqual(version1_22_0); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := escapeValidatePathSegments(&user, &repo, &prev, ¤t); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
basehead := fmt.Sprintf("%s...%s", prev, current)
|
||||
|
||||
apiResp := new(Compare)
|
||||
resp, err := c.getParsedResponse(
|
||||
"GET",
|
||||
fmt.Sprintf("/repos/%s/%s/compare/%s", user, repo, basehead),
|
||||
nil, nil, apiResp,
|
||||
)
|
||||
return apiResp, resp, err
|
||||
}
|
|
@ -10,7 +10,6 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
@ -128,7 +127,7 @@ func (c *Client) GetFile(owner, repo, ref, filepath string, resolveLFS ...bool)
|
|||
}
|
||||
defer reader.Close()
|
||||
|
||||
data, err2 := ioutil.ReadAll(reader)
|
||||
data, err2 := io.ReadAll(reader)
|
||||
if err2 != nil {
|
||||
return nil, resp, err2
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ func (opt *MigrateRepoOption) Validate(c *Client) error {
|
|||
} else if len(opt.RepoName) > 100 {
|
||||
return fmt.Errorf("RepoName to long")
|
||||
}
|
||||
if len(opt.Description) > 255 {
|
||||
if len(opt.Description) > 2048 {
|
||||
return fmt.Errorf("Description to long")
|
||||
}
|
||||
switch opt.Service {
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2023 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"
|
||||
)
|
||||
|
||||
type CreatePushMirrorOption struct {
|
||||
Interval string `json:"interval"`
|
||||
RemoteAddress string `json:"remote_address"`
|
||||
RemotePassword string `json:"remote_password"`
|
||||
RemoteUsername string `json:"remote_username"`
|
||||
SyncONCommit bool `json:"sync_on_commit"`
|
||||
}
|
||||
|
||||
// PushMirrorResponse returns a git push mirror
|
||||
type PushMirrorResponse struct {
|
||||
Created string `json:"created"`
|
||||
Interval string `json:"interval"`
|
||||
LastError string `json:"last_error"`
|
||||
LastUpdate string `json:"last_update"`
|
||||
RemoteAddress string `json:"remote_address"`
|
||||
RemoteName string `json:"remote_name"`
|
||||
RepoName string `json:"repo_name"`
|
||||
SyncONCommit bool `json:"sync_on_commit"`
|
||||
}
|
||||
|
||||
// PushMirrors add a push mirror to the repository
|
||||
func (c *Client) PushMirrors(user, repo string, opt CreatePushMirrorOption) (*PushMirrorResponse, *Response, error) {
|
||||
if err := escapeValidatePathSegments(&user, &repo); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
body, err := json.Marshal(opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pm := new(PushMirrorResponse)
|
||||
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/push_mirrors", user, repo), jsonHeader, bytes.NewReader(body), &pm)
|
||||
return pm, resp, err
|
||||
}
|
|
@ -65,7 +65,7 @@ func TestRepoMigrateAndLanguages(t *testing.T) {
|
|||
assert.NotEqual(t, zeroTime, repoG.MirrorUpdated)
|
||||
|
||||
log.Println("== TestRepoLanguages ==")
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(time.Second * 2)
|
||||
lang, _, err := c.GetRepoLanguages(repoM.Owner.UserName, repoM.Name)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, lang, 2)
|
||||
|
|
|
@ -9,6 +9,8 @@ import "time"
|
|||
type Secret struct {
|
||||
// the secret's name
|
||||
Name string `json:"name"`
|
||||
// the secret's data
|
||||
Data string `json:"data"`
|
||||
// Date and Time of secret creation
|
||||
Created time.Time `json:"created_at"`
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ func TestGetGlobalSettings(t *testing.T) {
|
|||
}
|
||||
assert.EqualValues(t, &GlobalAttachmentSettings{
|
||||
Enabled: true,
|
||||
MaxSize: 4,
|
||||
MaxSize: 2048,
|
||||
MaxFiles: 5,
|
||||
}, attachSettings)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@ type User struct {
|
|||
ID int64 `json:"id"`
|
||||
// the user's username
|
||||
UserName string `json:"login"`
|
||||
// The login_name of non local users (e.g. LDAP / OAuth / SMTP)
|
||||
LoginName string `json:"login_name"`
|
||||
// The ID of the Authentication Source for non local users.
|
||||
SourceID int64 `json:"source_id"`
|
||||
// the user's full name
|
||||
FullName string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
|
|
|
@ -19,7 +19,7 @@ func TestUserSettings(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.NotNil(t, userConf)
|
||||
assert.EqualValues(t, UserSettings{
|
||||
Theme: "auto",
|
||||
Theme: "gitea-auto",
|
||||
HideEmail: false,
|
||||
HideActivity: false,
|
||||
}, *userConf)
|
||||
|
@ -33,7 +33,7 @@ func TestUserSettings(t *testing.T) {
|
|||
assert.NotNil(t, userConf)
|
||||
assert.EqualValues(t, UserSettings{
|
||||
FullName: "Admin User on Test",
|
||||
Theme: "auto",
|
||||
Theme: "gitea-auto",
|
||||
Language: "de_de",
|
||||
HideEmail: true,
|
||||
HideActivity: false,
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestMyUser(t *testing.T) {
|
|||
assert.EqualValues(t, "test01", user.UserName)
|
||||
assert.EqualValues(t, "test01@gitea.io", user.Email)
|
||||
assert.EqualValues(t, "", user.FullName)
|
||||
assert.EqualValues(t, "https://secure.gravatar.com/avatar/d794373e882a68fb173cef817fb6180a?d=identicon", user.AvatarURL)
|
||||
assert.EqualValues(t, "http://gitea:3000/avatars/d794373e882a68fb173cef817fb6180a", user.AvatarURL)
|
||||
assert.True(t, user.IsAdmin)
|
||||
}
|
||||
|
||||
|
@ -144,14 +144,14 @@ func TestUserEmail(t *testing.T) {
|
|||
el, _, err := c.ListEmails(ListEmailsOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, el, 1)
|
||||
assert.EqualValues(t, "testuseremail@gitea.io", el[0].Email)
|
||||
assert.EqualValues(t, "TestUserEmail@gitea.io", el[0].Email)
|
||||
assert.True(t, el[0].Primary)
|
||||
|
||||
// AddEmail
|
||||
mails := []string{"wow@mail.send", "speed@mail.me"}
|
||||
el, _, err = c.AddEmail(CreateEmailOption{Emails: mails})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, el, 2)
|
||||
assert.Len(t, el, 3)
|
||||
_, _, err = c.AddEmail(CreateEmailOption{Emails: []string{mails[1]}})
|
||||
assert.Error(t, err)
|
||||
el, _, err = c.ListEmails(ListEmailsOptions{})
|
||||
|
|
|
@ -69,6 +69,7 @@ var (
|
|||
version1_15_0 = version.Must(version.NewVersion("1.15.0"))
|
||||
version1_16_0 = version.Must(version.NewVersion("1.16.0"))
|
||||
version1_17_0 = version.Must(version.NewVersion("1.17.0"))
|
||||
version1_22_0 = version.Must(version.NewVersion("1.22.0"))
|
||||
)
|
||||
|
||||
// ErrUnknownVersion is an unknown version from the API
|
||||
|
@ -77,14 +78,13 @@ type ErrUnknownVersion struct {
|
|||
}
|
||||
|
||||
// Error fulfills error
|
||||
func (e ErrUnknownVersion) Error() string {
|
||||
func (e *ErrUnknownVersion) Error() string {
|
||||
return fmt.Sprintf("unknown version: %s", e.raw)
|
||||
}
|
||||
|
||||
func (_ ErrUnknownVersion) Is(target error) bool {
|
||||
_, ok1 := target.(*ErrUnknownVersion)
|
||||
_, ok2 := target.(ErrUnknownVersion)
|
||||
return ok1 || ok2
|
||||
func (*ErrUnknownVersion) Is(target error) bool {
|
||||
_, ok := target.(*ErrUnknownVersion)
|
||||
return ok
|
||||
}
|
||||
|
||||
// checkServerVersionGreaterThanOrEqual is the canonical way in the SDK to check for versions for API compatibility reasons
|
||||
|
|
Loading…
Reference in New Issue