]> source.dussan.org Git - gitea.git/commitdiff
[API] Add repoCreateTag (#16165)
author6543 <6543@obermui.de>
Thu, 17 Jun 2021 16:04:10 +0000 (18:04 +0200)
committerGitHub <noreply@github.com>
Thu, 17 Jun 2021 16:04:10 +0000 (18:04 +0200)
* Add API CreateTag

* Add Test

* API: expose Tag Message

integrations/api_repo_tags_test.go
modules/convert/convert.go
modules/structs/repo_tag.go
routers/api/v1/api.go
routers/api/v1/repo/tag.go
routers/api/v1/swagger/options.go
templates/swagger/v1_json.tmpl

index 1ffec576d8a01d86ca1b0b61530b08087344f96c..1bd9fa616819e8a8983bdc9078f1e3e5d60e6fa7 100644 (file)
@@ -5,6 +5,7 @@
 package integrations
 
 import (
+       "fmt"
        "net/http"
        "testing"
 
@@ -15,14 +16,16 @@ import (
        "github.com/stretchr/testify/assert"
 )
 
-func TestAPIReposGetTags(t *testing.T) {
+func TestAPIRepoTags(t *testing.T) {
        defer prepareTestEnv(t)()
        user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
        // Login as User2.
        session := loginUser(t, user.Name)
        token := getTokenForLoggedInUser(t, session)
 
-       req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/tags?token="+token, user.Name)
+       repoName := "repo1"
+
+       req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/tags?token=%s", user.Name, repoName, token)
        resp := session.MakeRequest(t, req, http.StatusOK)
 
        var tags []*api.Tag
@@ -30,8 +33,36 @@ func TestAPIReposGetTags(t *testing.T) {
 
        assert.Len(t, tags, 1)
        assert.Equal(t, "v1.1", tags[0].Name)
+       assert.Equal(t, "Initial commit", tags[0].Message)
        assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.SHA)
        assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.URL)
        assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.zip", tags[0].ZipballURL)
        assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL)
+
+       newTag := createNewTagUsingAPI(t, session, token, user.Name, repoName, "awesome-tag", "", "nice!\nand some text")
+       resp = session.MakeRequest(t, req, http.StatusOK)
+       DecodeJSON(t, resp, &tags)
+       assert.Len(t, tags, 2)
+       for _, tag := range tags {
+               if tag.Name != "v1.1" {
+                       assert.EqualValues(t, newTag.Name, tag.Name)
+                       assert.EqualValues(t, newTag.Message, tag.Message)
+                       assert.EqualValues(t, "nice!\nand some text", tag.Message)
+                       assert.EqualValues(t, newTag.Commit.SHA, tag.Commit.SHA)
+               }
+       }
+}
+
+func createNewTagUsingAPI(t *testing.T, session *TestSession, token string, ownerName, repoName, name, target, msg string) *api.Tag {
+       urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/tags?token=%s", ownerName, repoName, token)
+       req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateTagOption{
+               TagName: name,
+               Message: msg,
+               Target:  target,
+       })
+       resp := session.MakeRequest(t, req, http.StatusCreated)
+
+       var respObj api.Tag
+       DecodeJSON(t, resp, &respObj)
+       return &respObj
 }
