Add ignoreVersion & manuall version set option (#560)
be able to skip version check if needed. !!! Be careful, because using it incorrectly can result in infinite loops with pagination !!! Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/560 Reviewed-by: Andrew Thornton <art27@cantab.net> Reviewed-by: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
parent
a87a2c7390
commit
635de1b821
8 changed files with 92 additions and 41 deletions
|
@ -30,18 +30,20 @@ func Version() string {
|
||||||
|
|
||||||
// Client represents a thread-safe Gitea API client.
|
// Client represents a thread-safe Gitea API client.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
url string
|
url string
|
||||||
accessToken string
|
accessToken string
|
||||||
username string
|
username string
|
||||||
password string
|
password string
|
||||||
otp string
|
otp string
|
||||||
sudo string
|
sudo string
|
||||||
debug bool
|
debug bool
|
||||||
client *http.Client
|
client *http.Client
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
|
|
||||||
serverVersion *version.Version
|
serverVersion *version.Version
|
||||||
getVersionOnce sync.Once
|
getVersionOnce sync.Once
|
||||||
|
ignoreVersion bool // only set by SetGiteaVersion so don't need a mutex lock
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response represents the gitea response
|
// Response represents the gitea response
|
||||||
|
@ -49,16 +51,21 @@ type Response struct {
|
||||||
*http.Response
|
*http.Response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClientOption are functions used to init a new client
|
||||||
|
type ClientOption func(*Client) error
|
||||||
|
|
||||||
// NewClient initializes and returns a API client.
|
// NewClient initializes and returns a API client.
|
||||||
// Usage of all gitea.Client methods is concurrency-safe.
|
// 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{
|
client := &Client{
|
||||||
url: strings.TrimSuffix(url, "/"),
|
url: strings.TrimSuffix(url, "/"),
|
||||||
client: &http.Client{},
|
client: &http.Client{},
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
}
|
}
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
opt(client)
|
if err := opt(client); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := client.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil {
|
if err := client.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -74,9 +81,10 @@ func NewClientWithHTTP(url string, httpClient *http.Client) *Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHTTPClient is an option for NewClient to set custom http client
|
// SetHTTPClient is an option for NewClient to set custom http client
|
||||||
func SetHTTPClient(httpClient *http.Client) func(client *Client) {
|
func SetHTTPClient(httpClient *http.Client) ClientOption {
|
||||||
return func(client *Client) {
|
return func(client *Client) error {
|
||||||
client.SetHTTPClient(httpClient)
|
client.SetHTTPClient(httpClient)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,18 +96,20 @@ func (c *Client) SetHTTPClient(client *http.Client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetToken is an option for NewClient to set token
|
// SetToken is an option for NewClient to set token
|
||||||
func SetToken(token string) func(client *Client) {
|
func SetToken(token string) ClientOption {
|
||||||
return func(client *Client) {
|
return func(client *Client) error {
|
||||||
client.mutex.Lock()
|
client.mutex.Lock()
|
||||||
client.accessToken = token
|
client.accessToken = token
|
||||||
client.mutex.Unlock()
|
client.mutex.Unlock()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBasicAuth is an option for NewClient to set username and password
|
// SetBasicAuth is an option for NewClient to set username and password
|
||||||
func SetBasicAuth(username, password string) func(client *Client) {
|
func SetBasicAuth(username, password string) ClientOption {
|
||||||
return func(client *Client) {
|
return func(client *Client) error {
|
||||||
client.SetBasicAuth(username, password)
|
client.SetBasicAuth(username, password)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,9 +121,10 @@ func (c *Client) SetBasicAuth(username, password string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetOTP is an option for NewClient to set OTP for 2FA
|
// SetOTP is an option for NewClient to set OTP for 2FA
|
||||||
func SetOTP(otp string) func(client *Client) {
|
func SetOTP(otp string) ClientOption {
|
||||||
return func(client *Client) {
|
return func(client *Client) error {
|
||||||
client.SetOTP(otp)
|
client.SetOTP(otp)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,14 +135,15 @@ func (c *Client) SetOTP(otp string) {
|
||||||
c.mutex.Unlock()
|
c.mutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetContext is an option for NewClient to set context
|
// SetContext is an option for NewClient to set the default context
|
||||||
func SetContext(ctx context.Context) func(client *Client) {
|
func SetContext(ctx context.Context) ClientOption {
|
||||||
return func(client *Client) {
|
return func(client *Client) error {
|
||||||
client.SetContext(ctx)
|
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) {
|
func (c *Client) SetContext(ctx context.Context) {
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
c.ctx = ctx
|
c.ctx = ctx
|
||||||
|
@ -139,9 +151,10 @@ func (c *Client) SetContext(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSudo is an option for NewClient to set sudo header
|
// SetSudo is an option for NewClient to set sudo header
|
||||||
func SetSudo(sudo string) func(client *Client) {
|
func SetSudo(sudo string) ClientOption {
|
||||||
return func(client *Client) {
|
return func(client *Client) error {
|
||||||
client.SetSudo(sudo)
|
client.SetSudo(sudo)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,11 +166,12 @@ func (c *Client) SetSudo(sudo string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDebugMode is an option for NewClient to enable debug mode
|
// SetDebugMode is an option for NewClient to enable debug mode
|
||||||
func SetDebugMode() func(client *Client) {
|
func SetDebugMode() ClientOption {
|
||||||
return func(client *Client) {
|
return func(client *Client) error {
|
||||||
client.mutex.Lock()
|
client.mutex.Lock()
|
||||||
client.debug = true
|
client.debug = true
|
||||||
client.mutex.Unlock()
|
client.mutex.Unlock()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ func (c *Client) GetMilestone(owner, repo string, id int64) (*Milestone, *Respon
|
||||||
|
|
||||||
// GetMilestoneByName get one milestone by repo and milestone name
|
// GetMilestoneByName get one milestone by repo and milestone name
|
||||||
func (c *Client) GetMilestoneByName(owner, repo string, name string) (*Milestone, *Response, error) {
|
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
|
// backwards compatibility mode
|
||||||
m, resp, err := c.resolveMilestoneByName(owner, repo, name)
|
m, resp, err := c.resolveMilestoneByName(owner, repo, name)
|
||||||
return m, resp, err
|
return m, resp, err
|
||||||
|
@ -164,7 +164,7 @@ func (c *Client) EditMilestone(owner, repo string, id int64, opt EditMilestoneOp
|
||||||
|
|
||||||
// EditMilestoneByName modify milestone with options
|
// EditMilestoneByName modify milestone with options
|
||||||
func (c *Client) EditMilestoneByName(owner, repo string, name string, opt EditMilestoneOption) (*Milestone, *Response, error) {
|
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
|
// backwards compatibility mode
|
||||||
m, _, err := c.resolveMilestoneByName(owner, repo, name)
|
m, _, err := c.resolveMilestoneByName(owner, repo, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -198,7 +198,7 @@ func (c *Client) DeleteMilestone(owner, repo string, id int64) (*Response, error
|
||||||
|
|
||||||
// DeleteMilestoneByName delete one milestone by name
|
// DeleteMilestoneByName delete one milestone by name
|
||||||
func (c *Client) DeleteMilestoneByName(owner, repo string, name string) (*Response, error) {
|
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
|
// backwards compatibility mode
|
||||||
m, _, err := c.resolveMilestoneByName(owner, repo, name)
|
m, _, err := c.resolveMilestoneByName(owner, repo, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -40,14 +40,16 @@ func enableRunGitea() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestClient() *Client {
|
func newTestClient() *Client {
|
||||||
|
c, _ := NewClient(getGiteaURL(), newTestClientAuth())
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestClientAuth() ClientOption {
|
||||||
token := getGiteaToken()
|
token := getGiteaToken()
|
||||||
if token == "" {
|
if token == "" {
|
||||||
client := NewClientWithHTTP(getGiteaURL(), &http.Client{})
|
return SetBasicAuth(getGiteaUsername(), getGiteaPassword())
|
||||||
client.SetBasicAuth(getGiteaUsername(), getGiteaPassword())
|
|
||||||
return client
|
|
||||||
}
|
}
|
||||||
c, _ := NewClient(getGiteaURL(), SetToken(getGiteaToken()))
|
return SetToken(getGiteaToken())
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func giteaMasterPath() string {
|
func giteaMasterPath() string {
|
||||||
|
|
|
@ -12,6 +12,8 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PRBranchInfo information about a branch
|
// PRBranchInfo information about a branch
|
||||||
|
@ -217,10 +219,12 @@ type MergePullRequestOption struct {
|
||||||
ForceMerge bool `json:"force_merge"`
|
ForceMerge bool `json:"force_merge"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var version1_11_5, _ = version.NewVersion("1.11.5")
|
||||||
|
|
||||||
// Validate the MergePullRequestOption struct
|
// Validate the MergePullRequestOption struct
|
||||||
func (opt MergePullRequestOption) Validate(c *Client) error {
|
func (opt MergePullRequestOption) Validate(c *Client) error {
|
||||||
if opt.Style == MergeStyleSquash {
|
if opt.Style == MergeStyleSquash {
|
||||||
if err := c.CheckServerVersionConstraint(">=1.11.5"); err != nil {
|
if err := c.checkServerVersionGreaterThanOrEqual(version1_11_5); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -335,7 +335,7 @@ func (opt CreateRepoOption) Validate(c *Client) error {
|
||||||
return fmt.Errorf("name has more than 100 chars")
|
return fmt.Errorf("name has more than 100 chars")
|
||||||
}
|
}
|
||||||
if len(opt.TrustModel) != 0 {
|
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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ func (c *Client) DeleteAccessToken(value interface{}) (*Response, error) {
|
||||||
case reflect.Int64:
|
case reflect.Int64:
|
||||||
token = fmt.Sprintf("%d", value.(int64))
|
token = fmt.Sprintf("%d", value.(int64))
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if err := c.CheckServerVersionConstraint(">= 1.13.0"); err != nil {
|
if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
token = value.(string)
|
token = value.(string)
|
||||||
|
|
|
@ -39,6 +39,25 @@ func (c *Client) CheckServerVersionConstraint(constraint string) error {
|
||||||
return nil
|
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
|
// predefined versions only have to be parsed by library once
|
||||||
var (
|
var (
|
||||||
version1_11_0, _ = version.NewVersion("1.11.0")
|
version1_11_0, _ = version.NewVersion("1.11.0")
|
||||||
|
@ -48,8 +67,11 @@ var (
|
||||||
version1_15_0, _ = version.NewVersion("1.15.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 {
|
func (c *Client) checkServerVersionGreaterThanOrEqual(v *version.Version) error {
|
||||||
|
if c.ignoreVersion {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if err := c.loadServerVersion(); err != nil {
|
if err := c.loadServerVersion(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,15 @@ func TestVersion(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, true, rawVersion != "")
|
assert.True(t, true, rawVersion != "")
|
||||||
|
|
||||||
assert.NoError(t, c.CheckServerVersionConstraint(">= 1.11.0"))
|
assert.NoError(t, c.checkServerVersionGreaterThanOrEqual(version1_11_0))
|
||||||
assert.Error(t, c.CheckServerVersionConstraint("< 1.11.0"))
|
assert.Error(t, c.CheckServerVersionConstraint("< 1.11.0"))
|
||||||
|
|
||||||
|
c.serverVersion = version1_11_0
|
||||||
|
assert.Error(t, c.checkServerVersionGreaterThanOrEqual(version1_15_0))
|
||||||
|
c.ignoreVersion = true
|
||||||
|
assert.NoError(t, c.checkServerVersionGreaterThanOrEqual(version1_15_0))
|
||||||
|
|
||||||
|
c, err = NewClient(getGiteaURL(), newTestClientAuth(), SetGiteaVersion("1.12.123"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, c.CheckServerVersionConstraint("=1.12.123"))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue