Skip to content
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
24 changes: 24 additions & 0 deletions models/fixtures/protected_tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-
id: 1
repo_id: 4
name_pattern: /v.+/
allowlist_user_i_ds: []
allowlist_team_i_ds: []
created_unix: 1715596037
updated_unix: 1715596037
-
id: 2
repo_id: 1
name_pattern: v-*
allowlist_user_i_ds: []
allowlist_team_i_ds: []
created_unix: 1715596037
updated_unix: 1715596037
-
id: 3
repo_id: 1
name_pattern: v-1.1
allowlist_user_i_ds: [2]
allowlist_team_i_ds: []
created_unix: 1715596037
updated_unix: 1715596037
11 changes: 8 additions & 3 deletions routers/api/v1/repo/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ func CreateRelease(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "409":
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"

form := web.GetForm(ctx).(*api.CreateReleaseOption)
if ctx.Repo.Repository.IsEmpty {
ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty"))
Expand Down Expand Up @@ -246,6 +249,8 @@ func CreateRelease(ctx *context.APIContext) {
if err := release_service.CreateRelease(ctx.Repo.GitRepo, rel, nil, ""); err != nil {
if repo_model.IsErrReleaseAlreadyExist(err) {
ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err)
} else if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusUnprocessableEntity, "ProtectedTagName", err)
} else {
ctx.Error(http.StatusInternalServerError, "CreateRelease", err)
}
Expand Down Expand Up @@ -386,8 +391,8 @@ func DeleteRelease(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
// "405":
// "$ref": "#/responses/empty"
// "422":
// "$ref": "#/responses/validationError"

id := ctx.ParamsInt64(":id")
rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id)
Expand All @@ -401,7 +406,7 @@ func DeleteRelease(ctx *context.APIContext) {
}
if err := release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, false); err != nil {
if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag")
return
}
ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
Expand Down
6 changes: 3 additions & 3 deletions routers/api/v1/repo/release_tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ func DeleteReleaseByTag(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
// "405":
// "$ref": "#/responses/empty"
// "422":
// "$ref": "#/responses/validationError"

tag := ctx.Params(":tag")

Expand All @@ -114,7 +114,7 @@ func DeleteReleaseByTag(ctx *context.APIContext) {

if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil {
if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag")
return
}
ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
Expand Down
8 changes: 6 additions & 2 deletions routers/api/v1/repo/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ func CreateTag(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "409":
// "$ref": "#/responses/conflict"
// "422":
// "$ref": "#/responses/validationError"
// "423":
// "$ref": "#/responses/repoArchivedError"
form := web.GetForm(ctx).(*api.CreateTagOption)
Expand All @@ -205,7 +207,7 @@ func CreateTag(ctx *context.APIContext) {
return
}
if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusMethodNotAllowed, "CreateNewTag", "user not allowed to create protected tag")
ctx.Error(http.StatusUnprocessableEntity, "CreateNewTag", "user not allowed to create protected tag")
return
}

Expand Down Expand Up @@ -253,6 +255,8 @@ func DeleteTag(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "409":
// "$ref": "#/responses/conflict"
// "422":
// "$ref": "#/responses/validationError"
// "423":
// "$ref": "#/responses/repoArchivedError"
tagName := ctx.Params("*")
Expand All @@ -274,7 +278,7 @@ func DeleteTag(ctx *context.APIContext) {

if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil {
if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag")
return
}
ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
Expand Down
17 changes: 13 additions & 4 deletions templates/swagger/v1_json.tmpl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions tests/integration/api_releases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,31 @@ func TestAPICreateAndUpdateRelease(t *testing.T) {
assert.EqualValues(t, rel.Note, newRelease.Note)
}

func TestAPICreateProtectedTagRelease(t *testing.T) {
defer tests.PrepareTestEnv(t)()

repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
writer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
session := loginUser(t, writer.LowerName)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)

gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
assert.NoError(t, err)
defer gitRepo.Close()

commit, err := gitRepo.GetBranchCommit("master")
assert.NoError(t, err)

req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/releases", repo.OwnerName, repo.Name), &api.CreateReleaseOption{
TagName: "v0.0.1",
Title: "v0.0.1",
IsDraft: false,
IsPrerelease: false,
Target: commit.ID.String(),
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusUnprocessableEntity)
}

func TestAPICreateReleaseToDefaultBranch(t *testing.T) {
defer tests.PrepareTestEnv(t)()

Expand Down
21 changes: 4 additions & 17 deletions tests/integration/repo_tag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,10 @@ func TestCreateNewTagProtected(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})

t.Run("API", func(t *testing.T) {
t.Run("Code", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-1", "first tag")
assert.NoError(t, err)

err = git_model.InsertProtectedTag(db.DefaultContext, &git_model.ProtectedTag{
RepoID: repo.ID,
NamePattern: "v-*",
})
assert.NoError(t, err)
err = git_model.InsertProtectedTag(db.DefaultContext, &git_model.ProtectedTag{
RepoID: repo.ID,
NamePattern: "v-1.1",
AllowlistUserIDs: []int64{repo.OwnerID},
})
err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "t-first", "first tag")
assert.NoError(t, err)

err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-2", "second tag")
Expand All @@ -54,13 +42,12 @@ func TestCreateNewTagProtected(t *testing.T) {

t.Run("Git", func(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
username := "user2"
httpContext := NewAPITestContext(t, username, "repo1")
httpContext := NewAPITestContext(t, owner.Name, repo.Name)

dstPath := t.TempDir()

u.Path = httpContext.GitPath()
u.User = url.UserPassword(username, userPassword)
u.User = url.UserPassword(owner.Name, userPassword)

doGitClone(dstPath, u)(t)

Expand Down