diff --git a/Makefile b/Makefile index da40a68..3caf6e2 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ revive: test: @export GITEA_SDK_TEST_URL=${GITEA_SDK_TEST_URL}; export GITEA_SDK_TEST_USERNAME=${GITEA_SDK_TEST_USERNAME}; export GITEA_SDK_TEST_PASSWORD=${GITEA_SDK_TEST_PASSWORD}; \ if [ -z "$(shell curl --noproxy "*" "${GITEA_SDK_TEST_URL}/api/v1/version" 2> /dev/null)" ]; then \echo "No test-instance detected!"; exit 1; else \ - cd gitea && $(GO) test -cover -coverprofile coverage.out; \ + cd gitea && $(GO) test -race -cover -coverprofile coverage.out; \ fi .PHONY: test-instance diff --git a/gitea/client.go b/gitea/client.go index 3c72db5..f63fe03 100644 --- a/gitea/client.go +++ b/gitea/client.go @@ -13,6 +13,9 @@ import ( "io/ioutil" "net/http" "strings" + "sync" + + "github.com/hashicorp/go-version" ) var jsonHeader = http.Header{"content-type": []string{"application/json"}} @@ -24,12 +27,14 @@ func Version() string { // Client represents a Gitea API client. type Client struct { - url string - accessToken string - username string - password string - sudo string - client *http.Client + url string + accessToken string + username string + password string + sudo string + client *http.Client + serverVersion *version.Version + versionLock sync.RWMutex } // NewClient initializes and returns a API client. diff --git a/gitea/go.mod b/gitea/go.mod index 5a44ede..7b0d75f 100644 --- a/gitea/go.mod +++ b/gitea/go.mod @@ -2,4 +2,7 @@ module code.gitea.io/sdk/gitea go 1.12 -require github.com/stretchr/testify v1.4.0 +require ( + github.com/hashicorp/go-version v1.2.0 + github.com/stretchr/testify v1.4.0 +) diff --git a/gitea/go.sum b/gitea/go.sum index 8fdee58..e210c1c 100644 --- a/gitea/go.sum +++ b/gitea/go.sum @@ -1,5 +1,7 @@ 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/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= diff --git a/gitea/issue_reaction.go b/gitea/issue_reaction.go index b13b0e3..fb7d6d6 100644 --- a/gitea/issue_reaction.go +++ b/gitea/issue_reaction.go @@ -20,12 +20,18 @@ type Reaction struct { // GetIssueReactions get a list reactions of an issue func (c *Client) GetIssueReactions(owner, repo string, index int64) ([]*Reaction, error) { + if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + return nil, err + } reactions := make([]*Reaction, 0, 10) return reactions, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/reactions", owner, repo, index), nil, nil, &reactions) } // GetIssueCommentReactions get a list of reactions from a comment of an issue func (c *Client) GetIssueCommentReactions(owner, repo string, commentID int64) ([]*Reaction, error) { + if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + return nil, err + } reactions := make([]*Reaction, 0, 10) return reactions, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/comments/%d/reactions", owner, repo, commentID), nil, nil, &reactions) } @@ -37,6 +43,9 @@ type editReactionOption struct { // PostIssueReaction add a reaction to an issue func (c *Client) PostIssueReaction(owner, repo string, index int64, reaction string) (*Reaction, error) { + if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + return nil, err + } reactionResponse := new(Reaction) body, err := json.Marshal(&editReactionOption{Reaction: reaction}) if err != nil { @@ -48,6 +57,9 @@ func (c *Client) PostIssueReaction(owner, repo string, index int64, reaction str // DeleteIssueReaction remove a reaction from an issue func (c *Client) DeleteIssueReaction(owner, repo string, index int64, reaction string) error { + if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + return err + } body, err := json.Marshal(&editReactionOption{Reaction: reaction}) if err != nil { return err @@ -58,6 +70,9 @@ func (c *Client) DeleteIssueReaction(owner, repo string, index int64, reaction s // PostIssueCommentReaction add a reaction to a comment of an issue func (c *Client) PostIssueCommentReaction(owner, repo string, commentID int64, reaction string) (*Reaction, error) { + if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + return nil, err + } reactionResponse := new(Reaction) body, err := json.Marshal(&editReactionOption{Reaction: reaction}) if err != nil { @@ -69,6 +84,9 @@ func (c *Client) PostIssueCommentReaction(owner, repo string, commentID int64, r // DeleteIssueCommentReaction remove a reaction from a comment of an issue func (c *Client) DeleteIssueCommentReaction(owner, repo string, commentID int64, reaction string) error { + if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + return err + } // swagger:operation DELETE /repos/{owner}/{repo}/issues/comments/{id}/reactions issue issueDeleteCommentReaction body, err := json.Marshal(&editReactionOption{Reaction: reaction}) if err != nil { diff --git a/gitea/issue_subscription.go b/gitea/issue_subscription.go index 8eedefa..55597aa 100644 --- a/gitea/issue_subscription.go +++ b/gitea/issue_subscription.go @@ -10,18 +10,27 @@ import ( // GetIssueSubscribers get list of users who subscribed on an issue func (c *Client) GetIssueSubscribers(owner, repo string, index int64) ([]*User, error) { + if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + return nil, err + } subscribers := make([]*User, 0, 10) return subscribers, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions", owner, repo, index), nil, nil, &subscribers) } // AddIssueSubscription Subscribe user to issue func (c *Client) AddIssueSubscription(owner, repo string, index int64, user string) error { + if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + return err + } _, err := c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil) return err } // DeleteIssueSubscription unsubscribe user from issue func (c *Client) DeleteIssueSubscription(owner, repo string, index int64, user string) error { + if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + return err + } _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil) return err } diff --git a/gitea/miscellaneous.go b/gitea/miscellaneous.go deleted file mode 100644 index fe06ac1..0000000 --- a/gitea/miscellaneous.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015 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. - -package gitea - -// ServerVersion returns the version of the server -func (c *Client) ServerVersion() (string, error) { - var v = struct { - Version string `json:"version"` - }{} - return v.Version, c.getParsedResponse("GET", "/version", nil, nil, &v) -} diff --git a/gitea/version.go b/gitea/version.go new file mode 100644 index 0000000..b0f1c7b --- /dev/null +++ b/gitea/version.go @@ -0,0 +1,57 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "fmt" + + "github.com/hashicorp/go-version" +) + +// ServerVersion returns the version of the server +func (c *Client) ServerVersion() (string, error) { + var v = struct { + Version string `json:"version"` + }{} + return v.Version, c.getParsedResponse("GET", "/version", nil, nil, &v) +} + +// CheckServerVersionConstraint validates that the login's server satisfies a +// given version constraint such as ">= 1.11.0+dev" +func (c *Client) CheckServerVersionConstraint(constraint string) error { + c.versionLock.RLock() + if c.serverVersion == nil { + c.versionLock.RUnlock() + if err := c.loadClientServerVersion(); err != nil { + return err + } + } else { + c.versionLock.RUnlock() + } + + check, err := version.NewConstraint(constraint) + if err != nil { + return err + } + if !check.Check(c.serverVersion) { + return fmt.Errorf("gitea server at %s does not satisfy version constraint %s", c.url, constraint) + } + return nil +} + +// loadClientServerVersion init the serverVersion variable +func (c *Client) loadClientServerVersion() error { + c.versionLock.Lock() + defer c.versionLock.Unlock() + + raw, err := c.ServerVersion() + if err != nil { + return err + } + if c.serverVersion, err = version.NewVersion(raw); err != nil { + return err + } + return nil +} diff --git a/gitea/version_test.go b/gitea/version_test.go new file mode 100644 index 0000000..f22522f --- /dev/null +++ b/gitea/version_test.go @@ -0,0 +1,23 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestVersion(t *testing.T) { + log.Printf("== TestVersion ==") + c := newTestClient() + rawVersion, err := c.ServerVersion() + assert.NoError(t, err) + assert.True(t, true, rawVersion != "") + + assert.NoError(t, c.CheckServerVersionConstraint(">= 1.11.0")) + assert.Error(t, c.CheckServerVersionConstraint("< 1.11.0")) +}