index 109931dbc343338a50a2060af44d379dbff72a6e..0b2135c5803dcfba15bca5f0b1e5ec166060f625 100644 (file)
@@ -8,6 +8,7 @@ package convert
 import (
        "fmt"
        "strconv"
+       "strings"
        "time"
 
        "code.gitea.io/gitea/models"
@@ -135,6 +136,7 @@ func ToBranchProtection(bp *models.ProtectedBranch) *api.BranchProtection {
 func ToTag(repo *models.Repository, t *git.Tag) *api.Tag {
        return &api.Tag{
                Name:       t.Name,
+               Message:    strings.TrimSpace(t.Message),
                ID:         t.ID.String(),
                Commit:     ToCommitMeta(repo, t),
                ZipballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".zip"),
index b62395cac498335cdad7c2abe5ebbf7ed76e9b9c..80ee1ccf177439099209b1fbe2ceb11652315859 100644 (file)
@@ -7,6 +7,7 @@ package structs
 // 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"`
@@ -30,3 +31,11 @@ type AnnotatedTagObject struct {
        URL  string `json:"url"`
        SHA  string `json:"sha"`
 }
+
+// CreateTagOption options when creating a tag
+type CreateTagOption struct {
+       // required: true
+       TagName string `json:"tag_name" binding:"Required"`
+       Message string `json:"message"`
+       Target  string `json:"target"`
+}
index 0b47953e5841d58a536c9b114c5492bc1bfd86e1..34cf80e0721c342459c93db18c49a87c3fc2938f 100644 (file)
@@ -775,6 +775,7 @@ func Routes() *web.Route {
                                }, reqToken(), reqAdmin())
                                m.Group("/tags", func() {
                                        m.Get("", repo.ListTags)
+                                       m.Post("", reqRepoWriter(models.UnitTypeCode), bind(api.CreateTagOption{}), repo.CreateTag)
                                        m.Delete("/{tag}", repo.DeleteTag)
                                }, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo(true))
                                m.Group("/keys", func() {
index ec9b541bd41d35095ea367af86499e112bf428a0..51ba43ea89ba628a6d1642c45196bd1be51adcfc 100644 (file)
@@ -6,12 +6,14 @@ package repo
 
 import (
        "errors"
+       "fmt"
        "net/http"
 
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/modules/context"
        "code.gitea.io/gitea/modules/convert"
        api "code.gitea.io/gitea/modules/structs"
+       "code.gitea.io/gitea/modules/web"
        "code.gitea.io/gitea/routers/api/v1/utils"
        releaseservice "code.gitea.io/gitea/services/release"
 )
@@ -160,3 +162,62 @@ func DeleteTag(ctx *context.APIContext) {
 
        ctx.Status(http.StatusNoContent)
 }
+
+// CreateTag create a new git tag in a repository
+func CreateTag(ctx *context.APIContext) {
+       // swagger:operation POST /repos/{owner}/{repo}/tags repository repoCreateTag
+       // ---
+       // summary: Create a new git tag in a repository
+       // produces:
+       // - application/json
+       // parameters:
+       // - name: owner
+       //   in: path
+       //   description: owner of the repo
+       //   type: string
+       //   required: true
+       // - name: repo
+       //   in: path
+       //   description: name of the repo
+       //   type: string
+       //   required: true
+       // - name: body
+       //   in: body
+       //   schema:
+       //     "$ref": "#/definitions/CreateTagOption"
+       // responses:
+       //   "200":
+       //     "$ref": "#/responses/AnnotatedTag"
+       //   "404":
+       //     "$ref": "#/responses/notFound"
+       //   "409":
+       //     "$ref": "#/responses/conflict"
+       form := web.GetForm(ctx).(*api.CreateTagOption)
+
+       // If target is not provided use default branch
+       if len(form.Target) == 0 {
+               form.Target = ctx.Repo.Repository.DefaultBranch
+       }
+
+       commit, err := ctx.Repo.GitRepo.GetCommit(form.Target)
+       if err != nil {
+               ctx.Error(http.StatusNotFound, "target not found", fmt.Errorf("target not found: %v", err))
+               return
+       }
+
+       if err := releaseservice.CreateNewTag(ctx.User, ctx.Repo.Repository, commit.ID.String(), form.TagName, form.Message); err != nil {
+               if models.IsErrTagAlreadyExists(err) {
+                       ctx.Error(http.StatusConflict, "tag exist", err)
+                       return
+               }
+               ctx.InternalServerError(err)
+               return
+       }
+
+       tag, err := ctx.Repo.GitRepo.GetTag(form.TagName)
+       if err != nil {
+               ctx.InternalServerError(err)
+               return
+       }
+       ctx.JSON(http.StatusCreated, convert.ToTag(ctx.Repo.Repository, tag))
+}
index dad025710dbadd7c05ccc1d5d73026e9c9f3a8c3..11158fb86d0e89e5bf1c7ff964fac7a5b5513fa0 100644 (file)
@@ -158,4 +158,7 @@ type swaggerParameterBodies struct {
 
        // in:body
        PullReviewRequestOptions api.PullReviewRequestOptions
+
+       // in:body
+       CreateTagOption api.CreateTagOption
 }
index 9b0d07ebfcde5f9b10b5ba710ca138695b6e3b8b..017dc824d7d62b2011be477c0db3270373f0432f 100644 (file)
             "$ref": "#/responses/TagList"
           }
         }
+      },
+      "post": {
+        "produces": [
+          "application/json"
+        ],
+        "tags": [
+          "repository"
+        ],
+        "summary": "Create a new git tag in a repository",
+        "operationId": "repoCreateTag",
+        "parameters": [
+          {
+            "type": "string",
+            "description": "owner of the repo",
+            "name": "owner",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "string",
+            "description": "name of the repo",
+            "name": "repo",
+            "in": "path",
+            "required": true
+          },
+          {
+            "name": "body",
+            "in": "body",
+            "schema": {
+              "$ref": "#/definitions/CreateTagOption"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "$ref": "#/responses/AnnotatedTag"
+          },
+          "404": {
+            "$ref": "#/responses/notFound"
+          },
+          "409": {
+            "$ref": "#/responses/conflict"
+          }
+        }
       }
     },
     "/repos/{owner}/{repo}/tags/{tag}": {
       },
       "x-go-package": "code.gitea.io/gitea/modules/structs"
     },
+    "CreateTagOption": {
+      "description": "CreateTagOption options when creating a tag",
+      "type": "object",
+      "required": [
+        "tag_name"
+      ],
+      "properties": {
+        "message": {
+          "type": "string",
+          "x-go-name": "Message"
+        },
+        "tag_name": {
+          "type": "string",
+          "x-go-name": "TagName"
+        },
+        "target": {
+          "type": "string",
+          "x-go-name": "Target"
+        }
+      },
+      "x-go-package": "code.gitea.io/gitea/modules/structs"
+    },
     "CreateTeamOption": {
       "description": "CreateTeamOption options for creating a team",
       "type": "object",
           "type": "string",
           "x-go-name": "ID"
         },
+        "message": {
+          "type": "string",
+          "x-go-name": "Message"
+        },
         "name": {
           "type": "string",
           "x-go-name": "Name"
     "parameterBodies": {
       "description": "parameterBodies",
       "schema": {
-        "$ref": "#/definitions/PullReviewRequestOptions"
+        "$ref": "#/definitions/CreateTagOption"
       }
     },
     "redirect": {