Propagate context and ensure git commands run in request context (#17868)

This PR continues the work in #17125 by progressively ensuring that git
commands run within the request context.

This now means that the if there is a git repo already open in the context it will be used instead of reopening it.

Signed-off-by: Andrew Thornton <art27@cantab.net>
pull/18338/head^2
zeripath 3 years ago committed by GitHub
parent 4563148a61
commit 5cb0c9aa0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      cmd/admin.go
  2. 3
      cmd/doctor.go
  3. 3
      integrations/api_repo_file_helpers.go
  4. 2
      integrations/api_repo_get_contents_list_test.go
  5. 2
      integrations/api_repo_get_contents_test.go
  6. 4
      integrations/git_helper_for_declarative_test.go
  7. 2
      integrations/mirror_pull_test.go
  8. 6
      integrations/pull_merge_test.go
  9. 15
      integrations/pull_update_test.go
  10. 6
      integrations/repo_tag_test.go
  11. 17
      integrations/repofiles_delete_test.go
  12. 20
      integrations/repofiles_update_test.go
  13. 8
      models/admin/notice.go
  14. 7
      models/db/context.go
  15. 1
      models/db/engine.go
  16. 25
      models/issue_comment.go
  17. 5
      models/issue_comment_test.go
  18. 2
      models/issue_xref_test.go
  19. 3
      models/migrations/v136.go
  20. 2
      models/migrations/v156.go
  21. 2
      models/migrations/v82.go
  22. 3
      models/pull.go
  23. 3
      models/repo/repo.go
  24. 13
      models/repo_activity.go
  25. 20
      models/review.go
  26. 11
      models/review_test.go
  27. 18
      modules/context/api.go
  28. 6
      modules/context/context.go
  29. 41
      modules/context/private.go
  30. 10
      modules/context/repo.go
  31. 5
      modules/convert/git_commit.go
  32. 11
      modules/convert/pull.go
  33. 13
      modules/convert/pull_review.go
  34. 5
      modules/convert/pull_test.go
  35. 3
      modules/doctor/authorizedkeys.go
  36. 3
      modules/doctor/checkOldArchives.go
  37. 8
      modules/doctor/dbconsistency.go
  38. 6
      modules/doctor/dbversion.go
  39. 4
      modules/doctor/doctor.go
  40. 3
      modules/doctor/fix16961.go
  41. 11
      modules/doctor/mergebase.go
  42. 17
      modules/doctor/misc.go
  43. 3
      modules/doctor/paths.go
  44. 4
      modules/doctor/storage.go
  45. 4
      modules/doctor/usertype.go
  46. 6
      modules/git/blame.go
  47. 31
      modules/git/commit.go
  48. 2
      modules/git/commit_info_test.go
  49. 6
      modules/git/commit_test.go
  50. 14
      modules/git/diff.go
  51. 13
      modules/git/pipeline/catfile.go
  52. 2
      modules/git/pipeline/lfs.go
  53. 4
      modules/git/pipeline/lfs_nogogit.go
  54. 5
      modules/git/pipeline/namerev.go
  55. 9
      modules/git/pipeline/revlist.go
  56. 169
      modules/git/repo.go
  57. 49
      modules/git/repo_base.go
  58. 3
      modules/git/repo_base_gogit.go
  59. 3
      modules/git/repo_base_nogogit.go
  60. 4
      modules/git/repo_branch.go
  61. 6
      modules/git/repo_branch_gogit.go
  62. 6
      modules/git/repo_commit.go
  63. 15
      modules/git/repo_compare.go
  64. 2
      modules/git/repo_test.go
  65. 2
      modules/git/tree.go
  66. 16
      modules/git/tree_entry_nogogit.go
  67. 4
      modules/git/tree_nogogit.go
  68. 2
      modules/gitgraph/graph.go
  69. 13
      modules/indexer/code/bleve.go
  70. 10
      modules/indexer/code/elastic_search.go
  71. 23
      modules/indexer/code/git.go
  72. 12
      modules/indexer/code/indexer.go
  73. 3
      modules/indexer/code/indexer_test.go
  74. 5
      modules/indexer/code/wrapped.go
  75. 8
      modules/lfs/pointer_scanner_nogogit.go
  76. 2
      modules/markup/html.go
  77. 2
      modules/markup/html_test.go
  78. 3
      modules/markup/markdown/markdown_test.go
  79. 11
      modules/notification/action/action.go
  80. 4
      modules/notification/base/notifier.go
  81. 4
      modules/notification/base/null.go
  82. 32
      modules/notification/mail/mail.go
  83. 8
      modules/notification/notification.go
  84. 98
      modules/notification/webhook/webhook.go
  85. 16
      modules/process/manager.go
  86. 11
      modules/repository/commits.go
  87. 2
      modules/repository/commits_test.go
  88. 16
      modules/repository/generate.go
  89. 22
      modules/repository/init.go
  90. 5
      modules/repository/push.go
  91. 18
      modules/repository/repo.go
  92. 24
      modules/templates/helper.go
  93. 4
      modules/test/context_tests.go
  94. 10
      modules/web/route.go
  95. 12
      routers/api/v1/api.go
  96. 6
      routers/api/v1/misc/markdown.go
  97. 2
      routers/api/v1/misc/signing.go
  98. 2
      routers/api/v1/repo/blob.go
  99. 8
      routers/api/v1/repo/branch.go
  100. 31
      routers/api/v1/repo/commits.go
  101. Some files were not shown because too many files have changed in this diff Show More

@ -669,7 +669,7 @@ func runRepoSyncReleases(_ *cli.Context) error {
log.Trace("Processing next %d repos of %d", len(repos), count) log.Trace("Processing next %d repos of %d", len(repos), count)
for _, repo := range repos { for _, repo := range repos {
log.Trace("Synchronizing repo %s with path %s", repo.FullName(), repo.RepoPath()) log.Trace("Synchronizing repo %s with path %s", repo.FullName(), repo.RepoPath())
gitRepo, err := git.OpenRepository(repo.RepoPath()) gitRepo, err := git.OpenRepositoryCtx(ctx, repo.RepoPath())
if err != nil { if err != nil {
log.Warn("OpenRepository: %v", err) log.Warn("OpenRepository: %v", err)
continue continue

@ -5,7 +5,6 @@
package cmd package cmd
import ( import (
"context"
"fmt" "fmt"
golog "log" golog "log"
"os" "os"
@ -116,7 +115,7 @@ func runRecreateTable(ctx *cli.Context) error {
} }
recreateTables := migrations.RecreateTables(beans...) recreateTables := migrations.RecreateTables(beans...)
return db.InitEngineWithMigration(context.Background(), func(x *xorm.Engine) error { return db.InitEngineWithMigration(stdCtx, func(x *xorm.Engine) error {
if err := migrations.EnsureUpToDate(x); err != nil { if err := migrations.EnsureUpToDate(x); err != nil {
return err return err
} }

@ -7,6 +7,7 @@ package integrations
import ( import (
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
files_service "code.gitea.io/gitea/services/repository/files" files_service "code.gitea.io/gitea/services/repository/files"
) )
@ -20,7 +21,7 @@ func createFileInBranch(user *user_model.User, repo *repo_model.Repository, tree
Author: nil, Author: nil,
Committer: nil, Committer: nil,
} }
return files_service.CreateOrUpdateRepoFile(repo, user, opts) return files_service.CreateOrUpdateRepoFile(git.DefaultContext, repo, user, opts)
} }
func createFile(user *user_model.User, repo *repo_model.Repository, treePath string) (*api.FileResponse, error) { func createFile(user *user_model.User, repo *repo_model.Repository, treePath string) (*api.FileResponse, error) {

@ -72,7 +72,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
// Make a new branch in repo1 // Make a new branch in repo1
newBranch := "test_branch" newBranch := "test_branch"
err := repo_service.CreateNewBranch(user2, repo1, repo1.DefaultBranch, newBranch) err := repo_service.CreateNewBranch(git.DefaultContext, user2, repo1, repo1.DefaultBranch, newBranch)
assert.NoError(t, err) assert.NoError(t, err)
// Get the commit ID of the default branch // Get the commit ID of the default branch
gitRepo, err := git.OpenRepository(repo1.RepoPath()) gitRepo, err := git.OpenRepository(repo1.RepoPath())

@ -73,7 +73,7 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
// Make a new branch in repo1 // Make a new branch in repo1
newBranch := "test_branch" newBranch := "test_branch"
err := repo_service.CreateNewBranch(user2, repo1, repo1.DefaultBranch, newBranch) err := repo_service.CreateNewBranch(git.DefaultContext, user2, repo1, repo1.DefaultBranch, newBranch)
assert.NoError(t, err) assert.NoError(t, err)
// Get the commit ID of the default branch // Get the commit ID of the default branch
gitRepo, err := git.OpenRepository(repo1.RepoPath()) gitRepo, err := git.OpenRepository(repo1.RepoPath())

@ -128,7 +128,7 @@ func doGitCloneFail(u *url.URL) func(*testing.T) {
tmpDir, err := os.MkdirTemp("", "doGitCloneFail") tmpDir, err := os.MkdirTemp("", "doGitCloneFail")
assert.NoError(t, err) assert.NoError(t, err)
defer util.RemoveAll(tmpDir) defer util.RemoveAll(tmpDir)
assert.Error(t, git.Clone(u.String(), tmpDir, git.CloneRepoOptions{})) assert.Error(t, git.Clone(git.DefaultContext, u.String(), tmpDir, git.CloneRepoOptions{}))
exist, err := util.IsExist(filepath.Join(tmpDir, "README.md")) exist, err := util.IsExist(filepath.Join(tmpDir, "README.md"))
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, exist) assert.False(t, exist)
@ -138,7 +138,7 @@ func doGitCloneFail(u *url.URL) func(*testing.T) {
func doGitInitTestRepository(dstPath string) func(*testing.T) { func doGitInitTestRepository(dstPath string) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
// Init repository in dstPath // Init repository in dstPath
assert.NoError(t, git.InitRepository(dstPath, false)) assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false))
// forcibly set default branch to master // forcibly set default branch to master
_, err := git.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(dstPath) _, err := git.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(dstPath)
assert.NoError(t, err) assert.NoError(t, err)

@ -86,7 +86,7 @@ func TestMirrorPull(t *testing.T) {
release, err := models.GetRelease(repo.ID, "v0.2") release, err := models.GetRelease(repo.ID, "v0.2")
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, release_service.DeleteReleaseByID(release.ID, user, true)) assert.NoError(t, release_service.DeleteReleaseByID(ctx, release.ID, user, true))
ok = mirror_service.SyncPullMirror(ctx, mirror.ID) ok = mirror_service.SyncPullMirror(ctx, mirror.ID)
assert.True(t, ok) assert.True(t, ok)

@ -241,11 +241,11 @@ func TestCantMergeConflict(t *testing.T) {
gitRepo, err := git.OpenRepository(repo_model.RepoPath(user1.Name, repo1.Name)) gitRepo, err := git.OpenRepository(repo_model.RepoPath(user1.Name, repo1.Name))
assert.NoError(t, err) assert.NoError(t, err)
err = pull.Merge(pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "CONFLICT") err = pull.Merge(git.DefaultContext, pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "CONFLICT")
assert.Error(t, err, "Merge should return an error due to conflict") assert.Error(t, err, "Merge should return an error due to conflict")
assert.True(t, models.IsErrMergeConflicts(err), "Merge error is not a conflict error") assert.True(t, models.IsErrMergeConflicts(err), "Merge error is not a conflict error")
err = pull.Merge(pr, user1, gitRepo, repo_model.MergeStyleRebase, "", "CONFLICT") err = pull.Merge(git.DefaultContext, pr, user1, gitRepo, repo_model.MergeStyleRebase, "", "CONFLICT")
assert.Error(t, err, "Merge should return an error due to conflict") assert.Error(t, err, "Merge should return an error due to conflict")
assert.True(t, models.IsErrRebaseConflicts(err), "Merge error is not a conflict error") assert.True(t, models.IsErrRebaseConflicts(err), "Merge error is not a conflict error")
gitRepo.Close() gitRepo.Close()
@ -329,7 +329,7 @@ func TestCantMergeUnrelated(t *testing.T) {
BaseBranch: "base", BaseBranch: "base",
}).(*models.PullRequest) }).(*models.PullRequest)
err = pull.Merge(pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "UNRELATED") err = pull.Merge(git.DefaultContext, pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "UNRELATED")
assert.Error(t, err, "Merge should return an error due to unrelated") assert.Error(t, err, "Merge should return an error due to unrelated")
assert.True(t, models.IsErrMergeUnrelatedHistories(err), "Merge error is not a unrelated histories error") assert.True(t, models.IsErrMergeUnrelatedHistories(err), "Merge error is not a unrelated histories error")
gitRepo.Close() gitRepo.Close()

@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
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" files_service "code.gitea.io/gitea/services/repository/files"
@ -28,7 +29,7 @@ func TestAPIPullUpdate(t *testing.T) {
pr := createOutdatedPR(t, user, org26) pr := createOutdatedPR(t, user, org26)
//Test GetDiverging //Test GetDiverging
diffCount, err := pull_service.GetDiverging(pr) diffCount, err := pull_service.GetDiverging(git.DefaultContext, pr)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, diffCount.Behind) assert.EqualValues(t, 1, diffCount.Behind)
assert.EqualValues(t, 1, diffCount.Ahead) assert.EqualValues(t, 1, diffCount.Ahead)
@ -41,7 +42,7 @@ func TestAPIPullUpdate(t *testing.T) {
session.MakeRequest(t, req, http.StatusOK) session.MakeRequest(t, req, http.StatusOK)
//Test GetDiverging after update //Test GetDiverging after update
diffCount, err = pull_service.GetDiverging(pr) diffCount, err = pull_service.GetDiverging(git.DefaultContext, pr)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 0, diffCount.Behind) assert.EqualValues(t, 0, diffCount.Behind)
assert.EqualValues(t, 2, diffCount.Ahead) assert.EqualValues(t, 2, diffCount.Ahead)
@ -56,7 +57,7 @@ func TestAPIPullUpdateByRebase(t *testing.T) {
pr := createOutdatedPR(t, user, org26) pr := createOutdatedPR(t, user, org26)
//Test GetDiverging //Test GetDiverging
diffCount, err := pull_service.GetDiverging(pr) diffCount, err := pull_service.GetDiverging(git.DefaultContext, pr)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, diffCount.Behind) assert.EqualValues(t, 1, diffCount.Behind)
assert.EqualValues(t, 1, diffCount.Ahead) assert.EqualValues(t, 1, diffCount.Ahead)
@ -69,7 +70,7 @@ func TestAPIPullUpdateByRebase(t *testing.T) {
session.MakeRequest(t, req, http.StatusOK) session.MakeRequest(t, req, http.StatusOK)
//Test GetDiverging after update //Test GetDiverging after update
diffCount, err = pull_service.GetDiverging(pr) diffCount, err = pull_service.GetDiverging(git.DefaultContext, pr)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 0, diffCount.Behind) assert.EqualValues(t, 0, diffCount.Behind)
assert.EqualValues(t, 1, diffCount.Ahead) assert.EqualValues(t, 1, diffCount.Ahead)
@ -98,7 +99,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *models.Pul
assert.NotEmpty(t, headRepo) assert.NotEmpty(t, headRepo)
//create a commit on base Repo //create a commit on base Repo
_, err = files_service.CreateOrUpdateRepoFile(baseRepo, actor, &files_service.UpdateRepoFileOptions{ _, err = files_service.CreateOrUpdateRepoFile(git.DefaultContext, 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",
@ -121,7 +122,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *models.Pul
assert.NoError(t, err) assert.NoError(t, err)
//create a commit on head Repo //create a commit on head Repo
_, err = files_service.CreateOrUpdateRepoFile(headRepo, actor, &files_service.UpdateRepoFileOptions{ _, err = files_service.CreateOrUpdateRepoFile(git.DefaultContext, 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",
@ -160,7 +161,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *models.Pul
BaseRepo: baseRepo, BaseRepo: baseRepo,
Type: models.PullRequestGitea, Type: models.PullRequestGitea,
} }
err = pull_service.NewPullRequest(baseRepo, pullIssue, nil, nil, pullRequest, nil) err = pull_service.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil)
assert.NoError(t, err) assert.NoError(t, err)
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "Test Pull -to-update-"}).(*models.Issue) issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "Test Pull -to-update-"}).(*models.Issue)

@ -29,7 +29,7 @@ func TestCreateNewTagProtected(t *testing.T) {
t.Run("API", func(t *testing.T) { t.Run("API", func(t *testing.T) {
defer PrintCurrentTest(t)() defer PrintCurrentTest(t)()
err := release.CreateNewTag(owner, repo, "master", "v-1", "first tag") err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-1", "first tag")
assert.NoError(t, err) assert.NoError(t, err)
err = models.InsertProtectedTag(&models.ProtectedTag{ err = models.InsertProtectedTag(&models.ProtectedTag{
@ -44,11 +44,11 @@ func TestCreateNewTagProtected(t *testing.T) {
}) })
assert.NoError(t, err) assert.NoError(t, err)
err = release.CreateNewTag(owner, repo, "master", "v-2", "second tag") err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-2", "second tag")
assert.Error(t, err) assert.Error(t, err)
assert.True(t, models.IsErrProtectedTagName(err)) assert.True(t, models.IsErrProtectedTagName(err))
err = release.CreateNewTag(owner, repo, "master", "v-1.1", "third tag") err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-1.1", "third tag")
assert.NoError(t, err) assert.NoError(t, err)
}) })

@ -10,6 +10,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
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" files_service "code.gitea.io/gitea/services/repository/files"
@ -80,7 +81,7 @@ func testDeleteRepoFile(t *testing.T, u *url.URL) {
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 := files_service.DeleteRepoFile(repo, doer, opts) fileResponse, err := files_service.DeleteRepoFile(git.DefaultContext, 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)
@ -92,7 +93,7 @@ func testDeleteRepoFile(t *testing.T, u *url.URL) {
}) })
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 := files_service.DeleteRepoFile(repo, doer, opts) fileResponse, err := files_service.DeleteRepoFile(git.DefaultContext, 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)
@ -122,7 +123,7 @@ func testDeleteRepoFileWithoutBranchNames(t *testing.T, u *url.URL) {
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 := files_service.DeleteRepoFile(repo, doer, opts) fileResponse, err := files_service.DeleteRepoFile(git.DefaultContext, 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)
@ -151,7 +152,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
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 := files_service.DeleteRepoFile(repo, doer, opts) fileResponse, err := files_service.DeleteRepoFile(git.DefaultContext, 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 + "]"
@ -162,7 +163,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
opts := getDeleteRepoFileOptions(repo) opts := getDeleteRepoFileOptions(repo)
origSHA := opts.SHA origSHA := opts.SHA
opts.SHA = "bad_sha" opts.SHA = "bad_sha"
fileResponse, err := files_service.DeleteRepoFile(repo, doer, opts) fileResponse, err := files_service.DeleteRepoFile(git.DefaultContext, 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 + "]"
@ -172,7 +173,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
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 := files_service.DeleteRepoFile(repo, doer, opts) fileResponse, err := files_service.DeleteRepoFile(git.DefaultContext, 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 + "]"
@ -182,7 +183,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
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 := files_service.DeleteRepoFile(repo, doer, opts) fileResponse, err := files_service.DeleteRepoFile(git.DefaultContext, 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: ]"
@ -192,7 +193,7 @@ func TestDeleteRepoFileErrors(t *testing.T) {
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 := files_service.DeleteRepoFile(repo, doer, opts) fileResponse, err := files_service.DeleteRepoFile(git.DefaultContext, 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 + "]"

@ -198,7 +198,7 @@ func TestCreateOrUpdateRepoFileForCreate(t *testing.T) {
opts := getCreateRepoFileOptions(repo) opts := getCreateRepoFileOptions(repo)
// test // test
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, repo, doer, opts)
// asserts // asserts
assert.NoError(t, err) assert.NoError(t, err)
@ -234,7 +234,7 @@ func TestCreateOrUpdateRepoFileForUpdate(t *testing.T) {
opts := getUpdateRepoFileOptions(repo) opts := getUpdateRepoFileOptions(repo)
// test // test
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, repo, doer, opts)
// asserts // asserts
assert.NoError(t, err) assert.NoError(t, err)
@ -269,7 +269,7 @@ func TestCreateOrUpdateRepoFileForUpdateWithFileMove(t *testing.T) {
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 := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, repo, doer, opts)
// asserts // asserts
assert.NoError(t, err) assert.NoError(t, err)
@ -319,7 +319,7 @@ func TestCreateOrUpdateRepoFileWithoutBranchNames(t *testing.T) {
opts.NewBranch = "" opts.NewBranch = ""
// test // test
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, repo, doer, opts)
// asserts // asserts
assert.NoError(t, err) assert.NoError(t, err)
@ -349,7 +349,7 @@ func TestCreateOrUpdateRepoFileErrors(t *testing.T) {
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 := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, 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 + "]"
@ -360,7 +360,7 @@ func TestCreateOrUpdateRepoFileErrors(t *testing.T) {
opts := getUpdateRepoFileOptions(repo) opts := getUpdateRepoFileOptions(repo)
origSHA := opts.SHA origSHA := opts.SHA
opts.SHA = "bad_sha" opts.SHA = "bad_sha"
fileResponse, err := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, 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 + "]"
@ -370,7 +370,7 @@ func TestCreateOrUpdateRepoFileErrors(t *testing.T) {
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 := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, 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 + "]"
@ -380,7 +380,7 @@ func TestCreateOrUpdateRepoFileErrors(t *testing.T) {
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 := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, 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: ]"
@ -390,7 +390,7 @@ func TestCreateOrUpdateRepoFileErrors(t *testing.T) {
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 := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, 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 + "]"
@ -400,7 +400,7 @@ func TestCreateOrUpdateRepoFileErrors(t *testing.T) {
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 := files_service.CreateOrUpdateRepoFile(repo, doer, opts) fileResponse, err := files_service.CreateOrUpdateRepoFile(git.DefaultContext, 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 + "]"

@ -56,6 +56,7 @@ func CreateNotice(ctx context.Context, tp NoticeType, desc string, args ...inter
// CreateRepositoryNotice creates new system notice with type NoticeRepository. // CreateRepositoryNotice creates new system notice with type NoticeRepository.
func CreateRepositoryNotice(desc string, args ...interface{}) error { func CreateRepositoryNotice(desc string, args ...interface{}) error {
// Note we use the db.DefaultContext here rather than passing in a context as the context may be cancelled
return CreateNotice(db.DefaultContext, NoticeRepository, desc, args...) return CreateNotice(db.DefaultContext, NoticeRepository, desc, args...)
} }
@ -65,7 +66,8 @@ func RemoveAllWithNotice(ctx context.Context, title, path string) {
if err := util.RemoveAll(path); err != nil { if err := util.RemoveAll(path); err != nil {
desc := fmt.Sprintf("%s [%s]: %v", title, path, err) desc := fmt.Sprintf("%s [%s]: %v", title, path, err)
log.Warn(title+" [%s]: %v", path, err) log.Warn(title+" [%s]: %v", path, err)
if err = CreateNotice(ctx, NoticeRepository, desc); err != nil { // Note we use the db.DefaultContext here rather than passing in a context as the context may be cancelled
if err = CreateNotice(db.DefaultContext, NoticeRepository, desc); err != nil {
log.Error("CreateRepositoryNotice: %v", err) log.Error("CreateRepositoryNotice: %v", err)
} }
} }
@ -77,7 +79,9 @@ func RemoveStorageWithNotice(ctx context.Context, bucket storage.ObjectStorage,
if err := bucket.Delete(path); err != nil { if err := bucket.Delete(path); err != nil {
desc := fmt.Sprintf("%s [%s]: %v", title, path, err) desc := fmt.Sprintf("%s [%s]: %v", title, path, err)
log.Warn(title+" [%s]: %v", path, err) log.Warn(title+" [%s]: %v", path, err)
if err = CreateNotice(ctx, NoticeRepository, desc); err != nil {
// Note we use the db.DefaultContext here rather than passing in a context as the context may be cancelled
if err = CreateNotice(db.DefaultContext, NoticeRepository, desc); err != nil {
log.Error("CreateRepositoryNotice: %v", err) log.Error("CreateRepositoryNotice: %v", err)
} }
} }

@ -35,7 +35,7 @@ type Context struct {
func WithEngine(ctx context.Context, e Engine) *Context { func WithEngine(ctx context.Context, e Engine) *Context {
return &Context{ return &Context{
Context: ctx, Context: ctx,
e: e, e: e.Context(ctx),
} }
} }
@ -52,6 +52,11 @@ func (ctx *Context) Value(key interface{}) interface{} {
return ctx.Context.Value(key) return ctx.Context.Value(key)
} }
// WithContext returns this engine tied to this context
func (ctx *Context) WithContext(other context.Context) *Context {
return WithEngine(other, ctx.e)
}
// Engined structs provide an Engine // Engined structs provide an Engine
type Engined interface { type Engined interface {
Engine() Engine Engine() Engine

@ -64,6 +64,7 @@ type Engine interface {
Distinct(...string) *xorm.Session Distinct(...string) *xorm.Session
Query(...interface{}) ([]map[string][]byte, error) Query(...interface{}) ([]map[string][]byte, error)
Cols(...string) *xorm.Session Cols(...string) *xorm.Session
Context(ctx context.Context) *xorm.Session
} }
// TableInfo returns table's information via an object // TableInfo returns table's information via an object

@ -724,7 +724,7 @@ func (c *Comment) CodeCommentURL() string {
} }
// LoadPushCommits Load push commits // LoadPushCommits Load push commits
func (c *Comment) LoadPushCommits() (err error) { func (c *Comment) LoadPushCommits(ctx context.Context) (err error) {
if c.Content == "" || c.Commits != nil || c.Type != CommentTypePullPush { if c.Content == "" || c.Commits != nil || c.Type != CommentTypePullPush {
return nil return nil
} }
@ -746,11 +746,11 @@ func (c *Comment) LoadPushCommits() (err error) {
c.NewCommit = data.CommitIDs[1] c.NewCommit = data.CommitIDs[1]
} else { } else {
repoPath := c.Issue.Repo.RepoPath() repoPath := c.Issue.Repo.RepoPath()
gitRepo, err := git.OpenRepository(repoPath) gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoPath)
if err != nil { if err != nil {
return err return err
} }
defer gitRepo.Close() defer closer.Close()
c.Commits = ConvertFromGitCommit(gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo) c.Commits = ConvertFromGitCommit(gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo)
c.CommitsNum = int64(len(c.Commits)) c.CommitsNum = int64(len(c.Commits))
@ -1272,6 +1272,7 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu
var err error var err error
if comment.RenderedContent, err = markdown.RenderString(&markup.RenderContext{ if comment.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
Ctx: ctx,
URLPrefix: issue.Repo.Link(), URLPrefix: issue.Repo.Link(),
Metas: issue.Repo.ComposeMetas(), Metas: issue.Repo.ComposeMetas(),
}, comment.Content); err != nil { }, comment.Content); err != nil {
@ -1282,19 +1283,19 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu
} }
// FetchCodeCommentsByLine fetches the code comments for a given treePath and line number // FetchCodeCommentsByLine fetches the code comments for a given treePath and line number
func FetchCodeCommentsByLine(issue *Issue, currentUser *user_model.User, treePath string, line int64) ([]*Comment, error) { func FetchCodeCommentsByLine(ctx context.Context, issue *Issue, currentUser *user_model.User, treePath string, line int64) ([]*Comment, error) {
opts := FindCommentsOptions{ opts := FindCommentsOptions{
Type: CommentTypeCode, Type: CommentTypeCode,
IssueID: issue.ID, IssueID: issue.ID,
TreePath: treePath, TreePath: treePath,
Line: line, Line: line,
} }
return findCodeComments(db.DefaultContext, opts, issue, currentUser, nil) return findCodeComments(ctx, opts, issue, currentUser, nil)
} }
// FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line // FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line
func FetchCodeComments(issue *Issue, currentUser *user_model.User) (CodeComments, error) { func FetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User) (CodeComments, error) {
return fetchCodeComments(db.DefaultContext, issue, currentUser) return fetchCodeComments(ctx, issue, currentUser)
} }
// UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id // UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id
@ -1318,7 +1319,7 @@ func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID
} }
// CreatePushPullComment create push code to pull base comment // CreatePushPullComment create push code to pull base comment
func CreatePushPullComment(pusher *user_model.User, pr *PullRequest, oldCommitID, newCommitID string) (comment *Comment, err error) { func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *PullRequest, oldCommitID, newCommitID string) (comment *Comment, err error) {
if pr.HasMerged || oldCommitID == "" || newCommitID == "" { if pr.HasMerged || oldCommitID == "" || newCommitID == "" {
return nil, nil return nil, nil
} }
@ -1331,7 +1332,7 @@ func CreatePushPullComment(pusher *user_model.User, pr *PullRequest, oldCommitID
var data PushActionContent var data PushActionContent
data.CommitIDs, data.IsForcePush, err = getCommitIDsFromRepo(pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch) data.CommitIDs, data.IsForcePush, err = getCommitIDsFromRepo(ctx, pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1353,13 +1354,13 @@ func CreatePushPullComment(pusher *user_model.User, pr *PullRequest, oldCommitID
// getCommitsFromRepo get commit IDs from repo in between oldCommitID and newCommitID // getCommitsFromRepo get commit IDs from repo in between oldCommitID and newCommitID
// isForcePush will be true if oldCommit isn't on the branch // isForcePush will be true if oldCommit isn't on the branch
// Commit on baseBranch will skip // Commit on baseBranch will skip
func getCommitIDsFromRepo(repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) { func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) {
repoPath := repo.RepoPath() repoPath := repo.RepoPath()
gitRepo, err := git.OpenRepository(repoPath) gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoPath)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
defer gitRepo.Close() defer closer.Close()
oldCommit, err := gitRepo.GetCommit(oldCommitID) oldCommit, err := gitRepo.GetCommit(oldCommitID)
if err != nil { if err != nil {

@ -8,6 +8,7 @@ import (
"testing" "testing"
"time" "time"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -49,7 +50,7 @@ func TestFetchCodeComments(t *testing.T) {
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue) issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
res, err := FetchCodeComments(issue, user) res, err := FetchCodeComments(db.DefaultContext, issue, user)
assert.NoError(t, err) assert.NoError(t, err)
assert.Contains(t, res, "README.md") assert.Contains(t, res, "README.md")
assert.Contains(t, res["README.md"], int64(4)) assert.Contains(t, res["README.md"], int64(4))
@ -57,7 +58,7 @@ func TestFetchCodeComments(t *testing.T) {
assert.Equal(t, int64(4), res["README.md"][4][0].ID) assert.Equal(t, int64(4), res["README.md"][4][0].ID)
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
res, err = FetchCodeComments(issue, user2) res, err = FetchCodeComments(db.DefaultContext, issue, user2)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, res, 1) assert.Len(t, res, 1)
} }

@ -162,7 +162,7 @@ func testCreatePR(t *testing.T, repo, doer int64, title, content string) *PullRe
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User) d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
i := &Issue{RepoID: r.ID, PosterID: d.ID, Poster: d, Title: title, Content: content, IsPull: true} i := &Issue{RepoID: r.ID, PosterID: d.ID, Poster: d, Title: title, Content: content, IsPull: true}
pr := &PullRequest{HeadRepoID: repo, BaseRepoID: repo, HeadBranch: "head", BaseBranch: "base", Status: PullRequestStatusMergeable} pr := &PullRequest{HeadRepoID: repo, BaseRepoID: repo, HeadBranch: "head", BaseBranch: "base", Status: PullRequestStatusMergeable}
assert.NoError(t, NewPullRequest(r, i, nil, nil, pr)) assert.NoError(t, NewPullRequest(db.DefaultContext, r, i, nil, nil, pr))
pr.Issue = i pr.Issue = i
return pr return pr
} }

@ -12,6 +12,7 @@ import (
"time" "time"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -90,7 +91,7 @@ func addCommitDivergenceToPulls(x *xorm.Engine) error {
gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index) gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
divergence, err := git.GetDivergingCommits(repoPath, pr.BaseBranch, gitRefName) divergence, err := git.GetDivergingCommits(graceful.GetManager().HammerContext(), repoPath, pr.BaseBranch, gitRefName)
if err != nil { if err != nil {
log.Warn("Could not recalculate Divergence for pull: %d", pr.ID) log.Warn("Could not recalculate Divergence for pull: %d", pr.ID)
pr.CommitsAhead = 0 pr.CommitsAhead = 0

@ -109,7 +109,7 @@ func fixPublisherIDforTagReleases(x *xorm.Engine) error {
return err return err
} }
} }
gitRepo, err = git.OpenRepository(repoPath(repo.OwnerName, repo.Name)) gitRepo, err = git.OpenRepositoryCtx(git.DefaultContext, repoPath(repo.OwnerName, repo.Name))
if err != nil { if err != nil {
log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err)
return err return err

@ -99,7 +99,7 @@ func fixReleaseSha1OnReleaseTable(x *xorm.Engine) error {
userCache[repo.OwnerID] = user userCache[repo.OwnerID] = user
} }
gitRepo, err = git.OpenRepository(RepoPath(user.Name, repo.Name)) gitRepo, err = git.OpenRepositoryCtx(git.DefaultContext, RepoPath(user.Name, repo.Name))
if err != nil { if err != nil {
return err return err
} }

@ -436,7 +436,7 @@ func (pr *PullRequest) SetMerged() (bool, error) {
} }
// NewPullRequest creates new pull request with labels for repository. // NewPullRequest creates new pull request with labels for repository.
func NewPullRequest(repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string, pr *PullRequest) (err error) { func NewPullRequest(outerCtx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string, pr *PullRequest) (err error) {
idx, err := db.GetNextResourceIndex("issue_index", repo.ID) idx, err := db.GetNextResourceIndex("issue_index", repo.ID)
if err != nil { if err != nil {
return fmt.Errorf("generate pull request index failed: %v", err) return fmt.Errorf("generate pull request index failed: %v", err)
@ -449,6 +449,7 @@ func NewPullRequest(repo *repo_model.Repository, issue *Issue, labelIDs []int64,
return err return err
} }
defer committer.Close() defer committer.Close()
ctx.WithContext(outerCtx)
if err = newIssue(ctx, issue.Poster, NewIssueOptions{ if err = newIssue(ctx, issue.Poster, NewIssueOptions{
Repo: repo, Repo: repo,

@ -485,8 +485,9 @@ func (repo *Repository) CanEnableEditor() bool {
} }
// DescriptionHTML does special handles to description and return HTML string. // DescriptionHTML does special handles to description and return HTML string.
func (repo *Repository) DescriptionHTML() template.HTML { func (repo *Repository) DescriptionHTML(ctx context.Context) template.HTML {
desc, err := markup.RenderDescriptionHTML(&markup.RenderContext{ desc, err := markup.RenderDescriptionHTML(&markup.RenderContext{
Ctx: ctx,
URLPrefix: repo.HTMLURL(), URLPrefix: repo.HTMLURL(),
Metas: repo.ComposeMetas(), Metas: repo.ComposeMetas(),
}, repo.Description) }, repo.Description)

@ -5,6 +5,7 @@
package models package models
import ( import (
"context"
"fmt" "fmt"
"sort" "sort"
"time" "time"
@ -43,7 +44,7 @@ type ActivityStats struct {
} }
// GetActivityStats return stats for repository at given time range // GetActivityStats return stats for repository at given time range
func GetActivityStats(repo *repo_model.Repository, timeFrom time.Time, releases, issues, prs, code bool) (*ActivityStats, error) { func GetActivityStats(ctx context.Context, repo *repo_model.Repository, timeFrom time.Time, releases, issues, prs, code bool) (*ActivityStats, error) {
stats := &ActivityStats{Code: &git.CodeActivityStats{}} stats := &ActivityStats{Code: &git.CodeActivityStats{}}
if releases { if releases {
if err := stats.FillReleases(repo.ID, timeFrom); err != nil { if err := stats.FillReleases(repo.ID, timeFrom); err != nil {
@ -64,11 +65,11 @@ func GetActivityStats(repo *repo_model.Repository, timeFrom time.Time, releases,
return nil, fmt.Errorf("FillUnresolvedIssues: %v", err) return nil, fmt.Errorf("FillUnresolvedIssues: %v", err)
} }
if code { if code {
gitRepo, err := git.OpenRepository(repo.RepoPath()) gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.RepoPath())
if err != nil { if err != nil {
return nil, fmt.Errorf("OpenRepository: %v", err) return nil, fmt.Errorf("OpenRepository: %v", err)
} }
defer gitRepo.Close() defer closer.Close()
code, err := gitRepo.GetCodeActivityStats(timeFrom, repo.DefaultBranch) code, err := gitRepo.GetCodeActivityStats(timeFrom, repo.DefaultBranch)
if err != nil { if err != nil {
@ -80,12 +81,12 @@ func GetActivityStats(repo *repo_model.Repository, timeFrom time.Time, releases,
} }
// GetActivityStatsTopAuthors returns top author stats for git commits for all branches // GetActivityStatsTopAuthors returns top author stats for git commits for all branches
func GetActivityStatsTopAuthors(repo *repo_model.Repository, timeFrom time.Time, count int) ([]*ActivityAuthorData, error) { func GetActivityStatsTopAuthors(ctx context.Context, repo *repo_model.Repository, timeFrom time.Time, count int) ([]*ActivityAuthorData, error) {
gitRepo, err := git.OpenRepository(repo.RepoPath()) gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.RepoPath())
if err != nil { if err != nil {
return nil, fmt.Errorf("OpenRepository: %v", err) return nil, fmt.Errorf("OpenRepository: %v", err)
} }
defer gitRepo.Close() defer closer.Close()
code, err := gitRepo.GetCodeActivityStats(timeFrom, "") code, err := gitRepo.GetCodeActivityStats(timeFrom, "")
if err != nil { if err != nil {

@ -86,7 +86,8 @@ func init() {
db.RegisterModel(new(Review)) db.RegisterModel(new(Review))
} }
func (r *Review) loadCodeComments(ctx context.Context) (err error) { // LoadCodeComments loads CodeComments
func (r *Review) LoadCodeComments(ctx context.Context) (err error) {
if r.CodeComments != nil { if r.CodeComments != nil {
return return
} }
@ -97,11 +98,6 @@ func (r *Review) loadCodeComments(ctx context.Context) (err error) {
return return
} }
// LoadCodeComments loads CodeComments
func (r *Review) LoadCodeComments() error {
return r.loadCodeComments(db.DefaultContext)
}
func (r *Review) loadIssue(e db.Engine) (err error) { func (r *Review) loadIssue(e db.Engine) (err error) {
if r.Issue != nil { if r.Issue != nil {
return return
@ -137,12 +133,13 @@ func (r *Review) LoadReviewerTeam() error {
return r.loadReviewerTeam(db.GetEngine(db.DefaultContext)) return r.loadReviewerTeam(db.GetEngine(db.DefaultContext))
} }
func (r *Review) loadAttributes(ctx context.Context) (err error) { // LoadAttributes loads all attributes except CodeComments
func (r *Review) LoadAttributes(ctx context.Context) (err error) {
e := db.GetEngine(ctx) e := db.GetEngine(ctx)
if err = r.loadIssue(e); err != nil { if err = r.loadIssue(e); err != nil {
return return
} }
if err = r.loadCodeComments(ctx); err != nil { if err = r.LoadCodeComments(ctx); err != nil {
return return
} }
if err = r.loadReviewer(e); err != nil { if err = r.loadReviewer(e); err != nil {
@ -154,11 +151,6 @@ func (r *Review) loadAttributes(ctx context.Context) (err error) {
return return
} }
// LoadAttributes loads all attributes except CodeComments
func (r *Review) LoadAttributes() error {
return r.loadAttributes(db.DefaultContext)
}
func getReviewByID(e db.Engine, id int64) (*Review, error) { func getReviewByID(e db.Engine, id int64) (*Review, error) {
review := new(Review) review := new(Review)
if has, err := e.ID(id).Get(review); err != nil { if has, err := e.ID(id).Get(review); err != nil {
@ -405,7 +397,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co
return nil, nil, err return nil, nil, err
} }
} else { } else {
if err := review.loadCodeComments(ctx); err != nil { if err := review.LoadCodeComments(ctx); err != nil {
return nil, nil, err return nil, nil, err
} }
if reviewType != ReviewTypeApprove && len(review.CodeComments) == 0 && len(strings.TrimSpace(content)) == 0 { if reviewType != ReviewTypeApprove && len(review.CodeComments) == 0 && len(strings.TrimSpace(content)) == 0 {

@ -7,6 +7,7 @@ package models
import ( import (
"testing" "testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -28,23 +29,23 @@ func TestGetReviewByID(t *testing.T) {
func TestReview_LoadAttributes(t *testing.T) { func TestReview_LoadAttributes(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
review := unittest.AssertExistsAndLoadBean(t, &Review{ID: 1}).(*Review) review := unittest.AssertExistsAndLoadBean(t, &Review{ID: 1}).(*Review)
assert.NoError(t, review.LoadAttributes()) assert.NoError(t, review.LoadAttributes(db.DefaultContext))
assert.NotNil(t, review.Issue) assert.NotNil(t, review.Issue)
assert.NotNil(t, review.Reviewer) assert.NotNil(t, review.Reviewer)
invalidReview1 := unittest.AssertExistsAndLoadBean(t, &Review{ID: 2}).(*Review) invalidReview1 := unittest.AssertExistsAndLoadBean(t, &Review{ID: 2}).(*Review)
assert.Error(t, invalidReview1.LoadAttributes()) assert.Error(t, invalidReview1.LoadAttributes(db.DefaultContext))
invalidReview2 := unittest.AssertExistsAndLoadBean(t, &Review{ID: 3}).(*Review) invalidReview2 := unittest.AssertExistsAndLoadBean(t, &Review{ID: 3}).(*Review)
assert.Error(t, invalidReview2.LoadAttributes()) assert.Error(t, invalidReview2.LoadAttributes(db.DefaultContext))
} }
func TestReview_LoadCodeComments(t *testing.T) { func TestReview_LoadCodeComments(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
review := unittest.AssertExistsAndLoadBean(t, &Review{ID: 4}).(*Review) review := unittest.AssertExistsAndLoadBean(t, &Review{ID: 4}).(*Review)
assert.NoError(t, review.LoadAttributes()) assert.NoError(t, review.LoadAttributes(db.DefaultContext))
assert.NoError(t, review.LoadCodeComments()) assert.NoError(t, review.LoadCodeComments(db.DefaultContext))
assert.Len(t, review.CodeComments, 1) assert.Len(t, review.CodeComments, 1)
assert.Equal(t, int64(4), review.CodeComments["README.md"][int64(4)][0].Line) assert.Equal(t, int64(4), review.CodeComments["README.md"][int64(4)][0].Line)
} }

@ -303,6 +303,7 @@ func APIContexter() func(http.Handler) http.Handler {
ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions) ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
ctx.Data["CsrfToken"] = html.EscapeString(ctx.csrf.GetToken()) ctx.Data["CsrfToken"] = html.EscapeString(ctx.csrf.GetToken())
ctx.Data["Context"] = &ctx
next.ServeHTTP(ctx.Resp, ctx.Req) next.ServeHTTP(ctx.Resp, ctx.Req)
@ -321,10 +322,8 @@ func APIContexter() func(http.Handler) http.Handler {
} }
// ReferencesGitRepo injects the GitRepo into the Context // ReferencesGitRepo injects the GitRepo into the Context
func ReferencesGitRepo(allowEmpty bool) func(http.Handler) http.Handler { func ReferencesGitRepo(allowEmpty bool) func(ctx *APIContext) (cancel context.CancelFunc) {
return func(next http.Handler) http.Handler { return func(ctx *APIContext) (cancel context.CancelFunc) {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ctx := GetAPIContext(req)
// Empty repository does not have reference information. // Empty repository does not have reference information.
if !allowEmpty && ctx.Repo.Repository.IsEmpty { if !allowEmpty && ctx.Repo.Repository.IsEmpty {
return return
@ -333,23 +332,22 @@ func ReferencesGitRepo(allowEmpty bool) func(http.Handler) http.Handler {
// For API calls. // For API calls.
if ctx.Repo.GitRepo == nil { if ctx.Repo.GitRepo == nil {
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
gitRepo, err := git.OpenRepository(repoPath) gitRepo, err := git.OpenRepositoryCtx(ctx, repoPath)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "RepoRef Invalid repo "+repoPath, err) ctx.Error(http.StatusInternalServerError, "RepoRef Invalid repo "+repoPath, err)
return return
} }
ctx.Repo.GitRepo = gitRepo ctx.Repo.GitRepo = gitRepo
// We opened it, we should close it // We opened it, we should close it
defer func() { return func() {
// If it's been set to nil then assume someone else has closed it. // If it's been set to nil then assume someone else has closed it.
if ctx.Repo.GitRepo != nil { if ctx.Repo.GitRepo != nil {
ctx.Repo.GitRepo.Close() ctx.Repo.GitRepo.Close()
} }
}() }
} }
next.ServeHTTP(w, req) return
})
} }
} }
@ -391,7 +389,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
if ctx.Repo.GitRepo == nil { if ctx.Repo.GitRepo == nil {
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath) ctx.Repo.GitRepo, err = git.OpenRepositoryCtx(ctx, repoPath)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return

@ -23,6 +23,7 @@ import (
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
mc "code.gitea.io/gitea/modules/cache" mc "code.gitea.io/gitea/modules/cache"
"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/setting" "code.gitea.io/gitea/modules/setting"
@ -529,6 +530,10 @@ func (ctx *Context) Err() error {
// Value is part of the interface for context.Context and we pass this to the request context // Value is part of the interface for context.Context and we pass this to the request context
func (ctx *Context) Value(key interface{}) interface{} { func (ctx *Context) Value(key interface{}) interface{} {
if key == git.RepositoryContextKey && ctx.Repo != nil {
return ctx.Repo.GitRepo
}
return ctx.Req.Context().Value(key) return ctx.Req.Context().Value(key)
} }
@ -631,6 +636,7 @@ func Contexter() func(next http.Handler) http.Handler {
// PageData is passed by reference, and it will be rendered to `window.config.pageData` in `head.tmpl` for JavaScript modules // PageData is passed by reference, and it will be rendered to `window.config.pageData` in `head.tmpl` for JavaScript modules
ctx.PageData = map[string]interface{}{} ctx.PageData = map[string]interface{}{}
ctx.Data["PageData"] = ctx.PageData ctx.Data["PageData"] = ctx.PageData
ctx.Data["Context"] = &ctx
ctx.Req = WithContext(req, &ctx) ctx.Req = WithContext(req, &ctx)
ctx.csrf = Csrfer(csrfOpts, &ctx) ctx.csrf = Csrfer(csrfOpts, &ctx)

@ -6,12 +6,42 @@ package context
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"time"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/process"
) )
// PrivateContext represents a context for private routes // PrivateContext represents a context for private routes
type PrivateContext struct { type PrivateContext struct {
*Context *Context
Override context.Context
}
// Deadline is part of the interface for context.Context and we pass this to the request context
func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) {
if ctx.Override != nil {
return ctx.Override.Deadline()
}
return ctx.Req.Context().Deadline()
}
// Done is part of the interface for context.Context and we pass this to the request context
func (ctx *PrivateContext) Done() <-chan struct{} {
if ctx.Override != nil {
return ctx.Override.Done()
}
return ctx.Req.Context().Done()
}
// Err is part of the interface for context.Context and we pass this to the request context
func (ctx *PrivateContext) Err() error {
if ctx.Override != nil {
return ctx.Override.Err()
}
return ctx.Req.Context().Err()
} }
var ( var (
@ -39,7 +69,18 @@ func PrivateContexter() func(http.Handler) http.Handler {
}, },
} }
ctx.Req = WithPrivateContext(req, ctx) ctx.Req = WithPrivateContext(req, ctx)
ctx.Data["Context"] = ctx
next.ServeHTTP(ctx.Resp, ctx.Req) next.ServeHTTP(ctx.Resp, ctx.Req)
}) })
} }
} }
// OverrideContext overrides the underlying request context for Done() etc.
// This function should be used when there is a need for work to continue even if the request has been cancelled.
// Primarily this affects hook/post-receive and hook/proc-receive both of which need to continue working even if
// the underlying request has timed out from the ssh/http push
func OverrideContext(ctx *PrivateContext) (cancel context.CancelFunc) {
// We now need to override the request context as the base for our work because even if the request is cancelled we have to continue this work
ctx.Override, _, cancel = process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("PrivateContext: %s", ctx.Req.RequestURI))
return
}

@ -109,7 +109,7 @@ type CanCommitToBranchResults struct {
// CanCommitToBranch returns true if repository is editable and user has proper access level // CanCommitToBranch returns true if repository is editable and user has proper access level
// and branch is not protected for push // and branch is not protected for push
func (r *Repository) CanCommitToBranch(doer *user_model.User) (CanCommitToBranchResults, error) { func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.User) (CanCommitToBranchResults, error) {
protectedBranch, err := models.GetProtectedBranchBy(r.Repository.ID, r.BranchName) protectedBranch, err := models.GetProtectedBranchBy(r.Repository.ID, r.BranchName)
if err != nil { if err != nil {
@ -122,7 +122,7 @@ func (r *Repository) CanCommitToBranch(doer *user_model.User) (CanCommitToBranch
requireSigned = protectedBranch.RequireSignedCommits requireSigned = protectedBranch.RequireSignedCommits
} }
sign, keyID, _, err := asymkey_service.SignCRUDAction(r.Repository.RepoPath(), doer, r.Repository.RepoPath(), git.BranchPrefix+r.BranchName) sign, keyID, _, err := asymkey_service.SignCRUDAction(ctx, r.Repository.RepoPath(), doer, r.Repository.RepoPath(), git.BranchPrefix+r.BranchName)
canCommit := r.CanEnableEditor() && userCanPush canCommit := r.CanEnableEditor() && userCanPush
if requireSigned { if requireSigned {
@ -180,14 +180,14 @@ func (r *Repository) GetCommitsCount() (int64, error) {
} }
// GetCommitGraphsCount returns cached commit count for current view // GetCommitGraphsCount returns cached commit count for current view
func (r *Repository) GetCommitGraphsCount(hidePRRefs bool, branches, files []string) (int64, error) { func (r *Repository) GetCommitGraphsCount(ctx context.Context, hidePRRefs bool, branches, files []string) (int64, error) {
cacheKey := fmt.Sprintf("commits-count-%d-graph-%t-%s-%s", r.Repository.ID, hidePRRefs, branches, files) cacheKey := fmt.Sprintf("commits-count-%d-graph-%t-%s-%s", r.Repository.ID, hidePRRefs, branches, files)
return cache.GetInt64(cacheKey, func() (int64, error) { return cache.GetInt64(cacheKey, func() (int64, error) {
if len(branches) == 0 { if len(branches) == 0 {
return git.AllCommitsCount(r.Repository.RepoPath(), hidePRRefs, files...) return git.AllCommitsCount(ctx, r.Repository.RepoPath(), hidePRRefs, files...)
} }
return git.CommitsCountFiles(r.Repository.RepoPath(), branches, files) return git.CommitsCountFiles(ctx, r.Repository.RepoPath(), branches, files)
}) })
} }

@ -72,8 +72,7 @@ func ToPayloadCommit(repo *repo_model.Repository, c *git.Commit) *api.PayloadCom
} }
// ToCommit convert a git.Commit to api.Commit // ToCommit convert a git.Commit to api.Commit
func ToCommit(repo *repo_model.Repository, commit *git.Commit, userCache map[string]*user_model.User) (*api.Commit, error) { func ToCommit(repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, userCache map[string]*user_model.User) (*api.Commit, error) {
var apiAuthor, apiCommitter *api.User var apiAuthor, apiCommitter *api.User
// Retrieve author and committer information // Retrieve author and committer information
@ -134,7 +133,7 @@ func ToCommit(repo *repo_model.Repository, commit *git.Commit, userCache map[str
} }
// Retrieve files affected by the commit // Retrieve files affected by the commit
fileStatus, err := git.GetCommitFileStatus(repo.RepoPath(), commit.ID.String()) fileStatus, err := git.GetCommitFileStatus(gitRepo.Ctx, repo.RepoPath(), commit.ID.String())
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -5,6 +5,7 @@
package convert package convert
import ( import (
"context"
"fmt" "fmt"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
@ -18,7 +19,7 @@ import (
// ToAPIPullRequest assumes following fields have been assigned with valid values: // ToAPIPullRequest assumes following fields have been assigned with valid values:
// Required - Issue // Required - Issue
// Optional - Merger // Optional - Merger
func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRequest { func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_model.User) *api.PullRequest {
var ( var (
baseBranch *git.Branch baseBranch *git.Branch
headBranch *git.Branch headBranch *git.Branch
@ -84,7 +85,7 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe
}, },
} }
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath()) gitRepo, err := git.OpenRepositoryCtx(ctx, pr.BaseRepo.RepoPath())
if err != nil { if err != nil {
log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err) log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err)
return nil return nil
@ -110,7 +111,7 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe
} }
if pr.Flow == models.PullRequestFlowAGit { if pr.Flow == models.PullRequestFlowAGit {
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath()) gitRepo, err := git.OpenRepositoryCtx(ctx, pr.BaseRepo.RepoPath())
if err != nil { if err != nil {
log.Error("OpenRepository[%s]: %v", pr.GetGitRefName(), err) log.Error("OpenRepository[%s]: %v", pr.GetGitRefName(), err)
return nil return nil
@ -137,7 +138,7 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe
apiPullRequest.Head.RepoID = pr.HeadRepo.ID apiPullRequest.Head.RepoID = pr.HeadRepo.ID
apiPullRequest.Head.Repository = ToRepo(pr.HeadRepo, p.AccessMode) apiPullRequest.Head.Repository = ToRepo(pr.HeadRepo, p.AccessMode)
headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath()) headGitRepo, err := git.OpenRepositoryCtx(ctx, pr.HeadRepo.RepoPath())
if err != nil { if err != nil {
log.Error("OpenRepository[%s]: %v", pr.HeadRepo.RepoPath(), err) log.Error("OpenRepository[%s]: %v", pr.HeadRepo.RepoPath(), err)
return nil return nil
@ -173,7 +174,7 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe
} }
if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 { if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 {
baseGitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath()) baseGitRepo, err := git.OpenRepositoryCtx(ctx, pr.BaseRepo.RepoPath())
if err != nil { if err != nil {
log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err) log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err)
return nil return nil

@ -5,6 +5,7 @@
package convert package convert
import ( import (
"context"
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
@ -13,8 +14,8 @@ import (
) )
// ToPullReview convert a review to api format // ToPullReview convert a review to api format
func ToPullReview(r *models.Review, doer *user_model.User) (*api.PullReview, error) { func ToPullReview(ctx context.Context, r *models.Review, doer *user_model.User) (*api.PullReview, error) {
if err := r.LoadAttributes(); err != nil { if err := r.LoadAttributes(ctx); err != nil {
if !user_model.IsErrUserNotExist(err) { if !user_model.IsErrUserNotExist(err) {
return nil, err return nil, err
} }
@ -54,14 +55,14 @@ func ToPullReview(r *models.Review, doer *user_model.User) (*api.PullReview, err
} }
// ToPullReviewList convert a list of review to it's api format // ToPullReviewList convert a list of review to it's api format
func ToPullReviewList(rl []*models.Review, doer *user_model.User) ([]*api.PullReview, error) { func ToPullReviewList(ctx context.Context, rl []*models.Review, doer *user_model.User) ([]*api.PullReview, error) {
result := make([]*api.PullReview, 0, len(rl)) result := make([]*api.PullReview, 0, len(rl))
for i := range rl { for i := range rl {
// show pending reviews only for the user who created them // show pending reviews only for the user who created them
if rl[i].Type == models.ReviewTypePending && !(doer.IsAdmin || doer.ID == rl[i].ReviewerID) { if rl[i].Type == models.ReviewTypePending && !(doer.IsAdmin || doer.ID == rl[i].ReviewerID) {
continue continue
} }
r, err := ToPullReview(rl[i], doer) r, err := ToPullReview(ctx, rl[i], doer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -71,8 +72,8 @@ func ToPullReviewList(rl []*models.Review, doer *user_model.User) ([]*api.PullRe
} }
// ToPullReviewCommentList convert the CodeComments of an review to it's api format // ToPullReviewCommentList convert the CodeComments of an review to it's api format
func ToPullReviewCommentList(review *models.Review, doer *user_model.User) ([]*api.PullReviewComment, error) { func ToPullReviewCommentList(ctx context.Context, review *models.Review, doer *user_model.User) ([]*api.PullReviewComment, error) {
if err := review.LoadAttributes(); err != nil { if err := review.LoadAttributes(ctx); err != nil {
if !user_model.IsErrUserNotExist(err) { if !user_model.IsErrUserNotExist(err) {
return nil, err return nil, err
} }

@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -23,7 +24,7 @@ func TestPullRequest_APIFormat(t *testing.T) {
pr := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 1}).(*models.PullRequest) pr := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 1}).(*models.PullRequest)
assert.NoError(t, pr.LoadAttributes()) assert.NoError(t, pr.LoadAttributes())
assert.NoError(t, pr.LoadIssue()) assert.NoError(t, pr.LoadIssue())
apiPullRequest := ToAPIPullRequest(pr, nil) apiPullRequest := ToAPIPullRequest(git.DefaultContext, pr, nil)
assert.NotNil(t, apiPullRequest) assert.NotNil(t, apiPullRequest)
assert.EqualValues(t, &structs.PRBranchInfo{ assert.EqualValues(t, &structs.PRBranchInfo{
Name: "branch1", Name: "branch1",
@ -40,7 +41,7 @@ func TestPullRequest_APIFormat(t *testing.T) {
// simulate fork deletion // simulate fork deletion
pr.HeadRepo = nil pr.HeadRepo = nil
pr.HeadRepoID = 100000 pr.HeadRepoID = 100000
apiPullRequest = ToAPIPullRequest(pr, nil) apiPullRequest = ToAPIPullRequest(git.DefaultContext, pr, nil)
assert.NotNil(t, apiPullRequest) assert.NotNil(t, apiPullRequest)
assert.Nil(t, apiPullRequest.Head.Repository) assert.Nil(t, apiPullRequest.Head.Repository)
assert.EqualValues(t, -1, apiPullRequest.Head.RepoID) assert.EqualValues(t, -1, apiPullRequest.Head.RepoID)

@ -7,6 +7,7 @@ package doctor
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
@ -19,7 +20,7 @@ import (
const tplCommentPrefix = `# gitea public key` const tplCommentPrefix = `# gitea public key`
func checkAuthorizedKeys(logger log.Logger, autofix bool) error { func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) error {
if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile { if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
return nil return nil
} }

@ -5,6 +5,7 @@
package doctor package doctor
import ( import (
"context"
"os" "os"
"path/filepath" "path/filepath"
@ -13,7 +14,7 @@ import (
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
) )
func checkOldArchives(logger log.Logger, autofix bool) error { func checkOldArchives(ctx context.Context, logger log.Logger, autofix bool) error {
numRepos := 0 numRepos := 0
numReposUpdated := 0 numReposUpdated := 0
err := iterateRepositories(func(repo *repo_model.Repository) error { err := iterateRepositories(func(repo *repo_model.Repository) error {

@ -22,7 +22,7 @@ type consistencyCheck struct {
FixedMessage string FixedMessage string
} }
func (c *consistencyCheck) Run(logger log.Logger, autofix bool) error { func (c *consistencyCheck) Run(ctx context.Context, logger log.Logger, autofix bool) error {
count, err := c.Counter() count, err := c.Counter()
if err != nil { if err != nil {
logger.Critical("Error: %v whilst counting %s", err, c.Name) logger.Critical("Error: %v whilst counting %s", err, c.Name)
@ -73,9 +73,9 @@ func genericOrphanCheck(name, subject, refobject, joincond string) consistencyCh
} }
} }
func checkDBConsistency(logger log.Logger, autofix bool) error { func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) error {
// make sure DB version is uptodate // make sure DB version is uptodate
if err := db.InitEngineWithMigration(context.Background(), migrations.EnsureUpToDate); err != nil { if err := db.InitEngineWithMigration(ctx, migrations.EnsureUpToDate); err != nil {
logger.Critical("Model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded") logger.Critical("Model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded")
return err return err
} }
@ -180,7 +180,7 @@ func checkDBConsistency(logger log.Logger, autofix bool) error {
) )
for _, c := range consistencyChecks { for _, c := range consistencyChecks {
if err := c.Run(logger, autofix); err != nil { if err := c.Run(ctx, logger, autofix); err != nil {
return err return err
} }
} }

@ -12,8 +12,8 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
) )
func checkDBVersion(logger log.Logger, autofix bool) error { func checkDBVersion(ctx context.Context, logger log.Logger, autofix bool) error {
if err := db.InitEngineWithMigration(context.Background(), migrations.EnsureUpToDate); err != nil { if err := db.InitEngineWithMigration(ctx, migrations.EnsureUpToDate); err != nil {
if !autofix { if !autofix {
logger.Critical("Error: %v during ensure up to date", err) logger.Critical("Error: %v during ensure up to date", err)
return err return err
@ -21,7 +21,7 @@ func checkDBVersion(logger log.Logger, autofix bool) error {
logger.Warn("Got Error: %v during ensure up to date", err) logger.Warn("Got Error: %v during ensure up to date", err)
logger.Warn("Attempting to migrate to the latest DB version to fix this.") logger.Warn("Attempting to migrate to the latest DB version to fix this.")
err = db.InitEngineWithMigration(context.Background(), migrations.Migrate) err = db.InitEngineWithMigration(ctx, migrations.Migrate)
if err != nil { if err != nil {
logger.Critical("Error: %v during migration", err) logger.Critical("Error: %v during migration", err)
} }

@ -20,7 +20,7 @@ type Check struct {
Title string Title string
Name string Name string
IsDefault bool IsDefault bool
Run func(logger log.Logger, autofix bool) error Run func(ctx context.Context, logger log.Logger, autofix bool) error
AbortIfFailed bool AbortIfFailed bool
SkipDatabaseInitialization bool SkipDatabaseInitialization bool
Priority int Priority int
@ -77,7 +77,7 @@ func RunChecks(ctx context.Context, logger log.Logger, autofix bool, checks []*C
} }
logger.Info("[%d] %s", log.NewColoredIDValue(i+1), check.Title) logger.Info("[%d] %s", log.NewColoredIDValue(i+1), check.Title)
logger.Flush() logger.Flush()
if err := check.Run(&wrappedLogger, autofix); err != nil { if err := check.Run(ctx, &wrappedLogger, autofix); err != nil {
if check.AbortIfFailed { if check.AbortIfFailed {
logger.Critical("FAIL") logger.Critical("FAIL")
return err return err

@ -6,6 +6,7 @@ package doctor
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
@ -254,7 +255,7 @@ func fixBrokenRepoUnit16961(repoUnit *repo_model.RepoUnit, bs []byte) (fixed boo
return true, nil return true, nil
} }
func fixBrokenRepoUnits16961(logger log.Logger, autofix bool) error { func fixBrokenRepoUnits16961(ctx context.Context, logger log.Logger, autofix bool) error {
// RepoUnit describes all units of a repository // RepoUnit describes all units of a repository
type RepoUnit struct { type RepoUnit struct {
ID int64 ID int64

@ -5,6 +5,7 @@
package doctor package doctor
import ( import (
"context"
"fmt" "fmt"
"strings" "strings"
@ -28,7 +29,7 @@ func iteratePRs(repo *repo_model.Repository, each func(*repo_model.Repository, *
) )
} }
func checkPRMergeBase(logger log.Logger, autofix bool) error { func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) error {
numRepos := 0 numRepos := 0
numPRs := 0 numPRs := 0
numPRsUpdated := 0 numPRsUpdated := 0
@ -43,17 +44,17 @@ func checkPRMergeBase(logger log.Logger, autofix bool) error {
if !pr.HasMerged { if !pr.HasMerged {
var err error var err error
pr.MergeBase, err = git.NewCommand("merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunInDir(repoPath) pr.MergeBase, err = git.NewCommandContext(ctx, "merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunInDir(repoPath)
if err != nil { if err != nil {
var err2 error var err2 error
pr.MergeBase, err2 = git.NewCommand("rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath) pr.MergeBase, err2 = git.NewCommandContext(ctx, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath)
if err2 != nil { if err2 != nil {
logger.Warn("Unable to get merge base for PR ID %d, #%d onto %s in %s/%s. Error: %v & %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err, err2) logger.Warn("Unable to get merge base for PR ID %d, #%d onto %s in %s/%s. Error: %v & %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err, err2)
return nil return nil
} }
} }
} else { } else {
parentsString, err := git.NewCommand("rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath) parentsString, err := git.NewCommandContext(ctx, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
if err != nil { if err != nil {
logger.Warn("Unable to get parents for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err) logger.Warn("Unable to get parents for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
return nil return nil
@ -66,7 +67,7 @@ func checkPRMergeBase(logger log.Logger, autofix bool) error {
args := append([]string{"merge-base", "--"}, parents[1:]...) args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, pr.GetGitRefName()) args = append(args, pr.GetGitRefName())
pr.MergeBase, err = git.NewCommand(args...).RunInDir(repoPath) pr.MergeBase, err = git.NewCommandContext(ctx, args...).RunInDir(repoPath)
if err != nil { if err != nil {
logger.Warn("Unable to get merge base for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err) logger.Warn("Unable to get merge base for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
return nil return nil

@ -5,6 +5,7 @@
package doctor package doctor
import ( import (
"context"
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
@ -38,7 +39,7 @@ func iterateRepositories(each func(*repo_model.Repository) error) error {
return err return err
} }
func checkScriptType(logger log.Logger, autofix bool) error { func checkScriptType(ctx context.Context, logger log.Logger, autofix bool) error {
path, err := exec.LookPath(setting.ScriptType) path, err := exec.LookPath(setting.ScriptType)
if err != nil { if err != nil {
logger.Critical("ScriptType \"%q\" is not on the current PATH. Error: %v", setting.ScriptType, err) logger.Critical("ScriptType \"%q\" is not on the current PATH. Error: %v", setting.ScriptType, err)
@ -48,7 +49,7 @@ func checkScriptType(logger log.Logger, autofix bool) error {
return nil return nil
} }
func checkHooks(logger log.Logger, autofix bool) error { func checkHooks(ctx context.Context, logger log.Logger, autofix bool) error {
if err := iterateRepositories(func(repo *repo_model.Repository) error { if err := iterateRepositories(func(repo *repo_model.Repository) error {
results, err := repository.CheckDelegateHooks(repo.RepoPath()) results, err := repository.CheckDelegateHooks(repo.RepoPath())
if err != nil { if err != nil {
@ -73,7 +74,7 @@ func checkHooks(logger log.Logger, autofix bool) error {
return nil return nil
} }
func checkUserStarNum(logger log.Logger, autofix bool) error { func checkUserStarNum(ctx context.Context, logger log.Logger, autofix bool) error {
if err := models.DoctorUserStarNum(); err != nil { if err := models.DoctorUserStarNum(); err != nil {
logger.Critical("Unable update User Stars numbers") logger.Critical("Unable update User Stars numbers")
return err return err
@ -81,24 +82,24 @@ func checkUserStarNum(logger log.Logger, autofix bool) error {
return nil return nil
} }
func checkEnablePushOptions(logger log.Logger, autofix bool) error { func checkEnablePushOptions(ctx context.Context, logger log.Logger, autofix bool) error {
numRepos := 0 numRepos := 0
numNeedUpdate := 0 numNeedUpdate := 0
if err := iterateRepositories(func(repo *repo_model.Repository) error { if err := iterateRepositories(func(repo *repo_model.Repository) error {
numRepos++ numRepos++
r, err := git.OpenRepository(repo.RepoPath()) r, err := git.OpenRepositoryCtx(git.DefaultContext, repo.RepoPath())
if err != nil { if err != nil {
return err return err
} }
defer r.Close() defer r.Close()
if autofix { if autofix {
_, err := git.NewCommand("config", "receive.advertisePushOptions", "true").RunInDir(r.Path) _, err := git.NewCommandContext(ctx, "config", "receive.advertisePushOptions", "true").RunInDir(r.Path)
return err return err
} }
value, err := git.NewCommand("config", "receive.advertisePushOptions").RunInDir(r.Path) value, err := git.NewCommandContext(ctx, "config", "receive.advertisePushOptions").RunInDir(r.Path)
if err != nil { if err != nil {
return err return err
} }
@ -124,7 +125,7 @@ func checkEnablePushOptions(logger log.Logger, autofix bool) error {
return nil return nil
} }
func checkDaemonExport(logger log.Logger, autofix bool) error { func checkDaemonExport(ctx context.Context, logger log.Logger, autofix bool) error {
numRepos := 0 numRepos := 0
numNeedUpdate := 0 numNeedUpdate := 0
cache, err := lru.New(512) cache, err := lru.New(512)

@ -5,6 +5,7 @@
package doctor package doctor
import ( import (
"context"
"fmt" "fmt"
"os" "os"
@ -58,7 +59,7 @@ func checkConfigurationFile(logger log.Logger, autofix bool, fileOpts configurat
return nil return nil
} }
func checkConfigurationFiles(logger log.Logger, autofix bool) error { func checkConfigurationFiles(ctx context.Context, logger log.Logger, autofix bool) error {
if fi, err := os.Stat(setting.CustomConf); err != nil || !fi.Mode().IsRegular() { if fi, err := os.Stat(setting.CustomConf); err != nil || !fi.Mode().IsRegular() {
logger.Error("Failed to find configuration file at '%s'.", setting.CustomConf) logger.Error("Failed to find configuration file at '%s'.", setting.CustomConf)
logger.Error("If you've never ran Gitea yet, this is normal and '%s' will be created for you on first run.", setting.CustomConf) logger.Error("If you've never ran Gitea yet, this is normal and '%s' will be created for you on first run.", setting.CustomConf)

@ -5,6 +5,8 @@
package doctor package doctor
import ( import (
"context"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/storage"
@ -55,7 +57,7 @@ func checkAttachmentStorageFiles(logger log.Logger, autofix bool) error {
return nil return nil
} }
func checkStorageFiles(logger log.Logger, autofix bool) error { func checkStorageFiles(ctx context.Context, logger log.Logger, autofix bool) error {
if err := storage.Init(); err != nil { if err := storage.Init(); err != nil {
logger.Error("storage.Init failed: %v", err) logger.Error("storage.Init failed: %v", err)
return err return err

@ -5,11 +5,13 @@
package doctor package doctor
import ( import (
"context"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
) )
func checkUserType(logger log.Logger, autofix bool) error { func checkUserType(ctx context.Context, logger log.Logger, autofix bool) error {
count, err := models.CountWrongUserType() count, err := models.CountWrongUserType()
if err != nil { if err != nil {
logger.Critical("Error: %v whilst counting wrong user types") logger.Critical("Error: %v whilst counting wrong user types")

@ -114,12 +114,6 @@ func (r *BlameReader) Close() error {
// CreateBlameReader creates reader for given repository, commit and file // CreateBlameReader creates reader for given repository, commit and file
func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) { func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) {
gitRepo, err := OpenRepositoryCtx(ctx, repoPath)
if err != nil {
return nil, err
}
gitRepo.Close()
return createBlameReader(ctx, repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file) return createBlameReader(ctx, repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file)
} }

@ -8,6 +8,7 @@ package git
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -138,12 +139,12 @@ func CommitChangesWithArgs(repoPath string, args []string, opts CommitChangesOpt
} }
// AllCommitsCount returns count of all commits in repository // AllCommitsCount returns count of all commits in repository
func AllCommitsCount(repoPath string, hidePRRefs bool, files ...string) (int64, error) { func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, files ...string) (int64, error) {
args := []string{"--all", "--count"} args := []string{"--all", "--count"}
if hidePRRefs { if hidePRRefs {
args = append([]string{"--exclude=" + PullPrefix + "*"}, args...) args = append([]string{"--exclude=" + PullPrefix + "*"}, args...)
} }
cmd := NewCommand("rev-list") cmd := NewCommandContext(ctx, "rev-list")
cmd.AddArguments(args...) cmd.AddArguments(args...)
if len(files) > 0 { if len(files) > 0 {
cmd.AddArguments("--") cmd.AddArguments("--")
@ -159,8 +160,8 @@ func AllCommitsCount(repoPath string, hidePRRefs bool, files ...string) (int64,
} }
// CommitsCountFiles returns number of total commits of until given revision. // CommitsCountFiles returns number of total commits of until given revision.
func CommitsCountFiles(repoPath string, revision, relpath []string) (int64, error) { func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) {
cmd := NewCommand("rev-list", "--count") cmd := NewCommandContext(ctx, "rev-list", "--count")
cmd.AddArguments(revision...) cmd.AddArguments(revision...)
if len(relpath) > 0 { if len(relpath) > 0 {
cmd.AddArguments("--") cmd.AddArguments("--")
@ -176,13 +177,13 @@ func CommitsCountFiles(repoPath string, revision, relpath []string) (int64, erro
} }
// CommitsCount returns number of total commits of until given revision. // CommitsCount returns number of total commits of until given revision.
func CommitsCount(repoPath string, revision ...string) (int64, error) { func CommitsCount(ctx context.Context, repoPath string, revision ...string) (int64, error) {
return CommitsCountFiles(repoPath, revision, []string{}) return CommitsCountFiles(ctx, repoPath, revision, []string{})
} }
// CommitsCount returns number of total commits of until current revision. // CommitsCount returns number of total commits of until current revision.
func (c *Commit) CommitsCount() (int64, error) { func (c *Commit) CommitsCount() (int64, error) {
return CommitsCount(c.repo.Path, c.ID.String()) return CommitsCount(c.repo.Ctx, c.repo.Path, c.ID.String())
} }
// CommitsByRange returns the specific page commits before current revision, every page's number default by CommitsRangeSize // CommitsByRange returns the specific page commits before current revision, every page's number default by CommitsRangeSize
@ -205,7 +206,7 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
} }
if err := CheckGitVersionAtLeast("1.8"); err == nil { if err := CheckGitVersionAtLeast("1.8"); err == nil {
_, err := NewCommand("merge-base", "--is-ancestor", that, this).RunInDir(c.repo.Path) _, err := NewCommandContext(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunInDir(c.repo.Path)
if err == nil { if err == nil {
return true, nil return true, nil
} }
@ -218,7 +219,7 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
return false, err return false, err
} }
result, err := NewCommand("rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunInDir(c.repo.Path) result, err := NewCommandContext(c.repo.Ctx, "rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunInDir(c.repo.Path)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -380,7 +381,7 @@ func (c *Commit) GetBranchName() (string, error) {
} }
args = append(args, "--name-only", "--no-undefined", c.ID.String()) args = append(args, "--name-only", "--no-undefined", c.ID.String())
data, err := NewCommand(args...).RunInDir(c.repo.Path) data, err := NewCommandContext(c.repo.Ctx, args...).RunInDir(c.repo.Path)
if err != nil { if err != nil {
// handle special case where git can not describe commit // handle special case where git can not describe commit
if strings.Contains(err.Error(), "cannot describe") { if strings.Contains(err.Error(), "cannot describe") {
@ -406,7 +407,7 @@ func (c *Commit) LoadBranchName() (err error) {
// GetTagName gets the current tag name for given commit // GetTagName gets the current tag name for given commit
func (c *Commit) GetTagName() (string, error) { func (c *Commit) GetTagName() (string, error) {
data, err := NewCommand("describe", "--exact-match", "--tags", "--always", c.ID.String()).RunInDir(c.repo.Path) data, err := NewCommandContext(c.repo.Ctx, "describe", "--exact-match", "--tags", "--always", c.ID.String()).RunInDir(c.repo.Path)
if err != nil { if err != nil {
// handle special case where there is no tag for this commit // handle special case where there is no tag for this commit
if strings.Contains(err.Error(), "no tag exactly matches") { if strings.Contains(err.Error(), "no tag exactly matches") {
@ -473,7 +474,7 @@ func parseCommitFileStatus(fileStatus *CommitFileStatus, stdout io.Reader) {
} }
// GetCommitFileStatus returns file status of commit in given repository. // GetCommitFileStatus returns file status of commit in given repository.
func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) { func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*CommitFileStatus, error) {
stdout, w := io.Pipe() stdout, w := io.Pipe()
done := make(chan struct{}) done := make(chan struct{})
fileStatus := NewCommitFileStatus() fileStatus := NewCommitFileStatus()
@ -485,7 +486,7 @@ func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) {
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
args := []string{"log", "--name-status", "-c", "--pretty=format:", "--parents", "--no-renames", "-z", "-1", commitID} args := []string{"log", "--name-status", "-c", "--pretty=format:", "--parents", "--no-renames", "-z", "-1", commitID}
err := NewCommand(args...).RunInDirPipeline(repoPath, w, stderr) err := NewCommandContext(ctx, args...).RunInDirPipeline(repoPath, w, stderr)
w.Close() // Close writer to exit parsing goroutine w.Close() // Close writer to exit parsing goroutine
if err != nil { if err != nil {
return nil, ConcatenateError(err, stderr.String()) return nil, ConcatenateError(err, stderr.String())
@ -496,8 +497,8 @@ func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) {
} }
// GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository. // GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository.
func GetFullCommitID(repoPath, shortID string) (string, error) { func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, error) {
commitID, err := NewCommand("rev-parse", shortID).RunInDir(repoPath) commitID, err := NewCommandContext(ctx, "rev-parse", shortID).RunInDir(repoPath)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "exit status 128") { if strings.Contains(err.Error(), "exit status 128") {
return "", ErrNotExist{shortID, ""} return "", ErrNotExist{shortID, ""}

@ -24,7 +24,7 @@ func cloneRepo(url, dir, name string) (string, error) {
if _, err := os.Stat(repoDir); err == nil { if _, err := os.Stat(repoDir); err == nil {
return repoDir, nil return repoDir, nil
} }
return repoDir, Clone(url, repoDir, CloneRepoOptions{ return repoDir, Clone(DefaultContext, url, repoDir, CloneRepoOptions{
Mirror: false, Mirror: false,
Bare: false, Bare: false,
Quiet: true, Quiet: true,

@ -15,7 +15,7 @@ import (
func TestCommitsCount(t *testing.T) { func TestCommitsCount(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
commitsCount, err := CommitsCount(bareRepo1Path, "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0") commitsCount, err := CommitsCount(DefaultContext, bareRepo1Path, "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, int64(3), commitsCount) assert.Equal(t, int64(3), commitsCount)
} }
@ -23,7 +23,7 @@ func TestCommitsCount(t *testing.T) {
func TestGetFullCommitID(t *testing.T) { func TestGetFullCommitID(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
id, err := GetFullCommitID(bareRepo1Path, "8006ff9a") id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "8006ff9a")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0", id) assert.Equal(t, "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0", id)
} }
@ -31,7 +31,7 @@ func TestGetFullCommitID(t *testing.T) {
func TestGetFullCommitIDError(t *testing.T) { func TestGetFullCommitIDError(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
id, err := GetFullCommitID(bareRepo1Path, "unknown") id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "unknown")
assert.Empty(t, id) assert.Empty(t, id)
if assert.Error(t, err) { if assert.Error(t, err) {
assert.EqualError(t, err, "object does not exist [id: unknown, rel_path: ]") assert.EqualError(t, err, "object does not exist [id: unknown, rel_path: ]")

@ -30,17 +30,17 @@ const (
) )
// GetRawDiff dumps diff results of repository in given commit ID to io.Writer. // GetRawDiff dumps diff results of repository in given commit ID to io.Writer.
func GetRawDiff(repoPath, commitID string, diffType RawDiffType, writer io.Writer) error { func GetRawDiff(ctx context.Context, repoPath, commitID string, diffType RawDiffType, writer io.Writer) error {
return GetRawDiffForFile(repoPath, "", commitID, diffType, "", writer) return GetRawDiffForFile(ctx, repoPath, "", commitID, diffType, "", writer)
} }
// GetRawDiffForFile dumps diff results of file in given commit ID to io.Writer. // GetRawDiffForFile dumps diff results of file in given commit ID to io.Writer.
func GetRawDiffForFile(repoPath, startCommit, endCommit string, diffType RawDiffType, file string, writer io.Writer) error { func GetRawDiffForFile(ctx context.Context, repoPath, startCommit, endCommit string, diffType RawDiffType, file string, writer io.Writer) error {
repo, err := OpenRepository(repoPath) repo, closer, err := RepositoryFromContextOrOpen(ctx, repoPath)
if err != nil { if err != nil {
return fmt.Errorf("OpenRepository: %v", err) return fmt.Errorf("OpenRepository: %v", err)
} }
defer repo.Close() defer closer.Close()
return GetRepoRawDiffForFile(repo, startCommit, endCommit, diffType, file, writer) return GetRepoRawDiffForFile(repo, startCommit, endCommit, diffType, file, writer)
} }
@ -276,7 +276,7 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi
} }
// GetAffectedFiles returns the affected files between two commits // GetAffectedFiles returns the affected files between two commits
func GetAffectedFiles(oldCommitID, newCommitID string, env []string, repo *Repository) ([]string, error) { func GetAffectedFiles(repo *Repository, oldCommitID, newCommitID string, env []string) ([]string, error) {
stdoutReader, stdoutWriter, err := os.Pipe() stdoutReader, stdoutWriter, err := os.Pipe()
if err != nil { if err != nil {
log.Error("Unable to create os.Pipe for %s", repo.Path) log.Error("Unable to create os.Pipe for %s", repo.Path)
@ -290,7 +290,7 @@ func GetAffectedFiles(oldCommitID, newCommitID string, env []string, repo *Repos
affectedFiles := make([]string, 0, 32) affectedFiles := make([]string, 0, 32)
// Run `git diff --name-only` to get the names of the changed files // Run `git diff --name-only` to get the names of the changed files
err = NewCommand("diff", "--name-only", oldCommitID, newCommitID). err = NewCommandContext(repo.Ctx, "diff", "--name-only", oldCommitID, newCommitID).
RunInDirTimeoutEnvFullPipelineFunc(env, -1, repo.Path, RunInDirTimeoutEnvFullPipelineFunc(env, -1, repo.Path,
stdoutWriter, nil, nil, stdoutWriter, nil, nil,
func(ctx context.Context, cancel context.CancelFunc) error { func(ctx context.Context, cancel context.CancelFunc) error {

@ -7,6 +7,7 @@ package pipeline
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
@ -18,27 +19,27 @@ import (
) )
// CatFileBatchCheck runs cat-file with --batch-check // CatFileBatchCheck runs cat-file with --batch-check
func CatFileBatchCheck(shasToCheckReader *io.PipeReader, catFileCheckWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string) { func CatFileBatchCheck(ctx context.Context, shasToCheckReader *io.PipeReader, catFileCheckWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string) {
defer wg.Done() defer wg.Done()
defer shasToCheckReader.Close() defer shasToCheckReader.Close()
defer catFileCheckWriter.Close() defer catFileCheckWriter.Close()
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
cmd := git.NewCommand("cat-file", "--batch-check") cmd := git.NewCommandContext(ctx, "cat-file", "--batch-check")
if err := cmd.RunInDirFullPipeline(tmpBasePath, catFileCheckWriter, stderr, shasToCheckReader); err != nil { if err := cmd.RunInDirFullPipeline(tmpBasePath, catFileCheckWriter, stderr, shasToCheckReader); err != nil {
_ = catFileCheckWriter.CloseWithError(fmt.Errorf("git cat-file --batch-check [%s]: %v - %s", tmpBasePath, err, errbuf.String())) _ = catFileCheckWriter.CloseWithError(fmt.Errorf("git cat-file --batch-check [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
} }
} }
// CatFileBatchCheckAllObjects runs cat-file with --batch-check --batch-all // CatFileBatchCheckAllObjects runs cat-file with --batch-check --batch-all
func CatFileBatchCheckAllObjects(catFileCheckWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string, errChan chan<- error) { func CatFileBatchCheckAllObjects(ctx context.Context, catFileCheckWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string, errChan chan<- error) {
defer wg.Done() defer wg.Done()
defer catFileCheckWriter.Close() defer catFileCheckWriter.Close()
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
cmd := git.NewCommand("cat-file", "--batch-check", "--batch-all-objects") cmd := git.NewCommandContext(ctx, "cat-file", "--batch-check", "--batch-all-objects")
if err := cmd.RunInDirPipeline(tmpBasePath, catFileCheckWriter, stderr); err != nil { if err := cmd.RunInDirPipeline(tmpBasePath, catFileCheckWriter, stderr); err != nil {
log.Error("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String()) log.Error("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String())
err = fmt.Errorf("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String()) err = fmt.Errorf("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String())
@ -48,14 +49,14 @@ func CatFileBatchCheckAllObjects(catFileCheckWriter *io.PipeWriter, wg *sync.Wai
} }
// CatFileBatch runs cat-file --batch // CatFileBatch runs cat-file --batch
func CatFileBatch(shasToBatchReader *io.PipeReader, catFileBatchWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string) { func CatFileBatch(ctx context.Context, shasToBatchReader *io.PipeReader, catFileBatchWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string) {
defer wg.Done() defer wg.Done()
defer shasToBatchReader.Close() defer shasToBatchReader.Close()
defer catFileBatchWriter.Close() defer catFileBatchWriter.Close()
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
if err := git.NewCommand("cat-file", "--batch").RunInDirFullPipeline(tmpBasePath, catFileBatchWriter, stderr, shasToBatchReader); err != nil { if err := git.NewCommandContext(ctx, "cat-file", "--batch").RunInDirFullPipeline(tmpBasePath, catFileBatchWriter, stderr, shasToBatchReader); err != nil {
_ = shasToBatchReader.CloseWithError(fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String())) _ = shasToBatchReader.CloseWithError(fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
} }
} }

@ -120,7 +120,7 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
i++ i++
} }
}() }()
go NameRevStdin(shasToNameReader, nameRevStdinWriter, &wg, basePath) go NameRevStdin(repo.Ctx, shasToNameReader, nameRevStdinWriter, &wg, basePath)
go func() { go func() {
defer wg.Done() defer wg.Done()
defer shasToNameWriter.Close() defer shasToNameWriter.Close()

@ -53,7 +53,7 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
go func() { go func() {
stderr := strings.Builder{} stderr := strings.Builder{}
err := git.NewCommand("rev-list", "--all").RunInDirPipeline(repo.Path, revListWriter, &stderr) err := git.NewCommandContext(repo.Ctx, "rev-list", "--all").RunInDirPipeline(repo.Path, revListWriter, &stderr)
if err != nil { if err != nil {
_ = revListWriter.CloseWithError(git.ConcatenateError(err, (&stderr).String())) _ = revListWriter.CloseWithError(git.ConcatenateError(err, (&stderr).String()))
} else { } else {
@ -212,7 +212,7 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
i++ i++
} }
}() }()
go NameRevStdin(shasToNameReader, nameRevStdinWriter, &wg, basePath) go NameRevStdin(repo.Ctx, shasToNameReader, nameRevStdinWriter, &wg, basePath)
go func() { go func() {
defer wg.Done() defer wg.Done()
defer shasToNameWriter.Close() defer shasToNameWriter.Close()

@ -6,6 +6,7 @@ package pipeline
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"io" "io"
"strings" "strings"
@ -15,14 +16,14 @@ import (
) )
// NameRevStdin runs name-rev --stdin // NameRevStdin runs name-rev --stdin
func NameRevStdin(shasToNameReader *io.PipeReader, nameRevStdinWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string) { func NameRevStdin(ctx context.Context, shasToNameReader *io.PipeReader, nameRevStdinWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath string) {
defer wg.Done() defer wg.Done()
defer shasToNameReader.Close() defer shasToNameReader.Close()
defer nameRevStdinWriter.Close() defer nameRevStdinWriter.Close()
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
if err := git.NewCommand("name-rev", "--stdin", "--name-only", "--always").RunInDirFullPipeline(tmpBasePath, nameRevStdinWriter, stderr, shasToNameReader); err != nil { if err := git.NewCommandContext(ctx, "name-rev", "--stdin", "--name-only", "--always").RunInDirFullPipeline(tmpBasePath, nameRevStdinWriter, stderr, shasToNameReader); err != nil {
_ = shasToNameReader.CloseWithError(fmt.Errorf("git name-rev [%s]: %v - %s", tmpBasePath, err, errbuf.String())) _ = shasToNameReader.CloseWithError(fmt.Errorf("git name-rev [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
} }
} }

@ -7,6 +7,7 @@ package pipeline
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"fmt" "fmt"
"io" "io"
"strings" "strings"
@ -17,13 +18,13 @@ import (
) )
// RevListAllObjects runs rev-list --objects --all and writes to a pipewriter // RevListAllObjects runs rev-list --objects --all and writes to a pipewriter
func RevListAllObjects(revListWriter *io.PipeWriter, wg *sync.WaitGroup, basePath string, errChan chan<- error) { func RevListAllObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.WaitGroup, basePath string, errChan chan<- error) {
defer wg.Done() defer wg.Done()
defer revListWriter.Close() defer revListWriter.Close()
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
cmd := git.NewCommand("rev-list", "--objects", "--all") cmd := git.NewCommandContext(ctx, "rev-list", "--objects", "--all")
if err := cmd.RunInDirPipeline(basePath, revListWriter, stderr); err != nil { if err := cmd.RunInDirPipeline(basePath, revListWriter, stderr); err != nil {
log.Error("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String()) log.Error("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String())
err = fmt.Errorf("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String()) err = fmt.Errorf("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String())
@ -33,12 +34,12 @@ func RevListAllObjects(revListWriter *io.PipeWriter, wg *sync.WaitGroup, basePat
} }
// RevListObjects run rev-list --objects from headSHA to baseSHA // RevListObjects run rev-list --objects from headSHA to baseSHA
func RevListObjects(revListWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath, headSHA, baseSHA string, errChan chan<- error) { func RevListObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.WaitGroup, tmpBasePath, headSHA, baseSHA string, errChan chan<- error) {
defer wg.Done() defer wg.Done()
defer revListWriter.Close() defer revListWriter.Close()
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
cmd := git.NewCommand("rev-list", "--objects", headSHA, "--not", baseSHA) cmd := git.NewCommandContext(ctx, "rev-list", "--objects", headSHA, "--not", baseSHA)
if err := cmd.RunInDirPipeline(tmpBasePath, revListWriter, stderr); err != nil { if err := cmd.RunInDirPipeline(tmpBasePath, revListWriter, stderr); err != nil {
log.Error("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()) log.Error("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String())
errChan <- fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()) errChan <- fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String())

@ -34,7 +34,7 @@ const prettyLogFormat = `--pretty=format:%H`
// GetAllCommitsCount returns count of all commits in repository // GetAllCommitsCount returns count of all commits in repository
func (repo *Repository) GetAllCommitsCount() (int64, error) { func (repo *Repository) GetAllCommitsCount() (int64, error) {
return AllCommitsCount(repo.Path, false) return AllCommitsCount(repo.Ctx, repo.Path, false)
} }
func (repo *Repository) parsePrettyFormatLogToList(logs []byte) ([]*Commit, error) { func (repo *Repository) parsePrettyFormatLogToList(logs []byte) ([]*Commit, error) {
@ -57,19 +57,19 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) ([]*Commit, erro
} }
// IsRepoURLAccessible checks if given repository URL is accessible. // IsRepoURLAccessible checks if given repository URL is accessible.
func IsRepoURLAccessible(url string) bool { func IsRepoURLAccessible(ctx context.Context, url string) bool {
_, err := NewCommand("ls-remote", "-q", "-h", url, "HEAD").Run() _, err := NewCommandContext(ctx, "ls-remote", "-q", "-h", url, "HEAD").Run()
return err == nil return err == nil
} }
// InitRepository initializes a new Git repository. // InitRepository initializes a new Git repository.
func InitRepository(repoPath string, bare bool) error { func InitRepository(ctx context.Context, repoPath string, bare bool) error {
err := os.MkdirAll(repoPath, os.ModePerm) err := os.MkdirAll(repoPath, os.ModePerm)
if err != nil { if err != nil {
return err return err
} }
cmd := NewCommand("init") cmd := NewCommandContext(ctx, "init")
if bare { if bare {
cmd.AddArguments("--bare") cmd.AddArguments("--bare")
} }
@ -80,7 +80,7 @@ func InitRepository(repoPath string, bare bool) error {
// IsEmpty Check if repository is empty. // IsEmpty Check if repository is empty.
func (repo *Repository) IsEmpty() (bool, error) { func (repo *Repository) IsEmpty() (bool, error) {
var errbuf strings.Builder var errbuf strings.Builder
if err := NewCommand("log", "-1").RunInDirPipeline(repo.Path, nil, &errbuf); err != nil { if err := NewCommandContext(repo.Ctx, "log", "-1").RunInDirPipeline(repo.Path, nil, &errbuf); err != nil {
if strings.Contains(errbuf.String(), "fatal: bad default revision 'HEAD'") || if strings.Contains(errbuf.String(), "fatal: bad default revision 'HEAD'") ||
strings.Contains(errbuf.String(), "fatal: your current branch 'master' does not have any commits yet") { strings.Contains(errbuf.String(), "fatal: your current branch 'master' does not have any commits yet") {
return true, nil return true, nil
@ -104,12 +104,7 @@ type CloneRepoOptions struct {
} }
// Clone clones original repository to target path. // Clone clones original repository to target path.
func Clone(from, to string, opts CloneRepoOptions) error { func Clone(ctx context.Context, from, to string, opts CloneRepoOptions) error {
return CloneWithContext(DefaultContext, from, to, opts)
}
// CloneWithContext clones original repository to target path.
func CloneWithContext(ctx context.Context, from, to string, opts CloneRepoOptions) error {
cargs := make([]string, len(GlobalCommandArgs)) cargs := make([]string, len(GlobalCommandArgs))
copy(cargs, GlobalCommandArgs) copy(cargs, GlobalCommandArgs)
return CloneWithArgs(ctx, from, to, cargs, opts) return CloneWithArgs(ctx, from, to, cargs, opts)
@ -171,35 +166,6 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
return nil return nil
} }
// PullRemoteOptions options when pull from remote
type PullRemoteOptions struct {
Timeout time.Duration
All bool
Rebase bool
Remote string
Branch string
}
// Pull pulls changes from remotes.
func Pull(repoPath string, opts PullRemoteOptions) error {
cmd := NewCommand("pull")
if opts.Rebase {
cmd.AddArguments("--rebase")
}
if opts.All {
cmd.AddArguments("--all")
} else {
cmd.AddArguments("--", opts.Remote, opts.Branch)
}
if opts.Timeout <= 0 {
opts.Timeout = -1
}
_, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
return err
}
// PushOptions options when push to remote // PushOptions options when push to remote
type PushOptions struct { type PushOptions struct {
Remote string Remote string
@ -262,116 +228,9 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
return err return err
} }
// CheckoutOptions options when heck out some branch
type CheckoutOptions struct {
Timeout time.Duration
Branch string
OldBranch string
}
// Checkout checkouts a branch
func Checkout(repoPath string, opts CheckoutOptions) error {
cmd := NewCommand("checkout")
if len(opts.OldBranch) > 0 {
cmd.AddArguments("-b")
}
if opts.Timeout <= 0 {
opts.Timeout = -1
}
cmd.AddArguments(opts.Branch)
if len(opts.OldBranch) > 0 {
cmd.AddArguments(opts.OldBranch)
}
_, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
return err
}
// ResetHEAD resets HEAD to given revision or head of branch.
func ResetHEAD(repoPath string, hard bool, revision string) error {
cmd := NewCommand("reset")
if hard {
cmd.AddArguments("--hard")
}
_, err := cmd.AddArguments(revision).RunInDir(repoPath)
return err
}
// MoveFile moves a file to another file or directory.
func MoveFile(repoPath, oldTreeName, newTreeName string) error {
_, err := NewCommand("mv").AddArguments(oldTreeName, newTreeName).RunInDir(repoPath)
return err
}
// CountObject represents repository count objects report
type CountObject struct {
Count int64
Size int64
InPack int64
Packs int64
SizePack int64
PrunePack int64
Garbage int64
SizeGarbage int64
}
const (
statCount = "count: "
statSize = "size: "
statInpack = "in-pack: "
statPacks = "packs: "
statSizePack = "size-pack: "
statPrunePackage = "prune-package: "
statGarbage = "garbage: "
statSizeGarbage = "size-garbage: "
)
// CountObjects returns the results of git count-objects on the repoPath
func CountObjects(repoPath string) (*CountObject, error) {
cmd := NewCommand("count-objects", "-v")
stdout, err := cmd.RunInDir(repoPath)
if err != nil {
return nil, err
}
return parseSize(stdout), nil
}
// parseSize parses the output from count-objects and return a CountObject
func parseSize(objects string) *CountObject {
repoSize := new(CountObject)
for _, line := range strings.Split(objects, "\n") {
switch {
case strings.HasPrefix(line, statCount):
repoSize.Count, _ = strconv.ParseInt(line[7:], 10, 64)
case strings.HasPrefix(line, statSize):
repoSize.Size, _ = strconv.ParseInt(line[6:], 10, 64)
repoSize.Size *= 1024
case strings.HasPrefix(line, statInpack):
repoSize.InPack, _ = strconv.ParseInt(line[9:], 10, 64)
case strings.HasPrefix(line, statPacks):
repoSize.Packs, _ = strconv.ParseInt(line[7:], 10, 64)
case strings.HasPrefix(line, statSizePack):
repoSize.Count, _ = strconv.ParseInt(line[11:], 10, 64)
repoSize.Count *= 1024
case strings.HasPrefix(line, statPrunePackage):
repoSize.PrunePack, _ = strconv.ParseInt(line[16:], 10, 64)
case strings.HasPrefix(line, statGarbage):
repoSize.Garbage, _ = strconv.ParseInt(line[9:], 10, 64)
case strings.HasPrefix(line, statSizeGarbage):
repoSize.SizeGarbage, _ = strconv.ParseInt(line[14:], 10, 64)
repoSize.SizeGarbage *= 1024
}
}
return repoSize
}
// GetLatestCommitTime returns time for latest commit in repository (across all branches) // GetLatestCommitTime returns time for latest commit in repository (across all branches)
func GetLatestCommitTime(repoPath string) (time.Time, error) { func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error) {
cmd := NewCommand("for-each-ref", "--sort=-committerdate", BranchPrefix, "--count", "1", "--format=%(committerdate)") cmd := NewCommandContext(ctx, "for-each-ref", "--sort=-committerdate", BranchPrefix, "--count", "1", "--format=%(committerdate)")
stdout, err := cmd.RunInDir(repoPath) stdout, err := cmd.RunInDir(repoPath)
if err != nil { if err != nil {
return time.Time{}, err return time.Time{}, err
@ -386,9 +245,9 @@ type DivergeObject struct {
Behind int Behind int
} }
func checkDivergence(repoPath, baseBranch, targetBranch string) (int, error) { func checkDivergence(ctx context.Context, repoPath, baseBranch, targetBranch string) (int, error) {
branches := fmt.Sprintf("%s..%s", baseBranch, targetBranch) branches := fmt.Sprintf("%s..%s", baseBranch, targetBranch)
cmd := NewCommand("rev-list", "--count", branches) cmd := NewCommandContext(ctx, "rev-list", "--count", branches)
stdout, err := cmd.RunInDir(repoPath) stdout, err := cmd.RunInDir(repoPath)
if err != nil { if err != nil {
return -1, err return -1, err
@ -401,15 +260,15 @@ func checkDivergence(repoPath, baseBranch, targetBranch string) (int, error) {
} }
// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch // GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
func GetDivergingCommits(repoPath, baseBranch, targetBranch string) (DivergeObject, error) { func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (DivergeObject, error) {
// $(git rev-list --count master..feature) commits ahead of master // $(git rev-list --count master..feature) commits ahead of master
ahead, errorAhead := checkDivergence(repoPath, baseBranch, targetBranch) ahead, errorAhead := checkDivergence(ctx, repoPath, baseBranch, targetBranch)
if errorAhead != nil { if errorAhead != nil {
return DivergeObject{}, errorAhead return DivergeObject{}, errorAhead
} }
// $(git rev-list --count feature..master) commits behind master // $(git rev-list --count feature..master) commits behind master
behind, errorBehind := checkDivergence(repoPath, targetBranch, baseBranch) behind, errorBehind := checkDivergence(ctx, repoPath, targetBranch, baseBranch)
if errorBehind != nil { if errorBehind != nil {
return DivergeObject{}, errorBehind return DivergeObject{}, errorBehind
} }

@ -0,0 +1,49 @@
// Copyright 2021 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 git
import (
"context"
"io"
)
// contextKey is a value for use with context.WithValue.
type contextKey struct {
name string
}
// RepositoryContextKey is a context key. It is used with context.Value() to get the current Repository for the context
var RepositoryContextKey = &contextKey{"repository"}
// RepositoryFromContext attempts to get the repository from the context
func RepositoryFromContext(ctx context.Context, path string) *Repository {
value := ctx.Value(RepositoryContextKey)
if value == nil {
return nil
}
if repo, ok := value.(*Repository); ok && repo != nil {
if repo.Path == path {
return repo
}
}
return nil
}
type nopCloser func()
func (nopCloser) Close() error { return nil }
// RepositoryFromContextOrOpen attempts to get the repository from the context or just opens it
func RepositoryFromContextOrOpen(ctx context.Context, path string) (*Repository, io.Closer, error) {
gitRepo := RepositoryFromContext(ctx, path)
if gitRepo != nil {
return gitRepo, nopCloser(nil), nil
}
gitRepo, err := OpenRepositoryCtx(ctx, path)
return gitRepo, gitRepo, err
}

@ -73,13 +73,14 @@ func OpenRepositoryCtx(ctx context.Context, repoPath string) (*Repository, error
} }
// Close this repository, in particular close the underlying gogitStorage if this is not nil // Close this repository, in particular close the underlying gogitStorage if this is not nil
func (repo *Repository) Close() { func (repo *Repository) Close() (err error) {
if repo == nil || repo.gogitStorage == nil { if repo == nil || repo.gogitStorage == nil {
return return
} }
if err := repo.gogitStorage.Close(); err != nil { if err := repo.gogitStorage.Close(); err != nil {
gitealog.Error("Error closing storage: %v", err) gitealog.Error("Error closing storage: %v", err)
} }
return
} }
// GoGitRepo gets the go-git repo representation // GoGitRepo gets the go-git repo representation

@ -86,7 +86,7 @@ func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError
} }
// Close this repository, in particular close the underlying gogitStorage if this is not nil // Close this repository, in particular close the underlying gogitStorage if this is not nil
func (repo *Repository) Close() { func (repo *Repository) Close() (err error) {
if repo == nil { if repo == nil {
return return
} }
@ -102,4 +102,5 @@ func (repo *Repository) Close() {
repo.checkReader = nil repo.checkReader = nil
repo.checkWriter = nil repo.checkWriter = nil
} }
return
} }

@ -88,8 +88,8 @@ func (repo *Repository) GetBranch(branch string) (*Branch, error) {
// GetBranchesByPath returns a branch by it's path // GetBranchesByPath returns a branch by it's path
// if limit = 0 it will not limit // if limit = 0 it will not limit
func GetBranchesByPath(path string, skip, limit int) ([]*Branch, int, error) { func GetBranchesByPath(ctx context.Context, path string, skip, limit int) ([]*Branch, int, error) {
gitRepo, err := OpenRepository(path) gitRepo, err := OpenRepositoryCtx(ctx, path)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }

@ -83,11 +83,15 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
// WalkReferences walks all the references from the repository // WalkReferences walks all the references from the repository
func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) { func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) {
repo, err := OpenRepositoryCtx(ctx, repoPath) repo := RepositoryFromContext(ctx, repoPath)
if repo == nil {
var err error
repo, err = OpenRepositoryCtx(ctx, repoPath)
if err != nil { if err != nil {
return 0, err return 0, err
} }
defer repo.Close() defer repo.Close()
}
i := 0 i := 0
iter, err := repo.gogitRepo.References() iter, err := repo.gogitRepo.References()

@ -195,7 +195,7 @@ func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bo
// FileCommitsCount return the number of files at a revision // FileCommitsCount return the number of files at a revision
func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) { func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) {
return CommitsCountFiles(repo.Path, []string{revision}, []string{file}) return CommitsCountFiles(repo.Ctx, repo.Path, []string{revision}, []string{file})
} }
// CommitsByFileAndRange return the commits according revision file and the page // CommitsByFileAndRange return the commits according revision file and the page
@ -321,11 +321,11 @@ func (repo *Repository) CommitsBetweenIDs(last, before string) ([]*Commit, error
// CommitsCountBetween return numbers of commits between two commits // CommitsCountBetween return numbers of commits between two commits
func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) { func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
count, err := CommitsCountFiles(repo.Path, []string{start + ".." + end}, []string{}) count, err := CommitsCountFiles(repo.Ctx, repo.Path, []string{start + ".." + end}, []string{})
if err != nil && strings.Contains(err.Error(), "no merge base") { if err != nil && strings.Contains(err.Error(), "no merge base") {
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated. // future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
// previously it would return the results of git rev-list before last so let's try that... // previously it would return the results of git rev-list before last so let's try that...
return CommitsCountFiles(repo.Path, []string{start, end}, []string{}) return CommitsCountFiles(repo.Ctx, repo.Path, []string{start, end}, []string{})
} }
return count, err return count, err

@ -8,6 +8,7 @@ package git
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -72,14 +73,14 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string,
compareInfo := new(CompareInfo) compareInfo := new(CompareInfo)
compareInfo.HeadCommitID, err = GetFullCommitID(repo.Path, headBranch) compareInfo.HeadCommitID, err = GetFullCommitID(repo.Ctx, repo.Path, headBranch)
if err != nil { if err != nil {
compareInfo.HeadCommitID = headBranch compareInfo.HeadCommitID = headBranch
} }
compareInfo.MergeBase, remoteBranch, err = repo.GetMergeBase(tmpRemote, baseBranch, headBranch) compareInfo.MergeBase, remoteBranch, err = repo.GetMergeBase(tmpRemote, baseBranch, headBranch)
if err == nil { if err == nil {
compareInfo.BaseCommitID, err = GetFullCommitID(repo.Path, remoteBranch) compareInfo.BaseCommitID, err = GetFullCommitID(repo.Ctx, repo.Path, remoteBranch)
if err != nil { if err != nil {
compareInfo.BaseCommitID = remoteBranch compareInfo.BaseCommitID = remoteBranch
} }
@ -105,7 +106,7 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string,
} }
} else { } else {
compareInfo.Commits = []*Commit{} compareInfo.Commits = []*Commit{}
compareInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch) compareInfo.MergeBase, err = GetFullCommitID(repo.Ctx, repo.Path, remoteBranch)
if err != nil { if err != nil {
compareInfo.MergeBase = remoteBranch compareInfo.MergeBase = remoteBranch
} }
@ -163,15 +164,15 @@ func (repo *Repository) GetDiffNumChangedFiles(base, head string, directComparis
// GetDiffShortStat counts number of changed files, number of additions and deletions // GetDiffShortStat counts number of changed files, number of additions and deletions
func (repo *Repository) GetDiffShortStat(base, head string) (numFiles, totalAdditions, totalDeletions int, err error) { func (repo *Repository) GetDiffShortStat(base, head string) (numFiles, totalAdditions, totalDeletions int, err error) {
numFiles, totalAdditions, totalDeletions, err = GetDiffShortStat(repo.Path, base+"..."+head) numFiles, totalAdditions, totalDeletions, err = GetDiffShortStat(repo.Ctx, repo.Path, base+"..."+head)
if err != nil && strings.Contains(err.Error(), "no merge base") { if err != nil && strings.Contains(err.Error(), "no merge base") {
return GetDiffShortStat(repo.Path, base, head) return GetDiffShortStat(repo.Ctx, repo.Path, base, head)
} }
return return
} }
// GetDiffShortStat counts number of changed files, number of additions and deletions // GetDiffShortStat counts number of changed files, number of additions and deletions
func GetDiffShortStat(repoPath string, args ...string) (numFiles, totalAdditions, totalDeletions int, err error) { func GetDiffShortStat(ctx context.Context, repoPath string, args ...string) (numFiles, totalAdditions, totalDeletions int, err error) {
// Now if we call: // Now if we call:
// $ git diff --shortstat 1ebb35b98889ff77299f24d82da426b434b0cca0...788b8b1440462d477f45b0088875 // $ git diff --shortstat 1ebb35b98889ff77299f24d82da426b434b0cca0...788b8b1440462d477f45b0088875
// we get: // we get:
@ -181,7 +182,7 @@ func GetDiffShortStat(repoPath string, args ...string) (numFiles, totalAdditions
"--shortstat", "--shortstat",
}, args...) }, args...)
stdout, err := NewCommand(args...).RunInDir(repoPath) stdout, err := NewCommandContext(ctx, args...).RunInDir(repoPath)
if err != nil { if err != nil {
return 0, 0, 0, err return 0, 0, 0, err
} }

@ -13,7 +13,7 @@ import (
func TestGetLatestCommitTime(t *testing.T) { func TestGetLatestCommitTime(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
lct, err := GetLatestCommitTime(bareRepo1Path) lct, err := GetLatestCommitTime(DefaultContext, bareRepo1Path)
assert.NoError(t, err) assert.NoError(t, err)
// Time is Sun Jul 21 22:43:13 2019 +0200 // Time is Sun Jul 21 22:43:13 2019 +0200
// which is the time of commit // which is the time of commit

@ -49,7 +49,7 @@ func (t *Tree) SubTree(rpath string) (*Tree, error) {
// LsTree checks if the given filenames are in the tree // LsTree checks if the given filenames are in the tree
func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error) { func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error) {
cmd := NewCommand("ls-tree", "-z", "--name-only", "--", ref) cmd := NewCommandContext(repo.Ctx, "ls-tree", "-z", "--name-only", "--", ref)
for _, arg := range filenames { for _, arg := range filenames {
if arg != "" { if arg != "" {
cmd.AddArguments(arg) cmd.AddArguments(arg)

@ -7,10 +7,7 @@
package git package git
import ( import "code.gitea.io/gitea/modules/log"
"strconv"
"strings"
)
// TreeEntry the leaf in the git tree // TreeEntry the leaf in the git tree
type TreeEntry struct { type TreeEntry struct {
@ -47,13 +44,20 @@ func (te *TreeEntry) Size() int64 {
return te.size return te.size
} }
stdout, err := NewCommand("cat-file", "-s", te.ID.String()).RunInDir(te.ptree.repo.Path) wr, rd, cancel := te.ptree.repo.CatFileBatchCheck(te.ptree.repo.Ctx)
defer cancel()
_, err := wr.Write([]byte(te.ID.String() + "\n"))
if err != nil { if err != nil {
log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err)
return 0
}
_, _, te.size, err = ReadBatchLine(rd)
if err != nil {
log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err)
return 0 return 0
} }
te.sized = true te.sized = true
te.size, _ = strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
return te.size return te.size
} }

@ -81,7 +81,7 @@ func (t *Tree) ListEntries() (Entries, error) {
} }
} }
stdout, err := NewCommand("ls-tree", "-l", t.ID.String()).RunInDirBytes(t.repo.Path) stdout, err := NewCommandContext(t.repo.Ctx, "ls-tree", "-l", t.ID.String()).RunInDirBytes(t.repo.Path)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "fatal: not a tree object") { if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "fatal: not a tree object") {
return nil, ErrNotExist{ return nil, ErrNotExist{
@ -104,7 +104,7 @@ func (t *Tree) ListEntriesRecursive() (Entries, error) {
if t.entriesRecursiveParsed { if t.entriesRecursiveParsed {
return t.entriesRecursive, nil return t.entriesRecursive, nil
} }
stdout, err := NewCommand("ls-tree", "-t", "-l", "-r", t.ID.String()).RunInDirBytes(t.repo.Path) stdout, err := NewCommandContext(t.repo.Ctx, "ls-tree", "-t", "-l", "-r", t.ID.String()).RunInDirBytes(t.repo.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -51,7 +51,7 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
args = append(args, files...) args = append(args, files...)
} }
graphCmd := git.NewCommand("log") graphCmd := git.NewCommandContext(r.Ctx, "log")
graphCmd.AddArguments(args...) graphCmd.AddArguments(args...)
graph := NewGraph() graph := NewGraph()

@ -6,6 +6,7 @@ package code
import ( import (
"bufio" "bufio"
"context"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -180,7 +181,7 @@ func NewBleveIndexer(indexDir string) (*BleveIndexer, bool, error) {
return indexer, created, err return indexer, created, err
} }
func (b *BleveIndexer) addUpdate(batchWriter git.WriteCloserError, batchReader *bufio.Reader, commitSha string, func (b *BleveIndexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserError, batchReader *bufio.Reader, commitSha string,
update fileUpdate, repo *repo_model.Repository, batch *gitea_bleve.FlushingBatch) error { update fileUpdate, repo *repo_model.Repository, batch *gitea_bleve.FlushingBatch) error {
// Ignore vendored files in code search // Ignore vendored files in code search
if setting.Indexer.ExcludeVendored && analyze.IsVendor(update.Filename) { if setting.Indexer.ExcludeVendored && analyze.IsVendor(update.Filename) {
@ -190,7 +191,7 @@ func (b *BleveIndexer) addUpdate(batchWriter git.WriteCloserError, batchReader *
size := update.Size size := update.Size
if !update.Sized { if !update.Sized {
stdout, err := git.NewCommand("cat-file", "-s", update.BlobSha). stdout, err := git.NewCommandContext(ctx, "cat-file", "-s", update.BlobSha).
RunInDir(repo.RepoPath()) RunInDir(repo.RepoPath())
if err != nil { if err != nil {
return err return err
@ -271,21 +272,21 @@ func (b *BleveIndexer) Close() {
} }
// Index indexes the data // Index indexes the data
func (b *BleveIndexer) Index(repo *repo_model.Repository, sha string, changes *repoChanges) error { func (b *BleveIndexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *repoChanges) error {
batch := gitea_bleve.NewFlushingBatch(b.indexer, maxBatchSize) batch := gitea_bleve.NewFlushingBatch(b.indexer, maxBatchSize)
if len(changes.Updates) > 0 { if len(changes.Updates) > 0 {
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! // Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
if err := git.EnsureValidGitRepository(git.DefaultContext, repo.RepoPath()); err != nil { if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil {
log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err) log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err)
return err return err
} }
batchWriter, batchReader, cancel := git.CatFileBatch(git.DefaultContext, repo.RepoPath()) batchWriter, batchReader, cancel := git.CatFileBatch(ctx, repo.RepoPath())
defer cancel() defer cancel()
for _, update := range changes.Updates { for _, update := range changes.Updates {
if err := b.addUpdate(batchWriter, batchReader, sha, update, repo, batch); err != nil { if err := b.addUpdate(ctx, batchWriter, batchReader, sha, update, repo, batch); err != nil {
return err return err
} }
} }

@ -177,7 +177,7 @@ func (b *ElasticSearchIndexer) init() (bool, error) {
return exists, nil return exists, nil
} }
func (b *ElasticSearchIndexer) addUpdate(batchWriter git.WriteCloserError, batchReader *bufio.Reader, sha string, update fileUpdate, repo *repo_model.Repository) ([]elastic.BulkableRequest, error) { func (b *ElasticSearchIndexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserError, batchReader *bufio.Reader, sha string, update fileUpdate, repo *repo_model.Repository) ([]elastic.BulkableRequest, error) {
// Ignore vendored files in code search // Ignore vendored files in code search
if setting.Indexer.ExcludeVendored && analyze.IsVendor(update.Filename) { if setting.Indexer.ExcludeVendored && analyze.IsVendor(update.Filename) {
return nil, nil return nil, nil
@ -186,7 +186,7 @@ func (b *ElasticSearchIndexer) addUpdate(batchWriter git.WriteCloserError, batch
size := update.Size size := update.Size
if !update.Sized { if !update.Sized {
stdout, err := git.NewCommand("cat-file", "-s", update.BlobSha). stdout, err := git.NewCommandContext(ctx, "cat-file", "-s", update.BlobSha).
RunInDir(repo.RepoPath()) RunInDir(repo.RepoPath())
if err != nil { if err != nil {
return nil, err return nil, err
@ -244,7 +244,7 @@ func (b *ElasticSearchIndexer) addDelete(filename string, repo *repo_model.Repos
} }
// Index will save the index data // Index will save the index data
func (b *ElasticSearchIndexer) Index(repo *repo_model.Repository, sha string, changes *repoChanges) error { func (b *ElasticSearchIndexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *repoChanges) error {
reqs := make([]elastic.BulkableRequest, 0) reqs := make([]elastic.BulkableRequest, 0)
if len(changes.Updates) > 0 { if len(changes.Updates) > 0 {
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! // Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
@ -253,11 +253,11 @@ func (b *ElasticSearchIndexer) Index(repo *repo_model.Repository, sha string, ch
return err return err
} }
batchWriter, batchReader, cancel := git.CatFileBatch(git.DefaultContext, repo.RepoPath()) batchWriter, batchReader, cancel := git.CatFileBatch(ctx, repo.RepoPath())
defer cancel() defer cancel()
for _, update := range changes.Updates { for _, update := range changes.Updates {
updateReqs, err := b.addUpdate(batchWriter, batchReader, sha, update, repo) updateReqs, err := b.addUpdate(ctx, batchWriter, batchReader, sha, update, repo)
if err != nil { if err != nil {
return err return err
} }

@ -5,6 +5,7 @@
package code package code
import ( import (
"context"
"strconv" "strconv"
"strings" "strings"
@ -27,8 +28,8 @@ type repoChanges struct {
RemovedFilenames []string RemovedFilenames []string
} }
func getDefaultBranchSha(repo *repo_model.Repository) (string, error) { func getDefaultBranchSha(ctx context.Context, repo *repo_model.Repository) (string, error) {
stdout, err := git.NewCommand("show-ref", "-s", git.BranchPrefix+repo.DefaultBranch).RunInDir(repo.RepoPath()) stdout, err := git.NewCommandContext(ctx, "show-ref", "-s", git.BranchPrefix+repo.DefaultBranch).RunInDir(repo.RepoPath())
if err != nil { if err != nil {
return "", err return "", err
} }
@ -36,16 +37,16 @@ func getDefaultBranchSha(repo *repo_model.Repository) (string, error) {
} }
// getRepoChanges returns changes to repo since last indexer update // getRepoChanges returns changes to repo since last indexer update
func getRepoChanges(repo *repo_model.Repository, revision string) (*repoChanges, error) { func getRepoChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) {
status, err := repo_model.GetIndexerStatus(repo, repo_model.RepoIndexerTypeCode) status, err := repo_model.GetIndexerStatus(repo, repo_model.RepoIndexerTypeCode)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(status.CommitSha) == 0 { if len(status.CommitSha) == 0 {
return genesisChanges(repo, revision) return genesisChanges(ctx, repo, revision)
} }
return nonGenesisChanges(repo, revision) return nonGenesisChanges(ctx, repo, revision)
} }
func isIndexable(entry *git.TreeEntry) bool { func isIndexable(entry *git.TreeEntry) bool {
@ -89,9 +90,9 @@ func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
} }
// genesisChanges get changes to add repo to the indexer for the first time // genesisChanges get changes to add repo to the indexer for the first time
func genesisChanges(repo *repo_model.Repository, revision string) (*repoChanges, error) { func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) {
var changes repoChanges var changes repoChanges
stdout, err := git.NewCommand("ls-tree", "--full-tree", "-l", "-r", revision). stdout, err := git.NewCommandContext(ctx, "ls-tree", "--full-tree", "-l", "-r", revision).
RunInDirBytes(repo.RepoPath()) RunInDirBytes(repo.RepoPath())
if err != nil { if err != nil {
return nil, err return nil, err
@ -101,8 +102,8 @@ func genesisChanges(repo *repo_model.Repository, revision string) (*repoChanges,
} }
// nonGenesisChanges get changes since the previous indexer update // nonGenesisChanges get changes since the previous indexer update
func nonGenesisChanges(repo *repo_model.Repository, revision string) (*repoChanges, error) { func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) {
diffCmd := git.NewCommand("diff", "--name-status", diffCmd := git.NewCommandContext(ctx, "diff", "--name-status",
repo.CodeIndexerStatus.CommitSha, revision) repo.CodeIndexerStatus.CommitSha, revision)
stdout, err := diffCmd.RunInDir(repo.RepoPath()) stdout, err := diffCmd.RunInDir(repo.RepoPath())
if err != nil { if err != nil {
@ -112,7 +113,7 @@ func nonGenesisChanges(repo *repo_model.Repository, revision string) (*repoChang
if err = indexer.Delete(repo.ID); err != nil { if err = indexer.Delete(repo.ID); err != nil {
return nil, err return nil, err
} }
return genesisChanges(repo, revision) return genesisChanges(ctx, repo, revision)
} }
var changes repoChanges var changes repoChanges
updatedFilenames := make([]string, 0, 10) updatedFilenames := make([]string, 0, 10)
@ -166,7 +167,7 @@ func nonGenesisChanges(repo *repo_model.Repository, revision string) (*repoChang
} }
} }
cmd := git.NewCommand("ls-tree", "--full-tree", "-l", revision, "--") cmd := git.NewCommandContext(ctx, "ls-tree", "--full-tree", "-l", revision, "--")
cmd.AddArguments(updatedFilenames...) cmd.AddArguments(updatedFilenames...)
lsTreeStdout, err := cmd.RunInDirBytes(repo.RepoPath()) lsTreeStdout, err := cmd.RunInDirBytes(repo.RepoPath())
if err != nil { if err != nil {

@ -42,7 +42,7 @@ type SearchResultLanguages struct {
// Indexer defines an interface to index and search code contents // Indexer defines an interface to index and search code contents
type Indexer interface { type Indexer interface {
Index(repo *repo_model.Repository, sha string, changes *repoChanges) error Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *repoChanges) error
Delete(repoID int64) error Delete(repoID int64) error
Search(repoIDs []int64, language, keyword string, page, pageSize int, isMatch bool) (int64, []*SearchResult, []*SearchResultLanguages, error) Search(repoIDs []int64, language, keyword string, page, pageSize int, isMatch bool) (int64, []*SearchResult, []*SearchResultLanguages, error)
Close() Close()
@ -82,7 +82,7 @@ var (
indexerQueue queue.UniqueQueue indexerQueue queue.UniqueQueue
) )
func index(indexer Indexer, repoID int64) error { func index(ctx context.Context, indexer Indexer, repoID int64) error {
repo, err := repo_model.GetRepositoryByID(repoID) repo, err := repo_model.GetRepositoryByID(repoID)
if repo_model.IsErrRepoNotExist(err) { if repo_model.IsErrRepoNotExist(err) {
return indexer.Delete(repoID) return indexer.Delete(repoID)
@ -91,18 +91,18 @@ func index(indexer Indexer, repoID int64) error {
return err return err
} }
sha, err := getDefaultBranchSha(repo) sha, err := getDefaultBranchSha(ctx, repo)
if err != nil { if err != nil {
return err return err
} }
changes, err := getRepoChanges(repo, sha) changes, err := getRepoChanges(ctx, repo, sha)
if err != nil { if err != nil {
return err return err
} else if changes == nil { } else if changes == nil {
return nil return nil
} }
if err := indexer.Index(repo, sha, changes); err != nil { if err := indexer.Index(ctx, repo, sha, changes); err != nil {
return err return err
} }
@ -150,7 +150,7 @@ func Init() {
} }
log.Trace("IndexerData Process Repo: %d", indexerData.RepoID) log.Trace("IndexerData Process Repo: %d", indexerData.RepoID)
if err := index(indexer, indexerData.RepoID); err != nil { if err := index(ctx, indexer, indexerData.RepoID); err != nil {
log.Error("index: %v", err) log.Error("index: %v", err)
continue continue
} }

@ -9,6 +9,7 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
@ -22,7 +23,7 @@ func TestMain(m *testing.M) {
func testIndexer(name string, t *testing.T, indexer Indexer) { func testIndexer(name string, t *testing.T, indexer Indexer) {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
var repoID int64 = 1 var repoID int64 = 1
err := index(indexer, repoID) err := index(git.DefaultContext, indexer, repoID)
assert.NoError(t, err) assert.NoError(t, err)
var ( var (
keywords = []struct { keywords = []struct {

@ -5,6 +5,7 @@
package code package code
import ( import (
"context"
"fmt" "fmt"
"sync" "sync"
@ -57,12 +58,12 @@ func (w *wrappedIndexer) get() (Indexer, error) {
return w.internal, nil return w.internal, nil
} }
func (w *wrappedIndexer) Index(repo *repo_model.Repository, sha string, changes *repoChanges) error { func (w *wrappedIndexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *repoChanges) error {
indexer, err := w.get() indexer, err := w.get()
if err != nil { if err != nil {
return err return err
} }
return indexer.Index(repo, sha, changes) return indexer.Index(ctx, repo, sha, changes)
} }
func (w *wrappedIndexer) Delete(repoID int64) error { func (w *wrappedIndexer) Delete(repoID int64) error {

@ -37,7 +37,7 @@ func SearchPointerBlobs(ctx context.Context, repo *git.Repository, pointerChan c
go createPointerResultsFromCatFileBatch(ctx, catFileBatchReader, &wg, pointerChan) go createPointerResultsFromCatFileBatch(ctx, catFileBatchReader, &wg, pointerChan)
// 3. Take the shas of the blobs and batch read them // 3. Take the shas of the blobs and batch read them
go pipeline.CatFileBatch(shasToBatchReader, catFileBatchWriter, &wg, basePath) go pipeline.CatFileBatch(ctx, shasToBatchReader, catFileBatchWriter, &wg, basePath)
// 2. From the provided objects restrict to blobs <=1k // 2. From the provided objects restrict to blobs <=1k
go pipeline.BlobsLessThan1024FromCatFileBatchCheck(catFileCheckReader, shasToBatchWriter, &wg) go pipeline.BlobsLessThan1024FromCatFileBatchCheck(catFileCheckReader, shasToBatchWriter, &wg)
@ -47,11 +47,11 @@ func SearchPointerBlobs(ctx context.Context, repo *git.Repository, pointerChan c
revListReader, revListWriter := io.Pipe() revListReader, revListWriter := io.Pipe()
shasToCheckReader, shasToCheckWriter := io.Pipe() shasToCheckReader, shasToCheckWriter := io.Pipe()
wg.Add(2) wg.Add(2)
go pipeline.CatFileBatchCheck(shasToCheckReader, catFileCheckWriter, &wg, basePath) go pipeline.CatFileBatchCheck(ctx, shasToCheckReader, catFileCheckWriter, &wg, basePath)
go pipeline.BlobsFromRevListObjects(revListReader, shasToCheckWriter, &wg) go pipeline.BlobsFromRevListObjects(revListReader, shasToCheckWriter, &wg)
go pipeline.RevListAllObjects(revListWriter, &wg, basePath, errChan) go pipeline.RevListAllObjects(ctx, revListWriter, &wg, basePath, errChan)
} else { } else {
go pipeline.CatFileBatchCheckAllObjects(catFileCheckWriter, &wg, basePath, errChan) go pipeline.CatFileBatchCheckAllObjects(ctx, catFileCheckWriter, &wg, basePath, errChan)
} }
wg.Wait() wg.Wait()

@ -1070,7 +1070,7 @@ func sha1CurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
if !inCache { if !inCache {
if ctx.GitRepo == nil { if ctx.GitRepo == nil {
var err error var err error
ctx.GitRepo, err = git.OpenRepository(ctx.Metas["repoPath"]) ctx.GitRepo, err = git.OpenRepositoryCtx(ctx.Ctx, ctx.Metas["repoPath"])
if err != nil { if err != nil {
log.Error("unable to open repository: %s Error: %v", ctx.Metas["repoPath"], err) log.Error("unable to open repository: %s Error: %v", ctx.Metas["repoPath"], err)
return return

@ -10,6 +10,7 @@ import (
"testing" "testing"
"code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/emoji"
"code.gitea.io/gitea/modules/git"
. "code.gitea.io/gitea/modules/markup" . "code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -28,6 +29,7 @@ func TestRender_Commits(t *testing.T) {
setting.AppURL = TestAppURL setting.AppURL = TestAppURL
test := func(input, expected string) { test := func(input, expected string) {
buffer, err := RenderString(&RenderContext{ buffer, err := RenderString(&RenderContext{
Ctx: git.DefaultContext,
Filename: ".md", Filename: ".md",
URLPrefix: TestRepoURL, URLPrefix: TestRepoURL,
Metas: localMetas, Metas: localMetas,

@ -8,6 +8,7 @@ import (
"strings" "strings"
"testing" "testing"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup"
. "code.gitea.io/gitea/modules/markup/markdown" . "code.gitea.io/gitea/modules/markup/markdown"
@ -279,6 +280,7 @@ func TestTotal_RenderWiki(t *testing.T) {
for i := 0; i < len(sameCases); i++ { for i := 0; i < len(sameCases); i++ {
line, err := RenderString(&markup.RenderContext{ line, err := RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: AppSubURL, URLPrefix: AppSubURL,
Metas: localMetas, Metas: localMetas,
IsWiki: true, IsWiki: true,
@ -318,6 +320,7 @@ func TestTotal_RenderString(t *testing.T) {
for i := 0; i < len(sameCases); i++ { for i := 0; i < len(sameCases); i++ {
line, err := RenderString(&markup.RenderContext{ line, err := RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
URLPrefix: util.URLJoin(AppSubURL, "src", "master/"), URLPrefix: util.URLJoin(AppSubURL, "src", "master/"),
Metas: localMetas, Metas: localMetas,
}, sameCases[i]) }, sameCases[i])

@ -12,9 +12,11 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/graceful"
"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/notification/base" "code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
) )
@ -206,11 +208,14 @@ func (a *actionNotifier) NotifyForkRepository(doer *user_model.User, oldRepo, re
} }
func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*user_model.User) { func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*user_model.User) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("actionNotifier.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
defer finished()
if err := review.LoadReviewer(); err != nil { if err := review.LoadReviewer(); err != nil {
log.Error("LoadReviewer '%d/%d': %v", review.ID, review.ReviewerID, err) log.Error("LoadReviewer '%d/%d': %v", review.ID, review.ReviewerID, err)
return return
} }
if err := review.LoadCodeComments(); err != nil { if err := review.LoadCodeComments(ctx); err != nil {
log.Error("LoadCodeComments '%d/%d': %v", review.Reviewer.ID, review.ID, err) log.Error("LoadCodeComments '%d/%d': %v", review.Reviewer.ID, review.ID, err)
return return
} }
@ -330,7 +335,7 @@ func (a *actionNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_m
} }
} }
func (a *actionNotifier) NotifyCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func (a *actionNotifier) NotifyCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
opType := models.ActionCommitRepo opType := models.ActionCommitRepo
if refType == "tag" { if refType == "tag" {
// has sent same action in `NotifyPushCommits`, so skip it. // has sent same action in `NotifyPushCommits`, so skip it.
@ -389,7 +394,7 @@ func (a *actionNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *re
} }
} }
func (a *actionNotifier) NotifySyncCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func (a *actionNotifier) NotifySyncCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
if err := models.NotifyWatchers(&models.Action{ if err := models.NotifyWatchers(&models.Action{
ActUserID: repo.OwnerID, ActUserID: repo.OwnerID,
ActUser: repo.MustOwner(), ActUser: repo.MustOwner(),

@ -53,11 +53,11 @@ type Notifier interface {
NotifyDeleteRelease(doer *user_model.User, rel *models.Release) NotifyDeleteRelease(doer *user_model.User, rel *models.Release)
NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits)
NotifyCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) NotifyCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string)
NotifyDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) NotifyDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string)
NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits)
NotifySyncCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) NotifySyncCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string)
NotifySyncDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) NotifySyncDeleteRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string)
NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository)

@ -142,7 +142,7 @@ func (*NullNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_model
} }
// NotifyCreateRef notifies branch or tag creation to notifiers // NotifyCreateRef notifies branch or tag creation to notifiers
func (*NullNotifier) NotifyCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func (*NullNotifier) NotifyCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
} }
// NotifyDeleteRef notifies branch or tag deletion to notifiers // NotifyDeleteRef notifies branch or tag deletion to notifiers
@ -162,7 +162,7 @@ func (*NullNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *repo_m
} }
// NotifySyncCreateRef places a place holder function // NotifySyncCreateRef places a place holder function
func (*NullNotifier) NotifySyncCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func (*NullNotifier) NotifySyncCreateRef(doer *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
} }
// NotifySyncDeleteRef places a place holder function // NotifySyncDeleteRef places a place holder function

@ -10,8 +10,10 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification/base" "code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/mailer"
) )
@ -30,6 +32,9 @@ func NewNotifier() base.Notifier {
func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository,
issue *models.Issue, comment *models.Comment, mentions []*user_model.User) { issue *models.Issue, comment *models.Comment, mentions []*user_model.User) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyCreateIssueComment Issue[%d] #%d in [%d]", issue.ID, issue.Index, issue.RepoID))
defer finished()
var act models.ActionType var act models.ActionType
if comment.Type == models.CommentTypeClose { if comment.Type == models.CommentTypeClose {
act = models.ActionCloseIssue act = models.ActionCloseIssue
@ -43,7 +48,7 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *rep
act = 0 act = 0
} }
if err := mailer.MailParticipantsComment(comment, act, issue, mentions); err != nil { if err := mailer.MailParticipantsComment(ctx, comment, act, issue, mentions); err != nil {
log.Error("MailParticipantsComment: %v", err) log.Error("MailParticipantsComment: %v", err)
} }
} }
@ -94,6 +99,9 @@ func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*
} }
func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment, mentions []*user_model.User) { func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment, mentions []*user_model.User) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
defer finished()
var act models.ActionType var act models.ActionType
if comment.Type == models.CommentTypeClose { if comment.Type == models.CommentTypeClose {
act = models.ActionCloseIssue act = models.ActionCloseIssue
@ -102,13 +110,16 @@ func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models
} else if comment.Type == models.CommentTypeComment { } else if comment.Type == models.CommentTypeComment {
act = models.ActionCommentPull act = models.ActionCommentPull
} }
if err := mailer.MailParticipantsComment(comment, act, pr.Issue, mentions); err != nil { if err := mailer.MailParticipantsComment(ctx, comment, act, pr.Issue, mentions); err != nil {
log.Error("MailParticipantsComment: %v", err) log.Error("MailParticipantsComment: %v", err)
} }
} }
func (m *mailNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*user_model.User) { func (m *mailNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*user_model.User) {
if err := mailer.MailMentionsComment(pr, comment, mentions); err != nil { ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestCodeComment Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
defer finished()
if err := mailer.MailMentionsComment(ctx, pr, comment, mentions); err != nil {
log.Error("MailMentionsComment: %v", err) log.Error("MailMentionsComment: %v", err)
} }
} }
@ -143,6 +154,9 @@ func (m *mailNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *user
} }
func (m *mailNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *models.PullRequest, comment *models.Comment) { func (m *mailNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *models.PullRequest, comment *models.Comment) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRequestPushCommits Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
defer finished()
var err error var err error
if err = comment.LoadIssue(); err != nil { if err = comment.LoadIssue(); err != nil {
log.Error("comment.LoadIssue: %v", err) log.Error("comment.LoadIssue: %v", err)
@ -160,19 +174,25 @@ func (m *mailNotifier) NotifyPullRequestPushCommits(doer *user_model.User, pr *m
log.Error("comment.Issue.PullRequest.LoadBaseRepo: %v", err) log.Error("comment.Issue.PullRequest.LoadBaseRepo: %v", err)
return return
} }
if err := comment.LoadPushCommits(); err != nil { if err := comment.LoadPushCommits(ctx); err != nil {
log.Error("comment.LoadPushCommits: %v", err) log.Error("comment.LoadPushCommits: %v", err)
} }
m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment, nil) m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment, nil)
} }
func (m *mailNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *models.Review, comment *models.Comment) { func (m *mailNotifier) NotifyPullRevieweDismiss(doer *user_model.User, review *models.Review, comment *models.Comment) {
if err := mailer.MailParticipantsComment(comment, models.ActionPullReviewDismissed, review.Issue, nil); err != nil { ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyPullRevieweDismiss Review[%d] in Issue[%d]", review.ID, review.IssueID))
defer finished()
if err := mailer.MailParticipantsComment(ctx, comment, models.ActionPullReviewDismissed, review.Issue, nil); err != nil {
log.Error("MailParticipantsComment: %v", err) log.Error("MailParticipantsComment: %v", err)
} }
} }
func (m *mailNotifier) NotifyNewRelease(rel *models.Release) { func (m *mailNotifier) NotifyNewRelease(rel *models.Release) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("mailNotifier.NotifyNewRelease rel[%d]%s in [%d]", rel.ID, rel.Title, rel.RepoID))
defer finished()
if err := rel.LoadAttributes(); err != nil { if err := rel.LoadAttributes(); err != nil {
log.Error("NotifyNewRelease: %v", err) log.Error("NotifyNewRelease: %v", err)
return return
@ -182,7 +202,7 @@ func (m *mailNotifier) NotifyNewRelease(rel *models.Release) {
return return
} }
mailer.MailNewRelease(rel) mailer.MailNewRelease(ctx, rel)
} }
func (m *mailNotifier) NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) { func (m *mailNotifier) NotifyRepoPendingTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository) {

@ -259,9 +259,9 @@ func NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opt
} }
// NotifyCreateRef notifies branch or tag creation to notifiers // NotifyCreateRef notifies branch or tag creation to notifiers
func NotifyCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func NotifyCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
for _, notifier := range notifiers { for _, notifier := range notifiers {
notifier.NotifyCreateRef(pusher, repo, refType, refFullName) notifier.NotifyCreateRef(pusher, repo, refType, refFullName, refID)
} }
} }
@ -280,9 +280,9 @@ func NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository,
} }
// NotifySyncCreateRef notifies branch or tag creation to notifiers // NotifySyncCreateRef notifies branch or tag creation to notifiers
func NotifySyncCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func NotifySyncCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
for _, notifier := range notifiers { for _, notifier := range notifiers {
notifier.NotifySyncCreateRef(pusher, repo, refType, refFullName) notifier.NotifySyncCreateRef(pusher, repo, refType, refFullName, refID)
} }
} }

@ -5,6 +5,8 @@
package webhook package webhook
import ( import (
"fmt"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -13,8 +15,10 @@ import (
"code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification/base" "code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/repository"
"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"
@ -35,6 +39,9 @@ func NewNotifier() base.Notifier {
} }
func (m *webhookNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *models.Issue) { func (m *webhookNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *models.Issue) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueClearLabels User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID))
defer finished()
if err := issue.LoadPoster(); err != nil { if err := issue.LoadPoster(); err != nil {
log.Error("loadPoster: %v", err) log.Error("loadPoster: %v", err)
return return
@ -56,7 +63,7 @@ func (m *webhookNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *m
err = webhook_services.PrepareWebhooks(issue.Repo, webhook.HookEventPullRequestLabel, &api.PullRequestPayload{ err = webhook_services.PrepareWebhooks(issue.Repo, webhook.HookEventPullRequestLabel, &api.PullRequestPayload{
Action: api.HookIssueLabelCleared, Action: api.HookIssueLabelCleared,
Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(issue.Repo, mode), Repository: convert.ToRepo(issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
}) })
@ -140,6 +147,9 @@ func (m *webhookNotifier) NotifyMigrateRepository(doer, u *user_model.User, repo
} }
func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) { func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue *models.Issue, assignee *user_model.User, removed bool, comment *models.Comment) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeAssignee User: %s[%d] Issue[%d] #%d in [%d] Assignee %s[%d] removed: %t", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID, assignee.Name, assignee.ID, removed))
defer finished()
if issue.IsPull { if issue.IsPull {
mode, _ := models.AccessLevelUnit(doer, issue.Repo, unit.TypePullRequests) mode, _ := models.AccessLevelUnit(doer, issue.Repo, unit.TypePullRequests)
@ -150,7 +160,7 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue
issue.PullRequest.Issue = issue issue.PullRequest.Issue = issue
apiPullRequest := &api.PullRequestPayload{ apiPullRequest := &api.PullRequestPayload{
Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(issue.Repo, mode), Repository: convert.ToRepo(issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
} }
@ -186,6 +196,9 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue
} }
func (m *webhookNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *models.Issue, oldTitle string) { func (m *webhookNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *models.Issue, oldTitle string) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeTitle User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID))
defer finished()
mode, _ := models.AccessLevel(issue.Poster, issue.Repo) mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
var err error var err error
if issue.IsPull { if issue.IsPull {
@ -202,7 +215,7 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *m
From: oldTitle, From: oldTitle,
}, },
}, },
PullRequest: convert.ToAPIPullRequest(issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(issue.Repo, mode), Repository: convert.ToRepo(issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
}) })
@ -227,6 +240,9 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *m
} }
func (m *webhookNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) { func (m *webhookNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeStatus User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID))
defer finished()
mode, _ := models.AccessLevel(issue.Poster, issue.Repo) mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
var err error var err error
if issue.IsPull { if issue.IsPull {
@ -237,7 +253,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue *
// Merge pull request calls issue.changeStatus so we need to handle separately. // Merge pull request calls issue.changeStatus so we need to handle separately.
apiPullRequest := &api.PullRequestPayload{ apiPullRequest := &api.PullRequestPayload{
Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(issue.Repo, mode), Repository: convert.ToRepo(issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
} }
@ -289,6 +305,9 @@ func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue, mentions []*user_m
} }
func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest, mentions []*user_model.User) { func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest, mentions []*user_model.User) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyNewPullRequest Pull[%d] #%d in [%d]", pull.ID, pull.Index, pull.BaseRepoID))
defer finished()
if err := pull.LoadIssue(); err != nil { if err := pull.LoadIssue(); err != nil {
log.Error("pull.LoadIssue: %v", err) log.Error("pull.LoadIssue: %v", err)
return return
@ -306,7 +325,7 @@ func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest, mention
if err := webhook_services.PrepareWebhooks(pull.Issue.Repo, webhook.HookEventPullRequest, &api.PullRequestPayload{ if err := webhook_services.PrepareWebhooks(pull.Issue.Repo, webhook.HookEventPullRequest, &api.PullRequestPayload{
Action: api.HookIssueOpened, Action: api.HookIssueOpened,
Index: pull.Issue.Index, Index: pull.Issue.Index,
PullRequest: convert.ToAPIPullRequest(pull, nil), PullRequest: convert.ToAPIPullRequest(ctx, pull, nil),
Repository: convert.ToRepo(pull.Issue.Repo, mode), Repository: convert.ToRepo(pull.Issue.Repo, mode),
Sender: convert.ToUser(pull.Issue.Poster, nil), Sender: convert.ToUser(pull.Issue.Poster, nil),
}); err != nil { }); err != nil {
@ -315,6 +334,9 @@ func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest, mention
} }
func (m *webhookNotifier) NotifyIssueChangeContent(doer *user_model.User, issue *models.Issue, oldContent string) { func (m *webhookNotifier) NotifyIssueChangeContent(doer *user_model.User, issue *models.Issue, oldContent string) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeContent User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID))
defer finished()
mode, _ := models.AccessLevel(issue.Poster, issue.Repo) mode, _ := models.AccessLevel(issue.Poster, issue.Repo)
var err error var err error
if issue.IsPull { if issue.IsPull {
@ -327,7 +349,7 @@ func (m *webhookNotifier) NotifyIssueChangeContent(doer *user_model.User, issue
From: oldContent, From: oldContent,
}, },
}, },
PullRequest: convert.ToAPIPullRequest(issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(issue.Repo, mode), Repository: convert.ToRepo(issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
}) })
@ -480,6 +502,9 @@ func (m *webhookNotifier) NotifyDeleteComment(doer *user_model.User, comment *mo
func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue *models.Issue, func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue *models.Issue,
addedLabels []*models.Label, removedLabels []*models.Label) { addedLabels []*models.Label, removedLabels []*models.Label) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeLabels User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID))
defer finished()
var err error var err error
if err = issue.LoadRepo(); err != nil { if err = issue.LoadRepo(); err != nil {
@ -505,7 +530,7 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue *
err = webhook_services.PrepareWebhooks(issue.Repo, webhook.HookEventPullRequestLabel, &api.PullRequestPayload{ err = webhook_services.PrepareWebhooks(issue.Repo, webhook.HookEventPullRequestLabel, &api.PullRequestPayload{
Action: api.HookIssueLabelUpdated, Action: api.HookIssueLabelUpdated,
Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(issue.Repo, perm.AccessModeNone), Repository: convert.ToRepo(issue.Repo, perm.AccessModeNone),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
}) })
@ -524,6 +549,9 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue *
} }
func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issue *models.Issue, oldMilestoneID int64) { func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issue *models.Issue, oldMilestoneID int64) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeMilestone User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID))
defer finished()
var hookAction api.HookIssueAction var hookAction api.HookIssueAction
var err error var err error
if issue.MilestoneID > 0 { if issue.MilestoneID > 0 {
@ -547,7 +575,7 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issu
err = webhook_services.PrepareWebhooks(issue.Repo, webhook.HookEventPullRequestMilestone, &api.PullRequestPayload{ err = webhook_services.PrepareWebhooks(issue.Repo, webhook.HookEventPullRequestMilestone, &api.PullRequestPayload{
Action: hookAction, Action: hookAction,
Index: issue.Index, Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(issue.Repo, mode), Repository: convert.ToRepo(issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
}) })
@ -566,8 +594,11 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issu
} }
func (m *webhookNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { func (m *webhookNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyPushCommits User: %s[%d] in %s[%d]", pusher.Name, pusher.ID, repo.FullName(), repo.ID))
defer finished()
apiPusher := convert.ToUser(pusher, nil) apiPusher := convert.ToUser(pusher, nil)
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL()) apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL())
if err != nil { if err != nil {
log.Error("commits.ToAPIPayloadCommits failed: %v", err) log.Error("commits.ToAPIPayloadCommits failed: %v", err)
return return
@ -589,6 +620,9 @@ func (m *webhookNotifier) NotifyPushCommits(pusher *user_model.User, repo *repo_
} }
func (*webhookNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) { func (*webhookNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *user_model.User) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyMergePullRequest Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
defer finished()
// Reload pull request information. // Reload pull request information.
if err := pr.LoadAttributes(); err != nil { if err := pr.LoadAttributes(); err != nil {
log.Error("LoadAttributes: %v", err) log.Error("LoadAttributes: %v", err)
@ -614,7 +648,7 @@ func (*webhookNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *use
// Merge pull request calls issue.changeStatus so we need to handle separately. // Merge pull request calls issue.changeStatus so we need to handle separately.
apiPullRequest := &api.PullRequestPayload{ apiPullRequest := &api.PullRequestPayload{
Index: pr.Issue.Index, Index: pr.Issue.Index,
PullRequest: convert.ToAPIPullRequest(pr, nil), PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
Repository: convert.ToRepo(pr.Issue.Repo, mode), Repository: convert.ToRepo(pr.Issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
Action: api.HookIssueClosed, Action: api.HookIssueClosed,
@ -627,6 +661,9 @@ func (*webhookNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *use
} }
func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *models.PullRequest, oldBranch string) { func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.User, pr *models.PullRequest, oldBranch string) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyPullRequestChangeTargetBranch Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
defer finished()
issue := pr.Issue issue := pr.Issue
if !issue.IsPull { if !issue.IsPull {
return return
@ -647,7 +684,7 @@ func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.U
From: oldBranch, From: oldBranch,
}, },
}, },
PullRequest: convert.ToAPIPullRequest(issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(issue.Repo, mode), Repository: convert.ToRepo(issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
}) })
@ -658,6 +695,9 @@ func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.U
} }
func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*user_model.User) { func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*user_model.User) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyPullRequestReview Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
defer finished()
var reviewHookType webhook.HookEventType var reviewHookType webhook.HookEventType
switch review.Type { switch review.Type {
@ -686,7 +726,7 @@ func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review
if err := webhook_services.PrepareWebhooks(review.Issue.Repo, reviewHookType, &api.PullRequestPayload{ if err := webhook_services.PrepareWebhooks(review.Issue.Repo, reviewHookType, &api.PullRequestPayload{
Action: api.HookIssueReviewed, Action: api.HookIssueReviewed,
Index: review.Issue.Index, Index: review.Issue.Index,
PullRequest: convert.ToAPIPullRequest(pr, nil), PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
Repository: convert.ToRepo(review.Issue.Repo, mode), Repository: convert.ToRepo(review.Issue.Repo, mode),
Sender: convert.ToUser(review.Reviewer, nil), Sender: convert.ToUser(review.Reviewer, nil),
Review: &api.ReviewPayload{ Review: &api.ReviewPayload{
@ -698,28 +738,14 @@ func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review
} }
} }
func (m *webhookNotifier) NotifyCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func (m *webhookNotifier) NotifyCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
apiPusher := convert.ToUser(pusher, nil) apiPusher := convert.ToUser(pusher, nil)
apiRepo := convert.ToRepo(repo, perm.AccessModeNone) apiRepo := convert.ToRepo(repo, perm.AccessModeNone)
refName := git.RefEndName(refFullName) refName := git.RefEndName(refFullName)
gitRepo, err := git.OpenRepository(repo.RepoPath()) if err := webhook_services.PrepareWebhooks(repo, webhook.HookEventCreate, &api.CreatePayload{
if err != nil {
log.Error("OpenRepository[%s]: %v", repo.RepoPath(), err)
return
}
shaSum, err := gitRepo.GetRefCommitID(refFullName)
if err != nil {
gitRepo.Close()
log.Error("GetRefCommitID[%s]: %v", refFullName, err)
return
}
gitRepo.Close()
if err = webhook_services.PrepareWebhooks(repo, webhook.HookEventCreate, &api.CreatePayload{
Ref: refName, Ref: refName,
Sha: shaSum, Sha: refID,
RefType: refType, RefType: refType,
Repo: apiRepo, Repo: apiRepo,
Sender: apiPusher, Sender: apiPusher,
@ -729,6 +755,9 @@ func (m *webhookNotifier) NotifyCreateRef(pusher *user_model.User, repo *repo_mo
} }
func (m *webhookNotifier) NotifyPullRequestSynchronized(doer *user_model.User, pr *models.PullRequest) { func (m *webhookNotifier) NotifyPullRequestSynchronized(doer *user_model.User, pr *models.PullRequest) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyPullRequestSynchronized Pull[%d] #%d in [%d]", pr.ID, pr.Index, pr.BaseRepoID))
defer finished()
if err := pr.LoadIssue(); err != nil { if err := pr.LoadIssue(); err != nil {
log.Error("pr.LoadIssue: %v", err) log.Error("pr.LoadIssue: %v", err)
return return
@ -741,7 +770,7 @@ func (m *webhookNotifier) NotifyPullRequestSynchronized(doer *user_model.User, p
if err := webhook_services.PrepareWebhooks(pr.Issue.Repo, webhook.HookEventPullRequestSync, &api.PullRequestPayload{ if err := webhook_services.PrepareWebhooks(pr.Issue.Repo, webhook.HookEventPullRequestSync, &api.PullRequestPayload{
Action: api.HookIssueSynchronized, Action: api.HookIssueSynchronized,
Index: pr.Issue.Index, Index: pr.Issue.Index,
PullRequest: convert.ToAPIPullRequest(pr, nil), PullRequest: convert.ToAPIPullRequest(ctx, pr, nil),
Repository: convert.ToRepo(pr.Issue.Repo, perm.AccessModeNone), Repository: convert.ToRepo(pr.Issue.Repo, perm.AccessModeNone),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
}); err != nil { }); err != nil {
@ -795,8 +824,11 @@ func (m *webhookNotifier) NotifyDeleteRelease(doer *user_model.User, rel *models
} }
func (m *webhookNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) { func (m *webhookNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifySyncPushCommits User: %s[%d] in %s[%d]", pusher.Name, pusher.ID, repo.FullName(), repo.ID))
defer finished()
apiPusher := convert.ToUser(pusher, nil) apiPusher := convert.ToUser(pusher, nil)
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(repo.RepoPath(), repo.HTMLURL()) apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL())
if err != nil { if err != nil {
log.Error("commits.ToAPIPayloadCommits failed: %v", err) log.Error("commits.ToAPIPayloadCommits failed: %v", err)
return return
@ -817,8 +849,8 @@ func (m *webhookNotifier) NotifySyncPushCommits(pusher *user_model.User, repo *r
} }
} }
func (m *webhookNotifier) NotifySyncCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func (m *webhookNotifier) NotifySyncCreateRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
m.NotifyCreateRef(pusher, repo, refType, refFullName) m.NotifyCreateRef(pusher, repo, refType, refFullName, refID)
} }
func (m *webhookNotifier) NotifySyncDeleteRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { func (m *webhookNotifier) NotifySyncDeleteRef(pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) {

@ -210,32 +210,32 @@ func (pm *Manager) Processes(onlyRoots bool) []*Process {
// Exec a command and use the default timeout. // Exec a command and use the default timeout.
func (pm *Manager) Exec(desc, cmdName string, args ...string) (string, string, error) { func (pm *Manager) Exec(desc, cmdName string, args ...string) (string, string, error) {
return pm.ExecDir(-1, "", desc, cmdName, args...) return pm.ExecDir(DefaultContext, -1, "", desc, cmdName, args...)
} }
// ExecTimeout a command and use a specific timeout duration. // ExecTimeout a command and use a specific timeout duration.
func (pm *Manager) ExecTimeout(timeout time.Duration, desc, cmdName string, args ...string) (string, string, error) { func (pm *Manager) ExecTimeout(timeout time.Duration, desc, cmdName string, args ...string) (string, string, error) {
return pm.ExecDir(timeout, "", desc, cmdName, args...) return pm.ExecDir(DefaultContext, timeout, "", desc, cmdName, args...)
} }
// ExecDir a command and use the default timeout. // ExecDir a command and use the default timeout.
func (pm *Manager) ExecDir(timeout time.Duration, dir, desc, cmdName string, args ...string) (string, string, error) { func (pm *Manager) ExecDir(ctx context.Context, timeout time.Duration, dir, desc, cmdName string, args ...string) (string, string, error) {
return pm.ExecDirEnv(timeout, dir, desc, nil, cmdName, args...) return pm.ExecDirEnv(ctx, timeout, dir, desc, nil, cmdName, args...)
} }
// ExecDirEnv runs a command in given path and environment variables, and waits for its completion // ExecDirEnv runs a command in given path and environment variables, and waits for its completion
// up to the given timeout (or DefaultTimeout if -1 is given). // up to the given timeout (or DefaultTimeout if -1 is given).
// Returns its complete stdout and stderr // Returns its complete stdout and stderr
// outputs and an error, if any (including timeout) // outputs and an error, if any (including timeout)
func (pm *Manager) ExecDirEnv(timeout time.Duration, dir, desc string, env []string, cmdName string, args ...string) (string, string, error) { func (pm *Manager) ExecDirEnv(ctx context.Context, timeout time.Duration, dir, desc string, env []string, cmdName string, args ...string) (string, string, error) {
return pm.ExecDirEnvStdIn(timeout, dir, desc, env, nil, cmdName, args...) return pm.ExecDirEnvStdIn(ctx, timeout, dir, desc, env, nil, cmdName, args...)
} }
// ExecDirEnvStdIn runs a command in given path and environment variables with provided stdIN, and waits for its completion // ExecDirEnvStdIn runs a command in given path and environment variables with provided stdIN, and waits for its completion
// up to the given timeout (or DefaultTimeout if -1 is given). // up to the given timeout (or DefaultTimeout if -1 is given).
// Returns its complete stdout and stderr // Returns its complete stdout and stderr
// outputs and an error, if any (including timeout) // outputs and an error, if any (including timeout)
func (pm *Manager) ExecDirEnvStdIn(timeout time.Duration, dir, desc string, env []string, stdIn io.Reader, cmdName string, args ...string) (string, string, error) { func (pm *Manager) ExecDirEnvStdIn(ctx context.Context, timeout time.Duration, dir, desc string, env []string, stdIn io.Reader, cmdName string, args ...string) (string, string, error) {
if timeout == -1 { if timeout == -1 {
timeout = 60 * time.Second timeout = 60 * time.Second
} }
@ -243,7 +243,7 @@ func (pm *Manager) ExecDirEnvStdIn(timeout time.Duration, dir, desc string, env
stdOut := new(bytes.Buffer) stdOut := new(bytes.Buffer)
stdErr := new(bytes.Buffer) stdErr := new(bytes.Buffer)
ctx, _, finished := pm.AddContextTimeout(DefaultContext, timeout, desc) ctx, _, finished := pm.AddContextTimeout(ctx, timeout, desc)
defer finished() defer finished()
cmd := exec.CommandContext(ctx, cmdName, args...) cmd := exec.CommandContext(ctx, cmdName, args...)

@ -5,6 +5,7 @@
package repository package repository
import ( import (
"context"
"fmt" "fmt"
"net/url" "net/url"
"time" "time"
@ -48,7 +49,7 @@ func NewPushCommits() *PushCommits {
} }
// toAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object. // toAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object.
func (pc *PushCommits) toAPIPayloadCommit(repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) { func (pc *PushCommits) toAPIPayloadCommit(ctx context.Context, repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) {
var err error var err error
authorUsername := "" authorUsername := ""
author, ok := pc.emailUsers[commit.AuthorEmail] author, ok := pc.emailUsers[commit.AuthorEmail]
@ -75,7 +76,7 @@ func (pc *PushCommits) toAPIPayloadCommit(repoPath, repoLink string, commit *Pus
committerUsername = committer.Name committerUsername = committer.Name
} }
fileStatus, err := git.GetCommitFileStatus(repoPath, commit.Sha1) fileStatus, err := git.GetCommitFileStatus(ctx, repoPath, commit.Sha1)
if err != nil { if err != nil {
return nil, fmt.Errorf("FileStatus [commit_sha1: %s]: %v", commit.Sha1, err) return nil, fmt.Errorf("FileStatus [commit_sha1: %s]: %v", commit.Sha1, err)
} }
@ -103,7 +104,7 @@ func (pc *PushCommits) toAPIPayloadCommit(repoPath, repoLink string, commit *Pus
// ToAPIPayloadCommits converts a PushCommits object to api.PayloadCommit format. // ToAPIPayloadCommits converts a PushCommits object to api.PayloadCommit format.
// It returns all converted commits and, if provided, the head commit or an error otherwise. // It returns all converted commits and, if provided, the head commit or an error otherwise.
func (pc *PushCommits) ToAPIPayloadCommits(repoPath, repoLink string) ([]*api.PayloadCommit, *api.PayloadCommit, error) { func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLink string) ([]*api.PayloadCommit, *api.PayloadCommit, error) {
commits := make([]*api.PayloadCommit, len(pc.Commits)) commits := make([]*api.PayloadCommit, len(pc.Commits))
var headCommit *api.PayloadCommit var headCommit *api.PayloadCommit
@ -111,7 +112,7 @@ func (pc *PushCommits) ToAPIPayloadCommits(repoPath, repoLink string) ([]*api.Pa
pc.emailUsers = make(map[string]*user_model.User) pc.emailUsers = make(map[string]*user_model.User)
} }
for i, commit := range pc.Commits { for i, commit := range pc.Commits {
apiCommit, err := pc.toAPIPayloadCommit(repoPath, repoLink, commit) apiCommit, err := pc.toAPIPayloadCommit(ctx, repoPath, repoLink, commit)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -123,7 +124,7 @@ func (pc *PushCommits) ToAPIPayloadCommits(repoPath, repoLink string) ([]*api.Pa
} }
if pc.HeadCommit != nil && headCommit == nil { if pc.HeadCommit != nil && headCommit == nil {
var err error var err error
headCommit, err = pc.toAPIPayloadCommit(repoPath, repoLink, pc.HeadCommit) headCommit, err = pc.toAPIPayloadCommit(ctx, repoPath, repoLink, pc.HeadCommit)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

@ -50,7 +50,7 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) {
pushCommits.HeadCommit = &PushCommit{Sha1: "69554a6"} pushCommits.HeadCommit = &PushCommit{Sha1: "69554a6"}
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository)
payloadCommits, headCommit, err := pushCommits.ToAPIPayloadCommits(repo.RepoPath(), "/user2/repo16") payloadCommits, headCommit, err := pushCommits.ToAPIPayloadCommits(git.DefaultContext, repo.RepoPath(), "/user2/repo16")
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, payloadCommits, 3) assert.Len(t, payloadCommits, 3)
assert.NotNil(t, headCommit) assert.NotNil(t, headCommit)

@ -99,7 +99,7 @@ func checkGiteaTemplate(tmpDir string) (*models.GiteaTemplate, error) {
return gt, nil return gt, nil
} }
func generateRepoCommit(repo, templateRepo, generateRepo *repo_model.Repository, tmpDir string) error { func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository, tmpDir string) error {
commitTimeStr := time.Now().Format(time.RFC3339) commitTimeStr := time.Now().Format(time.RFC3339)
authorSig := repo.Owner.NewGitSig() authorSig := repo.Owner.NewGitSig()
@ -115,7 +115,7 @@ func generateRepoCommit(repo, templateRepo, generateRepo *repo_model.Repository,
// Clone to temporary path and do the init commit. // Clone to temporary path and do the init commit.
templateRepoPath := templateRepo.RepoPath() templateRepoPath := templateRepo.RepoPath()
if err := git.Clone(templateRepoPath, tmpDir, git.CloneRepoOptions{ if err := git.Clone(ctx, templateRepoPath, tmpDir, git.CloneRepoOptions{
Depth: 1, Depth: 1,
Branch: templateRepo.DefaultBranch, Branch: templateRepo.DefaultBranch,
}); err != nil { }); err != nil {
@ -172,19 +172,19 @@ func generateRepoCommit(repo, templateRepo, generateRepo *repo_model.Repository,
} }
} }
if err := git.InitRepository(tmpDir, false); err != nil { if err := git.InitRepository(ctx, tmpDir, false); err != nil {
return err return err
} }
repoPath := repo.RepoPath() repoPath := repo.RepoPath()
if stdout, err := git.NewCommand("remote", "add", "origin", repoPath). if stdout, err := git.NewCommandContext(ctx, "remote", "add", "origin", repoPath).
SetDescription(fmt.Sprintf("generateRepoCommit (git remote add): %s to %s", templateRepoPath, tmpDir)). SetDescription(fmt.Sprintf("generateRepoCommit (git remote add): %s to %s", templateRepoPath, tmpDir)).
RunInDirWithEnv(tmpDir, env); err != nil { RunInDirWithEnv(tmpDir, env); err != nil {
log.Error("Unable to add %v as remote origin to temporary repo to %s: stdout %s\nError: %v", repo, tmpDir, stdout, err) log.Error("Unable to add %v as remote origin to temporary repo to %s: stdout %s\nError: %v", repo, tmpDir, stdout, err)
return fmt.Errorf("git remote add: %v", err) return fmt.Errorf("git remote add: %v", err)
} }
return initRepoCommit(tmpDir, repo, repo.Owner, templateRepo.DefaultBranch) return initRepoCommit(ctx, tmpDir, repo, repo.Owner, templateRepo.DefaultBranch)
} }
func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository) (err error) { func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository) (err error) {
@ -199,7 +199,7 @@ func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *r
} }
}() }()
if err = generateRepoCommit(repo, templateRepo, generateRepo, tmpDir); err != nil { if err = generateRepoCommit(ctx, repo, templateRepo, generateRepo, tmpDir); err != nil {
return fmt.Errorf("generateRepoCommit: %v", err) return fmt.Errorf("generateRepoCommit: %v", err)
} }
@ -209,7 +209,7 @@ func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *r
} }
repo.DefaultBranch = templateRepo.DefaultBranch repo.DefaultBranch = templateRepo.DefaultBranch
gitRepo, err := git.OpenRepository(repo.RepoPath()) gitRepo, err := git.OpenRepositoryCtx(ctx, repo.RepoPath())
if err != nil { if err != nil {
return fmt.Errorf("openRepository: %v", err) return fmt.Errorf("openRepository: %v", err)
} }
@ -273,7 +273,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
} }
} }
if err = checkInitRepository(owner.Name, generateRepo.Name); err != nil { if err = checkInitRepository(ctx, owner.Name, generateRepo.Name); err != nil {
return generateRepo, err return generateRepo, err
} }

@ -40,7 +40,7 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
) )
// Clone to temporary path and do the init commit. // Clone to temporary path and do the init commit.
if stdout, err := git.NewCommand("clone", repoPath, tmpDir). if stdout, err := git.NewCommandContext(ctx, "clone", repoPath, tmpDir).
SetDescription(fmt.Sprintf("prepareRepoCommit (git clone): %s to %s", repoPath, tmpDir)). SetDescription(fmt.Sprintf("prepareRepoCommit (git clone): %s to %s", repoPath, tmpDir)).
RunInDirWithEnv("", env); err != nil { RunInDirWithEnv("", env); err != nil {
log.Error("Failed to clone from %v into %s: stdout: %s\nError: %v", repo, tmpDir, stdout, err) log.Error("Failed to clone from %v into %s: stdout: %s\nError: %v", repo, tmpDir, stdout, err)
@ -103,7 +103,7 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
} }
// initRepoCommit temporarily changes with work directory. // initRepoCommit temporarily changes with work directory.
func initRepoCommit(tmpPath string, repo *repo_model.Repository, u *user_model.User, defaultBranch string) (err error) { func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Repository, u *user_model.User, defaultBranch string) (err error) {
commitTimeStr := time.Now().Format(time.RFC3339) commitTimeStr := time.Now().Format(time.RFC3339)
sig := u.NewGitSig() sig := u.NewGitSig()
@ -117,7 +117,7 @@ func initRepoCommit(tmpPath string, repo *repo_model.Repository, u *user_model.U
committerName := sig.Name committerName := sig.Name
committerEmail := sig.Email committerEmail := sig.Email
if stdout, err := git.NewCommand("add", "--all"). if stdout, err := git.NewCommandContext(ctx, "add", "--all").
SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)). SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)).
RunInDir(tmpPath); err != nil { RunInDir(tmpPath); err != nil {
log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err) log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err)
@ -135,7 +135,7 @@ func initRepoCommit(tmpPath string, repo *repo_model.Repository, u *user_model.U
} }
if git.CheckGitVersionAtLeast("1.7.9") == nil { if git.CheckGitVersionAtLeast("1.7.9") == nil {
sign, keyID, signer, _ := asymkey_service.SignInitialCommit(tmpPath, u) sign, keyID, signer, _ := asymkey_service.SignInitialCommit(ctx, tmpPath, u)
if sign { if sign {
args = append(args, "-S"+keyID) args = append(args, "-S"+keyID)
@ -154,7 +154,7 @@ func initRepoCommit(tmpPath string, repo *repo_model.Repository, u *user_model.U
"GIT_COMMITTER_EMAIL="+committerEmail, "GIT_COMMITTER_EMAIL="+committerEmail,
) )
if stdout, err := git.NewCommand(args...). if stdout, err := git.NewCommandContext(ctx, args...).
SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)). SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)).
RunInDirWithEnv(tmpPath, env); err != nil { RunInDirWithEnv(tmpPath, env); err != nil {
log.Error("Failed to commit: %v: Stdout: %s\nError: %v", args, stdout, err) log.Error("Failed to commit: %v: Stdout: %s\nError: %v", args, stdout, err)
@ -165,7 +165,7 @@ func initRepoCommit(tmpPath string, repo *repo_model.Repository, u *user_model.U
defaultBranch = setting.Repository.DefaultBranch defaultBranch = setting.Repository.DefaultBranch
} }
if stdout, err := git.NewCommand("push", "origin", "HEAD:"+defaultBranch). if stdout, err := git.NewCommandContext(ctx, "push", "origin", "HEAD:"+defaultBranch).
SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)). SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)).
RunInDirWithEnv(tmpPath, models.InternalPushingEnvironment(u, repo)); err != nil { RunInDirWithEnv(tmpPath, models.InternalPushingEnvironment(u, repo)); err != nil {
log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err) log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err)
@ -175,7 +175,7 @@ func initRepoCommit(tmpPath string, repo *repo_model.Repository, u *user_model.U
return nil return nil
} }
func checkInitRepository(owner, name string) (err error) { func checkInitRepository(ctx context.Context, owner, name string) (err error) {
// Somehow the directory could exist. // Somehow the directory could exist.
repoPath := repo_model.RepoPath(owner, name) repoPath := repo_model.RepoPath(owner, name)
isExist, err := util.IsExist(repoPath) isExist, err := util.IsExist(repoPath)
@ -191,7 +191,7 @@ func checkInitRepository(owner, name string) (err error) {
} }
// Init git bare new repository. // Init git bare new repository.
if err = git.InitRepository(repoPath, true); err != nil { if err = git.InitRepository(ctx, repoPath, true); err != nil {
return fmt.Errorf("git.InitRepository: %v", err) return fmt.Errorf("git.InitRepository: %v", err)
} else if err = createDelegateHooks(repoPath); err != nil { } else if err = createDelegateHooks(repoPath); err != nil {
return fmt.Errorf("createDelegateHooks: %v", err) return fmt.Errorf("createDelegateHooks: %v", err)
@ -201,7 +201,7 @@ func checkInitRepository(owner, name string) (err error) {
// InitRepository initializes README and .gitignore if needed. // InitRepository initializes README and .gitignore if needed.
func initRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, opts models.CreateRepoOptions) (err error) { func initRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, opts models.CreateRepoOptions) (err error) {
if err = checkInitRepository(repo.OwnerName, repo.Name); err != nil { if err = checkInitRepository(ctx, repo.OwnerName, repo.Name); err != nil {
return err return err
} }
@ -222,7 +222,7 @@ func initRepository(ctx context.Context, repoPath string, u *user_model.User, re
} }
// Apply changes and commit. // Apply changes and commit.
if err = initRepoCommit(tmpDir, repo, u, opts.DefaultBranch); err != nil { if err = initRepoCommit(ctx, tmpDir, repo, u, opts.DefaultBranch); err != nil {
return fmt.Errorf("initRepoCommit: %v", err) return fmt.Errorf("initRepoCommit: %v", err)
} }
} }
@ -241,7 +241,7 @@ func initRepository(ctx context.Context, repoPath string, u *user_model.User, re
if len(opts.DefaultBranch) > 0 { if len(opts.DefaultBranch) > 0 {
repo.DefaultBranch = opts.DefaultBranch repo.DefaultBranch = opts.DefaultBranch
gitRepo, err := git.OpenRepository(repo.RepoPath()) gitRepo, err := git.OpenRepositoryCtx(ctx, repo.RepoPath())
if err != nil { if err != nil {
return fmt.Errorf("openRepository: %v", err) return fmt.Errorf("openRepository: %v", err)
} }

@ -5,6 +5,7 @@
package repository package repository
import ( import (
"context"
"strings" "strings"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -98,12 +99,12 @@ func (opts *PushUpdateOptions) RepoFullName() string {
} }
// IsForcePush detect if a push is a force push // IsForcePush detect if a push is a force push
func IsForcePush(opts *PushUpdateOptions) (bool, error) { func IsForcePush(ctx context.Context, opts *PushUpdateOptions) (bool, error) {
if !opts.IsUpdateBranch() { if !opts.IsUpdateBranch() {
return false, nil return false, nil
} }
output, err := git.NewCommand("rev-list", "--max-count=1", opts.OldCommitID, "^"+opts.NewCommitID). output, err := git.NewCommandContext(ctx, "rev-list", "--max-count=1", opts.OldCommitID, "^"+opts.NewCommitID).
RunInDir(repo_model.RepoPath(opts.RepoUserName, opts.RepoName)) RunInDir(repo_model.RepoPath(opts.RepoUserName, opts.RepoName))
if err != nil { if err != nil {
return false, err return false, err

@ -36,11 +36,11 @@ var commonWikiURLSuffixes = []string{".wiki.git", ".git/wiki"}
// WikiRemoteURL returns accessible repository URL for wiki if exists. // WikiRemoteURL returns accessible repository URL for wiki if exists.
// Otherwise, it returns an empty string. // Otherwise, it returns an empty string.
func WikiRemoteURL(remote string) string { func WikiRemoteURL(ctx context.Context, remote string) string {
remote = strings.TrimSuffix(remote, ".git") remote = strings.TrimSuffix(remote, ".git")
for _, suffix := range commonWikiURLSuffixes { for _, suffix := range commonWikiURLSuffixes {
wikiURL := remote + suffix wikiURL := remote + suffix
if git.IsRepoURLAccessible(wikiURL) { if git.IsRepoURLAccessible(ctx, wikiURL) {
return wikiURL return wikiURL
} }
} }
@ -71,7 +71,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err) return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err)
} }
if err = git.CloneWithContext(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{ if err = git.Clone(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{
Mirror: true, Mirror: true,
Quiet: true, Quiet: true,
Timeout: migrateTimeout, Timeout: migrateTimeout,
@ -81,13 +81,13 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
if opts.Wiki { if opts.Wiki {
wikiPath := repo_model.WikiPath(u.Name, opts.RepoName) wikiPath := repo_model.WikiPath(u.Name, opts.RepoName)
wikiRemotePath := WikiRemoteURL(opts.CloneAddr) wikiRemotePath := WikiRemoteURL(ctx, opts.CloneAddr)
if len(wikiRemotePath) > 0 { if len(wikiRemotePath) > 0 {
if err := util.RemoveAll(wikiPath); err != nil { if err := util.RemoveAll(wikiPath); err != nil {
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
} }
if err = git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{ if err = git.Clone(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{
Mirror: true, Mirror: true,
Quiet: true, Quiet: true,
Timeout: migrateTimeout, Timeout: migrateTimeout,
@ -116,7 +116,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
return repo, fmt.Errorf("error in MigrateRepositoryGitData(git update-server-info): %v", err) return repo, fmt.Errorf("error in MigrateRepositoryGitData(git update-server-info): %v", err)
} }
gitRepo, err := git.OpenRepository(repoPath) gitRepo, err := git.OpenRepositoryCtx(ctx, repoPath)
if err != nil { if err != nil {
return repo, fmt.Errorf("OpenRepository: %v", err) return repo, fmt.Errorf("OpenRepository: %v", err)
} }
@ -196,7 +196,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
repo.IsMirror = true repo.IsMirror = true
err = models.UpdateRepository(repo, false) err = models.UpdateRepository(repo, false)
} else { } else {
repo, err = CleanUpMigrateInfo(repo) repo, err = CleanUpMigrateInfo(ctx, repo)
} }
return repo, err return repo, err
@ -217,7 +217,7 @@ func cleanUpMigrateGitConfig(configPath string) error {
} }
// CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors. // CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors.
func CleanUpMigrateInfo(repo *repo_model.Repository) (*repo_model.Repository, error) { func CleanUpMigrateInfo(ctx context.Context, repo *repo_model.Repository) (*repo_model.Repository, error) {
repoPath := repo.RepoPath() repoPath := repo.RepoPath()
if err := createDelegateHooks(repoPath); err != nil { if err := createDelegateHooks(repoPath); err != nil {
return repo, fmt.Errorf("createDelegateHooks: %v", err) return repo, fmt.Errorf("createDelegateHooks: %v", err)
@ -228,7 +228,7 @@ func CleanUpMigrateInfo(repo *repo_model.Repository) (*repo_model.Repository, er
} }
} }
_, err := git.NewCommand("remote", "rm", "origin").RunInDir(repoPath) _, err := git.NewCommandContext(ctx, "remote", "rm", "origin").RunInDir(repoPath)
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err) return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err)
} }

@ -7,6 +7,7 @@ package templates
import ( import (
"bytes" "bytes"
"context"
"errors" "errors"
"fmt" "fmt"
"html" "html"
@ -635,17 +636,18 @@ func Sha1(str string) string {
} }
// RenderCommitMessage renders commit message with XSS-safe and special links. // RenderCommitMessage renders commit message with XSS-safe and special links.
func RenderCommitMessage(msg, urlPrefix string, metas map[string]string) template.HTML { func RenderCommitMessage(ctx context.Context, msg, urlPrefix string, metas map[string]string) template.HTML {
return RenderCommitMessageLink(msg, urlPrefix, "", metas) return RenderCommitMessageLink(ctx, msg, urlPrefix, "", metas)
} }
// RenderCommitMessageLink renders commit message as a XXS-safe link to the provided // RenderCommitMessageLink renders commit message as a XXS-safe link to the provided
// default url, handling for special links. // default url, handling for special links.
func RenderCommitMessageLink(msg, urlPrefix, urlDefault string, metas map[string]string) template.HTML { func RenderCommitMessageLink(ctx context.Context, msg, urlPrefix, urlDefault string, metas map[string]string) template.HTML {
cleanMsg := template.HTMLEscapeString(msg) cleanMsg := template.HTMLEscapeString(msg)
// we can safely assume that it will not return any error, since there // we can safely assume that it will not return any error, since there
// shouldn't be any special HTML. // shouldn't be any special HTML.
fullMessage, err := markup.RenderCommitMessage(&markup.RenderContext{ fullMessage, err := markup.RenderCommitMessage(&markup.RenderContext{
Ctx: ctx,
URLPrefix: urlPrefix, URLPrefix: urlPrefix,
DefaultLink: urlDefault, DefaultLink: urlDefault,
Metas: metas, Metas: metas,
@ -663,7 +665,7 @@ func RenderCommitMessageLink(msg, urlPrefix, urlDefault string, metas map[string
// RenderCommitMessageLinkSubject renders commit message as a XXS-safe link to // RenderCommitMessageLinkSubject renders commit message as a XXS-safe link to
// the provided default url, handling for special links without email to links. // the provided default url, handling for special links without email to links.
func RenderCommitMessageLinkSubject(msg, urlPrefix, urlDefault string, metas map[string]string) template.HTML { func RenderCommitMessageLinkSubject(ctx context.Context, msg, urlPrefix, urlDefault string, metas map[string]string) template.HTML {
msgLine := strings.TrimLeftFunc(msg, unicode.IsSpace) msgLine := strings.TrimLeftFunc(msg, unicode.IsSpace)
lineEnd := strings.IndexByte(msgLine, '\n') lineEnd := strings.IndexByte(msgLine, '\n')
if lineEnd > 0 { if lineEnd > 0 {
@ -677,6 +679,7 @@ func RenderCommitMessageLinkSubject(msg, urlPrefix, urlDefault string, metas map
// we can safely assume that it will not return any error, since there // we can safely assume that it will not return any error, since there
// shouldn't be any special HTML. // shouldn't be any special HTML.
renderedMessage, err := markup.RenderCommitMessageSubject(&markup.RenderContext{ renderedMessage, err := markup.RenderCommitMessageSubject(&markup.RenderContext{
Ctx: ctx,
URLPrefix: urlPrefix, URLPrefix: urlPrefix,
DefaultLink: urlDefault, DefaultLink: urlDefault,
Metas: metas, Metas: metas,
@ -689,7 +692,7 @@ func RenderCommitMessageLinkSubject(msg, urlPrefix, urlDefault string, metas map
} }
// RenderCommitBody extracts the body of a commit message without its title. // RenderCommitBody extracts the body of a commit message without its title.
func RenderCommitBody(msg, urlPrefix string, metas map[string]string) template.HTML { func RenderCommitBody(ctx context.Context, msg, urlPrefix string, metas map[string]string) template.HTML {
msgLine := strings.TrimRightFunc(msg, unicode.IsSpace) msgLine := strings.TrimRightFunc(msg, unicode.IsSpace)
lineEnd := strings.IndexByte(msgLine, '\n') lineEnd := strings.IndexByte(msgLine, '\n')
if lineEnd > 0 { if lineEnd > 0 {
@ -703,6 +706,7 @@ func RenderCommitBody(msg, urlPrefix string, metas map[string]string) template.H
} }
renderedMessage, err := markup.RenderCommitMessage(&markup.RenderContext{ renderedMessage, err := markup.RenderCommitMessage(&markup.RenderContext{
Ctx: ctx,
URLPrefix: urlPrefix, URLPrefix: urlPrefix,
Metas: metas, Metas: metas,
}, template.HTMLEscapeString(msgLine)) }, template.HTMLEscapeString(msgLine))
@ -714,8 +718,9 @@ func RenderCommitBody(msg, urlPrefix string, metas map[string]string) template.H
} }
// RenderIssueTitle renders issue/pull title with defined post processors // RenderIssueTitle renders issue/pull title with defined post processors
func RenderIssueTitle(text, urlPrefix string, metas map[string]string) template.HTML { func RenderIssueTitle(ctx context.Context, text, urlPrefix string, metas map[string]string) template.HTML {
renderedText, err := markup.RenderIssueTitle(&markup.RenderContext{ renderedText, err := markup.RenderIssueTitle(&markup.RenderContext{
Ctx: ctx,
URLPrefix: urlPrefix, URLPrefix: urlPrefix,
Metas: metas, Metas: metas,
}, template.HTMLEscapeString(text)) }, template.HTMLEscapeString(text))
@ -750,9 +755,10 @@ func ReactionToEmoji(reaction string) template.HTML {
} }
// RenderNote renders the contents of a git-notes file as a commit message. // RenderNote renders the contents of a git-notes file as a commit message.
func RenderNote(msg, urlPrefix string, metas map[string]string) template.HTML { func RenderNote(ctx context.Context, msg, urlPrefix string, metas map[string]string) template.HTML {
cleanMsg := template.HTMLEscapeString(msg) cleanMsg := template.HTMLEscapeString(msg)
fullMessage, err := markup.RenderCommitMessage(&markup.RenderContext{ fullMessage, err := markup.RenderCommitMessage(&markup.RenderContext{
Ctx: ctx,
URLPrefix: urlPrefix, URLPrefix: urlPrefix,
Metas: metas, Metas: metas,
}, cleanMsg) }, cleanMsg)
@ -891,10 +897,10 @@ type remoteAddress struct {
Password string Password string
} }
func mirrorRemoteAddress(m repo_model.RemoteMirrorer) remoteAddress { func mirrorRemoteAddress(ctx context.Context, m repo_model.RemoteMirrorer) remoteAddress {
a := remoteAddress{} a := remoteAddress{}
u, err := git.GetRemoteAddress(git.DefaultContext, m.GetRepository().RepoPath(), m.GetRemoteName()) u, err := git.GetRemoteAddress(ctx, m.GetRepository().RepoPath(), m.GetRemoteName())
if err != nil { if err != nil {
log.Error("GetRemoteAddress %v", err) log.Error("GetRemoteAddress %v", err)
return a return a

@ -67,7 +67,7 @@ func LoadRepo(t *testing.T, ctx *context.Context, repoID int64) {
// LoadRepoCommit loads a repo's commit into a test context. // LoadRepoCommit loads a repo's commit into a test context.
func LoadRepoCommit(t *testing.T, ctx *context.Context) { func LoadRepoCommit(t *testing.T, ctx *context.Context) {
gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath()) gitRepo, err := git.OpenRepositoryCtx(ctx, ctx.Repo.Repository.RepoPath())
assert.NoError(t, err) assert.NoError(t, err)
defer gitRepo.Close() defer gitRepo.Close()
branch, err := gitRepo.GetHEADBranch() branch, err := gitRepo.GetHEADBranch()
@ -89,7 +89,7 @@ func LoadUser(t *testing.T, ctx *context.Context, userID int64) {
func LoadGitRepo(t *testing.T, ctx *context.Context) { func LoadGitRepo(t *testing.T, ctx *context.Context) {
assert.NoError(t, ctx.Repo.Repository.GetOwner(db.DefaultContext)) assert.NoError(t, ctx.Repo.Repository.GetOwner(db.DefaultContext))
var err error var err error
ctx.Repo.GitRepo, err = git.OpenRepository(ctx.Repo.Repository.RepoPath()) ctx.Repo.GitRepo, err = git.OpenRepositoryCtx(ctx, ctx.Repo.Repository.RepoPath())
assert.NoError(t, err) assert.NoError(t, err)
} }

@ -30,6 +30,7 @@ func Wrap(handlers ...interface{}) http.HandlerFunc {
func(ctx *context.Context), func(ctx *context.Context),
func(ctx *context.Context) goctx.CancelFunc, func(ctx *context.Context) goctx.CancelFunc,
func(*context.APIContext), func(*context.APIContext),
func(*context.APIContext) goctx.CancelFunc,
func(*context.PrivateContext), func(*context.PrivateContext),
func(*context.PrivateContext) goctx.CancelFunc, func(*context.PrivateContext) goctx.CancelFunc,
func(http.Handler) http.Handler: func(http.Handler) http.Handler:
@ -60,6 +61,15 @@ func Wrap(handlers ...interface{}) http.HandlerFunc {
if ctx.Written() { if ctx.Written() {
return return
} }
case func(*context.APIContext) goctx.CancelFunc:
ctx := context.GetAPIContext(req)
cancel := t(ctx)
if cancel != nil {
defer cancel()
}
if ctx.Written() {
return
}
case func(*context.PrivateContext) goctx.CancelFunc: case func(*context.PrivateContext) goctx.CancelFunc:
ctx := context.GetPrivateContext(req) ctx := context.GetPrivateContext(req)
cancel := t(ctx) cancel := t(ctx)

@ -778,10 +778,10 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
m.Combo("/forks").Get(repo.ListForks). m.Combo("/forks").Get(repo.ListForks).
Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork) Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
m.Group("/branches", func() { m.Group("/branches", func() {
m.Get("", repo.ListBranches) m.Get("", context.ReferencesGitRepo(false), repo.ListBranches)
m.Get("/*", repo.GetBranch) m.Get("/*", context.ReferencesGitRepo(false), repo.GetBranch)
m.Delete("/*", context.ReferencesGitRepo(false), reqRepoWriter(unit.TypeCode), repo.DeleteBranch) m.Delete("/*", reqRepoWriter(unit.TypeCode), context.ReferencesGitRepo(false), repo.DeleteBranch)
m.Post("", reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch) m.Post("", reqRepoWriter(unit.TypeCode), context.ReferencesGitRepo(false), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
}, reqRepoReader(unit.TypeCode)) }, reqRepoReader(unit.TypeCode))
m.Group("/branch_protections", func() { m.Group("/branch_protections", func() {
m.Get("", repo.ListBranchProtections) m.Get("", repo.ListBranchProtections)
@ -957,7 +957,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus) Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
}, reqRepoReader(unit.TypeCode)) }, reqRepoReader(unit.TypeCode))
m.Group("/commits", func() { m.Group("/commits", func() {
m.Get("", repo.GetAllCommits) m.Get("", context.ReferencesGitRepo(false), repo.GetAllCommits)
m.Group("/{ref}", func() { m.Group("/{ref}", func() {
m.Get("/status", repo.GetCombinedCommitStatusByRef) m.Get("/status", repo.GetCombinedCommitStatusByRef)
m.Get("/statuses", repo.GetCommitStatusesByRef) m.Get("/statuses", repo.GetCommitStatusesByRef)
@ -965,7 +965,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
}, reqRepoReader(unit.TypeCode)) }, reqRepoReader(unit.TypeCode))
m.Group("/git", func() { m.Group("/git", func() {
m.Group("/commits", func() { m.Group("/commits", func() {
m.Get("/{sha}", repo.GetSingleCommit) m.Get("/{sha}", context.ReferencesGitRepo(false), repo.GetSingleCommit)
m.Get("/{sha}.{diffType:diff|patch}", repo.DownloadCommitDiffOrPatch) m.Get("/{sha}.{diffType:diff|patch}", repo.DownloadCommitDiffOrPatch)
}) })
m.Get("/refs", repo.GetGitAllRefs) m.Get("/refs", repo.GetGitAllRefs)

@ -78,6 +78,7 @@ func Markdown(ctx *context.APIContext) {
} }
if err := markdown.Render(&markup.RenderContext{ if err := markdown.Render(&markup.RenderContext{
Ctx: ctx,
URLPrefix: urlPrefix, URLPrefix: urlPrefix,
Metas: meta, Metas: meta,
IsWiki: form.Wiki, IsWiki: form.Wiki,
@ -87,6 +88,7 @@ func Markdown(ctx *context.APIContext) {
} }
default: default:
if err := markdown.RenderRaw(&markup.RenderContext{ if err := markdown.RenderRaw(&markup.RenderContext{
Ctx: ctx,
URLPrefix: form.Context, URLPrefix: form.Context,
}, strings.NewReader(form.Text), ctx.Resp); err != nil { }, strings.NewReader(form.Text), ctx.Resp); err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
@ -117,7 +119,9 @@ func MarkdownRaw(ctx *context.APIContext) {
// "422": // "422":
// "$ref": "#/responses/validationError" // "$ref": "#/responses/validationError"
defer ctx.Req.Body.Close() defer ctx.Req.Body.Close()
if err := markdown.RenderRaw(&markup.RenderContext{}, ctx.Req.Body, ctx.Resp); err != nil { if err := markdown.RenderRaw(&markup.RenderContext{
Ctx: ctx,
}, ctx.Req.Body, ctx.Resp); err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
} }

@ -52,7 +52,7 @@ func SigningKey(ctx *context.APIContext) {
path = ctx.Repo.Repository.RepoPath() path = ctx.Repo.Repository.RepoPath()
} }
content, err := asymkey_service.PublicSigningKey(path) content, err := asymkey_service.PublicSigningKey(ctx, path)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "gpg export", err) ctx.Error(http.StatusInternalServerError, "gpg export", err)
return return

@ -45,7 +45,7 @@ func GetBlob(ctx *context.APIContext) {
ctx.Error(http.StatusBadRequest, "", "sha not provided") ctx.Error(http.StatusBadRequest, "", "sha not provided")
return return
} }
if blob, err := files_service.GetBlobBySHA(ctx.Repo.Repository, sha); err != nil { if blob, err := files_service.GetBlobBySHA(ctx, 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)

@ -53,7 +53,7 @@ func GetBranch(ctx *context.APIContext) {
branchName := ctx.Params("*") branchName := ctx.Params("*")
branch, err := repo_service.GetBranch(ctx.Repo.Repository, branchName) branch, err := ctx.Repo.GitRepo.GetBranch(branchName)
if err != nil { if err != nil {
if git.IsErrBranchNotExist(err) { if git.IsErrBranchNotExist(err) {
ctx.NotFound(err) ctx.NotFound(err)
@ -176,7 +176,7 @@ func CreateBranch(ctx *context.APIContext) {
opt.OldBranchName = ctx.Repo.Repository.DefaultBranch opt.OldBranchName = ctx.Repo.Repository.DefaultBranch
} }
err := repo_service.CreateNewBranch(ctx.User, ctx.Repo.Repository, opt.OldBranchName, opt.BranchName) err := repo_service.CreateNewBranch(ctx, ctx.User, ctx.Repo.Repository, opt.OldBranchName, opt.BranchName)
if err != nil { if err != nil {
if models.IsErrBranchDoesNotExist(err) { if models.IsErrBranchDoesNotExist(err) {
@ -198,7 +198,7 @@ func CreateBranch(ctx *context.APIContext) {
return return
} }
branch, err := repo_service.GetBranch(ctx.Repo.Repository, opt.BranchName) branch, err := ctx.Repo.GitRepo.GetBranch(opt.BranchName)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetBranch", err) ctx.Error(http.StatusInternalServerError, "GetBranch", err)
return return
@ -257,7 +257,7 @@ func ListBranches(ctx *context.APIContext) {
listOptions := utils.GetListOptions(ctx) listOptions := utils.GetListOptions(ctx)
skip, _ := listOptions.GetStartEnd() skip, _ := listOptions.GetStartEnd()
branches, totalNumOfBranches, err := repo_service.GetBranches(ctx.Repo.Repository, skip, listOptions.PageSize) branches, totalNumOfBranches, err := ctx.Repo.GitRepo.GetBranches(skip, listOptions.PageSize)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetBranches", err) ctx.Error(http.StatusInternalServerError, "GetBranches", err)
return return

@ -62,13 +62,7 @@ func GetSingleCommit(ctx *context.APIContext) {
} }
func getCommit(ctx *context.APIContext, identifier string) { func getCommit(ctx *context.APIContext, identifier string) {
gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath()) commit, err := ctx.Repo.GitRepo.GetCommit(identifier)
if err != nil {
ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
return
}
defer gitRepo.Close()
commit, err := gitRepo.GetCommit(identifier)
if err != nil { if err != nil {
if git.IsErrNotExist(err) { if git.IsErrNotExist(err) {
ctx.NotFound(identifier) ctx.NotFound(identifier)
@ -78,7 +72,7 @@ func getCommit(ctx *context.APIContext, identifier string) {
return return
} }
json, err := convert.ToCommit(ctx.Repo.Repository, commit, nil) json, err := convert.ToCommit(ctx.Repo.Repository, ctx.Repo.GitRepo, commit, nil)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "toCommit", err) ctx.Error(http.StatusInternalServerError, "toCommit", err)
return return
@ -136,13 +130,6 @@ func GetAllCommits(ctx *context.APIContext) {
return return
} }
gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath())
if err != nil {
ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
return
}
defer gitRepo.Close()
listOptions := utils.GetListOptions(ctx) listOptions := utils.GetListOptions(ctx)
if listOptions.Page <= 0 { if listOptions.Page <= 0 {
listOptions.Page = 1 listOptions.Page = 1
@ -158,26 +145,27 @@ func GetAllCommits(ctx *context.APIContext) {
var ( var (
commitsCountTotal int64 commitsCountTotal int64
commits []*git.Commit commits []*git.Commit
err error
) )
if len(path) == 0 { if len(path) == 0 {
var baseCommit *git.Commit var baseCommit *git.Commit
if len(sha) == 0 { if len(sha) == 0 {
// no sha supplied - use default branch // no sha supplied - use default branch
head, err := gitRepo.GetHEADBranch() head, err := ctx.Repo.GitRepo.GetHEADBranch()
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetHEADBranch", err) ctx.Error(http.StatusInternalServerError, "GetHEADBranch", err)
return return
} }
baseCommit, err = gitRepo.GetBranchCommit(head.Name) baseCommit, err = ctx.Repo.GitRepo.GetBranchCommit(head.Name)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetCommit", err) ctx.Error(http.StatusInternalServerError, "GetCommit", err)
return return
} }
} else { } else {
// get commit specified by sha // get commit specified by sha
baseCommit, err = gitRepo.GetCommit(sha) baseCommit, err = ctx.Repo.GitRepo.GetCommit(sha)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetCommit", err) ctx.Error(http.StatusInternalServerError, "GetCommit", err)
return return
@ -202,7 +190,7 @@ func GetAllCommits(ctx *context.APIContext) {
sha = ctx.Repo.Repository.DefaultBranch sha = ctx.Repo.Repository.DefaultBranch
} }
commitsCountTotal, err = gitRepo.FileCommitsCount(sha, path) commitsCountTotal, err = ctx.Repo.GitRepo.FileCommitsCount(sha, path)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "FileCommitsCount", err) ctx.Error(http.StatusInternalServerError, "FileCommitsCount", err)
return return
@ -211,7 +199,7 @@ func GetAllCommits(ctx *context.APIContext) {
return return
} }
commits, err = gitRepo.CommitsByFileAndRange(sha, path, listOptions.Page) commits, err = ctx.Repo.GitRepo.CommitsByFileAndRange(sha, path, listOptions.Page)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRange", err) ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRange", err)
return return
@ -225,7 +213,7 @@ func GetAllCommits(ctx *context.APIContext) {
apiCommits := make([]*api.Commit, len(commits)) apiCommits := make([]*api.Commit, len(commits))
for i, commit := range commits { for i, commit := range commits {
// Create json struct // Create json struct
apiCommits[i], err = convert.ToCommit(ctx.Repo.Repository, commit, userCache) apiCommits[i], err = convert.ToCommit(ctx.Repo.Repository, ctx.Repo.GitRepo, commit, userCache)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "toCommit", err) ctx.Error(http.StatusInternalServerError, "toCommit", err)
return return
@ -282,6 +270,7 @@ func DownloadCommitDiffOrPatch(ctx *context.APIContext) {
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
if err := git.GetRawDiff( if err := git.GetRawDiff(
ctx,
repoPath, repoPath,
ctx.Params(":sha"), ctx.Params(":sha"),
git.RawDiffType(ctx.Params(":diffType")), git.RawDiffType(ctx.Params(":diffType")),

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save