Browse Source

Move repofiles from modules/repofiles to services/repository/files (#17774)

* 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
Lunny Xiao 2 years ago
parent
commit
c97d66d23c
No account linked to committer's email address
37 changed files with 277 additions and 353 deletions
  1. 3
    3
      integrations/api_repo_file_helpers.go
  2. 9
    9
      integrations/pull_update_test.go
  3. 12
    12
      integrations/repofiles_delete_test.go
  4. 15
    15
      integrations/repofiles_update_test.go
  5. 8
    2
      modules/convert/pull.go
  6. 0
    41
      modules/repofiles/blob.go
  7. 0
    40
      modules/repofiles/blob_test.go
  8. 0
    19
      modules/repofiles/commit.go
  9. 0
    41
      modules/repofiles/commit_status.go
  10. 0
    23
      modules/repofiles/repofiles.go
  11. 0
    27
      modules/repofiles/repofiles_test.go
  12. 0
    33
      modules/repofiles/verification.go
  13. 0
    26
      modules/repository/branch.go
  14. 2
    2
      routers/api/v1/repo/blob.go
  15. 2
    3
      routers/api/v1/repo/branch.go
  16. 17
    17
      routers/api/v1/repo/file.go
  17. 2
    2
      routers/api/v1/repo/status.go
  18. 2
    2
      routers/api/v1/repo/tree.go
  19. 3
    3
      routers/web/repo/branch.go
  20. 9
    9
      routers/web/repo/editor.go
  21. 1
    1
      services/cron/tasks_basic.go
  22. 3
    4
      services/cron/tasks_extended.go
  23. 14
    0
      services/repository/branch.go
  24. 0
    0
      services/repository/check.go
  25. 73
    0
      services/repository/files/commit.go
  26. 29
    1
      services/repository/files/content.go
  27. 27
    2
      services/repository/files/content_test.go
  28. 4
    4
      services/repository/files/delete.go
  29. 1
    1
      services/repository/files/diff.go
  30. 1
    1
      services/repository/files/diff_test.go
  31. 15
    1
      services/repository/files/file.go
  32. 17
    1
      services/repository/files/file_test.go
  33. 1
    1
      services/repository/files/temp_repo.go
  34. 1
    1
      services/repository/files/tree.go
  35. 1
    1
      services/repository/files/tree_test.go
  36. 4
    4
      services/repository/files/update.go
  37. 1
    1
      services/repository/files/upload.go

+ 3
- 3
integrations/api_repo_file_helpers.go View File



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) {

+ 9
- 9
integrations/pull_update_test.go View File



"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(),
}, },

+ 12
- 12
integrations/repofiles_delete_test.go View File



"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 + "]"

+ 15
- 15
integrations/repofiles_update_test.go View File



"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 + "]"

+ 8
- 2
modules/convert/pull.go View File

"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

+ 0
- 41
modules/repofiles/blob.go View File

// 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
}

+ 0
- 40
modules/repofiles/blob_test.go View File

// 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)
}

+ 0
- 19
modules/repofiles/commit.go View File

// 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
}

+ 0
- 41
modules/repofiles/commit_status.go View File

// 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
}

+ 0
- 23
modules/repofiles/repofiles.go View File

// 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
}

+ 0
- 27
modules/repofiles/repofiles_test.go View File

// 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)
})
}

+ 0
- 33
modules/repofiles/verification.go View File

// 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
}

+ 0
- 26
modules/repository/branch.go View File

// 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)
}

+ 2
- 2
routers/api/v1/repo/blob.go View File

"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)

+ 2
- 3
routers/api/v1/repo/branch.go View File

"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

+ 17
- 17
routers/api/v1/repo/file.go View File

"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

+ 2
- 2
routers/api/v1/repo/status.go View File

"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
} }

+ 2
- 2
routers/api/v1/repo/tree.go View File

"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)

+ 3
- 3
routers/web/repo/branch.go View File

"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

+ 9
- 9
routers/web/repo/editor.go View File

"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
} }

+ 1
- 1
services/cron/tasks_basic.go View File



"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() {

+ 3
- 4
services/cron/tasks_extended.go View File

"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)
}) })
} }



+ 14
- 0
services/repository/branch.go View File

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) {

modules/repository/check.go → services/repository/check.go View File


+ 73
- 0
services/repository/files/commit.go View File

// 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
}

modules/repofiles/content.go → services/repository/files/content.go View File

// 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
}

modules/repofiles/content_test.go → services/repository/files/content_test.go View File

// 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)
}

modules/repofiles/delete.go → services/repository/files/delete.go View File

// 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
} }

modules/repofiles/diff.go → services/repository/files/diff.go View File

// 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"

modules/repofiles/diff_test.go → services/repository/files/diff_test.go View File

// 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"

modules/repofiles/file.go → services/repository/files/file.go View File

// 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
}

modules/repofiles/file_test.go → services/repository/files/file_test.go View File

// 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"

modules/repofiles/temp_repo.go → services/repository/files/temp_repo.go View File

// 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"

modules/repofiles/tree.go → services/repository/files/tree.go View File

// 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"

modules/repofiles/tree_test.go → services/repository/files/tree_test.go View File

// 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"

modules/repofiles/update.go → services/repository/files/update.go View File

// 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,

modules/repofiles/upload.go → services/repository/files/upload.go View File

// 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"

Loading…
Cancel
Save