loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix bug of branches API with tests (#25578)

Fix #25558
Extract from #22743

This PR added a repository's check when creating/deleting branches via
API. Mirror repository and archive repository cannot do that.

authored by

Lunny Xiao and committed by
GitHub
de981c39 1704c64a

+258 -4
+49
models/fixtures/mirror.yml
··· 1 + - 2 + id: 1 3 + repo_id: 5 4 + interval: 3600 5 + enable_prune: false 6 + updated_unix: 0 7 + next_update_unix: 0 8 + lfs_enabled: false 9 + lfs_endpoint: "" 10 + 11 + - 12 + id: 2 13 + repo_id: 25 14 + interval: 3600 15 + enable_prune: false 16 + updated_unix: 0 17 + next_update_unix: 0 18 + lfs_enabled: false 19 + lfs_endpoint: "" 20 + 21 + - 22 + id: 3 23 + repo_id: 26 24 + interval: 3600 25 + enable_prune: false 26 + updated_unix: 0 27 + next_update_unix: 0 28 + lfs_enabled: false 29 + lfs_endpoint: "" 30 + 31 + - 32 + id: 4 33 + repo_id: 27 34 + interval: 3600 35 + enable_prune: false 36 + updated_unix: 0 37 + next_update_unix: 0 38 + lfs_enabled: false 39 + lfs_endpoint: "" 40 + 41 + - 42 + id: 5 43 + repo_id: 28 44 + interval: 3600 45 + enable_prune: false 46 + updated_unix: 0 47 + next_update_unix: 0 48 + lfs_enabled: false 49 + lfs_endpoint: ""
+1 -1
models/fixtures/repository.yml
··· 141 141 num_projects: 0 142 142 num_closed_projects: 0 143 143 is_private: true 144 - is_empty: true 144 + is_empty: false 145 145 is_archived: false 146 146 is_mirror: true 147 147 status: 0
+35 -2
routers/api/v1/repo/branch.go
··· 118 118 // "404": 119 119 // "$ref": "#/responses/notFound" 120 120 121 + if ctx.Repo.Repository.IsEmpty { 122 + ctx.Error(http.StatusNotFound, "", "Git Repository is empty.") 123 + return 124 + } 125 + 126 + if ctx.Repo.Repository.IsArchived { 127 + ctx.Error(http.StatusForbidden, "", "Git Repository is archived.") 128 + return 129 + } 130 + 131 + if ctx.Repo.Repository.IsMirror { 132 + ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.") 133 + return 134 + } 135 + 121 136 branchName := ctx.Params("*") 122 137 123 138 if ctx.Repo.Repository.IsEmpty { ··· 195 210 // responses: 196 211 // "201": 197 212 // "$ref": "#/responses/Branch" 213 + // "403": 214 + // description: The branch is archived or a mirror. 198 215 // "404": 199 216 // description: The old branch does not exist. 200 217 // "409": 201 218 // description: The branch with the same name already exists. 202 219 203 - opt := web.GetForm(ctx).(*api.CreateBranchRepoOption) 204 220 if ctx.Repo.Repository.IsEmpty { 205 221 ctx.Error(http.StatusNotFound, "", "Git Repository is empty.") 206 222 return 207 223 } 208 224 225 + if ctx.Repo.Repository.IsArchived { 226 + ctx.Error(http.StatusForbidden, "", "Git Repository is archived.") 227 + return 228 + } 229 + 230 + if ctx.Repo.Repository.IsMirror { 231 + ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.") 232 + return 233 + } 234 + 235 + opt := web.GetForm(ctx).(*api.CreateBranchRepoOption) 236 + 209 237 var oldCommit *git.Commit 210 238 var err error 211 239 ··· 313 341 314 342 listOptions := utils.GetListOptions(ctx) 315 343 316 - if !ctx.Repo.Repository.IsEmpty && ctx.Repo.GitRepo != nil { 344 + if !ctx.Repo.Repository.IsEmpty { 345 + if ctx.Repo.GitRepo == nil { 346 + ctx.Error(http.StatusInternalServerError, "Load git repository failed", nil) 347 + return 348 + } 349 + 317 350 branchOpts := git_model.FindBranchOptions{ 318 351 ListOptions: listOptions, 319 352 RepoID: ctx.Repo.Repository.ID,
+3
templates/swagger/v1_json.tmpl
··· 3606 3606 "201": { 3607 3607 "$ref": "#/responses/Branch" 3608 3608 }, 3609 + "403": { 3610 + "description": "The branch is archived or a mirror." 3611 + }, 3609 3612 "404": { 3610 3613 "description": "The old branch does not exist." 3611 3614 },
+1
tests/gitea-repositories-meta/user3/repo5.git/HEAD
··· 1 + ref: refs/heads/master
+6
tests/gitea-repositories-meta/user3/repo5.git/config
··· 1 + [core] 2 + repositoryformatversion = 0 3 + filemode = true 4 + bare = true 5 + ignorecase = true 6 + precomposeunicode = true
+1
tests/gitea-repositories-meta/user3/repo5.git/description
··· 1 + Unnamed repository; edit this file 'description' to name the repository.
+7
tests/gitea-repositories-meta/user3/repo5.git/hooks/post-receive
··· 1 + #!/usr/bin/env bash 2 + ORI_DIR=`pwd` 3 + SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) 4 + cd "$ORI_DIR" 5 + for i in `ls "$SHELL_FOLDER/post-receive.d"`; do 6 + sh "$SHELL_FOLDER/post-receive.d/$i" 7 + done
+2
tests/gitea-repositories-meta/user3/repo5.git/hooks/post-receive.d/gitea
··· 1 + #!/usr/bin/env bash 2 + "$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
+7
tests/gitea-repositories-meta/user3/repo5.git/hooks/pre-receive
··· 1 + #!/usr/bin/env bash 2 + ORI_DIR=`pwd` 3 + SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) 4 + cd "$ORI_DIR" 5 + for i in `ls "$SHELL_FOLDER/pre-receive.d"`; do 6 + sh "$SHELL_FOLDER/pre-receive.d/$i" 7 + done
+2
tests/gitea-repositories-meta/user3/repo5.git/hooks/pre-receive.d/gitea
··· 1 + #!/usr/bin/env bash 2 + "$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
+7
tests/gitea-repositories-meta/user3/repo5.git/hooks/update
··· 1 + #!/usr/bin/env bash 2 + ORI_DIR=`pwd` 3 + SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) 4 + cd "$ORI_DIR" 5 + for i in `ls "$SHELL_FOLDER/update.d"`; do 6 + sh "$SHELL_FOLDER/update.d/$i" $1 $2 $3 7 + done
+2
tests/gitea-repositories-meta/user3/repo5.git/hooks/update.d/gitea
··· 1 + #!/usr/bin/env bash 2 + "$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
+6
tests/gitea-repositories-meta/user3/repo5.git/info/exclude
··· 1 + # git ls-files --others --exclude-from=.git/info/exclude 2 + # Lines that start with '#' are comments. 3 + # For a project mostly in C, the following would be a good set of 4 + # exclude patterns (uncomment them if you want to use them): 5 + # *.[oa] 6 + # *~
tests/gitea-repositories-meta/user3/repo5.git/objects/20/ade30d25e0ecaeec84e7f542a8456900858240

This is a binary file and will not be displayed.

tests/gitea-repositories-meta/user3/repo5.git/objects/27/74debeea6dc742cc4971a92db0e08b95b60588

This is a binary file and will not be displayed.

tests/gitea-repositories-meta/user3/repo5.git/objects/2a/47ca4b614a9f5a43abbd5ad851a54a616ffee6

This is a binary file and will not be displayed.

tests/gitea-repositories-meta/user3/repo5.git/objects/2f/9b22fd3159a43b7b4e5dd806fcd544edf8716f

This is a binary file and will not be displayed.

tests/gitea-repositories-meta/user3/repo5.git/objects/d2/2b4d4daa5be07329fcef6ed458f00cf3392da0

This is a binary file and will not be displayed.

tests/gitea-repositories-meta/user3/repo5.git/objects/d5/6a3073c1dbb7b15963110a049d50cdb5db99fc

This is a binary file and will not be displayed.

tests/gitea-repositories-meta/user3/repo5.git/objects/ec/f0db3c1ec806522de4b491fb9a3c7457398c61

This is a binary file and will not be displayed.

tests/gitea-repositories-meta/user3/repo5.git/objects/ee/16d127df463aa491e08958120f2108b02468df

This is a binary file and will not be displayed.

+1
tests/gitea-repositories-meta/user3/repo5.git/refs/heads/master
··· 1 + 2a47ca4b614a9f5a43abbd5ad851a54a616ffee6
+1
tests/gitea-repositories-meta/user3/repo5.git/refs/heads/test_branch
··· 1 + d22b4d4daa5be07329fcef6ed458f00cf3392da0
+126
tests/integration/api_repo_branch_test.go
··· 1 + // Copyright 2021 The Gitea Authors. All rights reserved. 2 + // SPDX-License-Identifier: MIT 3 + 4 + package integration 5 + 6 + import ( 7 + "bytes" 8 + "fmt" 9 + "io" 10 + "net/http" 11 + "net/url" 12 + "testing" 13 + 14 + auth_model "code.gitea.io/gitea/models/auth" 15 + repo_model "code.gitea.io/gitea/models/repo" 16 + "code.gitea.io/gitea/models/unittest" 17 + user_model "code.gitea.io/gitea/models/user" 18 + "code.gitea.io/gitea/modules/json" 19 + "code.gitea.io/gitea/modules/setting" 20 + api "code.gitea.io/gitea/modules/structs" 21 + "code.gitea.io/gitea/tests" 22 + 23 + "github.com/stretchr/testify/assert" 24 + ) 25 + 26 + func TestAPIRepoBranchesPlain(t *testing.T) { 27 + onGiteaRun(t, func(*testing.T, *url.URL) { 28 + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) 29 + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) 30 + session := loginUser(t, user1.LowerName) 31 + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) 32 + 33 + link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches", repo3.Name)) // a plain repo 34 + link.RawQuery = url.Values{"token": {token}}.Encode() 35 + resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 36 + bs, err := io.ReadAll(resp.Body) 37 + assert.NoError(t, err) 38 + 39 + var branches []*api.Branch 40 + assert.NoError(t, json.Unmarshal(bs, &branches)) 41 + assert.Len(t, branches, 2) 42 + assert.EqualValues(t, "test_branch", branches[0].Name) 43 + assert.EqualValues(t, "master", branches[1].Name) 44 + 45 + link2, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches/test_branch", repo3.Name)) 46 + link2.RawQuery = url.Values{"token": {token}}.Encode() 47 + resp = MakeRequest(t, NewRequest(t, "GET", link2.String()), http.StatusOK) 48 + bs, err = io.ReadAll(resp.Body) 49 + assert.NoError(t, err) 50 + var branch api.Branch 51 + assert.NoError(t, json.Unmarshal(bs, &branch)) 52 + assert.EqualValues(t, "test_branch", branch.Name) 53 + 54 + req := NewRequest(t, "POST", link.String()) 55 + req.Header.Add("Content-Type", "application/json") 56 + req.Body = io.NopCloser(bytes.NewBufferString(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`)) 57 + resp = MakeRequest(t, req, http.StatusCreated) 58 + bs, err = io.ReadAll(resp.Body) 59 + assert.NoError(t, err) 60 + var branch2 api.Branch 61 + assert.NoError(t, json.Unmarshal(bs, &branch2)) 62 + assert.EqualValues(t, "test_branch2", branch2.Name) 63 + assert.EqualValues(t, branch.Commit.ID, branch2.Commit.ID) 64 + 65 + resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 66 + bs, err = io.ReadAll(resp.Body) 67 + assert.NoError(t, err) 68 + 69 + branches = []*api.Branch{} 70 + assert.NoError(t, json.Unmarshal(bs, &branches)) 71 + assert.Len(t, branches, 3) 72 + assert.EqualValues(t, "test_branch", branches[0].Name) 73 + assert.EqualValues(t, "test_branch2", branches[1].Name) 74 + assert.EqualValues(t, "master", branches[2].Name) 75 + 76 + link3, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches/test_branch2", repo3.Name)) 77 + MakeRequest(t, NewRequest(t, "DELETE", link3.String()), http.StatusNotFound) 78 + 79 + link3.RawQuery = url.Values{"token": {token}}.Encode() 80 + MakeRequest(t, NewRequest(t, "DELETE", link3.String()), http.StatusNoContent) 81 + assert.NoError(t, err) 82 + }) 83 + } 84 + 85 + func TestAPIRepoBranchesMirror(t *testing.T) { 86 + defer tests.PrepareTestEnv(t)() 87 + 88 + repo5 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5}) 89 + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) 90 + session := loginUser(t, user1.LowerName) 91 + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) 92 + 93 + link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches", repo5.Name)) // a mirror repo 94 + link.RawQuery = url.Values{"token": {token}}.Encode() 95 + resp := MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK) 96 + bs, err := io.ReadAll(resp.Body) 97 + assert.NoError(t, err) 98 + 99 + var branches []*api.Branch 100 + assert.NoError(t, json.Unmarshal(bs, &branches)) 101 + assert.Len(t, branches, 2) 102 + assert.EqualValues(t, "test_branch", branches[0].Name) 103 + assert.EqualValues(t, "master", branches[1].Name) 104 + 105 + link2, _ := url.Parse(fmt.Sprintf("/api/v1/repos/user3/%s/branches/test_branch", repo5.Name)) 106 + link2.RawQuery = url.Values{"token": {token}}.Encode() 107 + resp = MakeRequest(t, NewRequest(t, "GET", link2.String()), http.StatusOK) 108 + bs, err = io.ReadAll(resp.Body) 109 + assert.NoError(t, err) 110 + var branch api.Branch 111 + assert.NoError(t, json.Unmarshal(bs, &branch)) 112 + assert.EqualValues(t, "test_branch", branch.Name) 113 + 114 + req := NewRequest(t, "POST", link.String()) 115 + req.Header.Add("Content-Type", "application/json") 116 + req.Body = io.NopCloser(bytes.NewBufferString(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`)) 117 + resp = MakeRequest(t, req, http.StatusForbidden) 118 + bs, err = io.ReadAll(resp.Body) 119 + assert.NoError(t, err) 120 + assert.EqualValues(t, "{\"message\":\"Git Repository is a mirror.\",\"url\":\""+setting.AppURL+"api/swagger\"}\n", string(bs)) 121 + 122 + resp = MakeRequest(t, NewRequest(t, "DELETE", link2.String()), http.StatusForbidden) 123 + bs, err = io.ReadAll(resp.Body) 124 + assert.NoError(t, err) 125 + assert.EqualValues(t, "{\"message\":\"Git Repository is a mirror.\",\"url\":\""+setting.AppURL+"api/swagger\"}\n", string(bs)) 126 + }
+1 -1
tests/integration/empty_repo_test.go
··· 34 34 "commit/1ae57b34ccf7e18373", 35 35 "graph", 36 36 } 37 - emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5}) 37 + emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 6}) 38 38 assert.True(t, emptyRepo.IsEmpty) 39 39 owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID}) 40 40 for _, subPath := range subPaths {