mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-19 13:24:32 -04:00
b06002f449
1. simplify "StorageRepo" code 2. simplify git.OpenRepository code 3. by the way, clean up some unused files in git test fixtures.
257 lines
8.7 KiB
Go
257 lines
8.7 KiB
Go
// Copyright 2024 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package integration
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"testing"
|
|
|
|
auth_model "gitea.dev/models/auth"
|
|
"gitea.dev/models/db"
|
|
git_model "gitea.dev/models/git"
|
|
repo_model "gitea.dev/models/repo"
|
|
"gitea.dev/models/unittest"
|
|
user_model "gitea.dev/models/user"
|
|
"gitea.dev/modules/git"
|
|
"gitea.dev/modules/git/gitcmd"
|
|
repo_service "gitea.dev/services/repository"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestGitPush(t *testing.T) {
|
|
onGiteaRun(t, testGitPush)
|
|
}
|
|
|
|
func testGitPush(t *testing.T, u *url.URL) {
|
|
t.Run("Push branches at once", func(t *testing.T) {
|
|
runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
|
|
for i := range 100 {
|
|
branchName := fmt.Sprintf("branch-%d", i)
|
|
pushed = append(pushed, branchName)
|
|
doGitCreateBranch(gitPath, branchName)(t)
|
|
}
|
|
pushed = append(pushed, "master")
|
|
doGitPushTestRepository(gitPath, "origin", "--all")(t)
|
|
return pushed, deleted
|
|
})
|
|
})
|
|
|
|
t.Run("Push branches exists", func(t *testing.T) {
|
|
runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
|
|
for i := range 10 {
|
|
branchName := fmt.Sprintf("branch-%d", i)
|
|
if i < 5 {
|
|
pushed = append(pushed, branchName)
|
|
}
|
|
doGitCreateBranch(gitPath, branchName)(t)
|
|
}
|
|
// only push master and the first 5 branches
|
|
pushed = append(pushed, "master")
|
|
args := append([]string{"origin"}, pushed...)
|
|
doGitPushTestRepository(gitPath, args...)(t)
|
|
|
|
pushed = pushed[:0]
|
|
// do some changes for the first 5 branches created above
|
|
for i := range 5 {
|
|
branchName := fmt.Sprintf("branch-%d", i)
|
|
pushed = append(pushed, branchName)
|
|
doGitCheckoutWriteFileCommit(localGitAddCommitOptions{
|
|
LocalRepoPath: gitPath,
|
|
CheckoutBranch: branchName,
|
|
TreeFilePath: fmt.Sprintf("file-%s.txt", branchName),
|
|
TreeFileContent: "file " + branchName,
|
|
})(t)
|
|
}
|
|
|
|
for i := 5; i < 10; i++ {
|
|
pushed = append(pushed, fmt.Sprintf("branch-%d", i))
|
|
}
|
|
pushed = append(pushed, "master")
|
|
|
|
// push all, so that master is not changed
|
|
doGitPushTestRepository(gitPath, "origin", "--all")(t)
|
|
|
|
return pushed, deleted
|
|
})
|
|
})
|
|
|
|
t.Run("Push branches one by one", func(t *testing.T) {
|
|
runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
|
|
for i := range 100 {
|
|
branchName := fmt.Sprintf("branch-%d", i)
|
|
doGitCreateBranch(gitPath, branchName)(t)
|
|
doGitPushTestRepository(gitPath, "origin", branchName)(t)
|
|
pushed = append(pushed, branchName)
|
|
}
|
|
return pushed, deleted
|
|
})
|
|
})
|
|
|
|
t.Run("Push branch with options", func(t *testing.T) {
|
|
runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
|
|
branchName := "branch-with-options"
|
|
doGitCreateBranch(gitPath, branchName)(t)
|
|
doGitPushTestRepository(gitPath, "origin", branchName, "-o", "repo.private=true", "-o", "repo.template=true")(t)
|
|
pushed = append(pushed, branchName)
|
|
|
|
return pushed, deleted
|
|
})
|
|
})
|
|
|
|
t.Run("Delete branches", func(t *testing.T) {
|
|
runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
|
|
doGitPushTestRepository(gitPath, "origin", "master")(t) // make sure master is the default branch instead of a branch we are going to delete
|
|
pushed = append(pushed, "master")
|
|
|
|
for i := range 100 {
|
|
branchName := fmt.Sprintf("branch-%d", i)
|
|
pushed = append(pushed, branchName)
|
|
doGitCreateBranch(gitPath, branchName)(t)
|
|
}
|
|
doGitPushTestRepository(gitPath, "origin", "--all")(t)
|
|
|
|
for i := range 10 {
|
|
branchName := fmt.Sprintf("branch-%d", i)
|
|
doGitPushTestRepository(gitPath, "origin", "--delete", branchName)(t)
|
|
deleted = append(deleted, branchName)
|
|
}
|
|
return pushed, deleted
|
|
})
|
|
})
|
|
|
|
t.Run("Push to deleted branch", func(t *testing.T) {
|
|
runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
|
|
doGitPushTestRepository(gitPath, "origin", "master")(t) // make sure master is the default branch instead of a branch we are going to delete
|
|
pushed = append(pushed, "master")
|
|
|
|
doGitCreateBranch(gitPath, "branch-1")(t)
|
|
doGitPushTestRepository(gitPath, "origin", "branch-1")(t)
|
|
pushed = append(pushed, "branch-1")
|
|
|
|
// delete and restore
|
|
doGitPushTestRepository(gitPath, "origin", "--delete", "branch-1")(t)
|
|
doGitPushTestRepository(gitPath, "origin", "branch-1")(t)
|
|
|
|
return pushed, deleted
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestGitPushVisibilityOption(t *testing.T) {
|
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
repo, err := repo_service.CreateRepository(t.Context(), user, user, repo_service.CreateRepoOptions{
|
|
Name: "repo-visibility-option",
|
|
AutoInit: false,
|
|
DefaultBranch: "master",
|
|
IsPrivate: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, repo)
|
|
|
|
gitPath := t.TempDir()
|
|
doGitInitTestRepository(gitPath)(t)
|
|
|
|
oldPath, oldUser := u.Path, u.User
|
|
defer func() { u.Path, u.User = oldPath, oldUser }()
|
|
u.Path = repo.FullName() + ".git"
|
|
u.User = url.UserPassword(user.LowerName, userPassword)
|
|
doGitAddRemote(gitPath, "origin", u)(t)
|
|
|
|
// The first push into an empty repository is a "push-to-create", so the
|
|
// repo.private push option is honored to set the initial visibility.
|
|
doGitPushTestRepository(gitPath, "origin", "master", "-o", "repo.private=true")(t)
|
|
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
|
|
assert.True(t, repo.IsPrivate, "repo.private option should apply on push-to-create")
|
|
|
|
// The repository is now populated; a later push must NOT silently flip
|
|
// visibility, otherwise a repo admin could change it bypassing the audit
|
|
// trail, webhooks, and notifications a proper settings change would fire.
|
|
doGitCreateBranch(gitPath, "branch2")(t)
|
|
doGitPushTestRepository(gitPath, "origin", "branch2", "-o", "repo.private=false")(t)
|
|
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
|
|
assert.True(t, repo.IsPrivate, "repo.private option must be ignored on an existing repository")
|
|
})
|
|
}
|
|
|
|
func runTestGitPush(t *testing.T, u *url.URL, gitOperation func(t *testing.T, gitPath string) (pushed, deleted []string)) {
|
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
repo, err := repo_service.CreateRepository(t.Context(), user, user, repo_service.CreateRepoOptions{
|
|
Name: "repo-to-push",
|
|
Description: "test git push",
|
|
AutoInit: false,
|
|
DefaultBranch: "main",
|
|
IsPrivate: false,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, repo)
|
|
|
|
gitPath := t.TempDir()
|
|
|
|
doGitInitTestRepository(gitPath)(t)
|
|
|
|
oldPath := u.Path
|
|
oldUser := u.User
|
|
defer func() {
|
|
u.Path = oldPath
|
|
u.User = oldUser
|
|
}()
|
|
u.Path = repo.FullName() + ".git"
|
|
u.User = url.UserPassword(user.LowerName, userPassword)
|
|
|
|
doGitAddRemote(gitPath, "origin", u)(t)
|
|
|
|
gitRepo, err := git.OpenRepositoryLocal(gitPath)
|
|
require.NoError(t, err)
|
|
defer gitRepo.Close()
|
|
|
|
pushedBranches, deletedBranches := gitOperation(t, gitPath)
|
|
|
|
dbBranches := make([]*git_model.Branch, 0)
|
|
require.NoError(t, db.GetEngine(t.Context()).Where("repo_id=?", repo.ID).Find(&dbBranches))
|
|
assert.Lenf(t, dbBranches, len(pushedBranches), "mismatched number of branches in db")
|
|
dbBranchesMap := make(map[string]*git_model.Branch, len(dbBranches))
|
|
for _, branch := range dbBranches {
|
|
dbBranchesMap[branch.Name] = branch
|
|
}
|
|
|
|
deletedBranchesMap := make(map[string]bool, len(deletedBranches))
|
|
for _, branchName := range deletedBranches {
|
|
deletedBranchesMap[branchName] = true
|
|
}
|
|
|
|
for _, branchName := range pushedBranches {
|
|
branch, ok := dbBranchesMap[branchName]
|
|
deleted := deletedBranchesMap[branchName]
|
|
assert.True(t, ok, "branch %s not found in database", branchName)
|
|
assert.Equal(t, deleted, branch.IsDeleted, "IsDeleted of %s is %v, but it's expected to be %v", branchName, branch.IsDeleted, deleted)
|
|
commitID, err := gitRepo.GetBranchCommitID(t.Context(), branchName)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, commitID, branch.CommitID)
|
|
}
|
|
|
|
require.NoError(t, repo_service.DeleteRepositoryDirectly(t.Context(), repo.ID))
|
|
}
|
|
|
|
func TestPushPullRefs(t *testing.T) {
|
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
|
baseAPITestContext := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
|
|
|
|
u.Path = baseAPITestContext.GitPath()
|
|
u.User = url.UserPassword("user2", userPassword)
|
|
|
|
dstPath := t.TempDir()
|
|
doGitClone(dstPath, u)(t)
|
|
|
|
cmd := gitcmd.NewCommand("push", "--delete", "origin", "refs/pull/2/head")
|
|
stdout, stderr, err := cmd.WithDir(dstPath).RunStdString(t.Context())
|
|
assert.Error(t, err)
|
|
assert.Empty(t, stdout)
|
|
assert.NotContains(t, stderr, "[deleted]", "stderr: %s", stderr)
|
|
})
|
|
}
|