@@ -5,7 +5,7 @@ go 1.16 | |||
require ( | |||
cloud.google.com/go v0.78.0 // indirect | |||
code.gitea.io/gitea-vet v0.2.1 | |||
code.gitea.io/sdk/gitea v0.14.0 | |||
code.gitea.io/sdk/gitea v0.15.1 | |||
gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be | |||
gitea.com/go-chi/cache v0.0.0-20211013020926-78790b11abf1 | |||
gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5 |
@@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX | |||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= | |||
code.gitea.io/gitea-vet v0.2.1 h1:b30by7+3SkmiftK0RjuXqFvZg2q4p68uoPGuxhzBN0s= | |||
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= | |||
code.gitea.io/sdk/gitea v0.14.0 h1:m4J352I3p9+bmJUfS+g0odeQzBY/5OXP91Gv6D4fnJ0= | |||
code.gitea.io/sdk/gitea v0.14.0/go.mod h1:89WiyOX1KEcvjP66sRHdu0RafojGo60bT9UqW17VbWs= | |||
code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= | |||
code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= | |||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= | |||
gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be h1:IzSwPVzd2hE6e67ujY8ReBCrQ5IFNd0uiBmC7Ux5IaY= | |||
gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be/go.mod h1:/vR0YjlusOYvosKYW7QKcSnrY0nPLe4RQ/DGi3+i/Do= |
@@ -26,14 +26,15 @@ func (c *Client) AdminListUsers(opt AdminListUsersOptions) ([]*User, *Response, | |||
// CreateUserOption create user options | |||
type CreateUserOption struct { | |||
SourceID int64 `json:"source_id"` | |||
LoginName string `json:"login_name"` | |||
Username string `json:"username"` | |||
FullName string `json:"full_name"` | |||
Email string `json:"email"` | |||
Password string `json:"password"` | |||
MustChangePassword *bool `json:"must_change_password"` | |||
SendNotify bool `json:"send_notify"` | |||
SourceID int64 `json:"source_id"` | |||
LoginName string `json:"login_name"` | |||
Username string `json:"username"` | |||
FullName string `json:"full_name"` | |||
Email string `json:"email"` | |||
Password string `json:"password"` | |||
MustChangePassword *bool `json:"must_change_password"` | |||
SendNotify bool `json:"send_notify"` | |||
Visibility *VisibleType `json:"visibility"` | |||
} | |||
// Validate the CreateUserOption struct | |||
@@ -63,21 +64,24 @@ func (c *Client) AdminCreateUser(opt CreateUserOption) (*User, *Response, error) | |||
// EditUserOption edit user options | |||
type EditUserOption struct { | |||
SourceID int64 `json:"source_id"` | |||
LoginName string `json:"login_name"` | |||
Email *string `json:"email"` | |||
FullName *string `json:"full_name"` | |||
Password string `json:"password"` | |||
MustChangePassword *bool `json:"must_change_password"` | |||
Website *string `json:"website"` | |||
Location *string `json:"location"` | |||
Active *bool `json:"active"` | |||
Admin *bool `json:"admin"` | |||
AllowGitHook *bool `json:"allow_git_hook"` | |||
AllowImportLocal *bool `json:"allow_import_local"` | |||
MaxRepoCreation *int `json:"max_repo_creation"` | |||
ProhibitLogin *bool `json:"prohibit_login"` | |||
AllowCreateOrganization *bool `json:"allow_create_organization"` | |||
SourceID int64 `json:"source_id"` | |||
LoginName string `json:"login_name"` | |||
Email *string `json:"email"` | |||
FullName *string `json:"full_name"` | |||
Password string `json:"password"` | |||
Description *string `json:"description"` | |||
MustChangePassword *bool `json:"must_change_password"` | |||
Website *string `json:"website"` | |||
Location *string `json:"location"` | |||
Active *bool `json:"active"` | |||
Admin *bool `json:"admin"` | |||
AllowGitHook *bool `json:"allow_git_hook"` | |||
AllowImportLocal *bool `json:"allow_import_local"` | |||
MaxRepoCreation *int `json:"max_repo_creation"` | |||
ProhibitLogin *bool `json:"prohibit_login"` | |||
AllowCreateOrganization *bool `json:"allow_create_organization"` | |||
Restricted *bool `json:"restricted"` | |||
Visibility *VisibleType `json:"visibility"` | |||
} | |||
// AdminEditUser modify user informations |
@@ -24,23 +24,25 @@ var jsonHeader = http.Header{"content-type": []string{"application/json"}} | |||
// Version return the library version | |||
func Version() string { | |||
return "0.14.0" | |||
return "0.15.1" | |||
} | |||
// Client represents a thread-safe Gitea API client. | |||
type Client struct { | |||
url string | |||
accessToken string | |||
username string | |||
password string | |||
otp string | |||
sudo string | |||
debug bool | |||
client *http.Client | |||
ctx context.Context | |||
mutex sync.RWMutex | |||
url string | |||
accessToken string | |||
username string | |||
password string | |||
otp string | |||
sudo string | |||
debug bool | |||
client *http.Client | |||
ctx context.Context | |||
mutex sync.RWMutex | |||
serverVersion *version.Version | |||
getVersionOnce sync.Once | |||
ignoreVersion bool // only set by SetGiteaVersion so don't need a mutex lock | |||
} | |||
// Response represents the gitea response | |||
@@ -48,16 +50,21 @@ type Response struct { | |||
*http.Response | |||
} | |||
// ClientOption are functions used to init a new client | |||
type ClientOption func(*Client) error | |||
// NewClient initializes and returns a API client. | |||
// Usage of all gitea.Client methods is concurrency-safe. | |||
func NewClient(url string, options ...func(*Client)) (*Client, error) { | |||
func NewClient(url string, options ...ClientOption) (*Client, error) { | |||
client := &Client{ | |||
url: strings.TrimSuffix(url, "/"), | |||
client: &http.Client{}, | |||
ctx: context.Background(), | |||
} | |||
for _, opt := range options { | |||
opt(client) | |||
if err := opt(client); err != nil { | |||
return nil, err | |||
} | |||
} | |||
if err := client.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { | |||
return nil, err | |||
@@ -73,9 +80,10 @@ func NewClientWithHTTP(url string, httpClient *http.Client) *Client { | |||
} | |||
// SetHTTPClient is an option for NewClient to set custom http client | |||
func SetHTTPClient(httpClient *http.Client) func(client *Client) { | |||
return func(client *Client) { | |||
func SetHTTPClient(httpClient *http.Client) ClientOption { | |||
return func(client *Client) error { | |||
client.SetHTTPClient(httpClient) | |||
return nil | |||
} | |||
} | |||
@@ -87,18 +95,20 @@ func (c *Client) SetHTTPClient(client *http.Client) { | |||
} | |||
// SetToken is an option for NewClient to set token | |||
func SetToken(token string) func(client *Client) { | |||
return func(client *Client) { | |||
func SetToken(token string) ClientOption { | |||
return func(client *Client) error { | |||
client.mutex.Lock() | |||
client.accessToken = token | |||
client.mutex.Unlock() | |||
return nil | |||
} | |||
} | |||
// SetBasicAuth is an option for NewClient to set username and password | |||
func SetBasicAuth(username, password string) func(client *Client) { | |||
return func(client *Client) { | |||
func SetBasicAuth(username, password string) ClientOption { | |||
return func(client *Client) error { | |||
client.SetBasicAuth(username, password) | |||
return nil | |||
} | |||
} | |||
@@ -110,9 +120,10 @@ func (c *Client) SetBasicAuth(username, password string) { | |||
} | |||
// SetOTP is an option for NewClient to set OTP for 2FA | |||
func SetOTP(otp string) func(client *Client) { | |||
return func(client *Client) { | |||
func SetOTP(otp string) ClientOption { | |||
return func(client *Client) error { | |||
client.SetOTP(otp) | |||
return nil | |||
} | |||
} | |||
@@ -123,14 +134,15 @@ func (c *Client) SetOTP(otp string) { | |||
c.mutex.Unlock() | |||
} | |||
// SetContext is an option for NewClient to set context | |||
func SetContext(ctx context.Context) func(client *Client) { | |||
return func(client *Client) { | |||
// SetContext is an option for NewClient to set the default context | |||
func SetContext(ctx context.Context) ClientOption { | |||
return func(client *Client) error { | |||
client.SetContext(ctx) | |||
return nil | |||
} | |||
} | |||
// SetContext set context witch is used for http requests | |||
// SetContext set default context witch is used for http requests | |||
func (c *Client) SetContext(ctx context.Context) { | |||
c.mutex.Lock() | |||
c.ctx = ctx | |||
@@ -138,9 +150,10 @@ func (c *Client) SetContext(ctx context.Context) { | |||
} | |||
// SetSudo is an option for NewClient to set sudo header | |||
func SetSudo(sudo string) func(client *Client) { | |||
return func(client *Client) { | |||
func SetSudo(sudo string) ClientOption { | |||
return func(client *Client) error { | |||
client.SetSudo(sudo) | |||
return nil | |||
} | |||
} | |||
@@ -152,11 +165,12 @@ func (c *Client) SetSudo(sudo string) { | |||
} | |||
// SetDebugMode is an option for NewClient to enable debug mode | |||
func SetDebugMode() func(client *Client) { | |||
return func(client *Client) { | |||
func SetDebugMode() ClientOption { | |||
return func(client *Client) error { | |||
client.mutex.Lock() | |||
client.debug = true | |||
client.mutex.Unlock() | |||
return nil | |||
} | |||
} | |||
@@ -3,6 +3,7 @@ module code.gitea.io/sdk/gitea | |||
go 1.13 | |||
require ( | |||
code.gitea.io/gitea-vet v0.2.1 // indirect | |||
github.com/hashicorp/go-version v1.2.1 | |||
github.com/stretchr/testify v1.4.0 | |||
) |
@@ -1,7 +1,7 @@ | |||
code.gitea.io/gitea-vet v0.2.1 h1:b30by7+3SkmiftK0RjuXqFvZg2q4p68uoPGuxhzBN0s= | |||
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= | |||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= | |||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= | |||
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= | |||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= | |||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |||
@@ -9,6 +9,24 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= | |||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | |||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | |||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI= | |||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= | |||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
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= | |||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= |
@@ -24,6 +24,28 @@ type Hook struct { | |||
Created time.Time `json:"created_at"` | |||
} | |||
// HookType represent all webhook types gitea currently offer | |||
type HookType string | |||
const ( | |||
// HookTypeDingtalk webhook that dingtalk understand | |||
HookTypeDingtalk HookType = "dingtalk" | |||
// HookTypeDiscord webhook that discord understand | |||
HookTypeDiscord HookType = "discord" | |||
// HookTypeGitea webhook that gitea understand | |||
HookTypeGitea HookType = "gitea" | |||
// HookTypeGogs webhook that gogs understand | |||
HookTypeGogs HookType = "gogs" | |||
// HookTypeMsteams webhook that msteams understand | |||
HookTypeMsteams HookType = "msteams" | |||
// HookTypeSlack webhook that slack understand | |||
HookTypeSlack HookType = "slack" | |||
// HookTypeTelegram webhook that telegram understand | |||
HookTypeTelegram HookType = "telegram" | |||
// HookTypeFeishu webhook that feishu understand | |||
HookTypeFeishu HookType = "feishu" | |||
) | |||
// ListHooksOptions options for listing hooks | |||
type ListHooksOptions struct { | |||
ListOptions | |||
@@ -73,7 +95,7 @@ func (c *Client) GetRepoHook(user, repo string, id int64) (*Hook, *Response, err | |||
// CreateHookOption options when create a hook | |||
type CreateHookOption struct { | |||
Type string `json:"type"` | |||
Type HookType `json:"type"` | |||
Config map[string]string `json:"config"` | |||
Events []string `json:"events"` | |||
BranchFilter string `json:"branch_filter"` |
@@ -42,10 +42,7 @@ type Issue struct { | |||
Ref string `json:"ref"` | |||
Labels []*Label `json:"labels"` | |||
Milestone *Milestone `json:"milestone"` | |||
// deprecated | |||
// TODO: rm on sdk 0.15.0 | |||
Assignee *User `json:"assignee"` | |||
Assignees []*User `json:"assignees"` | |||
Assignees []*User `json:"assignees"` | |||
// Whether the issue is open or closed | |||
State StateType `json:"state"` | |||
IsLocked bool `json:"is_locked"` | |||
@@ -66,6 +63,14 @@ type ListIssueOption struct { | |||
Labels []string | |||
Milestones []string | |||
KeyWord string | |||
Since time.Time | |||
Before time.Time | |||
// filter by created by username | |||
CreatedBy string | |||
// filter by assigned to username | |||
AssignedBy string | |||
// filter by username mentioned | |||
MentionedBy string | |||
} | |||
// StateType issue state type | |||
@@ -114,6 +119,23 @@ func (opt *ListIssueOption) QueryEncode() string { | |||
query.Add("milestones", strings.Join(opt.Milestones, ",")) | |||
} | |||
if !opt.Since.IsZero() { | |||
query.Add("since", opt.Since.Format(time.RFC3339)) | |||
} | |||
if !opt.Before.IsZero() { | |||
query.Add("before", opt.Before.Format(time.RFC3339)) | |||
} | |||
if len(opt.CreatedBy) > 0 { | |||
query.Add("created_by", opt.CreatedBy) | |||
} | |||
if len(opt.AssignedBy) > 0 { | |||
query.Add("assigned_by", opt.AssignedBy) | |||
} | |||
if len(opt.MentionedBy) > 0 { | |||
query.Add("mentioned_by", opt.MentionedBy) | |||
} | |||
return query.Encode() | |||
} | |||
@@ -178,12 +200,9 @@ func (c *Client) GetIssue(owner, repo string, index int64) (*Issue, *Response, e | |||
// CreateIssueOption options to create one issue | |||
type CreateIssueOption struct { | |||
Title string `json:"title"` | |||
Body string `json:"body"` | |||
Ref string `json:"ref"` | |||
// deprecated | |||
// TODO: rm on sdk 0.15.0 | |||
Assignee string `json:"assignee"` | |||
Title string `json:"title"` | |||
Body string `json:"body"` | |||
Ref string `json:"ref"` | |||
Assignees []string `json:"assignees"` | |||
Deadline *time.Time `json:"due_date"` | |||
// milestone id | |||
@@ -222,12 +241,9 @@ func (c *Client) CreateIssue(owner, repo string, opt CreateIssueOption) (*Issue, | |||
// EditIssueOption options for editing an issue | |||
type EditIssueOption struct { | |||
Title string `json:"title"` | |||
Body *string `json:"body"` | |||
Ref *string `json:"ref"` | |||
// deprecated | |||
// TODO: rm on sdk 0.15.0 | |||
Assignee *string `json:"assignee"` | |||
Title string `json:"title"` | |||
Body *string `json:"body"` | |||
Ref *string `json:"ref"` | |||
Assignees []string `json:"assignees"` | |||
Milestone *int64 `json:"milestone"` | |||
State *StateType `json:"state"` |
@@ -73,7 +73,7 @@ func (c *Client) GetMilestone(owner, repo string, id int64) (*Milestone, *Respon | |||
// GetMilestoneByName get one milestone by repo and milestone name | |||
func (c *Client) GetMilestoneByName(owner, repo string, name string) (*Milestone, *Response, error) { | |||
if c.CheckServerVersionConstraint(">=1.13") != nil { | |||
if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { | |||
// backwards compatibility mode | |||
m, resp, err := c.resolveMilestoneByName(owner, repo, name) | |||
return m, resp, err | |||
@@ -164,7 +164,7 @@ func (c *Client) EditMilestone(owner, repo string, id int64, opt EditMilestoneOp | |||
// EditMilestoneByName modify milestone with options | |||
func (c *Client) EditMilestoneByName(owner, repo string, name string, opt EditMilestoneOption) (*Milestone, *Response, error) { | |||
if c.CheckServerVersionConstraint(">=1.13") != nil { | |||
if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { | |||
// backwards compatibility mode | |||
m, _, err := c.resolveMilestoneByName(owner, repo, name) | |||
if err != nil { | |||
@@ -198,7 +198,7 @@ func (c *Client) DeleteMilestone(owner, repo string, id int64) (*Response, error | |||
// DeleteMilestoneByName delete one milestone by name | |||
func (c *Client) DeleteMilestoneByName(owner, repo string, name string) (*Response, error) { | |||
if c.CheckServerVersionConstraint(">=1.13") != nil { | |||
if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { | |||
// backwards compatibility mode | |||
m, _, err := c.resolveMilestoneByName(owner, repo, name) | |||
if err != nil { |
@@ -26,8 +26,13 @@ func (o ListOptions) getURLQuery() url.Values { | |||
return query | |||
} | |||
func (o ListOptions) setDefaults() { | |||
if o.Page < 1 { | |||
// setDefaults set default pagination options if none or wrong are set | |||
// if you set -1 as page it will set all to 0 | |||
func (o *ListOptions) setDefaults() { | |||
if o.Page < 0 { | |||
o.Page, o.PageSize = 0, 0 | |||
return | |||
} else if o.Page == 0 { | |||
o.Page = 1 | |||
} | |||
@@ -29,11 +29,11 @@ type NotificationThread struct { | |||
// NotificationSubject contains the notification subject (Issue/Pull/Commit) | |||
type NotificationSubject struct { | |||
Title string `json:"title"` | |||
URL string `json:"url"` | |||
LatestCommentURL string `json:"latest_comment_url"` | |||
Type string `json:"type"` | |||
State StateType `json:"state"` | |||
Title string `json:"title"` | |||
URL string `json:"url"` | |||
LatestCommentURL string `json:"latest_comment_url"` | |||
Type NotifySubjectType `json:"type"` | |||
State NotifySubjectState `json:"state"` | |||
} | |||
// NotifyStatus notification status type | |||
@@ -48,12 +48,39 @@ const ( | |||
NotifyStatusPinned NotifyStatus = "pinned" | |||
) | |||
// NotifySubjectType represent type of notification subject | |||
type NotifySubjectType string | |||
const ( | |||
// NotifySubjectIssue an issue is subject of an notification | |||
NotifySubjectIssue NotifySubjectType = "Issue" | |||
// NotifySubjectPull an pull is subject of an notification | |||
NotifySubjectPull NotifySubjectType = "Pull" | |||
// NotifySubjectCommit an commit is subject of an notification | |||
NotifySubjectCommit NotifySubjectType = "Commit" | |||
// NotifySubjectRepository an repository is subject of an notification | |||
NotifySubjectRepository NotifySubjectType = "Repository" | |||
) | |||
// NotifySubjectState reflect state of notification subject | |||
type NotifySubjectState string | |||
const ( | |||
// NotifySubjectOpen if subject is a pull/issue and is open at the moment | |||
NotifySubjectOpen NotifySubjectState = "open" | |||
// NotifySubjectClosed if subject is a pull/issue and is closed at the moment | |||
NotifySubjectClosed NotifySubjectState = "closed" | |||
// NotifySubjectMerged if subject is a pull and got merged | |||
NotifySubjectMerged NotifySubjectState = "merged" | |||
) | |||
// ListNotificationOptions represents the filter options | |||
type ListNotificationOptions struct { | |||
ListOptions | |||
Since time.Time | |||
Before time.Time | |||
Status []NotifyStatus | |||
Since time.Time | |||
Before time.Time | |||
Status []NotifyStatus | |||
SubjectTypes []NotifySubjectType | |||
} | |||
// MarkNotificationOptions represents the filter & modify options | |||
@@ -75,6 +102,9 @@ func (opt *ListNotificationOptions) QueryEncode() string { | |||
for _, s := range opt.Status { | |||
query.Add("status-types", string(s)) | |||
} | |||
for _, s := range opt.SubjectTypes { | |||
query.Add("subject-type", string(s)) | |||
} | |||
return query.Encode() | |||
} | |||
@@ -73,12 +73,13 @@ func (c *Client) GetOrg(orgname string) (*Organization, *Response, error) { | |||
// CreateOrgOption options for creating an organization | |||
type CreateOrgOption struct { | |||
Name string `json:"username"` | |||
FullName string `json:"full_name"` | |||
Description string `json:"description"` | |||
Website string `json:"website"` | |||
Location string `json:"location"` | |||
Visibility VisibleType `json:"visibility"` | |||
Name string `json:"username"` | |||
FullName string `json:"full_name"` | |||
Description string `json:"description"` | |||
Website string `json:"website"` | |||
Location string `json:"location"` | |||
Visibility VisibleType `json:"visibility"` | |||
RepoAdminChangeTeamAccess bool `json:"repo_admin_change_team_access"` | |||
} | |||
// checkVisibilityOpt check if mode exist |
@@ -12,16 +12,37 @@ import ( | |||
// Team represents a team in an organization | |||
type Team struct { | |||
ID int64 `json:"id"` | |||
Name string `json:"name"` | |||
Description string `json:"description"` | |||
Organization *Organization `json:"organization"` | |||
Permission AccessMode `json:"permission"` | |||
CanCreateOrgRepo bool `json:"can_create_org_repo"` | |||
IncludesAllRepositories bool `json:"includes_all_repositories"` | |||
// example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.ext_wiki"] | |||
Units []string `json:"units"` | |||
} | |||
ID int64 `json:"id"` | |||
Name string `json:"name"` | |||
Description string `json:"description"` | |||
Organization *Organization `json:"organization"` | |||
Permission AccessMode `json:"permission"` | |||
CanCreateOrgRepo bool `json:"can_create_org_repo"` | |||
IncludesAllRepositories bool `json:"includes_all_repositories"` | |||
Units []RepoUnitType `json:"units"` | |||
} | |||
// RepoUnitType represent all unit types of a repo gitea currently offer | |||
type RepoUnitType string | |||
const ( | |||
// RepoUnitCode represent file view of a repository | |||
RepoUnitCode RepoUnitType = "repo.code" | |||
// RepoUnitIssues represent issues of a repository | |||
RepoUnitIssues RepoUnitType = "repo.issues" | |||
// RepoUnitPulls represent pulls of a repository | |||
RepoUnitPulls RepoUnitType = "repo.pulls" | |||
// RepoUnitExtIssues represent external issues of a repository | |||
RepoUnitExtIssues RepoUnitType = "repo.ext_issues" | |||
// RepoUnitWiki represent wiki of a repository | |||
RepoUnitWiki RepoUnitType = "repo.wiki" | |||
// RepoUnitExtWiki represent external wiki of a repository | |||
RepoUnitExtWiki RepoUnitType = "repo.ext_wiki" | |||
// RepoUnitReleases represent releases of a repository | |||
RepoUnitReleases RepoUnitType = "repo.releases" | |||
// RepoUnitProjects represent projects of a repository | |||
RepoUnitProjects RepoUnitType = "repo.projects" | |||
) | |||
// ListTeamsOptions options for listing teams | |||
type ListTeamsOptions struct { | |||
@@ -56,13 +77,12 @@ func (c *Client) GetTeam(id int64) (*Team, *Response, error) { | |||
// CreateTeamOption options for creating a team | |||
type CreateTeamOption struct { | |||
Name string `json:"name"` | |||
Description string `json:"description"` | |||
Permission AccessMode `json:"permission"` | |||
CanCreateOrgRepo bool `json:"can_create_org_repo"` | |||
IncludesAllRepositories bool `json:"includes_all_repositories"` | |||
// example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.ext_wiki"] | |||
Units []string `json:"units"` | |||
Name string `json:"name"` | |||
Description string `json:"description"` | |||
Permission AccessMode `json:"permission"` | |||
CanCreateOrgRepo bool `json:"can_create_org_repo"` | |||
IncludesAllRepositories bool `json:"includes_all_repositories"` | |||
Units []RepoUnitType `json:"units"` | |||
} | |||
// Validate the CreateTeamOption struct | |||
@@ -103,13 +123,12 @@ func (c *Client) CreateTeam(org string, opt CreateTeamOption) (*Team, *Response, | |||
// EditTeamOption options for editing a team | |||
type EditTeamOption struct { | |||
Name string `json:"name"` | |||
Description *string `json:"description"` | |||
Permission AccessMode `json:"permission"` | |||
CanCreateOrgRepo *bool `json:"can_create_org_repo"` | |||
IncludesAllRepositories *bool `json:"includes_all_repositories"` | |||
// example: ["repo.code","repo.issues","repo.ext_issues","repo.wiki","repo.pulls","repo.releases","repo.ext_wiki"] | |||
Units []string `json:"units"` | |||
Name string `json:"name"` | |||
Description *string `json:"description"` | |||
Permission AccessMode `json:"permission"` | |||
CanCreateOrgRepo *bool `json:"can_create_org_repo"` | |||
IncludesAllRepositories *bool `json:"includes_all_repositories"` | |||
Units []RepoUnitType `json:"units"` | |||
} | |||
// Validate the EditTeamOption struct |
@@ -12,6 +12,8 @@ import ( | |||
"net/url" | |||
"strings" | |||
"time" | |||
"github.com/hashicorp/go-version" | |||
) | |||
// PRBranchInfo information about a branch | |||
@@ -214,10 +216,12 @@ type MergePullRequestOption struct { | |||
Message string `json:"MergeMessageField"` | |||
} | |||
var version1_11_5, _ = version.NewVersion("1.11.5") | |||
// Validate the MergePullRequestOption struct | |||
func (opt MergePullRequestOption) Validate(c *Client) error { | |||
if opt.Style == MergeStyleSquash { | |||
if err := c.CheckServerVersionConstraint(">=1.11.5"); err != nil { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_11_5); err != nil { | |||
return err | |||
} | |||
} | |||
@@ -285,6 +289,24 @@ func (c *Client) GetPullRequestDiff(owner, repo string, index int64) ([]byte, *R | |||
return c.getPullRequestDiffOrPatch(owner, repo, "diff", index) | |||
} | |||
// ListPullRequestCommitsOptions options for listing pull requests | |||
type ListPullRequestCommitsOptions struct { | |||
ListOptions | |||
} | |||
// ListPullRequestCommits list commits for a pull request | |||
func (c *Client) ListPullRequestCommits(owner, repo string, index int64, opt ListPullRequestCommitsOptions) ([]*Commit, *Response, error) { | |||
if err := escapeValidatePathSegments(&owner, &repo); err != nil { | |||
return nil, nil, err | |||
} | |||
link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/pulls/%d/commits", owner, repo, index)) | |||
opt.setDefaults() | |||
commits := make([]*Commit, 0, opt.PageSize) | |||
link.RawQuery = opt.getURLQuery().Encode() | |||
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &commits) | |||
return commits, resp, err | |||
} | |||
// fixPullHeadSha is a workaround for https://github.com/go-gitea/gitea/issues/12675 | |||
// When no head sha is available, this is because the branch got deleted in the base repo. | |||
// pr.Head.Ref points in this case not to the head repo branch name, but the base repo ref, |
@@ -57,6 +57,7 @@ type PullReviewComment struct { | |||
Body string `json:"body"` | |||
Reviewer *User `json:"user"` | |||
ReviewID int64 `json:"pull_request_review_id"` | |||
Resolver *User `json:"resolver"` | |||
Created time.Time `json:"created_at"` | |||
Updated time.Time `json:"updated_at"` |
@@ -35,6 +35,22 @@ type Release struct { | |||
// ListReleasesOptions options for listing repository's releases | |||
type ListReleasesOptions struct { | |||
ListOptions | |||
IsDraft *bool | |||
IsPreRelease *bool | |||
} | |||
// QueryEncode turns options into querystring argument | |||
func (opt *ListReleasesOptions) QueryEncode() string { | |||
query := opt.getURLQuery() | |||
if opt.IsDraft != nil { | |||
query.Add("draft", fmt.Sprintf("%t", *opt.IsDraft)) | |||
} | |||
if opt.IsPreRelease != nil { | |||
query.Add("draft", fmt.Sprintf("%t", *opt.IsPreRelease)) | |||
} | |||
return query.Encode() | |||
} | |||
// ListReleases list releases of a repository | |||
@@ -45,7 +61,7 @@ func (c *Client) ListReleases(owner, repo string, opt ListReleasesOptions) ([]*R | |||
opt.setDefaults() | |||
releases := make([]*Release, 0, opt.PageSize) | |||
resp, err := c.getParsedResponse("GET", | |||
fmt.Sprintf("/repos/%s/%s/releases?%s", owner, repo, opt.getURLQuery().Encode()), | |||
fmt.Sprintf("/repos/%s/%s/releases?%s", owner, repo, opt.QueryEncode()), | |||
nil, nil, &releases) | |||
return releases, resp, err | |||
} | |||
@@ -168,7 +184,7 @@ func (c *Client) DeleteReleaseByTag(user, repo string, tag string) (*Response, e | |||
// fallbackGetReleaseByTag is fallback for old gitea installations ( < 1.13.0 ) | |||
func (c *Client) fallbackGetReleaseByTag(owner, repo string, tag string) (*Release, *Response, error) { | |||
for i := 1; ; i++ { | |||
rl, resp, err := c.ListReleases(owner, repo, ListReleasesOptions{ListOptions{Page: i}}) | |||
rl, resp, err := c.ListReleases(owner, repo, ListReleasesOptions{ListOptions: ListOptions{Page: i}}) | |||
if err != nil { | |||
return nil, resp, err | |||
} |
@@ -93,6 +93,7 @@ type Repository struct { | |||
AvatarURL string `json:"avatar_url"` | |||
Internal bool `json:"internal"` | |||
MirrorInterval string `json:"mirror_interval"` | |||
DefaultMergeStyle MergeStyle `json:"default_merge_style"` | |||
} | |||
// RepoType represent repo type | |||
@@ -334,7 +335,7 @@ func (opt CreateRepoOption) Validate(c *Client) error { | |||
return fmt.Errorf("name has more than 100 chars") | |||
} | |||
if len(opt.TrustModel) != 0 { | |||
if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { | |||
return err | |||
} | |||
} | |||
@@ -382,6 +383,13 @@ func (c *Client) GetRepo(owner, reponame string) (*Repository, *Response, error) | |||
return repo, resp, err | |||
} | |||
// GetRepoByID returns information of a repository by a giver repository ID. | |||
func (c *Client) GetRepoByID(id int64) (*Repository, *Response, error) { | |||
repo := new(Repository) | |||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repositories/%d", id), nil, nil, repo) | |||
return repo, resp, err | |||
} | |||
// EditRepoOption options when editing a repository's properties | |||
type EditRepoOption struct { | |||
// name of the repository | |||
@@ -426,6 +434,13 @@ type EditRepoOption struct { | |||
Archived *bool `json:"archived,omitempty"` | |||
// set to a string like `8h30m0s` to set the mirror interval time | |||
MirrorInterval *string `json:"mirror_interval,omitempty"` | |||
// either `true` to allow mark pr as merged manually, or `false` to prevent it. `has_pull_requests` must be `true`. | |||
AllowManualMerge *bool `json:"allow_manual_merge,omitempty"` | |||
// either `true` to enable AutodetectManualMerge, or `false` to prevent it. `has_pull_requests` must be `true`, Note: In some special cases, misjudgments can occur. | |||
AutodetectManualMerge *bool `json:"autodetect_manual_merge,omitempty"` | |||
// set to a merge style to be used by this repository: "merge", "rebase", "rebase-merge", or "squash". `has_pull_requests` must be `true`. | |||
DefaultMergeStyle *MergeStyle `json:"default_merge_style,omitempty"` | |||
// set to `true` to archive this repository. | |||
} | |||
// EditRepo edit the properties of a repository |
@@ -1,3 +1,4 @@ | |||
// Copyright 2021 The Gitea Authors. All rights reserved. | |||
// Copyright 2016 The Gogs Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
@@ -107,3 +108,29 @@ func (c *Client) DeleteCollaborator(user, repo, collaborator string) (*Response, | |||
fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, nil) | |||
return resp, err | |||
} | |||
// GetReviewers return all users that can be requested to review in this repo | |||
func (c *Client) GetReviewers(user, repo string) ([]*User, *Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, nil, err | |||
} | |||
if err := escapeValidatePathSegments(&user, &repo); err != nil { | |||
return nil, nil, err | |||
} | |||
reviewers := make([]*User, 0, 5) | |||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/reviewers", user, repo), nil, nil, &reviewers) | |||
return reviewers, resp, err | |||
} | |||
// GetAssignees return all users that have write access and can be assigned to issues | |||
func (c *Client) GetAssignees(user, repo string) ([]*User, *Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, nil, err | |||
} | |||
if err := escapeValidatePathSegments(&user, &repo); err != nil { | |||
return nil, nil, err | |||
} | |||
assignees := make([]*User, 0, 5) | |||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/assignees", user, repo), nil, nil, &assignees) | |||
return assignees, resp, err | |||
} |
@@ -47,6 +47,8 @@ type MigrateRepoOption struct { | |||
PullRequests bool `json:"pull_requests"` | |||
Releases bool `json:"releases"` | |||
MirrorInterval string `json:"mirror_interval"` | |||
LFS bool `json:"lfs"` | |||
LFSEndpoint string `json:"lfs_endpoint"` | |||
} | |||
// Validate the MigrateRepoOption struct |
@@ -5,18 +5,39 @@ | |||
package gitea | |||
import ( | |||
"bytes" | |||
"encoding/json" | |||
"fmt" | |||
) | |||
// Tag represents a repository tag | |||
type Tag struct { | |||
Name string `json:"name"` | |||
Message string `json:"message"` | |||
ID string `json:"id"` | |||
Commit *CommitMeta `json:"commit"` | |||
ZipballURL string `json:"zipball_url"` | |||
TarballURL string `json:"tarball_url"` | |||
} | |||
// AnnotatedTag represents an annotated tag | |||
type AnnotatedTag struct { | |||
Tag string `json:"tag"` | |||
SHA string `json:"sha"` | |||
URL string `json:"url"` | |||
Message string `json:"message"` | |||
Tagger *CommitUser `json:"tagger"` | |||
Object *AnnotatedTagObject `json:"object"` | |||
Verification *PayloadCommitVerification `json:"verification"` | |||
} | |||
// AnnotatedTagObject contains meta information of the tag object | |||
type AnnotatedTagObject struct { | |||
Type string `json:"type"` | |||
URL string `json:"url"` | |||
SHA string `json:"sha"` | |||
} | |||
// ListRepoTagsOptions options for listing a repository's tags | |||
type ListRepoTagsOptions struct { | |||
ListOptions | |||
@@ -33,8 +54,69 @@ func (c *Client) ListRepoTags(user, repo string, opt ListRepoTagsOptions) ([]*Ta | |||
return tags, resp, err | |||
} | |||
// GetTag get the tag of a repository | |||
func (c *Client) GetTag(user, repo, tag string) (*Tag, *Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, nil, err | |||
} | |||
if err := escapeValidatePathSegments(&user, &repo, &tag); err != nil { | |||
return nil, nil, err | |||
} | |||
t := new(Tag) | |||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/tags/%s", user, repo, tag), nil, nil, &t) | |||
return t, resp, err | |||
} | |||
// GetAnnotatedTag get the tag object of an annotated tag (not lightweight tags) of a repository | |||
func (c *Client) GetAnnotatedTag(user, repo, sha string) (*AnnotatedTag, *Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, nil, err | |||
} | |||
if err := escapeValidatePathSegments(&user, &repo, &sha); err != nil { | |||
return nil, nil, err | |||
} | |||
t := new(AnnotatedTag) | |||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/git/tags/%s", user, repo, sha), nil, nil, &t) | |||
return t, resp, err | |||
} | |||
// CreateTagOption options when creating a tag | |||
type CreateTagOption struct { | |||
TagName string `json:"tag_name"` | |||
Message string `json:"message"` | |||
Target string `json:"target"` | |||
} | |||
// Validate validates CreateTagOption | |||
func (opt CreateTagOption) Validate() error { | |||
if len(opt.TagName) == 0 { | |||
return fmt.Errorf("TagName is required") | |||
} | |||
return nil | |||
} | |||
// CreateTag create a new git tag in a repository | |||
func (c *Client) CreateTag(user, repo string, opt CreateTagOption) (*Tag, *Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, nil, err | |||
} | |||
if err := escapeValidatePathSegments(&user, &repo); err != nil { | |||
return nil, nil, err | |||
} | |||
if err := opt.Validate(); err != nil { | |||
return nil, nil, err | |||
} | |||
body, err := json.Marshal(opt) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
t := new(Tag) | |||
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/tags", user, repo), jsonHeader, bytes.NewReader(body), &t) | |||
return t, resp, err | |||
} | |||
// DeleteTag deletes a tag from a repository, if no release refers to it | |||
func (c *Client) DeleteTag(user, repo string, tag string) (*Response, error) { | |||
func (c *Client) DeleteTag(user, repo, tag string) (*Response, error) { | |||
if err := escapeValidatePathSegments(&user, &repo, &tag); err != nil { | |||
return nil, err | |||
} |
@@ -0,0 +1,65 @@ | |||
// Copyright 2021 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" | |||
"net/http" | |||
) | |||
// GetRepoTeams return teams from a repository | |||
func (c *Client) GetRepoTeams(user, repo string) ([]*Team, *Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, nil, err | |||
} | |||
if err := escapeValidatePathSegments(&user, &repo); err != nil { | |||
return nil, nil, err | |||
} | |||
teams := make([]*Team, 0, 5) | |||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/teams", user, repo), nil, nil, &teams) | |||
return teams, resp, err | |||
} | |||
// AddRepoTeam add a team to a repository | |||
func (c *Client) AddRepoTeam(user, repo, team string) (*Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, err | |||
} | |||
if err := escapeValidatePathSegments(&user, &repo, &team); err != nil { | |||
return nil, err | |||
} | |||
_, resp, err := c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/teams/%s", user, repo, team), nil, nil) | |||
return resp, err | |||
} | |||
// RemoveRepoTeam delete a team from a repository | |||
func (c *Client) RemoveRepoTeam(user, repo, team string) (*Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, err | |||
} | |||
if err := escapeValidatePathSegments(&user, &repo, &team); err != nil { | |||
return nil, err | |||
} | |||
_, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/teams/%s", user, repo, team), nil, nil) | |||
return resp, err | |||
} | |||
// CheckRepoTeam check if team is assigned to repo by name and return it. | |||
// If not assigned, it will return nil. | |||
func (c *Client) CheckRepoTeam(user, repo, team string) (*Team, *Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, nil, err | |||
} | |||
if err := escapeValidatePathSegments(&user, &repo, &team); err != nil { | |||
return nil, nil, err | |||
} | |||
t := new(Team) | |||
resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/teams/%s", user, repo, team), nil, nil, &t) | |||
if resp != nil && resp.StatusCode == http.StatusNotFound { | |||
// if not found it's not an error, it indicates it's not assigned | |||
return nil, resp, nil | |||
} | |||
return t, resp, err | |||
} |
@@ -0,0 +1,65 @@ | |||
// Copyright 2021 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" | |||
) | |||
// CreateRepoFromTemplateOption options when creating repository using a template | |||
type CreateRepoFromTemplateOption struct { | |||
// Owner is the organization or person who will own the new repository | |||
Owner string `json:"owner"` | |||
// Name of the repository to create | |||
Name string `json:"name"` | |||
// Description of the repository to create | |||
Description string `json:"description"` | |||
// Private is whether the repository is private | |||
Private bool `json:"private"` | |||
// GitContent include git content of default branch in template repo | |||
GitContent bool `json:"git_content"` | |||
// Topics include topics of template repo | |||
Topics bool `json:"topics"` | |||
// GitHooks include git hooks of template repo | |||
GitHooks bool `json:"git_hooks"` | |||
// Webhooks include webhooks of template repo | |||
Webhooks bool `json:"webhooks"` | |||
// Avatar include avatar of the template repo | |||
Avatar bool `json:"avatar"` | |||
// Labels include labels of template repo | |||
Labels bool `json:"labels"` | |||
} | |||
// Validate validates CreateRepoFromTemplateOption | |||
func (opt CreateRepoFromTemplateOption) Validate() error { | |||
if len(opt.Owner) == 0 { | |||
return fmt.Errorf("field Owner is required") | |||
} | |||
if len(opt.Name) == 0 { | |||
return fmt.Errorf("field Name is required") | |||
} | |||
return nil | |||
} | |||
// CreateRepoFromTemplate create a repository using a template | |||
func (c *Client) CreateRepoFromTemplate(templateOwner, templateRepo string, opt CreateRepoFromTemplateOption) (*Repository, *Response, error) { | |||
if err := escapeValidatePathSegments(&templateOwner, &templateRepo); err != nil { | |||
return nil, nil, err | |||
} | |||
if err := opt.Validate(); err != nil { | |||
return nil, nil, err | |||
} | |||
body, err := json.Marshal(&opt) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
repo := new(Repository) | |||
resp, err := c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/generate", templateOwner, templateRepo), jsonHeader, bytes.NewReader(body), &repo) | |||
return repo, resp, err | |||
} |
@@ -8,13 +8,17 @@ package gitea | |||
type GlobalUISettings struct { | |||
DefaultTheme string `json:"default_theme"` | |||
AllowedReactions []string `json:"allowed_reactions"` | |||
CustomEmojis []string `json:"custom_emojis"` | |||
} | |||
// GlobalRepoSettings represent the global repository settings of a gitea instance witch is exposed by API | |||
type GlobalRepoSettings struct { | |||
MirrorsDisabled bool `json:"mirrors_disabled"` | |||
HTTPGitDisabled bool `json:"http_git_disabled"` | |||
MigrationsDisabled bool `json:"migrations_disabled"` | |||
MirrorsDisabled bool `json:"mirrors_disabled"` | |||
HTTPGitDisabled bool `json:"http_git_disabled"` | |||
MigrationsDisabled bool `json:"migrations_disabled"` | |||
StarsDisabled bool `json:"stars_disabled"` | |||
TimeTrackingDisabled bool `json:"time_tracking_disabled"` | |||
LFSDisabled bool `json:"lfs_disabled"` | |||
} | |||
// GlobalAPISettings contains global api settings exposed by it |
@@ -6,6 +6,8 @@ package gitea | |||
import ( | |||
"fmt" | |||
"net/url" | |||
"strconv" | |||
"time" | |||
) | |||
@@ -23,9 +25,30 @@ type User struct { | |||
// User locale | |||
Language string `json:"language"` | |||
// Is the user an administrator | |||
IsAdmin bool `json:"is_admin"` | |||
LastLogin time.Time `json:"last_login,omitempty"` | |||
Created time.Time `json:"created,omitempty"` | |||
IsAdmin bool `json:"is_admin"` | |||
// Date and Time of last login | |||
LastLogin time.Time `json:"last_login"` | |||
// Date and Time of user creation | |||
Created time.Time `json:"created"` | |||
// Is user restricted | |||
Restricted bool `json:"restricted"` | |||
// Is user active | |||
IsActive bool `json:"active"` | |||
// Is user login prohibited | |||
ProhibitLogin bool `json:"prohibit_login"` | |||
// the user's location | |||
Location string `json:"location"` | |||
// the user's website | |||
Website string `json:"website"` | |||
// the user's description | |||
Description string `json:"description"` | |||
// User visibility level option | |||
Visibility VisibleType `json:"visibility"` | |||
// user counts | |||
FollowerCount int `json:"followers_count"` | |||
FollowingCount int `json:"following_count"` | |||
StarredRepoCount int `json:"starred_repos_count"` | |||
} | |||
// GetUserInfo get user info by user's name | |||
@@ -44,3 +67,24 @@ func (c *Client) GetMyUserInfo() (*User, *Response, error) { | |||
resp, err := c.getParsedResponse("GET", "/user", nil, nil, u) | |||
return u, resp, err | |||
} | |||
// GetUserByID returns user by a given user ID | |||
func (c *Client) GetUserByID(id int64) (*User, *Response, error) { | |||
if id < 0 { | |||
return nil, nil, fmt.Errorf("invalid user id %d", id) | |||
} | |||
query := make(url.Values) | |||
query.Add("uid", strconv.FormatInt(id, 10)) | |||
users, resp, err := c.searchUsers(query.Encode()) | |||
if err != nil { | |||
return nil, resp, err | |||
} | |||
if len(users) == 1 { | |||
return users[0], resp, err | |||
} | |||
return nil, resp, fmt.Errorf("user not found with id %d", id) | |||
} |
@@ -77,7 +77,7 @@ func (c *Client) DeleteAccessToken(value interface{}) (*Response, error) { | |||
case reflect.Int64: | |||
token = fmt.Sprintf("%d", value.(int64)) | |||
case reflect.String: | |||
if err := c.CheckServerVersionConstraint(">= 1.13.0"); err != nil { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { | |||
return nil, err | |||
} | |||
token = value.(string) |
@@ -34,11 +34,15 @@ func (opt *SearchUsersOption) QueryEncode() string { | |||
return query.Encode() | |||
} | |||
// SearchUsers finds users by query | |||
func (c *Client) SearchUsers(opt SearchUsersOption) ([]*User, *Response, error) { | |||
func (c *Client) searchUsers(rawQuery string) ([]*User, *Response, error) { | |||
link, _ := url.Parse("/users/search") | |||
link.RawQuery = opt.QueryEncode() | |||
link.RawQuery = rawQuery | |||
userResp := new(searchUsersResponse) | |||
resp, err := c.getParsedResponse("GET", link.String(), nil, nil, &userResp) | |||
return userResp.Users, resp, err | |||
} | |||
// SearchUsers finds users by query | |||
func (c *Client) SearchUsers(opt SearchUsersOption) ([]*User, *Response, error) { | |||
return c.searchUsers(opt.QueryEncode()) | |||
} |
@@ -0,0 +1,62 @@ | |||
// Copyright 2021 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" | |||
) | |||
// UserSettings represents user settings | |||
type UserSettings struct { | |||
FullName string `json:"full_name"` | |||
Website string `json:"website"` | |||
Description string `json:"description"` | |||
Location string `json:"location"` | |||
Language string `json:"language"` | |||
Theme string `json:"theme"` | |||
DiffViewStyle string `json:"diff_view_style"` | |||
// Privacy | |||
HideEmail bool `json:"hide_email"` | |||
HideActivity bool `json:"hide_activity"` | |||
} | |||
// UserSettingsOptions represents options to change user settings | |||
type UserSettingsOptions struct { | |||
FullName *string `json:"full_name,omitempty"` | |||
Website *string `json:"website,omitempty"` | |||
Description *string `json:"description,omitempty"` | |||
Location *string `json:"location,omitempty"` | |||
Language *string `json:"language,omitempty"` | |||
Theme *string `json:"theme,omitempty"` | |||
DiffViewStyle *string `json:"diff_view_style,omitempty"` | |||
// Privacy | |||
HideEmail *bool `json:"hide_email,omitempty"` | |||
HideActivity *bool `json:"hide_activity,omitempty"` | |||
} | |||
// GetUserSettings returns user settings | |||
func (c *Client) GetUserSettings() (*UserSettings, *Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, nil, err | |||
} | |||
userConfig := new(UserSettings) | |||
resp, err := c.getParsedResponse("GET", "/user/settings", nil, nil, userConfig) | |||
return userConfig, resp, err | |||
} | |||
// UpdateUserSettings returns user settings | |||
func (c *Client) UpdateUserSettings(opt UserSettingsOptions) (*UserSettings, *Response, error) { | |||
if err := c.checkServerVersionGreaterThanOrEqual(version1_15_0); err != nil { | |||
return nil, nil, err | |||
} | |||
body, err := json.Marshal(&opt) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
userConfig := new(UserSettings) | |||
resp, err := c.getParsedResponse("PATCH", "/user/settings", jsonHeader, bytes.NewReader(body), userConfig) | |||
return userConfig, resp, err | |||
} |
@@ -39,16 +39,39 @@ func (c *Client) CheckServerVersionConstraint(constraint string) error { | |||
return nil | |||
} | |||
// SetGiteaVersion configures the Client to assume the given version of the | |||
// Gitea server, instead of querying the server for it when initializing. | |||
// Use "" to skip all canonical ways in the SDK to check for versions | |||
func SetGiteaVersion(v string) ClientOption { | |||
if v == "" { | |||
return func(c *Client) error { | |||
c.ignoreVersion = true | |||
return nil | |||
} | |||
} | |||
return func(c *Client) (err error) { | |||
c.getVersionOnce.Do(func() { | |||
c.serverVersion, err = version.NewVersion(v) | |||
return | |||
}) | |||
return | |||
} | |||
} | |||
// predefined versions only have to be parsed by library once | |||
var ( | |||
version1_11_0, _ = version.NewVersion("1.11.0") | |||
version1_12_0, _ = version.NewVersion("1.12.0") | |||
version1_13_0, _ = version.NewVersion("1.13.0") | |||
version1_14_0, _ = version.NewVersion("1.14.0") | |||
version1_15_0, _ = version.NewVersion("1.15.0") | |||
) | |||
// checkServerVersionGreaterThanOrEqual is internally used to speed up things and ignore issues with prerelease | |||
// checkServerVersionGreaterThanOrEqual is the canonical way in the SDK to check for versions for API compatibility reasons | |||
func (c *Client) checkServerVersionGreaterThanOrEqual(v *version.Version) error { | |||
if c.ignoreVersion { | |||
return nil | |||
} | |||
if err := c.loadServerVersion(); err != nil { | |||
return err | |||
} |
@@ -5,7 +5,7 @@ cloud.google.com/go/compute/metadata | |||
## explicit | |||
code.gitea.io/gitea-vet | |||
code.gitea.io/gitea-vet/checks | |||
# code.gitea.io/sdk/gitea v0.14.0 | |||
# code.gitea.io/sdk/gitea v0.15.1 | |||
## explicit | |||
code.gitea.io/sdk/gitea | |||
# gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be |