mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Add tag protection (#15629)
* Added tag protection in hook. * Prevent UI tag creation if protected. * Added settings page. * Added tests. * Added suggestions. * Moved tests. * Use individual errors. * Removed unneeded methods. * Switched delete selector. * Changed method names. * No reason to be unique. * Allow editing of protected tags. * Removed unique key from migration. * Added docs page. * Changed date. * Respond with 404 to not found tags. * Replaced glob with regex pattern. * Added support for glob and regex pattern. * Updated documentation. * Changed white* to allow*. * Fixed edit button link. * Added cancel button. Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
27
services/forms/repo_tag_form.go
Normal file
27
services/forms/repo_tag_form.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package forms
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
|
||||
"gitea.com/go-chi/binding"
|
||||
)
|
||||
|
||||
// ProtectTagForm form for changing protected tag settings
|
||||
type ProtectTagForm struct {
|
||||
NamePattern string `binding:"Required;GlobOrRegexPattern"`
|
||||
AllowlistUsers string
|
||||
AllowlistTeams string
|
||||
}
|
||||
|
||||
// Validate validates the fields
|
||||
func (f *ProtectTagForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||
ctx := context.GetContext(req)
|
||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
@@ -23,6 +23,25 @@ func createTag(gitRepo *git.Repository, rel *models.Release, msg string) (bool,
|
||||
// Only actual create when publish.
|
||||
if !rel.IsDraft {
|
||||
if !gitRepo.IsTagExist(rel.TagName) {
|
||||
if err := rel.LoadAttributes(); err != nil {
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
protectedTags, err := rel.Repo.GetProtectedTags()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("GetProtectedTags: %v", err)
|
||||
}
|
||||
isAllowed, err := models.IsUserAllowedToControlTag(protectedTags, rel.TagName, rel.PublisherID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !isAllowed {
|
||||
return false, models.ErrProtectedTagName{
|
||||
TagName: rel.TagName,
|
||||
}
|
||||
}
|
||||
|
||||
commit, err := gitRepo.GetCommit(rel.Target)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("GetCommit: %v", err)
|
||||
@@ -49,11 +68,7 @@ func createTag(gitRepo *git.Repository, rel *models.Release, msg string) (bool,
|
||||
}
|
||||
created = true
|
||||
rel.LowerTagName = strings.ToLower(rel.TagName)
|
||||
// Prepare Notify
|
||||
if err := rel.LoadAttributes(); err != nil {
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
notification.NotifyPushCommits(
|
||||
rel.Publisher, rel.Repo,
|
||||
&repository.PushUpdateOptions{
|
||||
@@ -137,7 +152,9 @@ func CreateNewTag(doer *models.User, repo *models.Repository, commit, tagName, m
|
||||
|
||||
rel := &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: doer.ID,
|
||||
Publisher: doer,
|
||||
TagName: tagName,
|
||||
Target: commit,
|
||||
IsDraft: false,
|
||||
|
@@ -33,7 +33,9 @@ func TestRelease_Create(t *testing.T) {
|
||||
|
||||
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v0.1",
|
||||
Target: "master",
|
||||
Title: "v0.1 is released",
|
||||
@@ -45,7 +47,9 @@ func TestRelease_Create(t *testing.T) {
|
||||
|
||||
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v0.1.1",
|
||||
Target: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
|
||||
Title: "v0.1.1 is released",
|
||||
@@ -57,7 +61,9 @@ func TestRelease_Create(t *testing.T) {
|
||||
|
||||
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v0.1.2",
|
||||
Target: "65f1bf2",
|
||||
Title: "v0.1.2 is released",
|
||||
@@ -69,7 +75,9 @@ func TestRelease_Create(t *testing.T) {
|
||||
|
||||
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v0.1.3",
|
||||
Target: "65f1bf2",
|
||||
Title: "v0.1.3 is released",
|
||||
@@ -81,7 +89,9 @@ func TestRelease_Create(t *testing.T) {
|
||||
|
||||
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v0.1.4",
|
||||
Target: "65f1bf2",
|
||||
Title: "v0.1.4 is released",
|
||||
@@ -99,7 +109,9 @@ func TestRelease_Create(t *testing.T) {
|
||||
|
||||
var release = models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v0.1.5",
|
||||
Target: "65f1bf2",
|
||||
Title: "v0.1.5 is released",
|
||||
@@ -125,7 +137,9 @@ func TestRelease_Update(t *testing.T) {
|
||||
// Test a changed release
|
||||
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v1.1.1",
|
||||
Target: "master",
|
||||
Title: "v1.1.1 is released",
|
||||
@@ -147,7 +161,9 @@ func TestRelease_Update(t *testing.T) {
|
||||
// Test a changed draft
|
||||
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v1.2.1",
|
||||
Target: "65f1bf2",
|
||||
Title: "v1.2.1 is draft",
|
||||
@@ -169,7 +185,9 @@ func TestRelease_Update(t *testing.T) {
|
||||
// Test a changed pre-release
|
||||
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v1.3.1",
|
||||
Target: "65f1bf2",
|
||||
Title: "v1.3.1 is pre-released",
|
||||
@@ -192,7 +210,9 @@ func TestRelease_Update(t *testing.T) {
|
||||
// Test create release
|
||||
release = &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v1.1.2",
|
||||
Target: "master",
|
||||
Title: "v1.1.2 is released",
|
||||
@@ -258,7 +278,9 @@ func TestRelease_createTag(t *testing.T) {
|
||||
// Test a changed release
|
||||
release := &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v2.1.1",
|
||||
Target: "master",
|
||||
Title: "v2.1.1 is released",
|
||||
@@ -280,7 +302,9 @@ func TestRelease_createTag(t *testing.T) {
|
||||
// Test a changed draft
|
||||
release = &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v2.2.1",
|
||||
Target: "65f1bf2",
|
||||
Title: "v2.2.1 is draft",
|
||||
@@ -301,7 +325,9 @@ func TestRelease_createTag(t *testing.T) {
|
||||
// Test a changed pre-release
|
||||
release = &models.Release{
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
PublisherID: user.ID,
|
||||
Publisher: user,
|
||||
TagName: "v2.3.1",
|
||||
Target: "65f1bf2",
|
||||
Title: "v2.3.1 is pre-released",
|
||||
|
Reference in New Issue
Block a user