Compare commits

...

23 Commits

Author SHA1 Message Date
appleboy 8110db1e6d feat: implement Gitea Repo Action Secrets Management (#662)
- Add imports for "bytes", "encoding/json", and "net/http" in `repo_action.go`
- Implement `CreateRepoActionSecret` function to create a secret for a repository in Gitea Actions
- Add a new test file `repo_action_test.go` with tests for creating, updating, and listing repository action secrets

<img width="518" alt="image" src="/attachments/c8e457c4-395f-4ffe-8482-0b7f5d2541cb">

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/662
Reviewed-by: techknowlogick <techknowlogick@noreply.gitea.com>
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
2024-05-08 09:29:30 +00:00
Bo-Yi Wu 83c73e79a5 ci: update Gitea testing configurations for 1.22 release (#663)
- Update Gitea image version to `1.22.0-rc1` in testing workflow
- Increase the number of milestones to be checked in the test from `2` to `3`
- Modify the theme setting from `auto` to `gitea-auto` in user settings test
- Update the Avatar URL in user test to use `http://gitea:3000/avatars/` instead of `https://secure.gravatar.com/avatar/`
- Increase the number of user emails to be checked in the test from `2` to `3`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/663
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-05-08 01:53:26 +00:00
Bo-Yi Wu 6c0938dc15 feat: implement organization action secret creation (#661)
- Add `bytes` and `encoding/json` imports to `org_action.go`
- Implement `CreateSecretOption` struct with validation in `org_action.go`
- Add `CreateOrgActionSecret` function to create or update organization secrets in `org_action.go`
- Create new test file `org_action_test.go` with tests for creating and updating organization secrets
- Add `Data` field to `Secret` struct in `secret.go`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/661
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-05-03 13:52:34 +00:00
tobiasbp 0a99bda0cb Get fields loginName & SourceID for users (#654)
This _PR_ adds the following fields to the _User_ struct:

-  _LoginName_: Currently returned by the Gitea API.
- _SourceID_: [Scheduled to be returned by the Gitea API as of version 1.22.0](https://github.com/go-gitea/gitea/pull/29718).

The fields are used for users with non-local Authentication Sources (LDAP, oAuth etc.).

Co-authored-by: tobias.petersen <tobias.petersen@unity3d.com>
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@noreply.gitea.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/654
Reviewed-by: appleboy <appleboy.tw@gmail.com>
Reviewed-by: techknowlogick <techknowlogick@noreply.gitea.com>
Co-authored-by: tobiasbp <tobiasbp@noreply.gitea.com>
Co-committed-by: tobiasbp <tobiasbp@noreply.gitea.com>
2024-05-02 17:33:09 +00:00
Bo-Yi Wu 36723e11c8 feat(repo): support list of repo secrets (#660)
- Update comment to correctly describe `ListOrgActionSecretOption` as listing organization secrets instead of members
- Add new file `repo_action.go` with functionality to list a repository's secrets including the structure and API call

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/660
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-05-02 06:04:51 +00:00
appleboy a991e370c5 feat: implement commit comparison feature in Gitea client (#659)
See the API: https://github.com/go-gitea/gitea/pull/30349

- Add a new file `repo_compare.go` with package `gitea` and `Compare` struct
- Implement `CompareCommits` method in `Client` struct in `repo_compare.go`
- Add `version1_22_0` constant in `version.go`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/659
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
2024-04-17 05:47:25 +00:00
appleboy bb25c989a0 chore: update Go module dependencies to latest versions (#658)
- Update the version of `golang.org/x/crypto` from `v0.17.0` to `v0.22.0` in `go.mod`
- Update the version of `golang.org/x/sys` from `v0.15.0` to `v0.19.0` in `go.mod`

Signed-off-by: appleboy <appleboy.tw@gmail.com>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/658
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
2024-04-16 08:15:01 +00:00
appleboy 18e5522f90 ci: update Gitea versions in workflows and Makefile (#657)
- Update Gitea Docker image version from `1.21.8` to `1.21.10` in testing workflow
- Update Gitea version from `1.21.1` to `1.21.10` in Makefile

Signed-off-by: appleboy <appleboy.tw@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/657
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
2024-04-14 13:09:31 +00:00
Lunny Xiao bad4de0196 Upgrade CI (#655)
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/655
2024-03-16 08:34:20 +00:00
rjhaverkamp 9ec1b82849 Fix typo in visibilty error (#653)
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/653
Reviewed-by: John Olheiser <jolheiser@noreply.gitea.com>
Co-authored-by: rjhaverkamp <rjhaverkamp@noreply.gitea.com>
Co-committed-by: rjhaverkamp <rjhaverkamp@noreply.gitea.com>
2024-02-28 00:12:39 +00:00
6543 bf71ec2fd9 Make only referenc of ErrUnknownVersion an error (#648)
just a refactor nit

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/648
Reviewed-by: John Olheiser <jolheiser@noreply.gitea.com>
2024-02-22 21:33:21 +00:00
Martijn van der Kleijn 001d5fad51 chore: Bump required Go version to 1.18 (#650)
Reasoning for the bump:
- Enforce (instead of assume) use of newer Go version to ensure presence of security fixes
- Enable use of more recent language features
- Go < 1.21 is EOL
- Testing workflow already uses >= 1.20

For sec fixes, see: https://go.dev/doc/devel/release#go1.21.minor

Signed-off-by: Martijn van der Kleijn <martijn.niji@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/650
Reviewed-by: 6543 <6543@obermui.de>
Co-authored-by: Martijn van der Kleijn <martijn.niji@gmail.com>
Co-committed-by: Martijn van der Kleijn <martijn.niji@gmail.com>
2024-02-22 21:28:11 +00:00
diogo464 5d0143e4e7 fix: updated repository field in Package struct (#647)
The definition for `Package` in the most recent api switch the
repository field from a string to a `Repository`.
Without this fix api calls like ListPackages will fail to deserialize
the response.

Co-authored-by: diogo464 <diogo464@protonmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/647
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: John Olheiser <jolheiser@noreply.gitea.com>
Co-authored-by: diogo464 <diogo464@noreply.gitea.com>
Co-committed-by: diogo464 <diogo464@noreply.gitea.com>
2024-01-29 05:38:16 +00:00
Simon Ser 53f735b911 Add support for user hooks (#644)
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/644
Reviewed-by: techknowlogick <techknowlogick@noreply.gitea.com>
Reviewed-by: John Olheiser <jolheiser@noreply.gitea.com>
Co-authored-by: Simon Ser <contact@emersion.fr>
Co-committed-by: Simon Ser <contact@emersion.fr>
2024-01-25 16:04:00 +00:00
Christian Groschupp 98b424a8af feat(release): add GetLatestRelease method (#639)
This PR adds the GetLatestRelease method to support the /repos/{owner}/{repo}/releases/latest endpoint.
ref: https://docs.gitea.com/api/1.20/#tag/repository/operation/repoGetLatestRelease

Resolves gitea/go-sdk#630

Co-authored-by: techknowlogick <techknowlogick@noreply.gitea.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/639
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Christian Groschupp <christian@groschupp.org>
Co-committed-by: Christian Groschupp <christian@groschupp.org>
2024-01-06 05:14:12 +00:00
Bo-Yi Wu 2abfdd7ba6 chore: update dependencies to latest versions (#646)
- Update the version of `github.com/hashicorp/go-version` from `v1.5.0` to `v1.6.0`
- Update the version of `golang.org/x/crypto` from `v0.0.0-20220525230936-793ad666bf5e` to `v0.17.0`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/646
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-12-31 04:06:05 +00:00
Andreas Wachter 8f4d3d8916 increased description limits to 2048 (#645)
I noticed that the description limits on gitea were changed to 2048 characters last year, but it was still 255 in the SDK.

Here the corresponding commit on gitea:
8351172b6e

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/645
Reviewed-by: techknowlogick <techknowlogick@noreply.gitea.com>
Co-authored-by: Andreas Wachter <andreas.wachter@buddyspencer.monster>
Co-committed-by: Andreas Wachter <andreas.wachter@buddyspencer.monster>
2023-12-30 04:48:39 +00:00
ysicing bde56fb9bb feat(repo): update repo field (#642)
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/642
Reviewed-by: techknowlogick <techknowlogick@noreply.gitea.com>
Co-authored-by: ysicing <i@ysicing.me>
Co-committed-by: ysicing <i@ysicing.me>
2023-12-24 20:16:02 +00:00
ysicing 228d6931f4 feat(repo-mirrors): add repo sync mirrors (#640)
add sync mirrors

Signed-off-by: ysicing <i@ysicing.me>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/640
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: ysicing <i@ysicing.me>
Co-committed-by: ysicing <i@ysicing.me>
2023-12-24 20:15:31 +00:00
appleboy c8745e1599 feat: add new constants for repository actions (#643)
- Add a new constant `RepoUnitActions` to represent the actions of a repository

Signed-off-by: appleboy <appleboy.tw@gmail.com>

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/643
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
2023-12-17 04:36:39 +00:00
Lauris BH 0e0a4691b6 Add Link header parsing in response (#638)
Helps if need to get all data that can not be requested in single page

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/638
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: appleboy <appleboy.tw@gmail.com>
Co-authored-by: Lauris BH <lauris@nix.lv>
Co-committed-by: Lauris BH <lauris@nix.lv>
2023-12-04 14:50:48 +00:00
crapStone e23e8aa300 add option to set user-agent to gitea client (#637)
This PR adds the ability to set a custom user-agent to the gitea client

Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/637
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: John Olheiser <john+gitea@jolheiser.com>
Co-authored-by: crapStone <crapstone01@gmail.com>
Co-committed-by: crapStone <crapstone01@gmail.com>
2023-11-15 01:43:37 +00:00
venc0r d5e174e5b5 feat(hook): add support for authorization_header in webhooks (#633)
fixes #632

Co-authored-by: Jörg Markert <venc0r@live.com>
Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/633
Reviewed-by: John Olheiser <john+gitea@jolheiser.com>
Co-authored-by: venc0r <venc0r@noreply.gitea.com>
Co-committed-by: venc0r <venc0r@noreply.gitea.com>
2023-09-26 00:01:48 +00:00
33 changed files with 562 additions and 84 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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
}

35
gitea/client_test.go Normal file
View File

@ -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)
}

View File

@ -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
)

View File

@ -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=

View File

@ -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 {

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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) {

View File

@ -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
}

View File

@ -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)
}
}

39
gitea/org_action_test.go Normal file
View File

@ -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)
}

View File

@ -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

View File

@ -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:

View File

@ -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 {

View File

@ -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)

View File

@ -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`.

66
gitea/repo_action.go Normal file
View File

@ -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)
}
}

41
gitea/repo_action_test.go Normal file
View File

@ -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)
}

View File

@ -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)

33
gitea/repo_compare.go Normal file
View File

@ -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, &current); 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
}

View File

@ -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
}

View File

@ -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 {

45
gitea/repo_mirror.go Normal file
View File

@ -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
}

View File

@ -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)

View File

@ -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"`
}

View File

@ -44,7 +44,7 @@ func TestGetGlobalSettings(t *testing.T) {
}
assert.EqualValues(t, &GlobalAttachmentSettings{
Enabled: true,
MaxSize: 4,
MaxSize: 2048,
MaxFiles: 5,
}, attachSettings)
}

View File

@ -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"`

View File

@ -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,

View File

@ -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{})

View File

@ -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