Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API] Add repoCreateTag #16165

Merged
merged 8 commits into from
Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions integrations/api_repo_tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package integrations

import (
"fmt"
"net/http"
"testing"

Expand All @@ -15,23 +16,53 @@ 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
DecodeJSON(t, resp, &tags)

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
}
2 changes: 2 additions & 0 deletions modules/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package convert
import (
"fmt"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/models"
Expand Down Expand Up @@ -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"),
Expand Down
9 changes: 9 additions & 0 deletions modules/structs/repo_tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand All @@ -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"`
}
1 change: 1 addition & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
61 changes: 61 additions & 0 deletions routers/api/v1/repo/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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 {
6543 marked this conversation as resolved.
Show resolved Hide resolved
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))
}
3 changes: 3 additions & 0 deletions routers/api/v1/swagger/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,7 @@ type swaggerParameterBodies struct {

// in:body
PullReviewRequestOptions api.PullReviewRequestOptions

// in:body
CreateTagOption api.CreateTagOption
}
72 changes: 71 additions & 1 deletion templates/swagger/v1_json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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}": {
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -16149,6 +16215,10 @@
"type": "string",
"x-go-name": "ID"
},
"message": {
"type": "string",
"x-go-name": "Message"
},
"name": {
"type": "string",
"x-go-name": "Name"
Expand Down Expand Up @@ -17265,7 +17335,7 @@
"parameterBodies": {
"description": "parameterBodies",
"schema": {
"$ref": "#/definitions/PullReviewRequestOptions"
"$ref": "#/definitions/CreateTagOption"
6543 marked this conversation as resolved.
Show resolved Hide resolved
}
},
"redirect": {
Expand Down