From f5cc003900ff51c62b4db8d3f0275c2349717fe9 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 13 Aug 2021 20:27:52 +0800 Subject: [PATCH] Add GetTag, GetAnnotatedTag & CreateTag (#533) Add func to manage git tags via api close #528 Co-authored-by: Andrew Thornton Reviewed-on: https://gitea.com/gitea/go-sdk/pulls/533 Reviewed-by: Lunny Xiao Reviewed-by: Andrew Thornton Co-authored-by: 6543 <6543@obermui.de> Co-committed-by: 6543 <6543@obermui.de> --- gitea/repo_tag.go | 83 +++++++++++++++++++++++++++++++++++++++++- gitea/repo_tag_test.go | 42 +++++++++++++-------- 2 files changed, 109 insertions(+), 16 deletions(-) diff --git a/gitea/repo_tag.go b/gitea/repo_tag.go index 24792b5..7317d3f 100644 --- a/gitea/repo_tag.go +++ b/gitea/repo_tag.go @@ -5,6 +5,8 @@ package gitea import ( + "bytes" + "encoding/json" "fmt" ) @@ -18,6 +20,24 @@ type Tag struct { 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 @@ -34,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 } diff --git a/gitea/repo_tag_test.go b/gitea/repo_tag_test.go index c3b3e96..71454a4 100644 --- a/gitea/repo_tag_test.go +++ b/gitea/repo_tag_test.go @@ -5,6 +5,7 @@ package gitea import ( + "fmt" "log" "testing" @@ -18,30 +19,41 @@ func TestTags(t *testing.T) { repo, _ := createTestRepo(t, "TestTags", c) // Create Tags - createTestTag(t, c, repo, "tag1") + cTagMSG := "A tag message.\n\n:)" + cTag, resp, err := c.CreateTag(repo.Owner.UserName, repo.Name, CreateTagOption{ + TagName: "tag1", + Message: cTagMSG, + Target: "master", + }) + assert.NoError(t, err) + assert.EqualValues(t, 201, resp.StatusCode) + assert.EqualValues(t, cTagMSG, cTag.Message) + assert.EqualValues(t, fmt.Sprintf("%s/test01/TestTags/archive/tag1.zip", c.url), cTag.ZipballURL) tags, _, err := c.ListRepoTags(repo.Owner.UserName, repo.Name, ListRepoTagsOptions{}) assert.NoError(t, err) assert.Len(t, tags, 1) + assert.EqualValues(t, cTag, tags[0]) + + // get tag + gTag, _, err := c.GetTag(repo.Owner.UserName, repo.Name, cTag.Name) + assert.NoError(t, err) + assert.EqualValues(t, cTag, gTag) + + aTag, _, err := c.GetAnnotatedTag(repo.Owner.UserName, repo.Name, cTag.ID) + assert.NoError(t, err) + assert.EqualValues(t, cTag.Name, aTag.Tag) + assert.EqualValues(t, cTag.ID, aTag.SHA) + assert.EqualValues(t, fmt.Sprintf("%s/api/v1/repos/test01/TestTags/git/tags/%s", c.url, cTag.ID), aTag.URL) + assert.EqualValues(t, cTag.Message+"\n", aTag.Message) + assert.EqualValues(t, false, aTag.Verification.Verified) + assert.EqualValues(t, "commit", aTag.Object.Type) // DeleteReleaseTag - resp, err := c.DeleteTag(repo.Owner.UserName, repo.Name, "tag1") + resp, err = c.DeleteTag(repo.Owner.UserName, repo.Name, "tag1") assert.NoError(t, err) assert.EqualValues(t, 204, resp.StatusCode) tags, _, err = c.ListRepoTags(repo.Owner.UserName, repo.Name, ListRepoTagsOptions{}) assert.NoError(t, err) assert.Len(t, tags, 0) } - -// createTestTag use create release api since there exist no api to create tag only -// https://github.com/go-gitea/gitea/issues/14669 -func createTestTag(t *testing.T, c *Client, repo *Repository, name string) { - rel, _, err := c.CreateRelease(repo.Owner.UserName, repo.Name, CreateReleaseOption{ - TagName: name, - Target: "master", - Title: "TMP Release", - }) - assert.NoError(t, err) - _, err = c.DeleteRelease(repo.Owner.UserName, repo.Name, rel.ID) - assert.NoError(t, err) -}