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

Fix bug of branches API with tests(#25578) #25579

Merged
merged 11 commits into from
Jul 3, 2023
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
49 changes: 49 additions & 0 deletions models/fixtures/mirror.yml
Original file line number Diff line number Diff line change
@@ -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: ""
2 changes: 1 addition & 1 deletion models/fixtures/repository.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
num_projects: 0
num_closed_projects: 0
is_private: true
is_empty: true
is_empty: false
is_archived: false
is_mirror: true
status: 0
Expand Down
37 changes: 35 additions & 2 deletions routers/api/v1/repo/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ func DeleteBranch(ctx *context.APIContext) {
// "404":
// "$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("*")

if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
Expand Down Expand Up @@ -162,17 +177,30 @@ func CreateBranch(ctx *context.APIContext) {
// responses:
// "201":
// "$ref": "#/responses/Branch"
// "403":
// description: The branch is archived or a mirror.
// "404":
// description: The old branch does not exist.
// "409":
// description: The branch with the same name already exists.

opt := web.GetForm(ctx).(*api.CreateBranchRepoOption)
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
}

opt := web.GetForm(ctx).(*api.CreateBranchRepoOption)

var oldCommit *git.Commit
var err error

Expand Down Expand Up @@ -280,7 +308,12 @@ func ListBranches(ctx *context.APIContext) {

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)
if err != nil {
ctx.Error(http.StatusInternalServerError, "FindMatchedProtectedBranchRules", err)
Expand Down
3 changes: 3 additions & 0 deletions templates/swagger/v1_json.tmpl

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

1 change: 1 addition & 0 deletions tests/gitea-repositories-meta/user3/repo5.git/HEAD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/master
6 changes: 6 additions & 0 deletions tests/gitea-repositories-meta/user3/repo5.git/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[core]
repositoryformatversion = 0
filemode = true
bare = true
ignorecase = true
precomposeunicode = true
1 change: 1 addition & 0 deletions tests/gitea-repositories-meta/user3/repo5.git/description
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
7 changes: 7 additions & 0 deletions tests/gitea-repositories-meta/user3/repo5.git/hooks/update
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
6 changes: 6 additions & 0 deletions tests/gitea-repositories-meta/user3/repo5.git/info/exclude
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2a47ca4b614a9f5a43abbd5ad851a54a616ffee6
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
d22b4d4daa5be07329fcef6ed458f00cf3392da0
136 changes: 136 additions & 0 deletions tests/integration/api_repo_branch_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
2 changes: 1 addition & 1 deletion tests/integration/empty_repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestEmptyRepo(t *testing.T) {
"commit/1ae57b34ccf7e18373",
"graph",
}
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5})
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 6})
assert.True(t, emptyRepo.IsEmpty)
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID})
for _, subPath := range subPaths {
Expand Down