code.gitea.io/gitea@v1.21.7/routers/api/v1/repo/tag.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package repo
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"net/http"
    10  
    11  	"code.gitea.io/gitea/models"
    12  	repo_model "code.gitea.io/gitea/models/repo"
    13  	"code.gitea.io/gitea/modules/context"
    14  	api "code.gitea.io/gitea/modules/structs"
    15  	"code.gitea.io/gitea/modules/web"
    16  	"code.gitea.io/gitea/routers/api/v1/utils"
    17  	"code.gitea.io/gitea/services/convert"
    18  	releaseservice "code.gitea.io/gitea/services/release"
    19  )
    20  
    21  // ListTags list all the tags of a repository
    22  func ListTags(ctx *context.APIContext) {
    23  	// swagger:operation GET /repos/{owner}/{repo}/tags repository repoListTags
    24  	// ---
    25  	// summary: List a repository's tags
    26  	// produces:
    27  	// - application/json
    28  	// parameters:
    29  	// - name: owner
    30  	//   in: path
    31  	//   description: owner of the repo
    32  	//   type: string
    33  	//   required: true
    34  	// - name: repo
    35  	//   in: path
    36  	//   description: name of the repo
    37  	//   type: string
    38  	//   required: true
    39  	// - name: page
    40  	//   in: query
    41  	//   description: page number of results to return (1-based)
    42  	//   type: integer
    43  	// - name: limit
    44  	//   in: query
    45  	//   description: page size of results, default maximum page size is 50
    46  	//   type: integer
    47  	// responses:
    48  	//   "200":
    49  	//     "$ref": "#/responses/TagList"
    50  	//   "404":
    51  	//     "$ref": "#/responses/notFound"
    52  
    53  	listOpts := utils.GetListOptions(ctx)
    54  
    55  	tags, total, err := ctx.Repo.GitRepo.GetTagInfos(listOpts.Page, listOpts.PageSize)
    56  	if err != nil {
    57  		ctx.Error(http.StatusInternalServerError, "GetTags", err)
    58  		return
    59  	}
    60  
    61  	apiTags := make([]*api.Tag, len(tags))
    62  	for i := range tags {
    63  		apiTags[i] = convert.ToTag(ctx.Repo.Repository, tags[i])
    64  	}
    65  
    66  	ctx.SetTotalCountHeader(int64(total))
    67  	ctx.JSON(http.StatusOK, &apiTags)
    68  }
    69  
    70  // GetAnnotatedTag get the tag of a repository.
    71  func GetAnnotatedTag(ctx *context.APIContext) {
    72  	// swagger:operation GET /repos/{owner}/{repo}/git/tags/{sha} repository GetAnnotatedTag
    73  	// ---
    74  	// summary: Gets the tag object of an annotated tag (not lightweight tags)
    75  	// produces:
    76  	// - application/json
    77  	// parameters:
    78  	// - name: owner
    79  	//   in: path
    80  	//   description: owner of the repo
    81  	//   type: string
    82  	//   required: true
    83  	// - name: repo
    84  	//   in: path
    85  	//   description: name of the repo
    86  	//   type: string
    87  	//   required: true
    88  	// - name: sha
    89  	//   in: path
    90  	//   description: sha of the tag. The Git tags API only supports annotated tag objects, not lightweight tags.
    91  	//   type: string
    92  	//   required: true
    93  	// responses:
    94  	//   "200":
    95  	//     "$ref": "#/responses/AnnotatedTag"
    96  	//   "400":
    97  	//     "$ref": "#/responses/error"
    98  	//   "404":
    99  	//     "$ref": "#/responses/notFound"
   100  
   101  	sha := ctx.Params("sha")
   102  	if len(sha) == 0 {
   103  		ctx.Error(http.StatusBadRequest, "", "SHA not provided")
   104  		return
   105  	}
   106  
   107  	if tag, err := ctx.Repo.GitRepo.GetAnnotatedTag(sha); err != nil {
   108  		ctx.Error(http.StatusBadRequest, "GetAnnotatedTag", err)
   109  	} else {
   110  		commit, err := tag.Commit(ctx.Repo.GitRepo)
   111  		if err != nil {
   112  			ctx.Error(http.StatusBadRequest, "GetAnnotatedTag", err)
   113  		}
   114  		ctx.JSON(http.StatusOK, convert.ToAnnotatedTag(ctx, ctx.Repo.Repository, tag, commit))
   115  	}
   116  }
   117  
   118  // GetTag get the tag of a repository
   119  func GetTag(ctx *context.APIContext) {
   120  	// swagger:operation GET /repos/{owner}/{repo}/tags/{tag} repository repoGetTag
   121  	// ---
   122  	// summary: Get the tag of a repository by tag name
   123  	// produces:
   124  	// - application/json
   125  	// parameters:
   126  	// - name: owner
   127  	//   in: path
   128  	//   description: owner of the repo
   129  	//   type: string
   130  	//   required: true
   131  	// - name: repo
   132  	//   in: path
   133  	//   description: name of the repo
   134  	//   type: string
   135  	//   required: true
   136  	// - name: tag
   137  	//   in: path
   138  	//   description: name of tag
   139  	//   type: string
   140  	//   required: true
   141  	// responses:
   142  	//   "200":
   143  	//     "$ref": "#/responses/Tag"
   144  	//   "404":
   145  	//     "$ref": "#/responses/notFound"
   146  	tagName := ctx.Params("*")
   147  
   148  	tag, err := ctx.Repo.GitRepo.GetTag(tagName)
   149  	if err != nil {
   150  		ctx.NotFound(tagName)
   151  		return
   152  	}
   153  	ctx.JSON(http.StatusOK, convert.ToTag(ctx.Repo.Repository, tag))
   154  }
   155  
   156  // CreateTag create a new git tag in a repository
   157  func CreateTag(ctx *context.APIContext) {
   158  	// swagger:operation POST /repos/{owner}/{repo}/tags repository repoCreateTag
   159  	// ---
   160  	// summary: Create a new git tag in a repository
   161  	// produces:
   162  	// - application/json
   163  	// parameters:
   164  	// - name: owner
   165  	//   in: path
   166  	//   description: owner of the repo
   167  	//   type: string
   168  	//   required: true
   169  	// - name: repo
   170  	//   in: path
   171  	//   description: name of the repo
   172  	//   type: string
   173  	//   required: true
   174  	// - name: body
   175  	//   in: body
   176  	//   schema:
   177  	//     "$ref": "#/definitions/CreateTagOption"
   178  	// responses:
   179  	//   "200":
   180  	//     "$ref": "#/responses/Tag"
   181  	//   "404":
   182  	//     "$ref": "#/responses/notFound"
   183  	//   "405":
   184  	//     "$ref": "#/responses/empty"
   185  	//   "409":
   186  	//     "$ref": "#/responses/conflict"
   187  	form := web.GetForm(ctx).(*api.CreateTagOption)
   188  
   189  	// If target is not provided use default branch
   190  	if len(form.Target) == 0 {
   191  		form.Target = ctx.Repo.Repository.DefaultBranch
   192  	}
   193  
   194  	commit, err := ctx.Repo.GitRepo.GetCommit(form.Target)
   195  	if err != nil {
   196  		ctx.Error(http.StatusNotFound, "target not found", fmt.Errorf("target not found: %w", err))
   197  		return
   198  	}
   199  
   200  	if err := releaseservice.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, commit.ID.String(), form.TagName, form.Message); err != nil {
   201  		if models.IsErrTagAlreadyExists(err) {
   202  			ctx.Error(http.StatusConflict, "tag exist", err)
   203  			return
   204  		}
   205  		if models.IsErrProtectedTagName(err) {
   206  			ctx.Error(http.StatusMethodNotAllowed, "CreateNewTag", "user not allowed to create protected tag")
   207  			return
   208  		}
   209  
   210  		ctx.InternalServerError(err)
   211  		return
   212  	}
   213  
   214  	tag, err := ctx.Repo.GitRepo.GetTag(form.TagName)
   215  	if err != nil {
   216  		ctx.InternalServerError(err)
   217  		return
   218  	}
   219  	ctx.JSON(http.StatusCreated, convert.ToTag(ctx.Repo.Repository, tag))
   220  }
   221  
   222  // DeleteTag delete a specific tag of in a repository by name
   223  func DeleteTag(ctx *context.APIContext) {
   224  	// swagger:operation DELETE /repos/{owner}/{repo}/tags/{tag} repository repoDeleteTag
   225  	// ---
   226  	// summary: Delete a repository's tag by name
   227  	// produces:
   228  	// - application/json
   229  	// parameters:
   230  	// - name: owner
   231  	//   in: path
   232  	//   description: owner of the repo
   233  	//   type: string
   234  	//   required: true
   235  	// - name: repo
   236  	//   in: path
   237  	//   description: name of the repo
   238  	//   type: string
   239  	//   required: true
   240  	// - name: tag
   241  	//   in: path
   242  	//   description: name of tag to delete
   243  	//   type: string
   244  	//   required: true
   245  	// responses:
   246  	//   "204":
   247  	//     "$ref": "#/responses/empty"
   248  	//   "404":
   249  	//     "$ref": "#/responses/notFound"
   250  	//   "405":
   251  	//     "$ref": "#/responses/empty"
   252  	//   "409":
   253  	//     "$ref": "#/responses/conflict"
   254  	tagName := ctx.Params("*")
   255  
   256  	tag, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName)
   257  	if err != nil {
   258  		if repo_model.IsErrReleaseNotExist(err) {
   259  			ctx.NotFound()
   260  			return
   261  		}
   262  		ctx.Error(http.StatusInternalServerError, "GetRelease", err)
   263  		return
   264  	}
   265  
   266  	if !tag.IsTag {
   267  		ctx.Error(http.StatusConflict, "IsTag", errors.New("a tag attached to a release cannot be deleted directly"))
   268  		return
   269  	}
   270  
   271  	if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil {
   272  		if models.IsErrProtectedTagName(err) {
   273  			ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
   274  			return
   275  		}
   276  		ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
   277  		return
   278  	}
   279  
   280  	ctx.Status(http.StatusNoContent)
   281  }