Backport #25578 This PR added a repository's check when creating/deleting branches via API. Mirror repository and archive repository cannot do that.
This commit is contained in:
parent
e5b684e567
commit
13ffa287b1
|
@ -0,0 +1,49 @@
|
||||||
|
-
|
||||||
|
id: 1
|
||||||
|
repo_id: 5
|
||||||
|
interval: 3600
|
||||||
|
enable_prune: false
|
||||||
|
updated_unix: 0
|
||||||
|
next_update_unix: 0
|
||||||
|
lfs_enabled: false
|
||||||
|
lfs_endpoint: ""
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2
|
||||||
|
repo_id: 25
|
||||||
|
interval: 3600
|
||||||
|
enable_prune: false
|
||||||
|
updated_unix: 0
|
||||||
|
next_update_unix: 0
|
||||||
|
lfs_enabled: false
|
||||||
|
lfs_endpoint: ""
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 3
|
||||||
|
repo_id: 26
|
||||||
|
interval: 3600
|
||||||
|
enable_prune: false
|
||||||
|
updated_unix: 0
|
||||||
|
next_update_unix: 0
|
||||||
|
lfs_enabled: false
|
||||||
|
lfs_endpoint: ""
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 4
|
||||||
|
repo_id: 27
|
||||||
|
interval: 3600
|
||||||
|
enable_prune: false
|
||||||
|
updated_unix: 0
|
||||||
|
next_update_unix: 0
|
||||||
|
lfs_enabled: false
|
||||||
|
lfs_endpoint: ""
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 5
|
||||||
|
repo_id: 28
|
||||||
|
interval: 3600
|
||||||
|
enable_prune: false
|
||||||
|
updated_unix: 0
|
||||||
|
next_update_unix: 0
|
||||||
|
lfs_enabled: false
|
||||||
|
lfs_endpoint: ""
|
|
@ -141,7 +141,7 @@
|
||||||
num_projects: 0
|
num_projects: 0
|
||||||
num_closed_projects: 0
|
num_closed_projects: 0
|
||||||
is_private: true
|
is_private: true
|
||||||
is_empty: true
|
is_empty: false
|
||||||
is_archived: false
|
is_archived: false
|
||||||
is_mirror: true
|
is_mirror: true
|
||||||
status: 0
|
status: 0
|
||||||
|
|
|
@ -116,6 +116,21 @@ func DeleteBranch(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
|
if ctx.Repo.Repository.IsEmpty {
|
||||||
|
ctx.Error(http.StatusNotFound, "", "Git Repository is empty.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Repo.Repository.IsArchived {
|
||||||
|
ctx.Error(http.StatusForbidden, "", "Git Repository is archived.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Repo.Repository.IsMirror {
|
||||||
|
ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
branchName := ctx.Params("*")
|
branchName := ctx.Params("*")
|
||||||
|
|
||||||
if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
|
if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
|
||||||
|
@ -162,17 +177,30 @@ func CreateBranch(ctx *context.APIContext) {
|
||||||
// responses:
|
// responses:
|
||||||
// "201":
|
// "201":
|
||||||
// "$ref": "#/responses/Branch"
|
// "$ref": "#/responses/Branch"
|
||||||
|
// "403":
|
||||||
|
// description: The branch is archived or a mirror.
|
||||||
// "404":
|
// "404":
|
||||||
// description: The old branch does not exist.
|
// description: The old branch does not exist.
|
||||||
// "409":
|
// "409":
|
||||||
// description: The branch with the same name already exists.
|
// description: The branch with the same name already exists.
|
||||||
|
|
||||||
opt := web.GetForm(ctx).(*api.CreateBranchRepoOption)
|
|
||||||
if ctx.Repo.Repository.IsEmpty {
|
if ctx.Repo.Repository.IsEmpty {
|
||||||
ctx.Error(http.StatusNotFound, "", "Git Repository is empty.")
|
ctx.Error(http.StatusNotFound, "", "Git Repository is empty.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctx.Repo.Repository.IsArchived {
|
||||||
|
ctx.Error(http.StatusForbidden, "", "Git Repository is archived.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Repo.Repository.IsMirror {
|
||||||
|
ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
opt := web.GetForm(ctx).(*api.CreateBranchRepoOption)
|
||||||
|
|
||||||
var oldCommit *git.Commit
|
var oldCommit *git.Commit
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -280,7 +308,12 @@ func ListBranches(ctx *context.APIContext) {
|
||||||
|
|
||||||
listOptions := utils.GetListOptions(ctx)
|
listOptions := utils.GetListOptions(ctx)
|
||||||
|
|
||||||
if !ctx.Repo.Repository.IsEmpty && ctx.Repo.GitRepo != nil {
|
if !ctx.Repo.Repository.IsEmpty {
|
||||||
|
if ctx.Repo.GitRepo == nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "Load git repository failed", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rules, err := git_model.FindRepoProtectedBranchRules(ctx, ctx.Repo.Repository.ID)
|
rules, err := git_model.FindRepoProtectedBranchRules(ctx, ctx.Repo.Repository.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "FindMatchedProtectedBranchRules", err)
|
ctx.Error(http.StatusInternalServerError, "FindMatchedProtectedBranchRules", err)
|
||||||
|
|
|
@ -3478,6 +3478,9 @@
|
||||||
"201": {
|
"201": {
|
||||||
"$ref": "#/responses/Branch"
|
"$ref": "#/responses/Branch"
|
||||||
},
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "The branch is archived or a mirror."
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "The old branch does not exist."
|
"description": "The old branch does not exist."
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
ref: refs/heads/master
|
|
@ -0,0 +1,6 @@
|
||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
||||||
|
ignorecase = true
|
||||||
|
precomposeunicode = true
|
|
@ -0,0 +1 @@
|
||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
ORI_DIR=`pwd`
|
||||||
|
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||||
|
cd "$ORI_DIR"
|
||||||
|
for i in `ls "$SHELL_FOLDER/post-receive.d"`; do
|
||||||
|
sh "$SHELL_FOLDER/post-receive.d/$i"
|
||||||
|
done
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
ORI_DIR=`pwd`
|
||||||
|
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||||
|
cd "$ORI_DIR"
|
||||||
|
for i in `ls "$SHELL_FOLDER/pre-receive.d"`; do
|
||||||
|
sh "$SHELL_FOLDER/pre-receive.d/$i"
|
||||||
|
done
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
ORI_DIR=`pwd`
|
||||||
|
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||||
|
cd "$ORI_DIR"
|
||||||
|
for i in `ls "$SHELL_FOLDER/update.d"`; do
|
||||||
|
sh "$SHELL_FOLDER/update.d/$i" $1 $2 $3
|
||||||
|
done
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
|
|
@ -0,0 +1,6 @@
|
||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
2a47ca4b614a9f5a43abbd5ad851a54a616ffee6
|
|
@ -0,0 +1 @@
|
||||||
|
d22b4d4daa5be07329fcef6ed458f00cf3392da0
|
|
@ -0,0 +1,136 @@
|
||||||
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAPIRepoBranchesPlain(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||||
|
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
||||||
|
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
|
session := loginUser(t, user1.LowerName)
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
|
||||||
|
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches", repo3.Name)) // a plain repo
|
||||||
|
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||||
|
resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||||
|
bs, err := io.ReadAll(resp.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var branches []*api.Branch
|
||||||
|
assert.NoError(t, json.Unmarshal(bs, &branches))
|
||||||
|
assert.Len(t, branches, 2)
|
||||||
|
sort.Slice(branches, func(i, j int) bool {
|
||||||
|
return branches[i].Name > branches[j].Name
|
||||||
|
})
|
||||||
|
assert.EqualValues(t, "test_branch", branches[0].Name)
|
||||||
|
assert.EqualValues(t, "master", branches[1].Name)
|
||||||
|
|
||||||
|
link2, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches/test_branch", repo3.Name))
|
||||||
|
link2.RawQuery = url.Values{"token": {token}}.Encode()
|
||||||
|
resp = MakeRequest(t, NewRequest(t, "GET", link2.String()), http.StatusOK)
|
||||||
|
bs, err = io.ReadAll(resp.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
var branch api.Branch
|
||||||
|
assert.NoError(t, json.Unmarshal(bs, &branch))
|
||||||
|
assert.EqualValues(t, "test_branch", branch.Name)
|
||||||
|
|
||||||
|
req := NewRequest(t, "POST", link.String())
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
req.Body = io.NopCloser(bytes.NewBufferString(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`))
|
||||||
|
resp = MakeRequest(t, req, http.StatusCreated)
|
||||||
|
bs, err = io.ReadAll(resp.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
var branch2 api.Branch
|
||||||
|
assert.NoError(t, json.Unmarshal(bs, &branch2))
|
||||||
|
assert.EqualValues(t, "test_branch2", branch2.Name)
|
||||||
|
assert.EqualValues(t, branch.Commit.ID, branch2.Commit.ID)
|
||||||
|
|
||||||
|
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||||
|
bs, err = io.ReadAll(resp.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
branches = []*api.Branch{}
|
||||||
|
assert.NoError(t, json.Unmarshal(bs, &branches))
|
||||||
|
assert.Len(t, branches, 3)
|
||||||
|
sort.Slice(branches, func(i, j int) bool {
|
||||||
|
return branches[i].Name > branches[j].Name
|
||||||
|
})
|
||||||
|
assert.EqualValues(t, "test_branch2", branches[0].Name)
|
||||||
|
assert.EqualValues(t, "test_branch", branches[1].Name)
|
||||||
|
assert.EqualValues(t, "master", branches[2].Name)
|
||||||
|
|
||||||
|
link3, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches/test_branch2", repo3.Name))
|
||||||
|
MakeRequest(t, NewRequest(t, "DELETE", link3.String()), http.StatusNotFound)
|
||||||
|
|
||||||
|
link3.RawQuery = url.Values{"token": {token}}.Encode()
|
||||||
|
MakeRequest(t, NewRequest(t, "DELETE", link3.String()), http.StatusNoContent)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPIRepoBranchesMirror(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
repo5 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5})
|
||||||
|
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
|
session := loginUser(t, user1.LowerName)
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
|
||||||
|
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches", repo5.Name)) // a mirror repo
|
||||||
|
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||||
|
resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||||
|
bs, err := io.ReadAll(resp.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var branches []*api.Branch
|
||||||
|
assert.NoError(t, json.Unmarshal(bs, &branches))
|
||||||
|
assert.Len(t, branches, 2)
|
||||||
|
sort.Slice(branches, func(i, j int) bool {
|
||||||
|
return branches[i].Name > branches[j].Name
|
||||||
|
})
|
||||||
|
assert.EqualValues(t, "test_branch", branches[0].Name)
|
||||||
|
assert.EqualValues(t, "master", branches[1].Name)
|
||||||
|
|
||||||
|
link2, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches/test_branch", repo5.Name))
|
||||||
|
link2.RawQuery = url.Values{"token": {token}}.Encode()
|
||||||
|
resp = MakeRequest(t, NewRequest(t, "GET", link2.String()), http.StatusOK)
|
||||||
|
bs, err = io.ReadAll(resp.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
var branch api.Branch
|
||||||
|
assert.NoError(t, json.Unmarshal(bs, &branch))
|
||||||
|
assert.EqualValues(t, "test_branch", branch.Name)
|
||||||
|
|
||||||
|
req := NewRequest(t, "POST", link.String())
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
req.Body = io.NopCloser(bytes.NewBufferString(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`))
|
||||||
|
resp = MakeRequest(t, req, http.StatusForbidden)
|
||||||
|
bs, err = io.ReadAll(resp.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, "{\"message\":\"Git Repository is a mirror.\",\"url\":\""+setting.AppURL+"api/swagger\"}\n", string(bs))
|
||||||
|
|
||||||
|
resp = MakeRequest(t, NewRequest(t, "DELETE", link2.String()), http.StatusForbidden)
|
||||||
|
bs, err = io.ReadAll(resp.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, "{\"message\":\"Git Repository is a mirror.\",\"url\":\""+setting.AppURL+"api/swagger\"}\n", string(bs))
|
||||||
|
}
|
|
@ -34,7 +34,7 @@ func TestEmptyRepo(t *testing.T) {
|
||||||
"commit/1ae57b34ccf7e18373",
|
"commit/1ae57b34ccf7e18373",
|
||||||
"graph",
|
"graph",
|
||||||
}
|
}
|
||||||
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5})
|
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 6})
|
||||||
assert.True(t, emptyRepo.IsEmpty)
|
assert.True(t, emptyRepo.IsEmpty)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID})
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID})
|
||||||
for _, subPath := range subPaths {
|
for _, subPath := range subPaths {
|
||||||
|
|
Loading…
Reference in New Issue