* Move repofiles from modules to services * rename services/repository/repofiles -> services/repository/files * Fix test Co-authored-by: 6543 <6543@obermui.de>tags/v1.16.0-rc1
import ( | import ( | ||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
) | ) | ||||
func createFileInBranch(user *models.User, repo *models.Repository, treePath, branchName, content string) (*api.FileResponse, error) { | func createFileInBranch(user *models.User, repo *models.Repository, treePath, branchName, content string) (*api.FileResponse, error) { | ||||
opts := &repofiles.UpdateRepoFileOptions{ | |||||
opts := &files_service.UpdateRepoFileOptions{ | |||||
OldBranch: branchName, | OldBranch: branchName, | ||||
TreePath: treePath, | TreePath: treePath, | ||||
Content: content, | Content: content, | ||||
Author: nil, | Author: nil, | ||||
Committer: nil, | Committer: nil, | ||||
} | } | ||||
return repofiles.CreateOrUpdateRepoFile(repo, user, opts) | |||||
return files_service.CreateOrUpdateRepoFile(repo, user, opts) | |||||
} | } | ||||
func createFile(user *models.User, repo *models.Repository, treePath string) (*api.FileResponse, error) { | func createFile(user *models.User, repo *models.Repository, treePath string) (*api.FileResponse, error) { |
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/models/unittest" | "code.gitea.io/gitea/models/unittest" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
pull_service "code.gitea.io/gitea/services/pull" | pull_service "code.gitea.io/gitea/services/pull" | ||||
repo_service "code.gitea.io/gitea/services/repository" | repo_service "code.gitea.io/gitea/services/repository" | ||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
"github.com/stretchr/testify/assert" | "github.com/stretchr/testify/assert" | ||||
) | ) | ||||
assert.NotEmpty(t, headRepo) | assert.NotEmpty(t, headRepo) | ||||
//create a commit on base Repo | //create a commit on base Repo | ||||
_, err = repofiles.CreateOrUpdateRepoFile(baseRepo, actor, &repofiles.UpdateRepoFileOptions{ | |||||
_, err = files_service.CreateOrUpdateRepoFile(baseRepo, actor, &files_service.UpdateRepoFileOptions{ | |||||
TreePath: "File_A", | TreePath: "File_A", | ||||
Message: "Add File A", | Message: "Add File A", | ||||
Content: "File A", | Content: "File A", | ||||
IsNewFile: true, | IsNewFile: true, | ||||
OldBranch: "master", | OldBranch: "master", | ||||
NewBranch: "master", | NewBranch: "master", | ||||
Author: &repofiles.IdentityOptions{ | |||||
Author: &files_service.IdentityOptions{ | |||||
Name: actor.Name, | Name: actor.Name, | ||||
Email: actor.Email, | Email: actor.Email, | ||||
}, | }, | ||||
Committer: &repofiles.IdentityOptions{ | |||||
Committer: &files_service.IdentityOptions{ | |||||
Name: actor.Name, | Name: actor.Name, | ||||
Email: actor.Email, | Email: actor.Email, | ||||
}, | }, | ||||
Dates: &repofiles.CommitDateOptions{ | |||||
Dates: &files_service.CommitDateOptions{ | |||||
Author: time.Now(), | Author: time.Now(), | ||||
Committer: time.Now(), | Committer: time.Now(), | ||||
}, | }, | ||||
assert.NoError(t, err) | assert.NoError(t, err) | ||||
//create a commit on head Repo | //create a commit on head Repo | ||||
_, err = repofiles.CreateOrUpdateRepoFile(headRepo, actor, &repofiles.UpdateRepoFileOptions{ | |||||
_, err = files_service.CreateOrUpdateRepoFile(headRepo, actor, &files_service.UpdateRepoFileOptions{ | |||||
TreePath: "File_B", | TreePath: "File_B", | ||||
Message: "Add File on PR branch", | Message: "Add File on PR branch", | ||||
Content: "File B", | Content: "File B", | ||||
IsNewFile: true, | IsNewFile: true, | ||||
OldBranch: "master", | OldBranch: "master", | ||||
NewBranch: "newBranch", | NewBranch: "newBranch", | ||||
Author: &repofiles.IdentityOptions{ | |||||
Author: &files_service.IdentityOptions{ | |||||
Name: actor.Name, | Name: actor.Name, | ||||
Email: actor.Email, | Email: actor.Email, | ||||
}, | }, | ||||
Committer: &repofiles.IdentityOptions{ | |||||
Committer: &files_service.IdentityOptions{ | |||||
Name: actor.Name, | Name: actor.Name, | ||||
Email: actor.Email, | Email: actor.Email, | ||||
}, | }, | ||||
Dates: &repofiles.CommitDateOptions{ | |||||
Dates: &files_service.CommitDateOptions{ | |||||
Author: time.Now(), | Author: time.Now(), | ||||
Committer: time.Now(), | Committer: time.Now(), | ||||
}, | }, |
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/models/unittest" | "code.gitea.io/gitea/models/unittest" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
"code.gitea.io/gitea/modules/test" | "code.gitea.io/gitea/modules/test" | ||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
"github.com/stretchr/testify/assert" | "github.com/stretchr/testify/assert" | ||||
) | ) | ||||
func getDeleteRepoFileOptions(repo *models.Repository) *repofiles.DeleteRepoFileOptions { | |||||
return &repofiles.DeleteRepoFileOptions{ | |||||
func getDeleteRepoFileOptions(repo *models.Repository) *files_service.DeleteRepoFileOptions { | |||||
return &files_service.DeleteRepoFileOptions{ | |||||
LastCommitID: "", | LastCommitID: "", | ||||
OldBranch: repo.DefaultBranch, | OldBranch: repo.DefaultBranch, | ||||
NewBranch: repo.DefaultBranch, | NewBranch: repo.DefaultBranch, | ||||
TreePath: "README.md", | TreePath: "README.md", | ||||
Message: "Deletes README.md", | Message: "Deletes README.md", | ||||
SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", | SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", | ||||
Author: &repofiles.IdentityOptions{ | |||||
Author: &files_service.IdentityOptions{ | |||||
Name: "Bob Smith", | Name: "Bob Smith", | ||||
Email: "bob@smith.com", | Email: "bob@smith.com", | ||||
}, | }, | ||||
opts := getDeleteRepoFileOptions(repo) | opts := getDeleteRepoFileOptions(repo) | ||||
t.Run("Delete README.md file", func(t *testing.T) { | t.Run("Delete README.md file", func(t *testing.T) { | ||||
fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.DeleteRepoFile(repo, doer, opts) | |||||
assert.NoError(t, err) | assert.NoError(t, err) | ||||
expectedFileResponse := getExpectedDeleteFileResponse(u) | expectedFileResponse := getExpectedDeleteFileResponse(u) | ||||
assert.NotNil(t, fileResponse) | assert.NotNil(t, fileResponse) | ||||
}) | }) | ||||
t.Run("Verify README.md has been deleted", func(t *testing.T) { | t.Run("Verify README.md has been deleted", func(t *testing.T) { | ||||
fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.DeleteRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
expectedError := "repository file does not exist [path: " + opts.TreePath + "]" | expectedError := "repository file does not exist [path: " + opts.TreePath + "]" | ||||
assert.EqualError(t, err, expectedError) | assert.EqualError(t, err, expectedError) | ||||
opts.NewBranch = "" | opts.NewBranch = "" | ||||
t.Run("Delete README.md without Branch Name", func(t *testing.T) { | t.Run("Delete README.md without Branch Name", func(t *testing.T) { | ||||
fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.DeleteRepoFile(repo, doer, opts) | |||||
assert.NoError(t, err) | assert.NoError(t, err) | ||||
expectedFileResponse := getExpectedDeleteFileResponse(u) | expectedFileResponse := getExpectedDeleteFileResponse(u) | ||||
assert.NotNil(t, fileResponse) | assert.NotNil(t, fileResponse) | ||||
t.Run("Bad branch", func(t *testing.T) { | t.Run("Bad branch", func(t *testing.T) { | ||||
opts := getDeleteRepoFileOptions(repo) | opts := getDeleteRepoFileOptions(repo) | ||||
opts.OldBranch = "bad_branch" | opts.OldBranch = "bad_branch" | ||||
fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.DeleteRepoFile(repo, doer, opts) | |||||
assert.Error(t, err) | assert.Error(t, err) | ||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
expectedError := "branch does not exist [name: " + opts.OldBranch + "]" | expectedError := "branch does not exist [name: " + opts.OldBranch + "]" | ||||
opts := getDeleteRepoFileOptions(repo) | opts := getDeleteRepoFileOptions(repo) | ||||
origSHA := opts.SHA | origSHA := opts.SHA | ||||
opts.SHA = "bad_sha" | opts.SHA = "bad_sha" | ||||
fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.DeleteRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
assert.Error(t, err) | assert.Error(t, err) | ||||
expectedError := "sha does not match [given: " + opts.SHA + ", expected: " + origSHA + "]" | expectedError := "sha does not match [given: " + opts.SHA + ", expected: " + origSHA + "]" | ||||
t.Run("New branch already exists", func(t *testing.T) { | t.Run("New branch already exists", func(t *testing.T) { | ||||
opts := getDeleteRepoFileOptions(repo) | opts := getDeleteRepoFileOptions(repo) | ||||
opts.NewBranch = "develop" | opts.NewBranch = "develop" | ||||
fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.DeleteRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
assert.Error(t, err) | assert.Error(t, err) | ||||
expectedError := "branch already exists [name: " + opts.NewBranch + "]" | expectedError := "branch already exists [name: " + opts.NewBranch + "]" | ||||
t.Run("TreePath is empty:", func(t *testing.T) { | t.Run("TreePath is empty:", func(t *testing.T) { | ||||
opts := getDeleteRepoFileOptions(repo) | opts := getDeleteRepoFileOptions(repo) | ||||
opts.TreePath = "" | opts.TreePath = "" | ||||
fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.DeleteRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
assert.Error(t, err) | assert.Error(t, err) | ||||
expectedError := "path contains a malformed path component [path: ]" | expectedError := "path contains a malformed path component [path: ]" | ||||
t.Run("TreePath is a git directory:", func(t *testing.T) { | t.Run("TreePath is a git directory:", func(t *testing.T) { | ||||
opts := getDeleteRepoFileOptions(repo) | opts := getDeleteRepoFileOptions(repo) | ||||
opts.TreePath = ".git" | opts.TreePath = ".git" | ||||
fileResponse, err := repofiles.DeleteRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.DeleteRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
assert.Error(t, err) | assert.Error(t, err) | ||||
expectedError := "path contains a malformed path component [path: " + opts.TreePath + "]" | expectedError := "path contains a malformed path component [path: " + opts.TreePath + "]" |
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
"code.gitea.io/gitea/modules/test" | "code.gitea.io/gitea/modules/test" | ||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
"github.com/stretchr/testify/assert" | "github.com/stretchr/testify/assert" | ||||
) | ) | ||||
func getCreateRepoFileOptions(repo *models.Repository) *repofiles.UpdateRepoFileOptions { | |||||
return &repofiles.UpdateRepoFileOptions{ | |||||
func getCreateRepoFileOptions(repo *models.Repository) *files_service.UpdateRepoFileOptions { | |||||
return &files_service.UpdateRepoFileOptions{ | |||||
OldBranch: repo.DefaultBranch, | OldBranch: repo.DefaultBranch, | ||||
NewBranch: repo.DefaultBranch, | NewBranch: repo.DefaultBranch, | ||||
TreePath: "new/file.txt", | TreePath: "new/file.txt", | ||||
} | } | ||||
} | } | ||||
func getUpdateRepoFileOptions(repo *models.Repository) *repofiles.UpdateRepoFileOptions { | |||||
return &repofiles.UpdateRepoFileOptions{ | |||||
func getUpdateRepoFileOptions(repo *models.Repository) *files_service.UpdateRepoFileOptions { | |||||
return &files_service.UpdateRepoFileOptions{ | |||||
OldBranch: repo.DefaultBranch, | OldBranch: repo.DefaultBranch, | ||||
NewBranch: repo.DefaultBranch, | NewBranch: repo.DefaultBranch, | ||||
TreePath: "README.md", | TreePath: "README.md", | ||||
opts := getCreateRepoFileOptions(repo) | opts := getCreateRepoFileOptions(repo) | ||||
// test | // test | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
// asserts | // asserts | ||||
assert.NoError(t, err) | assert.NoError(t, err) | ||||
opts := getUpdateRepoFileOptions(repo) | opts := getUpdateRepoFileOptions(repo) | ||||
// test | // test | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
// asserts | // asserts | ||||
assert.NoError(t, err) | assert.NoError(t, err) | ||||
opts.TreePath = "README_new.md" // new file name, README_new.md | opts.TreePath = "README_new.md" // new file name, README_new.md | ||||
// test | // test | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
// asserts | // asserts | ||||
assert.NoError(t, err) | assert.NoError(t, err) | ||||
opts.NewBranch = "" | opts.NewBranch = "" | ||||
// test | // test | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
// asserts | // asserts | ||||
assert.NoError(t, err) | assert.NoError(t, err) | ||||
t.Run("bad branch", func(t *testing.T) { | t.Run("bad branch", func(t *testing.T) { | ||||
opts := getUpdateRepoFileOptions(repo) | opts := getUpdateRepoFileOptions(repo) | ||||
opts.OldBranch = "bad_branch" | opts.OldBranch = "bad_branch" | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
assert.Error(t, err) | assert.Error(t, err) | ||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
expectedError := "branch does not exist [name: " + opts.OldBranch + "]" | expectedError := "branch does not exist [name: " + opts.OldBranch + "]" | ||||
opts := getUpdateRepoFileOptions(repo) | opts := getUpdateRepoFileOptions(repo) | ||||
origSHA := opts.SHA | origSHA := opts.SHA | ||||
opts.SHA = "bad_sha" | opts.SHA = "bad_sha" | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
assert.Error(t, err) | assert.Error(t, err) | ||||
expectedError := "sha does not match [given: " + opts.SHA + ", expected: " + origSHA + "]" | expectedError := "sha does not match [given: " + opts.SHA + ", expected: " + origSHA + "]" | ||||
t.Run("new branch already exists", func(t *testing.T) { | t.Run("new branch already exists", func(t *testing.T) { | ||||
opts := getUpdateRepoFileOptions(repo) | opts := getUpdateRepoFileOptions(repo) | ||||
opts.NewBranch = "develop" | opts.NewBranch = "develop" | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
assert.Error(t, err) | assert.Error(t, err) | ||||
expectedError := "branch already exists [name: " + opts.NewBranch + "]" | expectedError := "branch already exists [name: " + opts.NewBranch + "]" | ||||
t.Run("treePath is empty:", func(t *testing.T) { | t.Run("treePath is empty:", func(t *testing.T) { | ||||
opts := getUpdateRepoFileOptions(repo) | opts := getUpdateRepoFileOptions(repo) | ||||
opts.TreePath = "" | opts.TreePath = "" | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
assert.Error(t, err) | assert.Error(t, err) | ||||
expectedError := "path contains a malformed path component [path: ]" | expectedError := "path contains a malformed path component [path: ]" | ||||
t.Run("treePath is a git directory:", func(t *testing.T) { | t.Run("treePath is a git directory:", func(t *testing.T) { | ||||
opts := getUpdateRepoFileOptions(repo) | opts := getUpdateRepoFileOptions(repo) | ||||
opts.TreePath = ".git" | opts.TreePath = ".git" | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
assert.Error(t, err) | assert.Error(t, err) | ||||
expectedError := "path contains a malformed path component [path: " + opts.TreePath + "]" | expectedError := "path contains a malformed path component [path: " + opts.TreePath + "]" | ||||
t.Run("create file that already exists", func(t *testing.T) { | t.Run("create file that already exists", func(t *testing.T) { | ||||
opts := getCreateRepoFileOptions(repo) | opts := getCreateRepoFileOptions(repo) | ||||
opts.TreePath = "README.md" //already exists | opts.TreePath = "README.md" //already exists | ||||
fileResponse, err := repofiles.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) | |||||
assert.Nil(t, fileResponse) | assert.Nil(t, fileResponse) | ||||
assert.Error(t, err) | assert.Error(t, err) | ||||
expectedError := "repository file already exists [path: " + opts.TreePath + "]" | expectedError := "repository file already exists [path: " + opts.TreePath + "]" |
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
repo_module "code.gitea.io/gitea/modules/repository" | |||||
api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
) | ) | ||||
}, | }, | ||||
} | } | ||||
baseBranch, err = repo_module.GetBranch(pr.BaseRepo, pr.BaseBranch) | |||||
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath()) | |||||
if err != nil { | |||||
log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err) | |||||
return nil | |||||
} | |||||
defer gitRepo.Close() | |||||
baseBranch, err = gitRepo.GetBranch(pr.BaseBranch) | |||||
if err != nil && !git.IsErrBranchNotExist(err) { | if err != nil && !git.IsErrBranchNotExist(err) { | ||||
log.Error("GetBranch[%s]: %v", pr.BaseBranch, err) | log.Error("GetBranch[%s]: %v", pr.BaseBranch, err) | ||||
return nil | return nil |
// Copyright 2019 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 repofiles | |||||
import ( | |||||
"net/url" | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/git" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
api "code.gitea.io/gitea/modules/structs" | |||||
) | |||||
// GetBlobBySHA get the GitBlobResponse of a repository using a sha hash. | |||||
func GetBlobBySHA(repo *models.Repository, sha string) (*api.GitBlobResponse, error) { | |||||
gitRepo, err := git.OpenRepository(repo.RepoPath()) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
defer gitRepo.Close() | |||||
gitBlob, err := gitRepo.GetBlob(sha) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
content := "" | |||||
if gitBlob.Size() <= setting.API.DefaultMaxBlobSize { | |||||
content, err = gitBlob.GetBlobContentBase64() | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
} | |||||
return &api.GitBlobResponse{ | |||||
SHA: gitBlob.ID.String(), | |||||
URL: repo.APIURL() + "/git/blobs/" + url.PathEscape(gitBlob.ID.String()), | |||||
Size: gitBlob.Size(), | |||||
Encoding: "base64", | |||||
Content: content, | |||||
}, nil | |||||
} |
// Copyright 2019 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 repofiles | |||||
import ( | |||||
"testing" | |||||
"code.gitea.io/gitea/models/unittest" | |||||
api "code.gitea.io/gitea/modules/structs" | |||||
"code.gitea.io/gitea/modules/test" | |||||
"github.com/stretchr/testify/assert" | |||||
) | |||||
func TestGetBlobBySHA(t *testing.T) { | |||||
unittest.PrepareTestEnv(t) | |||||
ctx := test.MockContext(t, "user2/repo1") | |||||
test.LoadRepo(t, ctx, 1) | |||||
test.LoadRepoCommit(t, ctx) | |||||
test.LoadUser(t, ctx, 2) | |||||
test.LoadGitRepo(t, ctx) | |||||
defer ctx.Repo.GitRepo.Close() | |||||
sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d" | |||||
ctx.SetParams(":id", "1") | |||||
ctx.SetParams(":sha", sha) | |||||
gbr, err := GetBlobBySHA(ctx.Repo.Repository, ctx.Params(":sha")) | |||||
expectedGBR := &api.GitBlobResponse{ | |||||
Content: "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK", | |||||
Encoding: "base64", | |||||
URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/65f1bf27bc3bf70f64657658635e66094edbcb4d", | |||||
SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d", | |||||
Size: 180, | |||||
} | |||||
assert.NoError(t, err) | |||||
assert.Equal(t, expectedGBR, gbr) | |||||
} |
// Copyright 2019 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 repofiles | |||||
import ( | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/git" | |||||
) | |||||
// CountDivergingCommits determines how many commits a branch is ahead or behind the repository's base branch | |||||
func CountDivergingCommits(repo *models.Repository, branch string) (*git.DivergeObject, error) { | |||||
divergence, err := git.GetDivergingCommits(repo.RepoPath(), repo.DefaultBranch, branch) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
return &divergence, nil | |||||
} |
// Copyright 2019 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 repofiles | |||||
import ( | |||||
"fmt" | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/git" | |||||
) | |||||
// CreateCommitStatus creates a new CommitStatus given a bunch of parameters | |||||
// NOTE: All text-values will be trimmed from whitespaces. | |||||
// Requires: Repo, Creator, SHA | |||||
func CreateCommitStatus(repo *models.Repository, creator *models.User, sha string, status *models.CommitStatus) error { | |||||
repoPath := repo.RepoPath() | |||||
// confirm that commit is exist | |||||
gitRepo, err := git.OpenRepository(repoPath) | |||||
if err != nil { | |||||
return fmt.Errorf("OpenRepository[%s]: %v", repoPath, err) | |||||
} | |||||
if _, err := gitRepo.GetCommit(sha); err != nil { | |||||
gitRepo.Close() | |||||
return fmt.Errorf("GetCommit[%s]: %v", sha, err) | |||||
} | |||||
gitRepo.Close() | |||||
if err := models.NewCommitStatus(models.NewCommitStatusOptions{ | |||||
Repo: repo, | |||||
Creator: creator, | |||||
SHA: sha, | |||||
CommitStatus: status, | |||||
}); err != nil { | |||||
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %v", repo.ID, creator.ID, sha, err) | |||||
} | |||||
return nil | |||||
} |
// Copyright 2019 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 repofiles | |||||
package repofiles | |||||
import ( | |||||
"path" | |||||
"strings" | |||||
) | |||||
// CleanUploadFileName Trims a filename and returns empty string if it is a .git directory | |||||
func CleanUploadFileName(name string) string { | |||||
// Rebase the filename | |||||
name = strings.Trim(path.Clean("/"+name), " /") | |||||
// Git disallows any filenames to have a .git directory in them. | |||||
for _, part := range strings.Split(name, "/") { | |||||
if strings.ToLower(part) == ".git" { | |||||
return "" | |||||
} | |||||
} | |||||
return name | |||||
} |
// Copyright 2019 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 repofiles | |||||
import ( | |||||
"testing" | |||||
"github.com/stretchr/testify/assert" | |||||
) | |||||
func TestCleanUploadFileName(t *testing.T) { | |||||
t.Run("Clean regular file", func(t *testing.T) { | |||||
name := "this/is/test" | |||||
cleanName := CleanUploadFileName(name) | |||||
expectedCleanName := name | |||||
assert.EqualValues(t, expectedCleanName, cleanName) | |||||
}) | |||||
t.Run("Clean a .git path", func(t *testing.T) { | |||||
name := "this/is/test/.git" | |||||
cleanName := CleanUploadFileName(name) | |||||
expectedCleanName := "" | |||||
assert.EqualValues(t, expectedCleanName, cleanName) | |||||
}) | |||||
} |
// Copyright 2019 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 repofiles | |||||
import ( | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/git" | |||||
"code.gitea.io/gitea/modules/structs" | |||||
) | |||||
// GetPayloadCommitVerification returns the verification information of a commit | |||||
func GetPayloadCommitVerification(commit *git.Commit) *structs.PayloadCommitVerification { | |||||
verification := &structs.PayloadCommitVerification{} | |||||
commitVerification := models.ParseCommitWithSignature(commit) | |||||
if commit.Signature != nil { | |||||
verification.Signature = commit.Signature.Signature | |||||
verification.Payload = commit.Signature.Payload | |||||
} | |||||
if commitVerification.SigningUser != nil { | |||||
verification.Signer = &structs.PayloadUser{ | |||||
Name: commitVerification.SigningUser.Name, | |||||
Email: commitVerification.SigningUser.Email, | |||||
} | |||||
} | |||||
verification.Verified = commitVerification.Verified | |||||
verification.Reason = commitVerification.Reason | |||||
if verification.Reason == "" && !verification.Verified { | |||||
verification.Reason = "gpg.error.not_signed_commit" | |||||
} | |||||
return verification | |||||
} |
// Copyright 2020 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 repository | |||||
import ( | |||||
"fmt" | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/git" | |||||
) | |||||
// GetBranch returns a branch by its name | |||||
func GetBranch(repo *models.Repository, branch string) (*git.Branch, error) { | |||||
if len(branch) == 0 { | |||||
return nil, fmt.Errorf("GetBranch: empty string for branch") | |||||
} | |||||
gitRepo, err := git.OpenRepository(repo.RepoPath()) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
defer gitRepo.Close() | |||||
return gitRepo.GetBranch(branch) | |||||
} |
"net/http" | "net/http" | ||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
) | ) | ||||
// GetBlob get the blob of a repository file. | // GetBlob get the blob of a repository file. | ||||
ctx.Error(http.StatusBadRequest, "", "sha not provided") | ctx.Error(http.StatusBadRequest, "", "sha not provided") | ||||
return | return | ||||
} | } | ||||
if blob, err := repofiles.GetBlobBySHA(ctx.Repo.Repository, sha); err != nil { | |||||
if blob, err := files_service.GetBlobBySHA(ctx.Repo.Repository, sha); err != nil { | |||||
ctx.Error(http.StatusBadRequest, "", err) | ctx.Error(http.StatusBadRequest, "", err) | ||||
} else { | } else { | ||||
ctx.JSON(http.StatusOK, blob) | ctx.JSON(http.StatusOK, blob) |
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/convert" | "code.gitea.io/gitea/modules/convert" | ||||
"code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
repo_module "code.gitea.io/gitea/modules/repository" | |||||
api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
"code.gitea.io/gitea/modules/web" | "code.gitea.io/gitea/modules/web" | ||||
"code.gitea.io/gitea/routers/api/v1/utils" | "code.gitea.io/gitea/routers/api/v1/utils" | ||||
branchName := ctx.Params("*") | branchName := ctx.Params("*") | ||||
branch, err := repo_module.GetBranch(ctx.Repo.Repository, branchName) | |||||
branch, err := repo_service.GetBranch(ctx.Repo.Repository, branchName) | |||||
if err != nil { | if err != nil { | ||||
if git.IsErrBranchNotExist(err) { | if git.IsErrBranchNotExist(err) { | ||||
ctx.NotFound(err) | ctx.NotFound(err) | ||||
return | return | ||||
} | } | ||||
branch, err := repo_module.GetBranch(ctx.Repo.Repository, opt.BranchName) | |||||
branch, err := repo_service.GetBranch(ctx.Repo.Repository, opt.BranchName) | |||||
if err != nil { | if err != nil { | ||||
ctx.Error(http.StatusInternalServerError, "GetBranch", err) | ctx.Error(http.StatusInternalServerError, "GetBranch", err) | ||||
return | return |
"code.gitea.io/gitea/models/unit" | "code.gitea.io/gitea/models/unit" | ||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
"code.gitea.io/gitea/modules/web" | "code.gitea.io/gitea/modules/web" | ||||
"code.gitea.io/gitea/routers/common" | "code.gitea.io/gitea/routers/common" | ||||
"code.gitea.io/gitea/routers/web/repo" | "code.gitea.io/gitea/routers/web/repo" | ||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
) | ) | ||||
// GetRawFile get a file by path on a repository | // GetRawFile get a file by path on a repository | ||||
apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch | apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch | ||||
} | } | ||||
opts := &repofiles.UpdateRepoFileOptions{ | |||||
opts := &files_service.UpdateRepoFileOptions{ | |||||
Content: apiOpts.Content, | Content: apiOpts.Content, | ||||
IsNewFile: true, | IsNewFile: true, | ||||
Message: apiOpts.Message, | Message: apiOpts.Message, | ||||
TreePath: ctx.Params("*"), | TreePath: ctx.Params("*"), | ||||
OldBranch: apiOpts.BranchName, | OldBranch: apiOpts.BranchName, | ||||
NewBranch: apiOpts.NewBranchName, | NewBranch: apiOpts.NewBranchName, | ||||
Committer: &repofiles.IdentityOptions{ | |||||
Committer: &files_service.IdentityOptions{ | |||||
Name: apiOpts.Committer.Name, | Name: apiOpts.Committer.Name, | ||||
Email: apiOpts.Committer.Email, | Email: apiOpts.Committer.Email, | ||||
}, | }, | ||||
Author: &repofiles.IdentityOptions{ | |||||
Author: &files_service.IdentityOptions{ | |||||
Name: apiOpts.Author.Name, | Name: apiOpts.Author.Name, | ||||
Email: apiOpts.Author.Email, | Email: apiOpts.Author.Email, | ||||
}, | }, | ||||
Dates: &repofiles.CommitDateOptions{ | |||||
Dates: &files_service.CommitDateOptions{ | |||||
Author: apiOpts.Dates.Author, | Author: apiOpts.Dates.Author, | ||||
Committer: apiOpts.Dates.Committer, | Committer: apiOpts.Dates.Committer, | ||||
}, | }, | ||||
apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch | apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch | ||||
} | } | ||||
opts := &repofiles.UpdateRepoFileOptions{ | |||||
opts := &files_service.UpdateRepoFileOptions{ | |||||
Content: apiOpts.Content, | Content: apiOpts.Content, | ||||
SHA: apiOpts.SHA, | SHA: apiOpts.SHA, | ||||
IsNewFile: false, | IsNewFile: false, | ||||
TreePath: ctx.Params("*"), | TreePath: ctx.Params("*"), | ||||
OldBranch: apiOpts.BranchName, | OldBranch: apiOpts.BranchName, | ||||
NewBranch: apiOpts.NewBranchName, | NewBranch: apiOpts.NewBranchName, | ||||
Committer: &repofiles.IdentityOptions{ | |||||
Committer: &files_service.IdentityOptions{ | |||||
Name: apiOpts.Committer.Name, | Name: apiOpts.Committer.Name, | ||||
Email: apiOpts.Committer.Email, | Email: apiOpts.Committer.Email, | ||||
}, | }, | ||||
Author: &repofiles.IdentityOptions{ | |||||
Author: &files_service.IdentityOptions{ | |||||
Name: apiOpts.Author.Name, | Name: apiOpts.Author.Name, | ||||
Email: apiOpts.Author.Email, | Email: apiOpts.Author.Email, | ||||
}, | }, | ||||
Dates: &repofiles.CommitDateOptions{ | |||||
Dates: &files_service.CommitDateOptions{ | |||||
Author: apiOpts.Dates.Author, | Author: apiOpts.Dates.Author, | ||||
Committer: apiOpts.Dates.Committer, | Committer: apiOpts.Dates.Committer, | ||||
}, | }, | ||||
} | } | ||||
// Called from both CreateFile or UpdateFile to handle both | // Called from both CreateFile or UpdateFile to handle both | ||||
func createOrUpdateFile(ctx *context.APIContext, opts *repofiles.UpdateRepoFileOptions) (*api.FileResponse, error) { | |||||
func createOrUpdateFile(ctx *context.APIContext, opts *files_service.UpdateRepoFileOptions) (*api.FileResponse, error) { | |||||
if !canWriteFiles(ctx.Repo) { | if !canWriteFiles(ctx.Repo) { | ||||
return nil, models.ErrUserDoesNotHaveAccessToRepo{ | return nil, models.ErrUserDoesNotHaveAccessToRepo{ | ||||
UserID: ctx.User.ID, | UserID: ctx.User.ID, | ||||
} | } | ||||
opts.Content = string(content) | opts.Content = string(content) | ||||
return repofiles.CreateOrUpdateRepoFile(ctx.Repo.Repository, ctx.User, opts) | |||||
return files_service.CreateOrUpdateRepoFile(ctx.Repo.Repository, ctx.User, opts) | |||||
} | } | ||||
// DeleteFile Delete a fle in a repository | // DeleteFile Delete a fle in a repository | ||||
apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch | apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch | ||||
} | } | ||||
opts := &repofiles.DeleteRepoFileOptions{ | |||||
opts := &files_service.DeleteRepoFileOptions{ | |||||
Message: apiOpts.Message, | Message: apiOpts.Message, | ||||
OldBranch: apiOpts.BranchName, | OldBranch: apiOpts.BranchName, | ||||
NewBranch: apiOpts.NewBranchName, | NewBranch: apiOpts.NewBranchName, | ||||
SHA: apiOpts.SHA, | SHA: apiOpts.SHA, | ||||
TreePath: ctx.Params("*"), | TreePath: ctx.Params("*"), | ||||
Committer: &repofiles.IdentityOptions{ | |||||
Committer: &files_service.IdentityOptions{ | |||||
Name: apiOpts.Committer.Name, | Name: apiOpts.Committer.Name, | ||||
Email: apiOpts.Committer.Email, | Email: apiOpts.Committer.Email, | ||||
}, | }, | ||||
Author: &repofiles.IdentityOptions{ | |||||
Author: &files_service.IdentityOptions{ | |||||
Name: apiOpts.Author.Name, | Name: apiOpts.Author.Name, | ||||
Email: apiOpts.Author.Email, | Email: apiOpts.Author.Email, | ||||
}, | }, | ||||
Dates: &repofiles.CommitDateOptions{ | |||||
Dates: &files_service.CommitDateOptions{ | |||||
Author: apiOpts.Dates.Author, | Author: apiOpts.Dates.Author, | ||||
Committer: apiOpts.Dates.Committer, | Committer: apiOpts.Dates.Committer, | ||||
}, | }, | ||||
opts.Message = ctx.Tr("repo.editor.delete", opts.TreePath) | opts.Message = ctx.Tr("repo.editor.delete", opts.TreePath) | ||||
} | } | ||||
if fileResponse, err := repofiles.DeleteRepoFile(ctx.Repo.Repository, ctx.User, opts); err != nil { | |||||
if fileResponse, err := files_service.DeleteRepoFile(ctx.Repo.Repository, ctx.User, opts); err != nil { | |||||
if git.IsErrBranchNotExist(err) || models.IsErrRepoFileDoesNotExist(err) || git.IsErrNotExist(err) { | if git.IsErrBranchNotExist(err) || models.IsErrRepoFileDoesNotExist(err) || git.IsErrNotExist(err) { | ||||
ctx.Error(http.StatusNotFound, "DeleteFile", err) | ctx.Error(http.StatusNotFound, "DeleteFile", err) | ||||
return | return | ||||
treePath := ctx.Params("*") | treePath := ctx.Params("*") | ||||
ref := ctx.FormTrim("ref") | ref := ctx.FormTrim("ref") | ||||
if fileList, err := repofiles.GetContentsOrList(ctx.Repo.Repository, treePath, ref); err != nil { | |||||
if fileList, err := files_service.GetContentsOrList(ctx.Repo.Repository, treePath, ref); err != nil { | |||||
if git.IsErrNotExist(err) { | if git.IsErrNotExist(err) { | ||||
ctx.NotFound("GetContentsOrList", err) | ctx.NotFound("GetContentsOrList", err) | ||||
return | return |
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/convert" | "code.gitea.io/gitea/modules/convert" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
"code.gitea.io/gitea/modules/web" | "code.gitea.io/gitea/modules/web" | ||||
"code.gitea.io/gitea/routers/api/v1/utils" | "code.gitea.io/gitea/routers/api/v1/utils" | ||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
) | ) | ||||
// NewCommitStatus creates a new CommitStatus | // NewCommitStatus creates a new CommitStatus | ||||
Description: form.Description, | Description: form.Description, | ||||
Context: form.Context, | Context: form.Context, | ||||
} | } | ||||
if err := repofiles.CreateCommitStatus(ctx.Repo.Repository, ctx.User, sha, status); err != nil { | |||||
if err := files_service.CreateCommitStatus(ctx.Repo.Repository, ctx.User, sha, status); err != nil { | |||||
ctx.Error(http.StatusInternalServerError, "CreateCommitStatus", err) | ctx.Error(http.StatusInternalServerError, "CreateCommitStatus", err) | ||||
return | return | ||||
} | } |
"net/http" | "net/http" | ||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
) | ) | ||||
// GetTree get the tree of a repository. | // GetTree get the tree of a repository. | ||||
ctx.Error(http.StatusBadRequest, "", "sha not provided") | ctx.Error(http.StatusBadRequest, "", "sha not provided") | ||||
return | return | ||||
} | } | ||||
if tree, err := repofiles.GetTreeBySHA(ctx.Repo.Repository, sha, ctx.FormInt("page"), ctx.FormInt("per_page"), ctx.FormBool("recursive")); err != nil { | |||||
if tree, err := files_service.GetTreeBySHA(ctx.Repo.Repository, sha, ctx.FormInt("page"), ctx.FormInt("per_page"), ctx.FormBool("recursive")); err != nil { | |||||
ctx.Error(http.StatusBadRequest, "", err.Error()) | ctx.Error(http.StatusBadRequest, "", err.Error()) | ||||
} else { | } else { | ||||
ctx.JSON(http.StatusOK, tree) | ctx.JSON(http.StatusOK, tree) |
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
repo_module "code.gitea.io/gitea/modules/repository" | repo_module "code.gitea.io/gitea/modules/repository" | ||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"code.gitea.io/gitea/modules/util" | "code.gitea.io/gitea/modules/util" | ||||
"code.gitea.io/gitea/services/forms" | "code.gitea.io/gitea/services/forms" | ||||
release_service "code.gitea.io/gitea/services/release" | release_service "code.gitea.io/gitea/services/release" | ||||
repo_service "code.gitea.io/gitea/services/repository" | repo_service "code.gitea.io/gitea/services/repository" | ||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
) | ) | ||||
const ( | const ( | ||||
// loadBranches loads branches from the repository limited by page & pageSize. | // loadBranches loads branches from the repository limited by page & pageSize. | ||||
// NOTE: May write to context on error. | // NOTE: May write to context on error. | ||||
func loadBranches(ctx *context.Context, skip, limit int) ([]*Branch, int) { | func loadBranches(ctx *context.Context, skip, limit int) ([]*Branch, int) { | ||||
defaultBranch, err := repo_module.GetBranch(ctx.Repo.Repository, ctx.Repo.Repository.DefaultBranch) | |||||
defaultBranch, err := repo_service.GetBranch(ctx.Repo.Repository, ctx.Repo.Repository.DefaultBranch) | |||||
if err != nil { | if err != nil { | ||||
log.Error("loadBranches: get default branch: %v", err) | log.Error("loadBranches: get default branch: %v", err) | ||||
ctx.ServerError("GetDefaultBranch", err) | ctx.ServerError("GetDefaultBranch", err) | ||||
} | } | ||||
} | } | ||||
divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, git.BranchPrefix+branchName) | |||||
divergence, divergenceError := files_service.CountDivergingCommits(ctx.Repo.Repository, git.BranchPrefix+branchName) | |||||
if divergenceError != nil { | if divergenceError != nil { | ||||
ctx.ServerError("CountDivergingCommits", divergenceError) | ctx.ServerError("CountDivergingCommits", divergenceError) | ||||
return nil | return nil |
"code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
"code.gitea.io/gitea/modules/json" | "code.gitea.io/gitea/modules/json" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
"code.gitea.io/gitea/modules/repofiles" | |||||
repo_module "code.gitea.io/gitea/modules/repository" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"code.gitea.io/gitea/modules/typesniffer" | "code.gitea.io/gitea/modules/typesniffer" | ||||
"code.gitea.io/gitea/modules/upload" | "code.gitea.io/gitea/modules/upload" | ||||
"code.gitea.io/gitea/modules/web" | "code.gitea.io/gitea/modules/web" | ||||
"code.gitea.io/gitea/routers/utils" | "code.gitea.io/gitea/routers/utils" | ||||
"code.gitea.io/gitea/services/forms" | "code.gitea.io/gitea/services/forms" | ||||
repo_service "code.gitea.io/gitea/services/repository" | |||||
files_service "code.gitea.io/gitea/services/repository/files" | |||||
) | ) | ||||
const ( | const ( | ||||
message += "\n\n" + form.CommitMessage | message += "\n\n" + form.CommitMessage | ||||
} | } | ||||
if _, err := repofiles.CreateOrUpdateRepoFile(ctx.Repo.Repository, ctx.User, &repofiles.UpdateRepoFileOptions{ | |||||
if _, err := files_service.CreateOrUpdateRepoFile(ctx.Repo.Repository, ctx.User, &files_service.UpdateRepoFileOptions{ | |||||
LastCommitID: form.LastCommit, | LastCommitID: form.LastCommit, | ||||
OldBranch: ctx.Repo.BranchName, | OldBranch: ctx.Repo.BranchName, | ||||
NewBranch: branchName, | NewBranch: branchName, | ||||
IsNewFile: isNewFile, | IsNewFile: isNewFile, | ||||
Signoff: form.Signoff, | Signoff: form.Signoff, | ||||
}); err != nil { | }); err != nil { | ||||
// This is where we handle all the errors thrown by repofiles.CreateOrUpdateRepoFile | |||||
// This is where we handle all the errors thrown by files_service.CreateOrUpdateRepoFile | |||||
if git.IsErrNotExist(err) { | if git.IsErrNotExist(err) { | ||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_editing_no_longer_exists", ctx.Repo.TreePath), tplEditFile, &form) | ctx.RenderWithErr(ctx.Tr("repo.editor.file_editing_no_longer_exists", ctx.Repo.TreePath), tplEditFile, &form) | ||||
} else if models.IsErrLFSFileLocked(err) { | } else if models.IsErrLFSFileLocked(err) { | ||||
return | return | ||||
} | } | ||||
diff, err := repofiles.GetDiffPreview(ctx.Repo.Repository, ctx.Repo.BranchName, treePath, form.Content) | |||||
diff, err := files_service.GetDiffPreview(ctx.Repo.Repository, ctx.Repo.BranchName, treePath, form.Content) | |||||
if err != nil { | if err != nil { | ||||
ctx.Error(http.StatusInternalServerError, "GetDiffPreview: "+err.Error()) | ctx.Error(http.StatusInternalServerError, "GetDiffPreview: "+err.Error()) | ||||
return | return | ||||
message += "\n\n" + form.CommitMessage | message += "\n\n" + form.CommitMessage | ||||
} | } | ||||
if _, err := repofiles.DeleteRepoFile(ctx.Repo.Repository, ctx.User, &repofiles.DeleteRepoFileOptions{ | |||||
if _, err := files_service.DeleteRepoFile(ctx.Repo.Repository, ctx.User, &files_service.DeleteRepoFileOptions{ | |||||
LastCommitID: form.LastCommit, | LastCommitID: form.LastCommit, | ||||
OldBranch: ctx.Repo.BranchName, | OldBranch: ctx.Repo.BranchName, | ||||
NewBranch: branchName, | NewBranch: branchName, | ||||
} | } | ||||
if oldBranchName != branchName { | if oldBranchName != branchName { | ||||
if _, err := repo_module.GetBranch(ctx.Repo.Repository, branchName); err == nil { | |||||
if _, err := repo_service.GetBranch(ctx.Repo.Repository, branchName); err == nil { | |||||
ctx.Data["Err_NewBranchName"] = true | ctx.Data["Err_NewBranchName"] = true | ||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), tplUploadFile, &form) | ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), tplUploadFile, &form) | ||||
return | return | ||||
message += "\n\n" + form.CommitMessage | message += "\n\n" + form.CommitMessage | ||||
} | } | ||||
if err := repofiles.UploadRepoFiles(ctx.Repo.Repository, ctx.User, &repofiles.UploadRepoFileOptions{ | |||||
if err := files_service.UploadRepoFiles(ctx.Repo.Repository, ctx.User, &files_service.UploadRepoFileOptions{ | |||||
LastCommitID: ctx.Repo.CommitID, | LastCommitID: ctx.Repo.CommitID, | ||||
OldBranch: oldBranchName, | OldBranch: oldBranchName, | ||||
NewBranch: branchName, | NewBranch: branchName, | ||||
prefix := ctx.User.LowerName + "-patch-" | prefix := ctx.User.LowerName + "-patch-" | ||||
for i := 1; i <= 1000; i++ { | for i := 1; i <= 1000; i++ { | ||||
branchName := fmt.Sprintf("%s%d", prefix, i) | branchName := fmt.Sprintf("%s%d", prefix, i) | ||||
if _, err := repo_module.GetBranch(ctx.Repo.Repository, branchName); err != nil { | |||||
if _, err := repo_service.GetBranch(ctx.Repo.Repository, branchName); err != nil { | |||||
if git.IsErrBranchNotExist(err) { | if git.IsErrBranchNotExist(err) { | ||||
return branchName | return branchName | ||||
} | } |
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/models/webhook" | "code.gitea.io/gitea/models/webhook" | ||||
repository_service "code.gitea.io/gitea/modules/repository" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"code.gitea.io/gitea/services/auth" | "code.gitea.io/gitea/services/auth" | ||||
"code.gitea.io/gitea/services/migrations" | "code.gitea.io/gitea/services/migrations" | ||||
mirror_service "code.gitea.io/gitea/services/mirror" | mirror_service "code.gitea.io/gitea/services/mirror" | ||||
repository_service "code.gitea.io/gitea/services/repository" | |||||
) | ) | ||||
func registerUpdateMirrorTask() { | func registerUpdateMirrorTask() { |
"time" | "time" | ||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
repo_module "code.gitea.io/gitea/modules/repository" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"code.gitea.io/gitea/modules/updatechecker" | "code.gitea.io/gitea/modules/updatechecker" | ||||
repo_service "code.gitea.io/gitea/services/repository" | repo_service "code.gitea.io/gitea/services/repository" | ||||
Args: setting.Git.GCArgs, | Args: setting.Git.GCArgs, | ||||
}, func(ctx context.Context, _ *models.User, config Config) error { | }, func(ctx context.Context, _ *models.User, config Config) error { | ||||
rhcConfig := config.(*RepoHealthCheckConfig) | rhcConfig := config.(*RepoHealthCheckConfig) | ||||
return repo_module.GitGcRepos(ctx, rhcConfig.Timeout, rhcConfig.Args...) | |||||
return repo_service.GitGcRepos(ctx, rhcConfig.Timeout, rhcConfig.Args...) | |||||
}) | }) | ||||
} | } | ||||
RunAtStart: false, | RunAtStart: false, | ||||
Schedule: "@every 72h", | Schedule: "@every 72h", | ||||
}, func(ctx context.Context, _ *models.User, _ Config) error { | }, func(ctx context.Context, _ *models.User, _ Config) error { | ||||
return repo_module.ReinitMissingRepositories(ctx) | |||||
return repo_service.ReinitMissingRepositories(ctx) | |||||
}) | }) | ||||
} | } | ||||
RunAtStart: false, | RunAtStart: false, | ||||
Schedule: "@every 72h", | Schedule: "@every 72h", | ||||
}, func(ctx context.Context, user *models.User, _ Config) error { | }, func(ctx context.Context, user *models.User, _ Config) error { | ||||
return repo_module.DeleteMissingRepositories(ctx, user) | |||||
return repo_service.DeleteMissingRepositories(ctx, user) | |||||
}) | }) | ||||
} | } | ||||
return nil | return nil | ||||
} | } | ||||
// GetBranch returns a branch by its name | |||||
func GetBranch(repo *models.Repository, branch string) (*git.Branch, error) { | |||||
if len(branch) == 0 { | |||||
return nil, fmt.Errorf("GetBranch: empty string for branch") | |||||
} | |||||
gitRepo, err := git.OpenRepository(repo.RepoPath()) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
defer gitRepo.Close() | |||||
return gitRepo.GetBranch(branch) | |||||
} | |||||
// GetBranches returns branches from the repository, skipping skip initial branches and | // GetBranches returns branches from the repository, skipping skip initial branches and | ||||
// returning at most limit branches, or all branches if limit is 0. | // returning at most limit branches, or all branches if limit is 0. | ||||
func GetBranches(repo *models.Repository, skip, limit int) ([]*git.Branch, int, error) { | func GetBranches(repo *models.Repository, skip, limit int) ([]*git.Branch, int, error) { |
// Copyright 2019 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 files | |||||
import ( | |||||
"fmt" | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/git" | |||||
"code.gitea.io/gitea/modules/structs" | |||||
) | |||||
// CreateCommitStatus creates a new CommitStatus given a bunch of parameters | |||||
// NOTE: All text-values will be trimmed from whitespaces. | |||||
// Requires: Repo, Creator, SHA | |||||
func CreateCommitStatus(repo *models.Repository, creator *models.User, sha string, status *models.CommitStatus) error { | |||||
repoPath := repo.RepoPath() | |||||
// confirm that commit is exist | |||||
gitRepo, err := git.OpenRepository(repoPath) | |||||
if err != nil { | |||||
return fmt.Errorf("OpenRepository[%s]: %v", repoPath, err) | |||||
} | |||||
if _, err := gitRepo.GetCommit(sha); err != nil { | |||||
gitRepo.Close() | |||||
return fmt.Errorf("GetCommit[%s]: %v", sha, err) | |||||
} | |||||
gitRepo.Close() | |||||
if err := models.NewCommitStatus(models.NewCommitStatusOptions{ | |||||
Repo: repo, | |||||
Creator: creator, | |||||
SHA: sha, | |||||
CommitStatus: status, | |||||
}); err != nil { | |||||
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %v", repo.ID, creator.ID, sha, err) | |||||
} | |||||
return nil | |||||
} | |||||
// CountDivergingCommits determines how many commits a branch is ahead or behind the repository's base branch | |||||
func CountDivergingCommits(repo *models.Repository, branch string) (*git.DivergeObject, error) { | |||||
divergence, err := git.GetDivergingCommits(repo.RepoPath(), repo.DefaultBranch, branch) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
return &divergence, nil | |||||
} | |||||
// GetPayloadCommitVerification returns the verification information of a commit | |||||
func GetPayloadCommitVerification(commit *git.Commit) *structs.PayloadCommitVerification { | |||||
verification := &structs.PayloadCommitVerification{} | |||||
commitVerification := models.ParseCommitWithSignature(commit) | |||||
if commit.Signature != nil { | |||||
verification.Signature = commit.Signature.Signature | |||||
verification.Payload = commit.Signature.Payload | |||||
} | |||||
if commitVerification.SigningUser != nil { | |||||
verification.Signer = &structs.PayloadUser{ | |||||
Name: commitVerification.SigningUser.Name, | |||||
Email: commitVerification.SigningUser.Email, | |||||
} | |||||
} | |||||
verification.Verified = commitVerification.Verified | |||||
verification.Reason = commitVerification.Reason | |||||
if verification.Reason == "" && !verification.Verified { | |||||
verification.Reason = "gpg.error.not_signed_commit" | |||||
} | |||||
return verification | |||||
} |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"fmt" | "fmt" | ||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
"code.gitea.io/gitea/modules/setting" | |||||
api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
) | ) | ||||
return contentsResponse, nil | return contentsResponse, nil | ||||
} | } | ||||
// GetBlobBySHA get the GitBlobResponse of a repository using a sha hash. | |||||
func GetBlobBySHA(repo *models.Repository, sha string) (*api.GitBlobResponse, error) { | |||||
gitRepo, err := git.OpenRepository(repo.RepoPath()) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
defer gitRepo.Close() | |||||
gitBlob, err := gitRepo.GetBlob(sha) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
content := "" | |||||
if gitBlob.Size() <= setting.API.DefaultMaxBlobSize { | |||||
content, err = gitBlob.GetBlobContentBase64() | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
} | |||||
return &api.GitBlobResponse{ | |||||
SHA: gitBlob.ID.String(), | |||||
URL: repo.APIURL() + "/git/blobs/" + url.PathEscape(gitBlob.ID.String()), | |||||
Size: gitBlob.Size(), | |||||
Encoding: "base64", | |||||
Content: content, | |||||
}, nil | |||||
} |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"path/filepath" | "path/filepath" | ||||
) | ) | ||||
func TestMain(m *testing.M) { | func TestMain(m *testing.M) { | ||||
unittest.MainTest(m, filepath.Join("..", "..")) | |||||
unittest.MainTest(m, filepath.Join("..", "..", "..")) | |||||
} | } | ||||
func getExpectedReadmeContentsResponse() *api.ContentsResponse { | func getExpectedReadmeContentsResponse() *api.ContentsResponse { | ||||
assert.Empty(t, contents) | assert.Empty(t, contents) | ||||
}) | }) | ||||
} | } | ||||
func TestGetBlobBySHA(t *testing.T) { | |||||
unittest.PrepareTestEnv(t) | |||||
ctx := test.MockContext(t, "user2/repo1") | |||||
test.LoadRepo(t, ctx, 1) | |||||
test.LoadRepoCommit(t, ctx) | |||||
test.LoadUser(t, ctx, 2) | |||||
test.LoadGitRepo(t, ctx) | |||||
defer ctx.Repo.GitRepo.Close() | |||||
sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d" | |||||
ctx.SetParams(":id", "1") | |||||
ctx.SetParams(":sha", sha) | |||||
gbr, err := GetBlobBySHA(ctx.Repo.Repository, ctx.Params(":sha")) | |||||
expectedGBR := &api.GitBlobResponse{ | |||||
Content: "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK", | |||||
Encoding: "base64", | |||||
URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/65f1bf27bc3bf70f64657658635e66094edbcb4d", | |||||
SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d", | |||||
Size: 180, | |||||
} | |||||
assert.NoError(t, err) | |||||
assert.Equal(t, expectedGBR, gbr) | |||||
} |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"fmt" | "fmt" | ||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
repo_module "code.gitea.io/gitea/modules/repository" | |||||
api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
repo_service "code.gitea.io/gitea/services/repository" | |||||
) | ) | ||||
// DeleteRepoFileOptions holds the repository delete file options | // DeleteRepoFileOptions holds the repository delete file options | ||||
} | } | ||||
// oldBranch must exist for this operation | // oldBranch must exist for this operation | ||||
if _, err := repo_module.GetBranch(repo, opts.OldBranch); err != nil { | |||||
if _, err := repo_service.GetBranch(repo, opts.OldBranch); err != nil { | |||||
return nil, err | return nil, err | ||||
} | } | ||||
// Check to make sure the branch does not already exist, otherwise we can't proceed. | // Check to make sure the branch does not already exist, otherwise we can't proceed. | ||||
// If we aren't branching to a new branch, make sure user can commit to the given branch | // If we aren't branching to a new branch, make sure user can commit to the given branch | ||||
if opts.NewBranch != opts.OldBranch { | if opts.NewBranch != opts.OldBranch { | ||||
newBranch, err := repo_module.GetBranch(repo, opts.NewBranch) | |||||
newBranch, err := repo_service.GetBranch(repo, opts.NewBranch) | |||||
if err != nil && !git.IsErrBranchNotExist(err) { | if err != nil && !git.IsErrBranchNotExist(err) { | ||||
return nil, err | return nil, err | ||||
} | } |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"strings" | "strings" |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"testing" | "testing" |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"fmt" | "fmt" | ||||
"net/url" | "net/url" | ||||
"path" | |||||
"strings" | "strings" | ||||
"time" | "time" | ||||
} | } | ||||
return authorUser, committerUser | return authorUser, committerUser | ||||
} | } | ||||
// CleanUploadFileName Trims a filename and returns empty string if it is a .git directory | |||||
func CleanUploadFileName(name string) string { | |||||
// Rebase the filename | |||||
name = strings.Trim(path.Clean("/"+name), " /") | |||||
// Git disallows any filenames to have a .git directory in them. | |||||
for _, part := range strings.Split(name, "/") { | |||||
if strings.ToLower(part) == ".git" { | |||||
return "" | |||||
} | |||||
} | |||||
return name | |||||
} |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"testing" | "testing" | ||||
"github.com/stretchr/testify/assert" | "github.com/stretchr/testify/assert" | ||||
) | ) | ||||
func TestCleanUploadFileName(t *testing.T) { | |||||
t.Run("Clean regular file", func(t *testing.T) { | |||||
name := "this/is/test" | |||||
cleanName := CleanUploadFileName(name) | |||||
expectedCleanName := name | |||||
assert.EqualValues(t, expectedCleanName, cleanName) | |||||
}) | |||||
t.Run("Clean a .git path", func(t *testing.T) { | |||||
name := "this/is/test/.git" | |||||
cleanName := CleanUploadFileName(name) | |||||
expectedCleanName := "" | |||||
assert.EqualValues(t, expectedCleanName, cleanName) | |||||
}) | |||||
} | |||||
func getExpectedFileResponse() *api.FileResponse { | func getExpectedFileResponse() *api.FileResponse { | ||||
treePath := "README.md" | treePath := "README.md" | ||||
sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f" | sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f" |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"bytes" | "bytes" |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"fmt" | "fmt" |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"testing" | "testing" |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"bytes" | "bytes" | ||||
"code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
"code.gitea.io/gitea/modules/lfs" | "code.gitea.io/gitea/modules/lfs" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
repo_module "code.gitea.io/gitea/modules/repository" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"code.gitea.io/gitea/modules/structs" | "code.gitea.io/gitea/modules/structs" | ||||
"code.gitea.io/gitea/modules/util" | "code.gitea.io/gitea/modules/util" | ||||
repo_service "code.gitea.io/gitea/services/repository" | |||||
stdcharset "golang.org/x/net/html/charset" | stdcharset "golang.org/x/net/html/charset" | ||||
"golang.org/x/text/transform" | "golang.org/x/text/transform" | ||||
} | } | ||||
// oldBranch must exist for this operation | // oldBranch must exist for this operation | ||||
if _, err := repo_module.GetBranch(repo, opts.OldBranch); err != nil { | |||||
if _, err := repo_service.GetBranch(repo, opts.OldBranch); err != nil { | |||||
return nil, err | return nil, err | ||||
} | } | ||||
// Check to make sure the branch does not already exist, otherwise we can't proceed. | // Check to make sure the branch does not already exist, otherwise we can't proceed. | ||||
// If we aren't branching to a new branch, make sure user can commit to the given branch | // If we aren't branching to a new branch, make sure user can commit to the given branch | ||||
if opts.NewBranch != opts.OldBranch { | if opts.NewBranch != opts.OldBranch { | ||||
existingBranch, err := repo_module.GetBranch(repo, opts.NewBranch) | |||||
existingBranch, err := repo_service.GetBranch(repo, opts.NewBranch) | |||||
if existingBranch != nil { | if existingBranch != nil { | ||||
return nil, models.ErrBranchAlreadyExists{ | return nil, models.ErrBranchAlreadyExists{ | ||||
BranchName: opts.NewBranch, | BranchName: opts.NewBranch, |
// Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package repofiles | |||||
package files | |||||
import ( | import ( | ||||
"fmt" | "fmt" |