mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 09:44:21 +00:00 
			
		
		
		
	[API] Add repoCreateTag (#16165)
* Add API CreateTag * Add Test * API: expose Tag Message
This commit is contained in:
		@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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"),
 | 
			
		||||
 
 | 
			
		||||
@@ -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"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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() {
 | 
			
		||||
 
 | 
			
		||||
@@ -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))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -158,4 +158,7 @@ type swaggerParameterBodies struct {
 | 
			
		||||
 | 
			
		||||
	// in:body
 | 
			
		||||
	PullReviewRequestOptions api.PullReviewRequestOptions
 | 
			
		||||
 | 
			
		||||
	// in:body
 | 
			
		||||
	CreateTagOption api.CreateTagOption
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9082,6 +9082,50 @@
 | 
			
		||||
            "$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}": {
 | 
			
		||||
@@ -13092,6 +13136,28 @@
 | 
			
		||||
      },
 | 
			
		||||
      "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",
 | 
			
		||||
@@ -16149,6 +16215,10 @@
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "x-go-name": "ID"
 | 
			
		||||
        },
 | 
			
		||||
        "message": {
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "x-go-name": "Message"
 | 
			
		||||
        },
 | 
			
		||||
        "name": {
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "x-go-name": "Name"
 | 
			
		||||
@@ -17265,7 +17335,7 @@
 | 
			
		||||
    "parameterBodies": {
 | 
			
		||||
      "description": "parameterBodies",
 | 
			
		||||
      "schema": {
 | 
			
		||||
        "$ref": "#/definitions/PullReviewRequestOptions"
 | 
			
		||||
        "$ref": "#/definitions/CreateTagOption"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "redirect": {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user