1
0
mirror of https://github.com/go-gitea/gitea synced 2024-12-24 03:35:55 +01:00

Remove git.Command.Run and git.Command.RunInDir* (#19280)

Follows #19266, #8553, Close #18553, now there are only three `Run..(&RunOpts{})` functions.
 * before: `stdout, err := RunInDir(path)`
 * now: `stdout, _, err := RunStdString(&git.RunOpts{Dir:path})`
This commit is contained in:
wxiaoguang 2022-04-01 10:55:30 +08:00 committed by GitHub
parent 3a73645502
commit 124b072f0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
78 changed files with 594 additions and 672 deletions

@ -309,7 +309,7 @@ func runHookPostReceive(c *cli.Context) error {
defer cancel()
// First of all run update-server-info no matter what
if _, err := git.NewCommand(ctx, "update-server-info").Run(); err != nil {
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
return fmt.Errorf("Failed to call 'git update-server-info': %v", err)
}

@ -28,8 +28,8 @@ func TestAPIGitTags(t *testing.T) {
token := getTokenForLoggedInUser(t, session)
// Set up git config for the tagger
git.NewCommand(git.DefaultContext, "config", "user.name", user.Name).RunInDir(repo.RepoPath())
git.NewCommand(git.DefaultContext, "config", "user.email", user.Email).RunInDir(repo.RepoPath())
_ = git.NewCommand(git.DefaultContext, "config", "user.name", user.Name).Run(&git.RunOpts{Dir: repo.RepoPath()})
_ = git.NewCommand(git.DefaultContext, "config", "user.email", user.Email).Run(&git.RunOpts{Dir: repo.RepoPath()})
gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
defer gitRepo.Close()

@ -134,7 +134,7 @@ func doGitInitTestRepository(dstPath string) func(*testing.T) {
// Init repository in dstPath
assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false))
// forcibly set default branch to master
_, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", dstPath)), 0o644))
assert.NoError(t, git.AddChanges(dstPath, true))
@ -153,49 +153,49 @@ func doGitInitTestRepository(dstPath string) func(*testing.T) {
func doGitAddRemote(dstPath, remoteName string, u *url.URL) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "remote", "add", remoteName, u.String()).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, "remote", "add", remoteName, u.String()).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitPushTestRepository(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, append([]string{"push", "-u"}, args...)...).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, append([]string{"push", "-u"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitPushTestRepositoryFail(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, append([]string{"push"}, args...)...).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, append([]string{"push"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.Error(t, err)
}
}
func doGitCreateBranch(dstPath, branch string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "checkout", "-b", branch).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, "checkout", "-b", branch).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "checkout"), args...)...).RunInDir(dstPath)
_, _, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "checkout"), args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitMerge(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, append([]string{"merge"}, args...)...).RunInDir(dstPath)
_, _, err := git.NewCommand(git.DefaultContext, append([]string{"merge"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitPull(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
_, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "pull"), args...)...).RunInDir(dstPath)
_, _, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "pull"), args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}

@ -160,9 +160,9 @@ func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS strin
return
}
prefix := "lfs-data-file-"
_, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").RunInDir(dstPath)
err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("track", prefix+"*").RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("track", prefix+"*").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
err = git.AddChanges(dstPath, false, ".gitattributes")
assert.NoError(t, err)
@ -292,20 +292,20 @@ func lockTest(t *testing.T, repoPath string) {
}
func lockFileTest(t *testing.T, filename, repoPath string) {
_, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunInDir(repoPath)
_, _, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("lock", filename).RunInDir(repoPath)
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("lock", filename).RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunInDir(repoPath)
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("unlock", filename).RunInDir(repoPath)
_, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("unlock", filename).RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
}
func doCommitAndPush(t *testing.T, size int, repoPath, prefix string) string {
name, err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two", prefix)
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "push", "origin", "master").RunInDir(repoPath) // Push
_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "master").RunStdString(&git.RunOpts{Dir: repoPath}) // Push
assert.NoError(t, err)
return name
}
@ -671,7 +671,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
})
t.Run("Push", func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).RunInDir(dstPath)
err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) {
return
}
@ -692,7 +692,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
assert.Contains(t, "Testing commit 1", prMsg.Body)
assert.Equal(t, commit, prMsg.Head.Sha)
_, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) {
return
}
@ -745,7 +745,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
})
t.Run("Push2", func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).RunInDir(dstPath)
err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) {
return
}
@ -757,7 +757,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
assert.Equal(t, false, prMsg.HasMerged)
assert.Equal(t, commit, prMsg.Head.Sha)
_, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) {
return
}

@ -269,25 +269,24 @@ func TestCantMergeUnrelated(t *testing.T) {
}).(*repo_model.Repository)
path := repo_model.RepoPath(user1.Name, repo1.Name)
_, err := git.NewCommand(git.DefaultContext, "read-tree", "--empty").RunInDir(path)
err := git.NewCommand(git.DefaultContext, "read-tree", "--empty").Run(&git.RunOpts{Dir: path})
assert.NoError(t, err)
stdin := bytes.NewBufferString("Unrelated File")
var stdout strings.Builder
err = git.NewCommand(git.DefaultContext, "hash-object", "-w", "--stdin").RunWithContext(&git.RunContext{
Timeout: -1,
Dir: path,
Stdin: stdin,
Stdout: &stdout,
err = git.NewCommand(git.DefaultContext, "hash-object", "-w", "--stdin").Run(&git.RunOpts{
Dir: path,
Stdin: stdin,
Stdout: &stdout,
})
assert.NoError(t, err)
sha := strings.TrimSpace(stdout.String())
_, err = git.NewCommand(git.DefaultContext, "update-index", "--add", "--replace", "--cacheinfo", "100644", sha, "somewher-over-the-rainbow").RunInDir(path)
_, _, err = git.NewCommand(git.DefaultContext, "update-index", "--add", "--replace", "--cacheinfo", "100644", sha, "somewher-over-the-rainbow").RunStdString(&git.RunOpts{Dir: path})
assert.NoError(t, err)
treeSha, err := git.NewCommand(git.DefaultContext, "write-tree").RunInDir(path)
treeSha, _, err := git.NewCommand(git.DefaultContext, "write-tree").RunStdString(&git.RunOpts{Dir: path})
assert.NoError(t, err)
treeSha = strings.TrimSpace(treeSha)
@ -308,17 +307,16 @@ func TestCantMergeUnrelated(t *testing.T) {
stdout.Reset()
err = git.NewCommand(git.DefaultContext, "commit-tree", treeSha).
RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: path,
Stdin: messageBytes,
Stdout: &stdout,
Run(&git.RunOpts{
Env: env,
Dir: path,
Stdin: messageBytes,
Stdout: &stdout,
})
assert.NoError(t, err)
commitSha := strings.TrimSpace(stdout.String())
_, err = git.NewCommand(git.DefaultContext, "branch", "unrelated", commitSha).RunInDir(path)
_, _, err = git.NewCommand(git.DefaultContext, "branch", "unrelated", commitSha).RunStdString(&git.RunOpts{Dir: path})
assert.NoError(t, err)
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")

@ -66,10 +66,10 @@ func TestCreateNewTagProtected(t *testing.T) {
doGitClone(dstPath, u)(t)
_, err = git.NewCommand(git.DefaultContext, "tag", "v-2").RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "tag", "v-2").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunInDir(dstPath)
_, _, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunStdString(&git.RunOpts{Dir: dstPath})
assert.Error(t, err)
assert.Contains(t, err.Error(), "Tag v-2 is protected")
})

@ -83,17 +83,17 @@ func fixMergeBase(x *xorm.Engine) error {
if !pr.HasMerged {
var err error
pr.MergeBase, err = git.NewCommand(git.DefaultContext, "merge-base", "--", pr.BaseBranch, gitRefName).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, "merge-base", "--", pr.BaseBranch, gitRefName).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
var err2 error
pr.MergeBase, err2 = git.NewCommand(git.DefaultContext, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath)
pr.MergeBase, _, err2 = git.NewCommand(git.DefaultContext, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunStdString(&git.RunOpts{Dir: repoPath})
if err2 != nil {
log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2)
continue
}
}
} else {
parentsString, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue
@ -106,7 +106,7 @@ func fixMergeBase(x *xorm.Engine) error {
args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, gitRefName)
pr.MergeBase, err = git.NewCommand(git.DefaultContext, args...).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, args...).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue

@ -80,7 +80,7 @@ func refixMergeBase(x *xorm.Engine) error {
gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
parentsString, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue
@ -94,7 +94,7 @@ func refixMergeBase(x *xorm.Engine) error {
args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, gitRefName)
pr.MergeBase, err = git.NewCommand(git.DefaultContext, args...).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, args...).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue

@ -44,17 +44,17 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
if !pr.HasMerged {
var err error
pr.MergeBase, err = git.NewCommand(ctx, "merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(ctx, "merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
var err2 error
pr.MergeBase, err2 = git.NewCommand(ctx, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath)
pr.MergeBase, _, err2 = git.NewCommand(ctx, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunStdString(&git.RunOpts{Dir: repoPath})
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)
return nil
}
}
} else {
parentsString, err := git.NewCommand(ctx, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
parentsString, _, err := git.NewCommand(ctx, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
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)
return nil
@ -67,7 +67,7 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, pr.GetGitRefName())
pr.MergeBase, err = git.NewCommand(ctx, args...).RunInDir(repoPath)
pr.MergeBase, _, err = git.NewCommand(ctx, args...).RunStdString(&git.RunOpts{Dir: repoPath})
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)
return nil

@ -95,11 +95,11 @@ func checkEnablePushOptions(ctx context.Context, logger log.Logger, autofix bool
defer r.Close()
if autofix {
_, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions", "true").RunInDir(r.Path)
_, _, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions", "true").RunStdString(&git.RunOpts{Dir: r.Path})
return err
}
value, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions").RunInDir(r.Path)
value, _, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions").RunStdString(&git.RunOpts{Dir: r.Path})
if err != nil {
return err
}

@ -34,10 +34,9 @@ func EnsureValidGitRepository(ctx context.Context, repoPath string) error {
stderr := strings.Builder{}
err := NewCommand(ctx, "rev-parse").
SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stderr: &stderr,
Run(&RunOpts{
Dir: repoPath,
Stderr: &stderr,
})
if err != nil {
return ConcatenateError(err, (&stderr).String())
@ -65,12 +64,11 @@ func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
stderr := strings.Builder{}
err := NewCommand(ctx, "cat-file", "--batch-check").
SetDescription(fmt.Sprintf("%s cat-file --batch-check [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdin: batchStdinReader,
Stdout: batchStdoutWriter,
Stderr: &stderr,
Run(&RunOpts{
Dir: repoPath,
Stdin: batchStdinReader,
Stdout: batchStdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
@ -110,12 +108,11 @@ func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
stderr := strings.Builder{}
err := NewCommand(ctx, "cat-file", "--batch").
SetDescription(fmt.Sprintf("%s cat-file --batch [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdin: batchStdinReader,
Stdout: batchStdoutWriter,
Stderr: &stderr,
Run(&RunOpts{
Dir: repoPath,
Stdin: batchStdinReader,
Stdout: batchStdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))

@ -94,8 +94,8 @@ func (c *Command) AddArguments(args ...string) *Command {
return c
}
// RunContext represents parameters to run the command
type RunContext struct {
// RunOpts represents parameters to run the command
type RunOpts struct {
Env []string
Timeout time.Duration
Dir string
@ -104,16 +104,19 @@ type RunContext struct {
PipelineFunc func(context.Context, context.CancelFunc) error
}
// RunWithContext run the command with context
func (c *Command) RunWithContext(rc *RunContext) error {
if rc.Timeout <= 0 {
rc.Timeout = defaultCommandExecutionTimeout
// Run runs the command with the RunOpts
func (c *Command) Run(opts *RunOpts) error {
if opts == nil {
opts = &RunOpts{}
}
if opts.Timeout <= 0 {
opts.Timeout = defaultCommandExecutionTimeout
}
if len(rc.Dir) == 0 {
if len(opts.Dir) == 0 {
log.Debug("%s", c)
} else {
log.Debug("%s: %v", rc.Dir, c)
log.Debug("%s: %v", opts.Dir, c)
}
desc := c.desc
@ -132,17 +135,17 @@ func (c *Command) RunWithContext(rc *RunContext) error {
args[urlArgIndex] = util.SanitizeCredentialURLs(args[urlArgIndex])
}
}
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), rc.Dir)
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir)
}
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, rc.Timeout, desc)
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
defer finished()
cmd := exec.CommandContext(ctx, c.name, c.args...)
if rc.Env == nil {
if opts.Env == nil {
cmd.Env = os.Environ()
} else {
cmd.Env = rc.Env
cmd.Env = opts.Env
}
cmd.Env = append(
@ -154,16 +157,16 @@ func (c *Command) RunWithContext(rc *RunContext) error {
"GIT_NO_REPLACE_OBJECTS=1",
)
cmd.Dir = rc.Dir
cmd.Stdout = rc.Stdout
cmd.Stderr = rc.Stderr
cmd.Stdin = rc.Stdin
cmd.Dir = opts.Dir
cmd.Stdout = opts.Stdout
cmd.Stderr = opts.Stderr
cmd.Stdin = opts.Stdin
if err := cmd.Start(); err != nil {
return err
}
if rc.PipelineFunc != nil {
err := rc.PipelineFunc(ctx, cancel)
if opts.PipelineFunc != nil {
err := opts.PipelineFunc(ctx, cancel)
if err != nil {
cancel()
_ = cmd.Wait()
@ -178,18 +181,18 @@ func (c *Command) RunWithContext(rc *RunContext) error {
return ctx.Err()
}
type RunError interface {
type RunStdError interface {
error
Stderr() string
}
type runError struct {
type runStdError struct {
err error
stderr string
errMsg string
}
func (r *runError) Error() string {
func (r *runStdError) Error() string {
// the stderr must be in the returned error text, some code only checks `strings.Contains(err.Error(), "git error")`
if r.errMsg == "" {
r.errMsg = ConcatenateError(r.err, r.stderr).Error()
@ -197,11 +200,11 @@ func (r *runError) Error() string {
return r.errMsg
}
func (r *runError) Unwrap() error {
func (r *runStdError) Unwrap() error {
return r.err
}
func (r *runError) Stderr() string {
func (r *runStdError) Stderr() string {
return r.stderr
}
@ -209,64 +212,40 @@ func bytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b)) // that's what Golang's strings.Builder.String() does (go/src/strings/builder.go)
}
// RunWithContextString run the command with context and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
func (c *Command) RunWithContextString(rc *RunContext) (stdout, stderr string, runErr RunError) {
stdoutBytes, stderrBytes, err := c.RunWithContextBytes(rc)
// RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
stdoutBytes, stderrBytes, err := c.RunStdBytes(opts)
stdout = bytesToString(stdoutBytes)
stderr = bytesToString(stderrBytes)
if err != nil {
return stdout, stderr, &runError{err: err, stderr: stderr}
return stdout, stderr, &runStdError{err: err, stderr: stderr}
}
// even if there is no err, there could still be some stderr output, so we just return stdout/stderr as they are
return stdout, stderr, nil
}
// RunWithContextBytes run the command with context and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr).
func (c *Command) RunWithContextBytes(rc *RunContext) (stdout, stderr []byte, runErr RunError) {
if rc.Stdout != nil || rc.Stderr != nil {
// RunStdBytes runs the command with options and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr).
func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
if opts == nil {
opts = &RunOpts{}
}
if opts.Stdout != nil || opts.Stderr != nil {
// we must panic here, otherwise there would be bugs if developers set Stdin/Stderr by mistake, and it would be very difficult to debug
panic("stdout and stderr field must be nil when using RunWithContextBytes")
panic("stdout and stderr field must be nil when using RunStdBytes")
}
stdoutBuf := &bytes.Buffer{}
stderrBuf := &bytes.Buffer{}
rc.Stdout = stdoutBuf
rc.Stderr = stderrBuf
err := c.RunWithContext(rc)
opts.Stdout = stdoutBuf
opts.Stderr = stderrBuf
err := c.Run(opts)
stderr = stderrBuf.Bytes()
if err != nil {
return nil, stderr, &runError{err: err, stderr: string(stderr)}
return nil, stderr, &runStdError{err: err, stderr: bytesToString(stderr)}
}
// even if there is no err, there could still be some stderr output
return stdoutBuf.Bytes(), stderr, nil
}
// RunInDirBytes executes the command in given directory
// and returns stdout in []byte and error (combined with stderr).
func (c *Command) RunInDirBytes(dir string) ([]byte, error) {
stdout, _, err := c.RunWithContextBytes(&RunContext{Dir: dir})
return stdout, err
}
// RunInDir executes the command in given directory
// and returns stdout in string and error (combined with stderr).
func (c *Command) RunInDir(dir string) (string, error) {
return c.RunInDirWithEnv(dir, nil)
}
// RunInDirWithEnv executes the command in given directory
// and returns stdout in string and error (combined with stderr).
func (c *Command) RunInDirWithEnv(dir string, env []string) (string, error) {
stdout, _, err := c.RunWithContextString(&RunContext{Env: env, Dir: dir})
return stdout, err
}
// Run executes the command in default working directory
// and returns stdout in string and error (combined with stderr).
func (c *Command) Run() (string, error) {
stdout, _, err := c.RunWithContextString(&RunContext{})
return stdout, err
}
// AllowLFSFiltersArgs return globalCommandArgs with lfs filter, it should only be used for tests
func AllowLFSFiltersArgs() []string {
// Now here we should explicitly allow lfs filters to run

@ -19,7 +19,7 @@ func TestRunWithContextNoTimeout(t *testing.T) {
// 'git --version' does not block so it must be finished before the timeout triggered.
cmd := NewCommand(context.Background(), "--version")
for i := 0; i < maxLoops; i++ {
if err := cmd.RunWithContext(&RunContext{}); err != nil {
if err := cmd.Run(&RunOpts{}); err != nil {
t.Fatal(err)
}
}
@ -31,7 +31,7 @@ func TestRunWithContextTimeout(t *testing.T) {
// 'git hash-object --stdin' blocks on stdin so we can have the timeout triggered.
cmd := NewCommand(context.Background(), "hash-object", "--stdin")
for i := 0; i < maxLoops; i++ {
if err := cmd.RunWithContext(&RunContext{Timeout: 1 * time.Millisecond}); err != nil {
if err := cmd.Run(&RunOpts{Timeout: 1 * time.Millisecond}); err != nil {
if err != context.DeadlineExceeded {
t.Fatalf("Testing %d/%d: %v", i, maxLoops, err)
}

@ -13,13 +13,13 @@ import (
func TestRunWithContextStd(t *testing.T) {
cmd := NewCommand(context.Background(), "--version")
stdout, stderr, err := cmd.RunWithContextString(&RunContext{})
stdout, stderr, err := cmd.RunStdString(&RunOpts{})
assert.NoError(t, err)
assert.Empty(t, stderr)
assert.Contains(t, stdout, "git version")
cmd = NewCommand(context.Background(), "--no-such-arg")
stdout, stderr, err = cmd.RunWithContextString(&RunContext{})
stdout, stderr, err = cmd.RunStdString(&RunOpts{})
if assert.Error(t, err) {
assert.Equal(t, stderr, err.Stderr())
assert.Contains(t, err.Stderr(), "unknown option:")

@ -94,7 +94,7 @@ func AddChangesWithArgs(repoPath string, globalArgs []string, all bool, files ..
cmd.AddArguments("--all")
}
cmd.AddArguments("--")
_, err := cmd.AddArguments(files...).RunInDir(repoPath)
_, _, err := cmd.AddArguments(files...).RunStdString(&RunOpts{Dir: repoPath})
return err
}
@ -130,7 +130,7 @@ func CommitChangesWithArgs(repoPath string, args []string, opts CommitChangesOpt
}
cmd.AddArguments("-m", opts.Message)
_, err := cmd.RunInDir(repoPath)
_, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
// No stderr but exit status 1 means nothing to commit.
if err != nil && err.Error() == "exit status 1" {
return nil
@ -151,7 +151,7 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file
cmd.AddArguments(files...)
}
stdout, err := cmd.RunInDir(repoPath)
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return 0, err
}
@ -168,7 +168,7 @@ func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath [
cmd.AddArguments(relpath...)
}
stdout, err := cmd.RunInDir(repoPath)
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return 0, err
}
@ -206,7 +206,7 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
}
if err := CheckGitVersionAtLeast("1.8"); err == nil {
_, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunInDir(c.repo.Path)
_, _, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunStdString(&RunOpts{Dir: c.repo.Path})
if err == nil {
return true, nil
}
@ -219,7 +219,7 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
return false, err
}
result, err := NewCommand(c.repo.Ctx, "rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunInDir(c.repo.Path)
result, _, err := NewCommand(c.repo.Ctx, "rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunStdString(&RunOpts{Dir: c.repo.Path})
if err != nil {
return false, err
}
@ -381,7 +381,7 @@ func (c *Commit) GetBranchName() (string, error) {
}
args = append(args, "--name-only", "--no-undefined", c.ID.String())
data, err := NewCommand(c.repo.Ctx, args...).RunInDir(c.repo.Path)
data, _, err := NewCommand(c.repo.Ctx, args...).RunStdString(&RunOpts{Dir: c.repo.Path})
if err != nil {
// handle special case where git can not describe commit
if strings.Contains(err.Error(), "cannot describe") {
@ -407,7 +407,7 @@ func (c *Commit) LoadBranchName() (err error) {
// GetTagName gets the current tag name for given commit
func (c *Commit) GetTagName() (string, error) {
data, err := NewCommand(c.repo.Ctx, "describe", "--exact-match", "--tags", "--always", c.ID.String()).RunInDir(c.repo.Path)
data, _, err := NewCommand(c.repo.Ctx, "describe", "--exact-match", "--tags", "--always", c.ID.String()).RunStdString(&RunOpts{Dir: c.repo.Path})
if err != nil {
// handle special case where there is no tag for this commit
if strings.Contains(err.Error(), "no tag exactly matches") {
@ -486,11 +486,10 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
stderr := new(bytes.Buffer)
args := []string{"log", "--name-status", "-c", "--pretty=format:", "--parents", "--no-renames", "-z", "-1", commitID}
err := NewCommand(ctx, args...).RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdout: w,
Stderr: stderr,
err := NewCommand(ctx, args...).Run(&RunOpts{
Dir: repoPath,
Stdout: w,
Stderr: stderr,
})
w.Close() // Close writer to exit parsing goroutine
if err != nil {
@ -503,7 +502,7 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
// GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository.
func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, error) {
commitID, err := NewCommand(ctx, "rev-parse", shortID).RunInDir(repoPath)
commitID, _, err := NewCommand(ctx, "rev-parse", shortID).RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
if strings.Contains(err.Error(), "exit status 128") {
return "", ErrNotExist{shortID, ""}

@ -36,11 +36,10 @@ func GetRawDiff(ctx context.Context, repoPath, commitID string, diffType RawDiff
func GetReverseRawDiff(ctx context.Context, repoPath, commitID string, writer io.Writer) error {
stderr := new(bytes.Buffer)
cmd := NewCommand(ctx, "show", "--pretty=format:revert %H%n", "-R", commitID)
if err := cmd.RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdout: writer,
Stderr: stderr,
if err := cmd.Run(&RunOpts{
Dir: repoPath,
Stdout: writer,
Stderr: stderr,
}); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr)
}
@ -97,11 +96,10 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
stderr := new(bytes.Buffer)
cmd := NewCommand(repo.Ctx, args...)
if err = cmd.RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: writer,
Stderr: stderr,
if err = cmd.Run(&RunOpts{
Dir: repo.Path,
Stdout: writer,
Stderr: stderr,
}); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr)
}
@ -301,11 +299,10 @@ func GetAffectedFiles(repo *Repository, oldCommitID, newCommitID string, env []s
// Run `git diff --name-only` to get the names of the changed files
err = NewCommand(repo.Ctx, "diff", "--name-only", oldCommitID, newCommitID).
RunWithContext(&RunContext{
Env: env,
Timeout: -1,
Dir: repo.Path,
Stdout: stdoutWriter,
Run(&RunOpts{
Env: env,
Dir: repo.Path,
Stdout: stdoutWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
// Close the writer end of the pipe to begin processing
_ = stdoutWriter.Close()

@ -54,9 +54,9 @@ func LoadGitVersion() error {
return nil
}
stdout, err := NewCommand(context.Background(), "version").Run()
if err != nil {
return err
stdout, _, runErr := NewCommand(context.Background(), "version").RunStdString(nil)
if runErr != nil {
return runErr
}
fields := strings.Fields(stdout)
@ -74,6 +74,7 @@ func LoadGitVersion() error {
versionString = fields[2]
}
var err error
gitVersion, err = version.NewVersion(versionString)
return err
}
@ -297,5 +298,5 @@ func checkAndRemoveConfig(key, value string) error {
// Fsck verifies the connectivity and validity of the objects in the database
func Fsck(ctx context.Context, repoPath string, timeout time.Duration, args ...string) error {
return NewCommand(ctx, "fsck").AddArguments(args...).RunWithContext(&RunContext{Timeout: timeout, Dir: repoPath})
return NewCommand(ctx, "fsck").AddArguments(args...).Run(&RunOpts{Timeout: timeout, Dir: repoPath})
}

@ -55,11 +55,10 @@ func LogNameStatusRepo(ctx context.Context, repository, head, treepath string, p
go func() {
stderr := strings.Builder{}
err := NewCommand(ctx, args...).RunWithContext(&RunContext{
Timeout: -1,
Dir: repository,
Stdout: stdoutWriter,
Stderr: &stderr,
err := NewCommand(ctx, args...).Run(&RunOpts{
Dir: repository,
Stdout: stdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))

@ -27,12 +27,11 @@ func CatFileBatchCheck(ctx context.Context, shasToCheckReader *io.PipeReader, ca
stderr := new(bytes.Buffer)
var errbuf strings.Builder
cmd := git.NewCommand(ctx, "cat-file", "--batch-check")
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdin: shasToCheckReader,
Stdout: catFileCheckWriter,
Stderr: stderr,
if err := cmd.Run(&git.RunOpts{
Dir: tmpBasePath,
Stdin: shasToCheckReader,
Stdout: catFileCheckWriter,
Stderr: stderr,
}); err != nil {
_ = catFileCheckWriter.CloseWithError(fmt.Errorf("git cat-file --batch-check [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
}
@ -46,11 +45,10 @@ func CatFileBatchCheckAllObjects(ctx context.Context, catFileCheckWriter *io.Pip
stderr := new(bytes.Buffer)
var errbuf strings.Builder
cmd := git.NewCommand(ctx, "cat-file", "--batch-check", "--batch-all-objects")
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: catFileCheckWriter,
Stderr: stderr,
if err := cmd.Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: catFileCheckWriter,
Stderr: stderr,
}); err != nil {
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())
@ -67,12 +65,11 @@ func CatFileBatch(ctx context.Context, shasToBatchReader *io.PipeReader, catFile
stderr := new(bytes.Buffer)
var errbuf strings.Builder
if err := git.NewCommand(ctx, "cat-file", "--batch").RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: catFileBatchWriter,
Stdin: shasToBatchReader,
Stderr: stderr,
if err := git.NewCommand(ctx, "cat-file", "--batch").Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: catFileBatchWriter,
Stdin: shasToBatchReader,
Stderr: stderr,
}); err != nil {
_ = shasToBatchReader.CloseWithError(fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
}

@ -53,11 +53,10 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
go func() {
stderr := strings.Builder{}
err := git.NewCommand(repo.Ctx, "rev-list", "--all").RunWithContext(&git.RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: revListWriter,
Stderr: &stderr,
err := git.NewCommand(repo.Ctx, "rev-list", "--all").Run(&git.RunOpts{
Dir: repo.Path,
Stdout: revListWriter,
Stderr: &stderr,
})
if err != nil {
_ = revListWriter.CloseWithError(git.ConcatenateError(err, (&stderr).String()))

@ -23,12 +23,11 @@ func NameRevStdin(ctx context.Context, shasToNameReader *io.PipeReader, nameRevS
stderr := new(bytes.Buffer)
var errbuf strings.Builder
if err := git.NewCommand(ctx, "name-rev", "--stdin", "--name-only", "--always").RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: nameRevStdinWriter,
Stdin: shasToNameReader,
Stderr: stderr,
if err := git.NewCommand(ctx, "name-rev", "--stdin", "--name-only", "--always").Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: nameRevStdinWriter,
Stdin: shasToNameReader,
Stderr: stderr,
}); err != nil {
_ = shasToNameReader.CloseWithError(fmt.Errorf("git name-rev [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
}

@ -25,11 +25,10 @@ func RevListAllObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sy
stderr := new(bytes.Buffer)
var errbuf strings.Builder
cmd := git.NewCommand(ctx, "rev-list", "--objects", "--all")
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: basePath,
Stdout: revListWriter,
Stderr: stderr,
if err := cmd.Run(&git.RunOpts{
Dir: basePath,
Stdout: revListWriter,
Stderr: stderr,
}); err != nil {
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())
@ -45,11 +44,10 @@ func RevListObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.
stderr := new(bytes.Buffer)
var errbuf strings.Builder
cmd := git.NewCommand(ctx, "rev-list", "--objects", headSHA, "--not", baseSHA)
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: revListWriter,
Stderr: stderr,
if err := cmd.Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: revListWriter,
Stderr: stderr,
}); err != nil {
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())

@ -22,7 +22,7 @@ func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.UR
cmd = NewCommand(ctx, "config", "--get", "remote."+remoteName+".url")
}
result, err := cmd.RunInDir(repoPath)
result, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return nil, err
}

@ -59,7 +59,7 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) ([]*Commit, erro
// IsRepoURLAccessible checks if given repository URL is accessible.
func IsRepoURLAccessible(ctx context.Context, url string) bool {
_, err := NewCommand(ctx, "ls-remote", "-q", "-h", url, "HEAD").Run()
_, _, err := NewCommand(ctx, "ls-remote", "-q", "-h", url, "HEAD").RunStdString(nil)
return err == nil
}
@ -74,7 +74,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool) error {
if bare {
cmd.AddArguments("--bare")
}
_, err = cmd.RunInDir(repoPath)
_, _, err = cmd.RunStdString(&RunOpts{Dir: repoPath})
return err
}
@ -82,11 +82,10 @@ func InitRepository(ctx context.Context, repoPath string, bare bool) error {
func (repo *Repository) IsEmpty() (bool, error) {
var errbuf, output strings.Builder
if err := NewCommand(repo.Ctx, "show-ref", "--head", "^HEAD$").
RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: &output,
Stderr: &errbuf,
Run(&RunOpts{
Dir: repo.Path,
Stdout: &output,
Stderr: &errbuf,
}); err != nil {
if err.Error() == "exit status 1" && errbuf.String() == "" {
return true, nil
@ -174,7 +173,7 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
}
stderr := new(bytes.Buffer)
if err = cmd.RunWithContext(&RunContext{
if err = cmd.Run(&RunOpts{
Timeout: opts.Timeout,
Env: envs,
Stdout: io.Discard,
@ -219,7 +218,7 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
opts.Timeout = -1
}
err := cmd.RunWithContext(&RunContext{
err := cmd.Run(&RunOpts{
Env: opts.Env,
Timeout: opts.Timeout,
Dir: repoPath,
@ -261,7 +260,7 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
// GetLatestCommitTime returns time for latest commit in repository (across all branches)
func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error) {
cmd := NewCommand(ctx, "for-each-ref", "--sort=-committerdate", BranchPrefix, "--count", "1", "--format=%(committerdate)")
stdout, err := cmd.RunInDir(repoPath)
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return time.Time{}, err
}
@ -278,7 +277,7 @@ type DivergeObject struct {
func checkDivergence(ctx context.Context, repoPath, baseBranch, targetBranch string) (int, error) {
branches := fmt.Sprintf("%s..%s", baseBranch, targetBranch)
cmd := NewCommand(ctx, "rev-list", "--count", branches)
stdout, err := cmd.RunInDir(repoPath)
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return -1, err
}
@ -315,23 +314,23 @@ func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.
defer os.RemoveAll(tmp)
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
_, err = NewCommand(ctx, "init", "--bare").RunInDirWithEnv(tmp, env)
_, _, err = NewCommand(ctx, "init", "--bare").RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}
_, err = NewCommand(ctx, "reset", "--soft", commit).RunInDirWithEnv(tmp, env)
_, _, err = NewCommand(ctx, "reset", "--soft", commit).RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}
_, err = NewCommand(ctx, "branch", "-m", "bundle").RunInDirWithEnv(tmp, env)
_, _, err = NewCommand(ctx, "branch", "-m", "bundle").RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}
tmpFile := filepath.Join(tmp, "bundle")
_, err = NewCommand(ctx, "bundle", "create", tmpFile, "bundle", "HEAD").RunInDirWithEnv(tmp, env)
_, _, err = NewCommand(ctx, "bundle", "create", tmpFile, "bundle", "HEAD").RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil {
return err
}

@ -57,11 +57,10 @@ func (repo *Repository) CreateArchive(ctx context.Context, format ArchiveType, t
)
var stderr strings.Builder
err := NewCommand(ctx, args...).RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: target,
Stderr: &stderr,
err := NewCommand(ctx, args...).Run(&RunOpts{
Dir: repo.Path,
Stdout: target,
Stderr: &stderr,
})
if err != nil {
return ConcatenateError(err, stderr.String())

@ -76,12 +76,11 @@ func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[
cmd := NewCommand(repo.Ctx, cmdArgs...)
if err := cmd.RunWithContext(&RunContext{
Env: env,
Timeout: -1,
Dir: repo.Path,
Stdout: stdOut,
Stderr: stdErr,
if err := cmd.Run(&RunOpts{
Env: env,
Dir: repo.Path,
Stdout: stdOut,
Stderr: stdErr,
}); err != nil {
return nil, fmt.Errorf("failed to run check-attr: %v\n%s\n%s", err, stdOut.String(), stdErr.String())
}
@ -189,13 +188,12 @@ func (c *CheckAttributeReader) Run() error {
_ = c.stdOut.Close()
}()
stdErr := new(bytes.Buffer)
err := c.cmd.RunWithContext(&RunContext{
Env: c.env,
Timeout: -1,
Dir: c.Repo.Path,
Stdin: c.stdinReader,
Stdout: c.stdOut,
Stderr: stdErr,
err := c.cmd.Run(&RunOpts{
Env: c.env,
Dir: c.Repo.Path,
Stdin: c.stdinReader,
Stdout: c.stdOut,
Stderr: stdErr,
PipelineFunc: func(_ context.Context, _ context.CancelFunc) error {
select {
case <-c.running:

@ -8,12 +8,13 @@ import "fmt"
// FileBlame return the Blame object of file
func (repo *Repository) FileBlame(revision, path, file string) ([]byte, error) {
return NewCommand(repo.Ctx, "blame", "--root", "--", file).RunInDirBytes(path)
stdout, _, err := NewCommand(repo.Ctx, "blame", "--root", "--", file).RunStdBytes(&RunOpts{Dir: path})
return stdout, err
}
// LineBlame returns the latest commit at the given line
func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) {
res, err := NewCommand(repo.Ctx, "blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunInDir(path)
res, _, err := NewCommand(repo.Ctx, "blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunStdString(&RunOpts{Dir: path})
if err != nil {
return nil, err
}

@ -24,7 +24,7 @@ const PullRequestPrefix = "refs/for/"
// IsReferenceExist returns true if given reference exists in the repository.
func IsReferenceExist(ctx context.Context, repoPath, name string) bool {
_, err := NewCommand(ctx, "show-ref", "--verify", "--", name).RunInDir(repoPath)
_, _, err := NewCommand(ctx, "show-ref", "--verify", "--", name).RunStdString(&RunOpts{Dir: repoPath})
return err == nil
}
@ -46,7 +46,7 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
if repo == nil {
return nil, fmt.Errorf("nil repo")
}
stdout, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -65,13 +65,14 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
// SetDefaultBranch sets default branch of repository.
func (repo *Repository) SetDefaultBranch(name string) error {
_, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD", BranchPrefix+name).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD", BranchPrefix+name).RunStdString(&RunOpts{Dir: repo.Path})
return err
}
// GetDefaultBranch gets default branch of repository.
func (repo *Repository) GetDefaultBranch() (string, error) {
return NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repo.Path})
return stdout, err
}
// GetBranch returns a branch by it's name
@ -133,7 +134,7 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
}
cmd.AddArguments("--", name)
_, err := cmd.RunInDir(repo.Path)
_, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err
}
@ -143,7 +144,7 @@ func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
cmd := NewCommand(repo.Ctx, "branch")
cmd.AddArguments("--", branch, oldbranchOrCommit)
_, err := cmd.RunInDir(repo.Path)
_, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err
}
@ -156,13 +157,13 @@ func (repo *Repository) AddRemote(name, url string, fetch bool) error {
}
cmd.AddArguments(name, url)
_, err := cmd.RunInDir(repo.Path)
_, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err
}
// RemoveRemote removes a remote from repository.
func (repo *Repository) RemoveRemote(name string) error {
_, err := NewCommand(repo.Ctx, "remote", "rm", name).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "remote", "rm", name).RunStdString(&RunOpts{Dir: repo.Path})
return err
}
@ -173,6 +174,6 @@ func (branch *Branch) GetCommit() (*Commit, error) {
// RenameBranch rename a branch
func (repo *Repository) RenameBranch(from, to string) error {
_, err := NewCommand(repo.Ctx, "branch", "-m", from, to).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "branch", "-m", from, to).RunStdString(&RunOpts{Dir: repo.Path})
return err
}

@ -112,11 +112,10 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
if arg != "" {
args = append(args, arg)
}
err := NewCommand(ctx, args...).RunWithContext(&RunContext{
Timeout: -1,
Dir: repoPath,
Stdout: stdoutWriter,
Stderr: stderrBuilder,
err := NewCommand(ctx, args...).Run(&RunOpts{
Dir: repoPath,
Stdout: stdoutWriter,
Stderr: stderrBuilder,
})
if err != nil {
if stderrBuilder.Len() == 0 {

@ -58,12 +58,12 @@ func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit,
relpath = `\` + relpath
}
stdout, err := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, id.String(), "--", relpath).RunInDir(repo.Path)
if err != nil {
return nil, err
stdout, _, runErr := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, id.String(), "--", relpath).RunStdString(&RunOpts{Dir: repo.Path})
if runErr != nil {
return nil, runErr
}
id, err = NewIDFromString(stdout)
id, err := NewIDFromString(stdout)
if err != nil {
return nil, err
}
@ -73,9 +73,9 @@ func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit,
// GetCommitByPath returns the last commit of relative path.
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
stdout, err := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, "--", relpath).RunInDirBytes(repo.Path)
if err != nil {
return nil, err
stdout, _, runErr := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, "--", relpath).RunStdBytes(&RunOpts{Dir: repo.Path})
if runErr != nil {
return nil, runErr
}
commits, err := repo.parsePrettyFormatLogToList(stdout)
@ -86,8 +86,8 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
}
func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) ([]*Commit, error) {
stdout, err := NewCommand(repo.Ctx, "log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize),
"--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunInDirBytes(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize),
"--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -139,7 +139,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
// search for commits matching given constraints and keywords in commit msg
cmd.AddArguments(args...)
stdout, err := cmd.RunInDirBytes(repo.Path)
stdout, _, err := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -161,7 +161,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
hashCmd.AddArguments(v)
// search with given constraints for commit matching sha hash of v
hashMatching, err := hashCmd.RunInDirBytes(repo.Path)
hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil || bytes.Contains(stdout, hashMatching) {
continue
}
@ -175,7 +175,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
}
func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
stdout, err := NewCommand(repo.Ctx, "diff", "--name-only", id1, id2).RunInDirBytes(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", id1, id2).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -185,7 +185,7 @@ func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
// You must ensure that id1 and id2 are valid commit ids.
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
stdout, err := NewCommand(repo.Ctx, "diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", "-z", id1, id2, "--", filename).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return false, err
}
@ -211,11 +211,10 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
err := NewCommand(repo.Ctx, "log", revision, "--follow",
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page),
prettyLogFormat, "--", file).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: &stderr,
Run(&RunOpts{
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
@ -244,8 +243,8 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
// CommitsByFileAndRangeNoFollow return the commits according revision file and the page
func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, page int) ([]*Commit, error) {
stdout, err := NewCommand(repo.Ctx, "log", revision, "--skip="+strconv.Itoa((page-1)*50),
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "log", revision, "--skip="+strconv.Itoa((page-1)*50),
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize), prettyLogFormat, "--", file).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -254,11 +253,11 @@ func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, pag
// FilesCountBetween return the number of files changed between two commits
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
stdout, err := NewCommand(repo.Ctx, "diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", startCommitID+"..."+endCommitID).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil && strings.Contains(err.Error(), "no merge base") {
// git >= 2.28 now returns an error if startCommitID and endCommitID have become unrelated.
// previously it would return the results of git diff --name-only startCommitID endCommitID so let's try that...
stdout, err = NewCommand(repo.Ctx, "diff", "--name-only", startCommitID, endCommitID).RunInDir(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "diff", "--name-only", startCommitID, endCommitID).RunStdString(&RunOpts{Dir: repo.Path})
}
if err != nil {
return 0, err
@ -272,13 +271,13 @@ func (repo *Repository) CommitsBetween(last, before *Commit) ([]*Commit, error)
var stdout []byte
var err error
if before == nil {
stdout, err = NewCommand(repo.Ctx, "rev-list", last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
} else {
stdout, err = NewCommand(repo.Ctx, "rev-list", before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", before.ID.String()+".."+last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
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.
// previously it would return the results of git rev-list before last so let's try that...
stdout, err = NewCommand(repo.Ctx, "rev-list", before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", before.ID.String(), last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
}
}
if err != nil {
@ -292,13 +291,13 @@ func (repo *Repository) CommitsBetweenLimit(last, before *Commit, limit, skip in
var stdout []byte
var err error
if before == nil {
stdout, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
} else {
stdout, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+".."+last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
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.
// previously it would return the results of git rev-list --max-count n before last so let's try that...
stdout, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
stdout, _, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String(), last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
}
}
if err != nil {
@ -344,9 +343,9 @@ func (repo *Repository) commitsBefore(id SHA1, limit int) ([]*Commit, error) {
cmd.AddArguments(prettyLogFormat, id.String())
}
stdout, err := cmd.RunInDirBytes(repo.Path)
if err != nil {
return nil, err
stdout, _, runErr := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if runErr != nil {
return nil, runErr
}
formattedLog, err := repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
@ -381,7 +380,7 @@ func (repo *Repository) getCommitsBeforeLimit(id SHA1, num int) ([]*Commit, erro
func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) {
if CheckGitVersionAtLeast("2.7.0") == nil {
stdout, err := NewCommand(repo.Ctx, "for-each-ref", "--count="+strconv.Itoa(limit), "--format=%(refname:strip=2)", "--contains", commit.ID.String(), BranchPrefix).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "for-each-ref", "--count="+strconv.Itoa(limit), "--format=%(refname:strip=2)", "--contains", commit.ID.String(), BranchPrefix).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -390,7 +389,7 @@ func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error)
return branches, nil
}
stdout, err := NewCommand(repo.Ctx, "branch", "--contains", commit.ID.String()).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "branch", "--contains", commit.ID.String()).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -429,7 +428,7 @@ func (repo *Repository) GetCommitsFromIDs(commitIDs []string) []*Commit {
// IsCommitInBranch check if the commit is on the branch
func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err error) {
stdout, err := NewCommand(repo.Ctx, "branch", "--contains", commitID, branch).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "branch", "--contains", commitID, branch).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return false, err
}

@ -50,7 +50,7 @@ func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
}
}
actualCommitID, err := NewCommand(repo.Ctx, "rev-parse", "--verify", commitID).RunInDir(repo.Path)
actualCommitID, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify", commitID).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
if strings.Contains(err.Error(), "unknown revision or path") ||
strings.Contains(err.Error(), "fatal: Needed a single revision") {

@ -18,7 +18,7 @@ import (
// ResolveReference resolves a name to a reference
func (repo *Repository) ResolveReference(name string) (string, error) {
stdout, err := NewCommand(repo.Ctx, "show-ref", "--hash", name).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "show-ref", "--hash", name).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
if strings.Contains(err.Error(), "not a valid ref") {
return "", ErrNotExist{name, ""}
@ -51,19 +51,19 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) {
// SetReference sets the commit ID string of given reference (e.g. branch or tag).
func (repo *Repository) SetReference(name, commitID string) error {
_, err := NewCommand(repo.Ctx, "update-ref", name, commitID).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "update-ref", name, commitID).RunStdString(&RunOpts{Dir: repo.Path})
return err
}
// RemoveReference removes the given reference (e.g. branch or tag).
func (repo *Repository) RemoveReference(name string) error {
_, err := NewCommand(repo.Ctx, "update-ref", "--no-deref", "-d", name).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "update-ref", "--no-deref", "-d", name).RunStdString(&RunOpts{Dir: repo.Path})
return err
}
// IsCommitExist returns true if given commit exists in current repository.
func (repo *Repository) IsCommitExist(name string) bool {
_, err := NewCommand(repo.Ctx, "cat-file", "-e", name).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "cat-file", "-e", name).RunStdString(&RunOpts{Dir: repo.Path})
return err == nil
}

@ -13,7 +13,7 @@ import (
// this requires git v2.18 to be installed
func WriteCommitGraph(ctx context.Context, repoPath string) error {
if CheckGitVersionAtLeast("2.18") == nil {
if _, err := NewCommand(ctx, "commit-graph", "write").RunInDir(repoPath); err != nil {
if _, _, err := NewCommand(ctx, "commit-graph", "write").RunStdString(&RunOpts{Dir: repoPath}); err != nil {
return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err)
}
}

@ -40,13 +40,13 @@ func (repo *Repository) GetMergeBase(tmpRemote, base, head string) (string, stri
if tmpRemote != "origin" {
tmpBaseName := RemotePrefix + tmpRemote + "/tmp_" + base
// Fetch commit into a temporary branch in order to be able to handle commits and tags
_, err := NewCommand(repo.Ctx, "fetch", tmpRemote, base+":"+tmpBaseName).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "fetch", tmpRemote, base+":"+tmpBaseName).RunStdString(&RunOpts{Dir: repo.Path})
if err == nil {
base = tmpBaseName
}
}
stdout, err := NewCommand(repo.Ctx, "merge-base", "--", base, head).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "merge-base", "--", base, head).RunStdString(&RunOpts{Dir: repo.Path})
return strings.TrimSpace(stdout), base, err
}
@ -93,7 +93,8 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string,
// We have a common base - therefore we know that ... should work
if !fileOnly {
logs, err := NewCommand(repo.Ctx, "log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
var logs []byte
logs, _, err = NewCommand(repo.Ctx, "log", baseCommitID+separator+headBranch, prettyLogFormat).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -147,22 +148,20 @@ func (repo *Repository) GetDiffNumChangedFiles(base, head string, directComparis
}
if err := NewCommand(repo.Ctx, "diff", "-z", "--name-only", base+separator+head).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: w,
Stderr: stderr,
Run(&RunOpts{
Dir: repo.Path,
Stdout: w,
Stderr: stderr,
}); err != nil {
if strings.Contains(stderr.String(), "no merge base") {
// git >= 2.28 now returns an error if base and head have become unrelated.
// previously it would return the results of git diff -z --name-only base head so let's try that...
w = &lineCountWriter{}
stderr.Reset()
if err = NewCommand(repo.Ctx, "diff", "-z", "--name-only", base, head).RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: w,
Stderr: stderr,
if err = NewCommand(repo.Ctx, "diff", "-z", "--name-only", base, head).Run(&RunOpts{
Dir: repo.Path,
Stdout: w,
Stderr: stderr,
}); err == nil {
return w.numLines, nil
}
@ -192,7 +191,7 @@ func GetDiffShortStat(ctx context.Context, repoPath string, args ...string) (num
"--shortstat",
}, args...)
stdout, err := NewCommand(ctx, args...).RunInDir(repoPath)
stdout, _, err := NewCommand(ctx, args...).RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return 0, 0, 0, err
}
@ -248,26 +247,23 @@ func (repo *Repository) GetDiffOrPatch(base, head string, w io.Writer, patch, bi
// GetDiff generates and returns patch data between given revisions, optimized for human readability
func (repo *Repository) GetDiff(base, head string, w io.Writer) error {
return NewCommand(repo.Ctx, "diff", "-p", base, head).RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: w,
return NewCommand(repo.Ctx, "diff", "-p", base, head).Run(&RunOpts{
Dir: repo.Path,
Stdout: w,
})
}
// GetDiffBinary generates and returns patch data between given revisions, including binary diffs.
func (repo *Repository) GetDiffBinary(base, head string, w io.Writer) error {
if CheckGitVersionAtLeast("1.7.7") == nil {
return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--histogram", base, head).RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: w,
return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--histogram", base, head).Run(&RunOpts{
Dir: repo.Path,
Stdout: w,
})
}
return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--patience", base, head).RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: w,
return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--patience", base, head).Run(&RunOpts{
Dir: repo.Path,
Stdout: w,
})
}
@ -275,18 +271,16 @@ func (repo *Repository) GetDiffBinary(base, head string, w io.Writer) error {
func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
stderr := new(bytes.Buffer)
err := NewCommand(repo.Ctx, "format-patch", "--binary", "--stdout", base+"..."+head).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: w,
Stderr: stderr,
Run(&RunOpts{
Dir: repo.Path,
Stdout: w,
Stderr: stderr,
})
if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) {
return NewCommand(repo.Ctx, "format-patch", "--binary", "--stdout", base, head).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: w,
Run(&RunOpts{
Dir: repo.Path,
Stdout: w,
})
}
return err
@ -296,11 +290,10 @@ func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
func (repo *Repository) GetDiffFromMergeBase(base, head string, w io.Writer) error {
stderr := new(bytes.Buffer)
err := NewCommand(repo.Ctx, "diff", "-p", "--binary", base+"..."+head).
RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: w,
Stderr: stderr,
Run(&RunOpts{
Dir: repo.Path,
Stdout: w,
Stderr: stderr,
})
if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) {
return repo.GetDiffBinary(base, head, w)

@ -34,7 +34,7 @@ func (repo *Repository) GetDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings,
Sign: true,
}
value, _ := NewCommand(repo.Ctx, "config", "--get", "commit.gpgsign").RunInDir(repo.Path)
value, _, _ := NewCommand(repo.Ctx, "config", "--get", "commit.gpgsign").RunStdString(&RunOpts{Dir: repo.Path})
sign, valid := ParseBool(strings.TrimSpace(value))
if !sign || !valid {
gpgSettings.Sign = false
@ -42,13 +42,13 @@ func (repo *Repository) GetDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings,
return gpgSettings, nil
}
signingKey, _ := NewCommand(repo.Ctx, "config", "--get", "user.signingkey").RunInDir(repo.Path)
signingKey, _, _ := NewCommand(repo.Ctx, "config", "--get", "user.signingkey").RunStdString(&RunOpts{Dir: repo.Path})
gpgSettings.KeyID = strings.TrimSpace(signingKey)
defaultEmail, _ := NewCommand(repo.Ctx, "config", "--get", "user.email").RunInDir(repo.Path)
defaultEmail, _, _ := NewCommand(repo.Ctx, "config", "--get", "user.email").RunStdString(&RunOpts{Dir: repo.Path})
gpgSettings.Email = strings.TrimSpace(defaultEmail)
defaultName, _ := NewCommand(repo.Ctx, "config", "--get", "user.name").RunInDir(repo.Path)
defaultName, _, _ := NewCommand(repo.Ctx, "config", "--get", "user.name").RunStdString(&RunOpts{Dir: repo.Path})
gpgSettings.Name = strings.TrimSpace(defaultName)
if err := gpgSettings.LoadPublicKeyContent(); err != nil {

@ -18,7 +18,7 @@ import (
// ReadTreeToIndex reads a treeish to the index
func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error {
if len(treeish) != 40 {
res, err := NewCommand(repo.Ctx, "rev-parse", "--verify", treeish).RunInDir(repo.Path)
res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify", treeish).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return err
}
@ -38,7 +38,7 @@ func (repo *Repository) readTreeToIndex(id SHA1, indexFilename ...string) error
if len(indexFilename) > 0 {
env = append(os.Environ(), "GIT_INDEX_FILE="+indexFilename[0])
}
_, err := NewCommand(repo.Ctx, "read-tree", id.String()).RunInDirWithEnv(repo.Path, env)
_, _, err := NewCommand(repo.Ctx, "read-tree", id.String()).RunStdString(&RunOpts{Dir: repo.Path, Env: env})
if err != nil {
return err
}
@ -69,7 +69,7 @@ func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (filename, tmpD
// EmptyIndex empties the index
func (repo *Repository) EmptyIndex() error {
_, err := NewCommand(repo.Ctx, "read-tree", "--empty").RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "read-tree", "--empty").RunStdString(&RunOpts{Dir: repo.Path})
return err
}
@ -81,7 +81,7 @@ func (repo *Repository) LsFiles(filenames ...string) ([]string, error) {
cmd.AddArguments(arg)
}
}
res, err := cmd.RunInDirBytes(repo.Path)
res, _, err := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}
@ -106,29 +106,28 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
buffer.WriteByte('\000')
}
}
return cmd.RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdin: bytes.NewReader(buffer.Bytes()),
Stdout: stdout,
Stderr: stderr,
return cmd.Run(&RunOpts{
Dir: repo.Path,
Stdin: bytes.NewReader(buffer.Bytes()),
Stdout: stdout,
Stderr: stderr,
})
}
// AddObjectToIndex adds the provided object hash to the index at the provided filename
func (repo *Repository) AddObjectToIndex(mode string, object SHA1, filename string) error {
cmd := NewCommand(repo.Ctx, "update-index", "--add", "--replace", "--cacheinfo", mode, object.String(), filename)
_, err := cmd.RunInDir(repo.Path)
_, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err
}
// WriteTree writes the current index as a tree to the object db and returns its hash
func (repo *Repository) WriteTree() (*Tree, error) {
res, err := NewCommand(repo.Ctx, "write-tree").RunInDir(repo.Path)
if err != nil {
return nil, err
stdout, _, runErr := NewCommand(repo.Ctx, "write-tree").RunStdString(&RunOpts{Dir: repo.Path})
if runErr != nil {
return nil, runErr
}
id, err := NewIDFromString(strings.TrimSpace(res))
id, err := NewIDFromString(strings.TrimSpace(stdout))
if err != nil {
return nil, err
}

@ -45,12 +45,11 @@ func (repo *Repository) hashObject(reader io.Reader) (string, error) {
cmd := NewCommand(repo.Ctx, "hash-object", "-w", "--stdin")
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
err := cmd.RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdin: reader,
Stdout: stdout,
Stderr: stderr,
err := cmd.Run(&RunOpts{
Dir: repo.Path,
Stdin: reader,
Stdout: stdout,
Stderr: stderr,
})
if err != nil {
return "", err

@ -23,11 +23,10 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
go func() {
stderrBuilder := &strings.Builder{}
err := NewCommand(repo.Ctx, "for-each-ref").RunWithContext(&RunContext{
Timeout: -1,
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: stderrBuilder,
err := NewCommand(repo.Ctx, "for-each-ref").Run(&RunOpts{
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: stderrBuilder,
})
if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String()))

@ -39,12 +39,12 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
since := fromTime.Format(time.RFC3339)
stdout, err := NewCommand(repo.Ctx, "rev-list", "--count", "--no-merges", "--branches=*", "--date=iso", fmt.Sprintf("--since='%s'", since)).RunInDirBytes(repo.Path)
if err != nil {
return nil, err
stdout, _, runErr := NewCommand(repo.Ctx, "rev-list", "--count", "--no-merges", "--branches=*", "--date=iso", fmt.Sprintf("--since='%s'", since)).RunStdString(&RunOpts{Dir: repo.Path})
if runErr != nil {
return nil, runErr
}
c, err := strconv.ParseInt(strings.TrimSpace(string(stdout)), 10, 64)
c, err := strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
if err != nil {
return nil, err
}
@ -67,12 +67,11 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
}
stderr := new(strings.Builder)
err = NewCommand(repo.Ctx, args...).RunWithContext(&RunContext{
Env: []string{},
Timeout: -1,
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: stderr,
err = NewCommand(repo.Ctx, args...).Run(&RunOpts{
Env: []string{},
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: stderr,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
scanner := bufio.NewScanner(stdoutReader)

@ -25,13 +25,13 @@ func IsTagExist(ctx context.Context, repoPath, name string) bool {
// CreateTag create one tag in the repository
func (repo *Repository) CreateTag(name, revision string) error {
_, err := NewCommand(repo.Ctx, "tag", "--", name, revision).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "tag", "--", name, revision).RunStdString(&RunOpts{Dir: repo.Path})
return err
}
// CreateAnnotatedTag create one annotated tag in the repository
func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error {
_, err := NewCommand(repo.Ctx, "tag", "-a", "-m", message, "--", name, revision).RunInDir(repo.Path)
_, _, err := NewCommand(repo.Ctx, "tag", "-a", "-m", message, "--", name, revision).RunStdString(&RunOpts{Dir: repo.Path})
return err
}
@ -41,7 +41,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
return "", fmt.Errorf("SHA is too short: %s", sha)
}
stdout, err := NewCommand(repo.Ctx, "show-ref", "--tags", "-d").RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "show-ref", "--tags", "-d").RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return "", err
}
@ -64,7 +64,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA)
func (repo *Repository) GetTagID(name string) (string, error) {
stdout, err := NewCommand(repo.Ctx, "show-ref", "--tags", "--", name).RunInDir(repo.Path)
stdout, _, err := NewCommand(repo.Ctx, "show-ref", "--tags", "--", name).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return "", err
}
@ -119,10 +119,10 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
defer stdoutReader.Close()
defer stdoutWriter.Close()
stderr := strings.Builder{}
rc := &RunContext{Dir: repo.Path, Stdout: stdoutWriter, Stderr: &stderr, Timeout: -1}
rc := &RunOpts{Dir: repo.Path, Stdout: stdoutWriter, Stderr: &stderr}
go func() {
err := NewCommand(repo.Ctx, "for-each-ref", "--format", forEachRefFmt.Flag(), "--sort", "-*creatordate", "refs/tags").RunWithContext(rc)
err := NewCommand(repo.Ctx, "for-each-ref", "--format", forEachRefFmt.Flag(), "--sort", "-*creatordate", "refs/tags").Run(rc)
if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderr.String()))
} else {

@ -60,13 +60,12 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
err = cmd.RunWithContext(&RunContext{
Env: env,
Timeout: -1,
Dir: repo.Path,
Stdin: messageBytes,
Stdout: stdout,
Stderr: stderr,
err = cmd.Run(&RunOpts{
Env: env,
Dir: repo.Path,
Stdin: messageBytes,
Stdout: stdout,
Stderr: stderr,
})
if err != nil {

@ -22,7 +22,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
// GetTree find the tree object in the repository.
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
if len(idStr) != 40 {
res, err := NewCommand(repo.Ctx, "rev-parse", "--verify", idStr).RunInDir(repo.Path)
res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify", idStr).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}

@ -55,7 +55,7 @@ func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error
cmd.AddArguments(arg)
}
}
res, err := cmd.RunInDirBytes(repo.Path)
res, _, err := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err
}

@ -81,16 +81,17 @@ func (t *Tree) ListEntries() (Entries, error) {
}
}
stdout, err := NewCommand(t.repo.Ctx, "ls-tree", "-l", t.ID.String()).RunInDirBytes(t.repo.Path)
if err != nil {
if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "fatal: not a tree object") {
stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-l", t.ID.String()).RunStdBytes(&RunOpts{Dir: t.repo.Path})
if runErr != nil {
if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") {
return nil, ErrNotExist{
ID: t.ID.String(),
}
}
return nil, err
return nil, runErr
}
var err error
t.entries, err = parseTreeEntries(stdout, t)
if err == nil {
t.entriesParsed = true
@ -104,11 +105,13 @@ func (t *Tree) ListEntriesRecursive() (Entries, error) {
if t.entriesRecursiveParsed {
return t.entriesRecursive, nil
}
stdout, err := NewCommand(t.repo.Ctx, "ls-tree", "-t", "-l", "-r", t.ID.String()).RunInDirBytes(t.repo.Path)
if err != nil {
return nil, err
stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-t", "-l", "-r", t.ID.String()).RunStdBytes(&RunOpts{Dir: t.repo.Path})
if runErr != nil {
return nil, runErr
}
var err error
t.entriesRecursive, err = parseTreeEntries(stdout, t)
if err == nil {
t.entriesRecursiveParsed = true

@ -64,11 +64,10 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
scanner := bufio.NewScanner(stdoutReader)
if err := graphCmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: r.Path,
Stdout: stdoutWriter,
Stderr: stderr,
if err := graphCmd.Run(&git.RunOpts{
Dir: r.Path,
Stdout: stdoutWriter,
Stderr: stderr,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
defer stdoutReader.Close()

@ -191,9 +191,10 @@ func (b *BleveIndexer) addUpdate(ctx context.Context, batchWriter git.WriteClose
size := update.Size
var err error
if !update.Sized {
stdout, err := git.NewCommand(ctx, "cat-file", "-s", update.BlobSha).
RunInDir(repo.RepoPath())
var stdout string
stdout, _, err = git.NewCommand(ctx, "cat-file", "-s", update.BlobSha).RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
if err != nil {
return err
}
@ -210,7 +211,7 @@ func (b *BleveIndexer) addUpdate(ctx context.Context, batchWriter git.WriteClose
return err
}
_, _, size, err := git.ReadBatchLine(batchReader)
_, _, size, err = git.ReadBatchLine(batchReader)
if err != nil {
return err
}

@ -220,10 +220,10 @@ func (b *ElasticSearchIndexer) addUpdate(ctx context.Context, batchWriter git.Wr
}
size := update.Size
var err error
if !update.Sized {
stdout, err := git.NewCommand(ctx, "cat-file", "-s", update.BlobSha).
RunInDir(repo.RepoPath())
var stdout string
stdout, _, err = git.NewCommand(ctx, "cat-file", "-s", update.BlobSha).RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
if err != nil {
return nil, err
}
@ -240,7 +240,7 @@ func (b *ElasticSearchIndexer) addUpdate(ctx context.Context, batchWriter git.Wr
return nil, err
}
_, _, size, err := git.ReadBatchLine(batchReader)
_, _, size, err = git.ReadBatchLine(batchReader)
if err != nil {
return nil, err
}

@ -29,7 +29,7 @@ type repoChanges struct {
}
func getDefaultBranchSha(ctx context.Context, repo *repo_model.Repository) (string, error) {
stdout, err := git.NewCommand(ctx, "show-ref", "-s", git.BranchPrefix+repo.DefaultBranch).RunInDir(repo.RepoPath())
stdout, _, err := git.NewCommand(ctx, "show-ref", "-s", git.BranchPrefix+repo.DefaultBranch).RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
if err != nil {
return "", err
}
@ -92,30 +92,32 @@ func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
// genesisChanges get changes to add repo to the indexer for the first time
func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) {
var changes repoChanges
stdout, err := git.NewCommand(ctx, "ls-tree", "--full-tree", "-l", "-r", revision).
RunInDirBytes(repo.RepoPath())
if err != nil {
return nil, err
stdout, _, runErr := git.NewCommand(ctx, "ls-tree", "--full-tree", "-l", "-r", revision).RunStdBytes(&git.RunOpts{Dir: repo.RepoPath()})
if runErr != nil {
return nil, runErr
}
var err error
changes.Updates, err = parseGitLsTreeOutput(stdout)
return &changes, err
}
// nonGenesisChanges get changes since the previous indexer update
func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) {
diffCmd := git.NewCommand(ctx, "diff", "--name-status",
repo.CodeIndexerStatus.CommitSha, revision)
stdout, err := diffCmd.RunInDir(repo.RepoPath())
if err != nil {
diffCmd := git.NewCommand(ctx, "diff", "--name-status", repo.CodeIndexerStatus.CommitSha, revision)
stdout, _, runErr := diffCmd.RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
if runErr != nil {
// previous commit sha may have been removed by a force push, so
// try rebuilding from scratch
log.Warn("git diff: %v", err)
if err = indexer.Delete(repo.ID); err != nil {
log.Warn("git diff: %v", runErr)
if err := indexer.Delete(repo.ID); err != nil {
return nil, err
}
return genesisChanges(ctx, repo, revision)
}
var changes repoChanges
var err error
updatedFilenames := make([]string, 0, 10)
for _, line := range strings.Split(stdout, "\n") {
line = strings.TrimSpace(line)
@ -169,7 +171,7 @@ func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revisio
cmd := git.NewCommand(ctx, "ls-tree", "--full-tree", "-l", revision, "--")
cmd.AddArguments(updatedFilenames...)
lsTreeStdout, err := cmd.RunInDirBytes(repo.RepoPath())
lsTreeStdout, _, err := cmd.RunStdBytes(&git.RunOpts{Dir: repo.RepoPath()})
if err != nil {
return nil, err
}

@ -111,9 +111,9 @@ func CreateRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (
return fmt.Errorf("checkDaemonExportOK: %v", err)
}
if stdout, err := git.NewCommand(ctx, "update-server-info").
if stdout, _, err := git.NewCommand(ctx, "update-server-info").
SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
RunInDir(repoPath); err != nil {
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
rollbackRepo = repo
rollbackRepo.OwnerID = u.ID

@ -177,9 +177,9 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
}
repoPath := repo.RepoPath()
if stdout, err := git.NewCommand(ctx, "remote", "add", "origin", repoPath).
if stdout, _, err := git.NewCommand(ctx, "remote", "add", "origin", repoPath).
SetDescription(fmt.Sprintf("generateRepoCommit (git remote add): %s to %s", templateRepoPath, tmpDir)).
RunInDirWithEnv(tmpDir, env); err != nil {
RunStdString(&git.RunOpts{Dir: tmpDir, Env: 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)
return fmt.Errorf("git remote add: %v", err)
}
@ -292,9 +292,9 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
return generateRepo, fmt.Errorf("checkDaemonExportOK: %v", err)
}
if stdout, err := git.NewCommand(ctx, "update-server-info").
if stdout, _, err := git.NewCommand(ctx, "update-server-info").
SetDescription(fmt.Sprintf("GenerateRepository(git update-server-info): %s", repoPath)).
RunInDir(repoPath); err != nil {
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("GenerateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", generateRepo, stdout, err)
return generateRepo, fmt.Errorf("error in GenerateRepository(git update-server-info): %v", err)
}

@ -229,9 +229,9 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
)
// Clone to temporary path and do the init commit.
if stdout, err := git.NewCommand(ctx, "clone", repoPath, tmpDir).
if stdout, _, err := git.NewCommand(ctx, "clone", repoPath, tmpDir).
SetDescription(fmt.Sprintf("prepareRepoCommit (git clone): %s to %s", repoPath, tmpDir)).
RunInDirWithEnv("", env); err != nil {
RunStdString(&git.RunOpts{Dir: "", Env: env}); err != nil {
log.Error("Failed to clone from %v into %s: stdout: %s\nError: %v", repo, tmpDir, stdout, err)
return fmt.Errorf("git clone: %v", err)
}
@ -306,9 +306,9 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
committerName := sig.Name
committerEmail := sig.Email
if stdout, err := git.NewCommand(ctx, "add", "--all").
if stdout, _, err := git.NewCommand(ctx, "add", "--all").
SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)).
RunInDir(tmpPath); err != nil {
RunStdString(&git.RunOpts{Dir: tmpPath}); err != nil {
log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err)
return fmt.Errorf("git add --all: %v", err)
}
@ -343,9 +343,9 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
"GIT_COMMITTER_EMAIL="+committerEmail,
)
if stdout, err := git.NewCommand(ctx, args...).
if stdout, _, err := git.NewCommand(ctx, args...).
SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)).
RunInDirWithEnv(tmpPath, env); err != nil {
RunStdString(&git.RunOpts{Dir: tmpPath, Env: env}); err != nil {
log.Error("Failed to commit: %v: Stdout: %s\nError: %v", args, stdout, err)
return fmt.Errorf("git commit: %v", err)
}
@ -354,9 +354,9 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
defaultBranch = setting.Repository.DefaultBranch
}
if stdout, err := git.NewCommand(ctx, "push", "origin", "HEAD:"+defaultBranch).
if stdout, _, err := git.NewCommand(ctx, "push", "origin", "HEAD:"+defaultBranch).
SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)).
RunInDirWithEnv(tmpPath, models.InternalPushingEnvironment(u, repo)); err != nil {
RunStdString(&git.RunOpts{Dir: tmpPath, Env: models.InternalPushingEnvironment(u, repo)}); err != nil {
log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err)
return fmt.Errorf("git push: %v", err)
}

@ -104,8 +104,8 @@ func IsForcePush(ctx context.Context, opts *PushUpdateOptions) (bool, error) {
return false, nil
}
output, err := git.NewCommand(ctx, "rev-list", "--max-count=1", opts.OldCommitID, "^"+opts.NewCommitID).
RunInDir(repo_model.RepoPath(opts.RepoUserName, opts.RepoName))
output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1", opts.OldCommitID, "^"+opts.NewCommitID).
RunStdString(&git.RunOpts{Dir: repo_model.RepoPath(opts.RepoUserName, opts.RepoName)})
if err != nil {
return false, err
} else if len(output) > 0 {

@ -119,9 +119,9 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
return repo, fmt.Errorf("checkDaemonExportOK: %v", err)
}
if stdout, err := git.NewCommand(ctx, "update-server-info").
if stdout, _, err := git.NewCommand(ctx, "update-server-info").
SetDescription(fmt.Sprintf("MigrateRepositoryGitData(git update-server-info): %s", repoPath)).
RunInDir(repoPath); err != nil {
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("MigrateRepositoryGitData(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
return repo, fmt.Errorf("error in MigrateRepositoryGitData(git update-server-info): %v", err)
}
@ -241,7 +241,7 @@ func CleanUpMigrateInfo(ctx context.Context, repo *repo_model.Repository) (*repo
}
}
_, err := git.NewCommand(ctx, "remote", "rm", "origin").RunInDir(repoPath)
_, _, err := git.NewCommand(ctx, "remote", "rm", "origin").RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err)
}

@ -179,7 +179,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
// 2. Disallow force pushes to protected branches
if git.EmptySHA != oldCommitID {
output, err := git.NewCommand(ctx, "rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDirWithEnv(repo.RepoPath(), ctx.env)
output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env})
if err != nil {
log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err)
ctx.JSON(http.StatusInternalServerError, private.Response{

@ -45,11 +45,10 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
// This is safe as force pushes are already forbidden
err = git.NewCommand(repo.Ctx, "rev-list", oldCommitID+"..."+newCommitID).
RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: repo.Path,
Stdout: stdoutWriter,
Run(&git.RunOpts{
Env: env,
Dir: repo.Path,
Stdout: stdoutWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env)
@ -93,11 +92,10 @@ func readAndVerifyCommit(sha string, repo *git.Repository, env []string) error {
hash := git.MustIDFromString(sha)
return git.NewCommand(repo.Ctx, "cat-file", "commit", sha).
RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: repo.Path,
Stdout: stdoutWriter,
Run(&git.RunOpts{
Env: env,
Dir: repo.Path,
Stdout: stdoutWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
commit, err := git.CommitFromReader(repo, hash, stdoutReader)

@ -313,7 +313,7 @@ func dummyInfoRefs(ctx *context.Context) {
return
}
refs, err := git.NewCommand(ctx, "receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunInDirBytes(tmpDir)
refs, _, err := git.NewCommand(ctx, "receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Dir: tmpDir})
if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
}
@ -397,7 +397,7 @@ func (h *serviceHandler) sendFile(contentType, file string) {
var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`)
func getGitConfig(ctx gocontext.Context, option, dir string) string {
out, err := git.NewCommand(ctx, "config", option).RunInDir(dir)
out, _, err := git.NewCommand(ctx, "config", option).RunStdString(&git.RunOpts{Dir: dir})
if err != nil {
log.Error("%v - %s", err, out)
}
@ -472,13 +472,12 @@ func serviceRPC(ctx gocontext.Context, h serviceHandler, service string) {
var stderr bytes.Buffer
cmd := git.NewCommand(h.r.Context(), service, "--stateless-rpc", h.dir)
cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir))
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: h.dir,
Env: append(os.Environ(), h.environ...),
Stdout: h.w,
Stdin: reqBody,
Stderr: &stderr,
if err := cmd.Run(&git.RunOpts{
Dir: h.dir,
Env: append(os.Environ(), h.environ...),
Stdout: h.w,
Stdin: reqBody,
Stderr: &stderr,
}); err != nil {
if err.Error() != "signal: killed" {
log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String())
@ -512,7 +511,7 @@ func getServiceType(r *http.Request) string {
}
func updateServerInfo(ctx gocontext.Context, dir string) []byte {
out, err := git.NewCommand(ctx, "update-server-info").RunInDirBytes(dir)
out, _, err := git.NewCommand(ctx, "update-server-info").RunStdBytes(&git.RunOpts{Dir: dir})
if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(out)))
}
@ -542,7 +541,7 @@ func GetInfoRefs(ctx *context.Context) {
}
h.environ = append(os.Environ(), h.environ...)
refs, _, err := git.NewCommand(ctx, service, "--stateless-rpc", "--advertise-refs", ".").RunWithContextBytes(&git.RunContext{Env: h.environ, Dir: h.dir})
refs, _, err := git.NewCommand(ctx, service, "--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Env: h.environ, Dir: h.dir})
if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
}

@ -340,7 +340,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C
}
if commitSHA != "" {
// Get immediate parent of the first commit in the patch, grab history back
parentCommit, err = git.NewCommand(ctx, "rev-list", "-1", "--skip=1", commitSHA).RunInDir(ctx.Repo.GitRepo.Path)
parentCommit, _, err = git.NewCommand(ctx, "rev-list", "-1", "--skip=1", commitSHA).RunStdString(&git.RunOpts{Dir: ctx.Repo.GitRepo.Path})
if err == nil {
parentCommit = strings.TrimSpace(parentCommit)
}

@ -205,7 +205,7 @@ func ProcRecive(ctx *context.PrivateContext, opts *private.HookOptions) []privat
}
if !forcePush {
output, err := git.NewCommand(ctx, "rev-list", "--max-count=1", oldCommitID, "^"+opts.NewCommitIDs[i]).RunInDirWithEnv(repo.RepoPath(), os.Environ())
output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1", oldCommitID, "^"+opts.NewCommitIDs[i]).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: os.Environ()})
if err != nil {
log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, opts.NewCommitIDs[i], repo, err)
ctx.JSON(http.StatusInternalServerError, private.Response{

@ -90,15 +90,15 @@ func SigningKey(ctx context.Context, repoPath string) (string, *git.Signature) {
if setting.Repository.Signing.SigningKey == "default" || setting.Repository.Signing.SigningKey == "" {
// Can ignore the error here as it means that commit.gpgsign is not set
value, _ := git.NewCommand(ctx, "config", "--get", "commit.gpgsign").RunInDir(repoPath)
value, _, _ := git.NewCommand(ctx, "config", "--get", "commit.gpgsign").RunStdString(&git.RunOpts{Dir: repoPath})
sign, valid := git.ParseBool(strings.TrimSpace(value))
if !sign || !valid {
return "", nil
}
signingKey, _ := git.NewCommand(ctx, "config", "--get", "user.signingkey").RunInDir(repoPath)
signingName, _ := git.NewCommand(ctx, "config", "--get", "user.name").RunInDir(repoPath)
signingEmail, _ := git.NewCommand(ctx, "config", "--get", "user.email").RunInDir(repoPath)
signingKey, _, _ := git.NewCommand(ctx, "config", "--get", "user.signingkey").RunStdString(&git.RunOpts{Dir: repoPath})
signingName, _, _ := git.NewCommand(ctx, "config", "--get", "user.name").RunStdString(&git.RunOpts{Dir: repoPath})
signingEmail, _, _ := git.NewCommand(ctx, "config", "--get", "user.email").RunStdString(&git.RunOpts{Dir: repoPath})
return strings.TrimSpace(signingKey), &git.Signature{
Name: strings.TrimSpace(signingName),
Email: strings.TrimSpace(signingEmail),

@ -1378,7 +1378,7 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
go func(ctx context.Context, diffArgs []string, repoPath string, writer *io.PipeWriter) {
cmd := git.NewCommand(ctx, diffArgs...)
cmd.SetDescription(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath))
if err := cmd.RunWithContext(&git.RunContext{
if err := cmd.Run(&git.RunOpts{
Timeout: time.Duration(setting.Git.Timeout.Default) * time.Second,
Dir: repoPath,
Stderr: os.Stderr,

@ -479,7 +479,7 @@ func (g *RepositoryDumper) CreatePullRequests(prs ...*base.PullRequest) error {
}
if ok {
_, err = git.NewCommand(g.ctx, "fetch", remote, pr.Head.Ref).RunInDir(g.gitPath())
_, _, err = git.NewCommand(g.ctx, "fetch", remote, pr.Head.Ref).RunStdString(&git.RunOpts{Dir: g.gitPath()})
if err != nil {
log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err)
} else {

@ -553,7 +553,7 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(pr *base.PullRequest) (head
}
if ok {
_, err = git.NewCommand(g.ctx, "fetch", remote, pr.Head.Ref).RunInDir(g.repo.RepoPath())
_, _, err = git.NewCommand(g.ctx, "fetch", remote, pr.Head.Ref).RunStdString(&git.RunOpts{Dir: g.repo.RepoPath()})
if err != nil {
log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err)
} else {
@ -577,7 +577,7 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(pr *base.PullRequest) (head
} else {
head = pr.Head.Ref
// Ensure the closed PR SHA still points to an existing ref
_, err = git.NewCommand(g.ctx, "rev-list", "--quiet", "-1", pr.Head.SHA).RunInDir(g.repo.RepoPath())
_, _, err = git.NewCommand(g.ctx, "rev-list", "--quiet", "-1", pr.Head.SHA).RunStdString(&git.RunOpts{Dir: g.repo.RepoPath()})
if err != nil {
if pr.Head.SHA != "" {
// Git update-ref remove bad references with a relative path

@ -233,7 +233,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
baseRef := "master"
assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false))
_, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+baseRef).RunInDir(fromRepo.RepoPath())
err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644))
assert.NoError(t, git.AddChanges(fromRepo.RepoPath(), true))
@ -257,7 +257,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
// fromRepo branch1
//
headRef := "branch1"
_, err = git.NewCommand(git.DefaultContext, "checkout", "-b", headRef).RunInDir(fromRepo.RepoPath())
_, _, err = git.NewCommand(git.DefaultContext, "checkout", "-b", headRef).RunStdString(&git.RunOpts{Dir: fromRepo.RepoPath()})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte("SOMETHING"), 0o644))
assert.NoError(t, git.AddChanges(fromRepo.RepoPath(), true))
@ -281,7 +281,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
assert.NoError(t, git.CloneWithArgs(git.DefaultContext, fromRepo.RepoPath(), forkRepo.RepoPath(), []string{}, git.CloneRepoOptions{
Branch: headRef,
}))
_, err = git.NewCommand(git.DefaultContext, "checkout", "-b", forkHeadRef).RunInDir(forkRepo.RepoPath())
_, _, err = git.NewCommand(git.DefaultContext, "checkout", "-b", forkHeadRef).RunStdString(&git.RunOpts{Dir: forkRepo.RepoPath()})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(forkRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# branch2 %s", forkRepo.RepoPath())), 0o644))
assert.NoError(t, git.AddChanges(forkRepo.RepoPath(), true))

@ -33,7 +33,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
remoteName := m.GetRemoteName()
repoPath := m.Repo.RepoPath()
// Remove old remote
_, err := git.NewCommand(ctx, "remote", "rm", remoteName).RunInDir(repoPath)
_, _, err := git.NewCommand(ctx, "remote", "rm", remoteName).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err
}
@ -44,7 +44,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
} else {
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, addr, repoPath))
}
_, err = cmd.RunInDir(repoPath)
_, _, err = cmd.RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err
}
@ -53,7 +53,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
wikiPath := m.Repo.WikiPath()
wikiRemotePath := repo_module.WikiRemoteURL(ctx, addr)
// Remove old remote of wiki
_, err := git.NewCommand(ctx, "remote", "rm", remoteName).RunInDir(wikiPath)
_, _, err = git.NewCommand(ctx, "remote", "rm", remoteName).RunStdString(&git.RunOpts{Dir: wikiPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err
}
@ -64,7 +64,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
} else {
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, wikiRemotePath, wikiPath))
}
_, err = cmd.RunInDir(wikiPath)
_, _, err = cmd.RunStdString(&git.RunOpts{Dir: wikiPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err
}
@ -171,7 +171,7 @@ func pruneBrokenReferences(ctx context.Context,
stdoutBuilder.Reset()
pruneErr := git.NewCommand(ctx, "remote", "prune", m.GetRemoteName()).
SetDescription(fmt.Sprintf("Mirror.runSync %ssPrune references: %s ", wiki, m.Repo.FullName())).
RunWithContext(&git.RunContext{
Run(&git.RunOpts{
Timeout: timeout,
Dir: repoPath,
Stdout: stdoutBuilder,
@ -219,7 +219,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
stderrBuilder := strings.Builder{}
if err := git.NewCommand(ctx, gitArgs...).
SetDescription(fmt.Sprintf("Mirror.runSync: %s", m.Repo.FullName())).
RunWithContext(&git.RunContext{
Run(&git.RunOpts{
Timeout: timeout,
Dir: repoPath,
Stdout: &stdoutBuilder,
@ -245,7 +245,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
stdoutBuilder.Reset()
if err = git.NewCommand(ctx, gitArgs...).
SetDescription(fmt.Sprintf("Mirror.runSync: %s", m.Repo.FullName())).
RunWithContext(&git.RunContext{
Run(&git.RunOpts{
Timeout: timeout,
Dir: repoPath,
Stdout: &stdoutBuilder,
@ -310,7 +310,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
stdoutBuilder.Reset()
if err := git.NewCommand(ctx, "remote", "update", "--prune", m.GetRemoteName()).
SetDescription(fmt.Sprintf("Mirror.runSync Wiki: %s ", m.Repo.FullName())).
RunWithContext(&git.RunContext{
Run(&git.RunOpts{
Timeout: timeout,
Dir: wikiPath,
Stdout: &stdoutBuilder,
@ -337,7 +337,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
if err = git.NewCommand(ctx, "remote", "update", "--prune", m.GetRemoteName()).
SetDescription(fmt.Sprintf("Mirror.runSync Wiki: %s ", m.Repo.FullName())).
RunWithContext(&git.RunContext{
Run(&git.RunOpts{
Timeout: timeout,
Dir: wikiPath,
Stdout: &stdoutBuilder,

@ -35,13 +35,13 @@ func AddPushMirrorRemote(ctx context.Context, m *repo_model.PushMirror, addr str
} else {
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, addr, path))
}
if _, err := cmd.RunInDir(path); err != nil {
if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: path}); err != nil {
return err
}
if _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/heads/*:refs/heads/*").RunInDir(path); err != nil {
if _, _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/heads/*:refs/heads/*").RunStdString(&git.RunOpts{Dir: path}); err != nil {
return err
}
if _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/tags/*:refs/tags/*").RunInDir(path); err != nil {
if _, _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/tags/*:refs/tags/*").RunStdString(&git.RunOpts{Dir: path}); err != nil {
return err
}
return nil
@ -67,12 +67,12 @@ func AddPushMirrorRemote(ctx context.Context, m *repo_model.PushMirror, addr str
func RemovePushMirrorRemote(ctx context.Context, m *repo_model.PushMirror) error {
cmd := git.NewCommand(ctx, "remote", "rm", m.RemoteName)
if _, err := cmd.RunInDir(m.Repo.RepoPath()); err != nil {
if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: m.Repo.RepoPath()}); err != nil {
return err
}
if m.Repo.HasWiki() {
if _, err := cmd.RunInDir(m.Repo.WikiPath()); err != nil {
if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: m.Repo.WikiPath()}); err != nil {
// The wiki remote may not exist
log.Warn("Wiki Remote[%d] could not be removed: %v", m.ID, err)
}

@ -175,8 +175,8 @@ func getMergeCommit(ctx context.Context, pr *models.PullRequest) (*git.Commit, e
headFile := pr.GetGitRefName()
// Check if a pull request is merged into BaseBranch
_, err = git.NewCommand(ctx, "merge-base", "--is-ancestor", headFile, pr.BaseBranch).
RunInDirWithEnv(pr.BaseRepo.RepoPath(), []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
_, _, err = git.NewCommand(ctx, "merge-base", "--is-ancestor", headFile, pr.BaseBranch).
RunStdString(&git.RunOpts{Dir: pr.BaseRepo.RepoPath(), Env: []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}})
if err != nil {
// Errors are signaled by a non-zero status that is not 1
if strings.Contains(err.Error(), "exit status 1") {
@ -196,8 +196,8 @@ func getMergeCommit(ctx context.Context, pr *models.PullRequest) (*git.Commit, e
cmd := commitID[:40] + ".." + pr.BaseBranch
// Get the commit from BaseBranch where the pull request got merged
mergeCommit, err := git.NewCommand(ctx, "rev-list", "--ancestry-path", "--merges", "--reverse", cmd).
RunInDirWithEnv("", []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
mergeCommit, _, err := git.NewCommand(ctx, "rev-list", "--ancestry-path", "--merges", "--reverse", cmd).
RunStdString(&git.RunOpts{Dir: "", Env: []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}})
if err != nil {
return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v", err)
} else if len(mergeCommit) < 40 {

@ -141,7 +141,7 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
stagingBranch := "staging"
if expectedHeadCommitID != "" {
trackingCommitID, err := git.NewCommand(ctx, "show-ref", "--hash", git.BranchPrefix+trackingBranch).RunInDir(tmpBasePath)
trackingCommitID, _, err := git.NewCommand(ctx, "show-ref", "--hash", git.BranchPrefix+trackingBranch).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil {
log.Error("show-ref[%s] --hash refs/heads/trackingn: %v", tmpBasePath, git.BranchPrefix+trackingBranch, err)
return "", fmt.Errorf("getDiffTree: %v", err)
@ -188,11 +188,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
// Switch off LFS process (set required, clean and smudge here also)
if err := gitConfigCommand().AddArguments("filter.lfs.process", "").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git config [filter.lfs.process -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [filter.lfs.process -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -201,11 +200,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
errbuf.Reset()
if err := gitConfigCommand().AddArguments("filter.lfs.required", "false").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git config [filter.lfs.required -> <false> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [filter.lfs.required -> <false> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -214,11 +212,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
errbuf.Reset()
if err := gitConfigCommand().AddArguments("filter.lfs.clean", "").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git config [filter.lfs.clean -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [filter.lfs.clean -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -227,11 +224,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
errbuf.Reset()
if err := gitConfigCommand().AddArguments("filter.lfs.smudge", "").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git config [filter.lfs.smudge -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [filter.lfs.smudge -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -240,11 +236,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
errbuf.Reset()
if err := gitConfigCommand().AddArguments("core.sparseCheckout", "true").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git config [core.sparseCheckout -> true ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [core.sparsecheckout -> true]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -254,11 +249,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
// Read base branch index
if err := git.NewCommand(ctx, "read-tree", "HEAD").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git read-tree HEAD: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("Unable to read base branch in to the index: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -315,11 +309,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
case repo_model.MergeStyleRebaseMerge:
// Checkout head branch
if err := git.NewCommand(ctx, "checkout", "-b", stagingBranch, trackingBranch).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -329,11 +322,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
// Rebase before merging
if err := git.NewCommand(ctx, "rebase", baseBranch).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
// Rebase will leave a REBASE_HEAD file in .git if there is a conflict
if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "REBASE_HEAD")); statErr == nil {
@ -383,11 +375,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
// Checkout base branch again
if err := git.NewCommand(ctx, "checkout", baseBranch).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -429,12 +420,11 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
sig := pr.Issue.Poster.NewGitSig()
if signArg == "" {
if err := git.NewCommand(ctx, "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).
RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Env: env,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -445,12 +435,11 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
message += fmt.Sprintf("\nCo-authored-by: %s\nCo-committed-by: %s\n", sig.String(), sig.String())
}
if err := git.NewCommand(ctx, "commit", signArg, fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).
RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Env: env,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -515,12 +504,11 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
}
// Push back to upstream.
if err := pushCmd.RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
if err := pushCmd.Run(&git.RunOpts{
Env: env,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
if strings.Contains(errbuf.String(), "non-fast-forward") {
return "", &git.ErrPushOutOfDate{
@ -549,24 +537,22 @@ func commitAndSignNoAuthor(ctx context.Context, pr *models.PullRequest, message,
var outbuf, errbuf strings.Builder
if signArg == "" {
if err := git.NewCommand(ctx, "commit", "-m", message).
RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Env: env,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
}
} else {
if err := git.NewCommand(ctx, "commit", signArg, "-m", message).
RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Env: env,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -577,11 +563,10 @@ func commitAndSignNoAuthor(ctx context.Context, pr *models.PullRequest, message,
func runMergeCommand(pr *models.PullRequest, mergeStyle repo_model.MergeStyle, cmd *git.Command, tmpBasePath string) error {
var outbuf, errbuf strings.Builder
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
if err := cmd.Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
// Merge will leave a MERGE_HEAD file in the .git folder if there is a conflict
if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "MERGE_HEAD")); statErr == nil {
@ -616,11 +601,10 @@ func getDiffTree(ctx context.Context, repoPath, baseBranch, headBranch string) (
var outbuf, errbuf strings.Builder
// Compute the diff-tree for sparse-checkout
if err := git.NewCommand(ctx, "diff-tree", "--no-commit-id", "--name-only", "-r", "-z", "--root", baseBranch, headBranch, "--").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: repoPath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: repoPath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
return "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, errbuf.String())
}

@ -76,7 +76,7 @@ func TestPatch(pr *models.PullRequest) error {
defer gitRepo.Close()
// 1. update merge base
pr.MergeBase, err = git.NewCommand(ctx, "merge-base", "--", "base", "tracking").RunInDir(tmpBasePath)
pr.MergeBase, _, err = git.NewCommand(ctx, "merge-base", "--", "base", "tracking").RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil {
var err2 error
pr.MergeBase, err2 = gitRepo.GetRefCommitID(git.BranchPrefix + "base")
@ -166,7 +166,7 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
}
// Need to get the objects from the object db to attempt to merge
root, err := git.NewCommand(ctx, "unpack-file", file.stage1.sha).RunInDir(tmpBasePath)
root, _, err := git.NewCommand(ctx, "unpack-file", file.stage1.sha).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil {
return fmt.Errorf("unable to get root object: %s at path: %s for merging. Error: %w", file.stage1.sha, file.stage1.path, err)
}
@ -175,7 +175,7 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
_ = util.Remove(filepath.Join(tmpBasePath, root))
}()
base, err := git.NewCommand(ctx, "unpack-file", file.stage2.sha).RunInDir(tmpBasePath)
base, _, err := git.NewCommand(ctx, "unpack-file", file.stage2.sha).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil {
return fmt.Errorf("unable to get base object: %s at path: %s for merging. Error: %w", file.stage2.sha, file.stage2.path, err)
}
@ -183,7 +183,7 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
defer func() {
_ = util.Remove(base)
}()
head, err := git.NewCommand(ctx, "unpack-file", file.stage3.sha).RunInDir(tmpBasePath)
head, _, err := git.NewCommand(ctx, "unpack-file", file.stage3.sha).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil {
return fmt.Errorf("unable to get head object:%s at path: %s for merging. Error: %w", file.stage3.sha, file.stage3.path, err)
}
@ -193,13 +193,13 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
}()
// now git merge-file annoyingly takes a different order to the merge-tree ...
_, conflictErr := git.NewCommand(ctx, "merge-file", base, root, head).RunInDir(tmpBasePath)
_, _, conflictErr := git.NewCommand(ctx, "merge-file", base, root, head).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if conflictErr != nil {
return &errMergeConflict{file.stage2.path}
}
// base now contains the merged data
hash, err := git.NewCommand(ctx, "hash-object", "-w", "--path", file.stage2.path, base).RunInDir(tmpBasePath)
hash, _, err := git.NewCommand(ctx, "hash-object", "-w", "--path", file.stage2.path, base).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil {
return err
}
@ -223,7 +223,7 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo
defer cancel()
// First we use read-tree to do a simple three-way merge
if _, err := git.NewCommand(ctx, "read-tree", "-m", base, ours, theirs).RunInDir(gitPath); err != nil {
if _, _, err := git.NewCommand(ctx, "read-tree", "-m", base, ours, theirs).RunStdString(&git.RunOpts{Dir: gitPath}); err != nil {
log.Error("Unable to run read-tree -m! Error: %v", err)
return false, nil, fmt.Errorf("unable to run read-tree -m! Error: %v", err)
}
@ -282,7 +282,8 @@ func checkConflicts(ctx context.Context, pr *models.PullRequest, gitRepo *git.Re
}
if !conflict {
treeHash, err := git.NewCommand(ctx, "write-tree").RunInDir(tmpBasePath)
var treeHash string
treeHash, _, err = git.NewCommand(ctx, "write-tree").RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil {
return false, err
}
@ -334,7 +335,7 @@ func checkConflicts(ctx context.Context, pr *models.PullRequest, gitRepo *git.Re
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
// 4. Read the base branch in to the index of the temporary repository
_, err = git.NewCommand(gitRepo.Ctx, "read-tree", "base").RunInDir(tmpBasePath)
_, _, err = git.NewCommand(gitRepo.Ctx, "read-tree", "base").RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil {
return false, fmt.Errorf("git read-tree %s: %v", pr.BaseBranch, err)
}
@ -379,10 +380,9 @@ func checkConflicts(ctx context.Context, pr *models.PullRequest, gitRepo *git.Re
// 8. Run the check command
conflict = false
err = git.NewCommand(gitRepo.Ctx, args...).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stderr: stderrWriter,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stderr: stderrWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
// Close the writer end of the pipe to begin processing
_ = stderrWriter.Close()

@ -63,11 +63,10 @@ func readUnmergedLsFileLines(ctx context.Context, tmpBasePath string, outputChan
stderr := &strings.Builder{}
err = git.NewCommand(ctx, "ls-files", "-u", "-z").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: lsFilesWriter,
Stderr: stderr,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: lsFilesWriter,
Stderr: stderr,
PipelineFunc: func(_ context.Context, _ context.CancelFunc) error {
_ = lsFilesWriter.Close()
defer func() {

@ -479,7 +479,7 @@ func UpdateRef(ctx context.Context, pr *models.PullRequest) (err error) {
return err
}
_, err = git.NewCommand(ctx, "update-ref", pr.GetGitRefName(), pr.HeadCommitID).RunInDir(pr.BaseRepo.RepoPath())
_, _, err = git.NewCommand(ctx, "update-ref", pr.GetGitRefName(), pr.HeadCommitID).RunStdString(&git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
if err != nil {
log.Error("Unable to update ref in base repository for PR[%d] Error: %v", pr.ID, err)
}

@ -93,11 +93,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
var outbuf, errbuf strings.Builder
if err := git.NewCommand(ctx, "remote", "add", "-t", pr.BaseBranch, "-m", pr.BaseBranch, "origin", baseRepoPath).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("Unable to add base repository as origin [%s -> %s]: %v\n%s\n%s", pr.BaseRepo.FullName(), tmpBasePath, err, outbuf.String(), errbuf.String())
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
@ -109,11 +108,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
errbuf.Reset()
if err := git.NewCommand(ctx, "fetch", "origin", "--no-tags", "--", pr.BaseBranch+":"+baseBranch, pr.BaseBranch+":original_"+baseBranch).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("Unable to fetch origin base branch [%s:%s -> base, original_base in %s]: %v:\n%s\n%s", pr.BaseRepo.FullName(), pr.BaseBranch, tmpBasePath, err, outbuf.String(), errbuf.String())
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
@ -125,11 +123,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
errbuf.Reset()
if err := git.NewCommand(ctx, "symbolic-ref", "HEAD", git.BranchPrefix+baseBranch).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("Unable to set HEAD as base branch [%s]: %v\n%s\n%s", tmpBasePath, err, outbuf.String(), errbuf.String())
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
@ -149,11 +146,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
}
if err := git.NewCommand(ctx, "remote", "add", remoteRepoName, headRepoPath).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
log.Error("Unable to add head repository as head_repo [%s -> %s]: %v\n%s\n%s", pr.HeadRepo.FullName(), tmpBasePath, err, outbuf.String(), errbuf.String())
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
@ -175,11 +171,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
headBranch = pr.GetGitRefName()
}
if err := git.NewCommand(ctx, "fetch", "--no-tags", remoteRepoName, headBranch+":"+trackingBranch).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
Run(&git.RunOpts{
Dir: tmpBasePath,
Stdout: &outbuf,
Stderr: &errbuf,
}); err != nil {
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
log.Error("CreateTempRepo: RemoveTemporaryPath: %s", err)

@ -297,9 +297,9 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del
}
if delTag {
if stdout, err := git.NewCommand(ctx, "tag", "-d", rel.TagName).
if stdout, _, err := git.NewCommand(ctx, "tag", "-d", rel.TagName).
SetDescription(fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID)).
RunInDir(repo.RepoPath()); err != nil && !strings.Contains(err.Error(), "not found") {
RunStdString(&git.RunOpts{Dir: repo.RepoPath()}); err != nil && !strings.Contains(err.Error(), "not found") {
log.Error("DeleteReleaseByID (git tag -d): %d in %v Failed:\nStdout: %s\nError: %v", rel.ID, repo, stdout, err)
return fmt.Errorf("git tag -d: %v", err)
}

@ -84,9 +84,9 @@ func AdoptRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (*
}
}
if stdout, err := git.NewCommand(ctx, "update-server-info").
if stdout, _, err := git.NewCommand(ctx, "update-server-info").
SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
RunInDir(repoPath); err != nil {
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
return fmt.Errorf("CreateRepository(git update-server-info): %v", err)
}

@ -77,7 +77,7 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args ...string) erro
SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName()))
var stdout string
var err error
stdout, _, err = command.RunWithContextString(&git.RunContext{Timeout: timeout, Dir: repo.RepoPath()})
stdout, _, err = command.RunStdString(&git.RunOpts{Timeout: timeout, Dir: repo.RepoPath()})
if err != nil {
log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)

@ -145,12 +145,11 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
}
cmd := git.NewCommand(ctx, args...)
if err := cmd.RunWithContext(&git.RunContext{
Timeout: -1,
Dir: t.basePath,
Stdout: stdout,
Stderr: stderr,
Stdin: strings.NewReader(opts.Content),
if err := cmd.Run(&git.RunOpts{
Dir: t.basePath,
Stdout: stdout,
Stderr: stderr,
Stdin: strings.NewReader(opts.Content),
}); err != nil {
return nil, fmt.Errorf("Error: Stdout: %s\nStderr: %s\nErr: %v", stdout.String(), stderr.String(), err)
}

@ -52,7 +52,7 @@ func (t *TemporaryUploadRepository) Close() {
// Clone the base repository to our path and set branch as the HEAD
func (t *TemporaryUploadRepository) Clone(branch string) error {
if _, err := git.NewCommand(t.ctx, "clone", "-s", "--bare", "-b", branch, t.repo.RepoPath(), t.basePath).Run(); err != nil {
if _, _, err := git.NewCommand(t.ctx, "clone", "-s", "--bare", "-b", branch, t.repo.RepoPath(), t.basePath).RunStdString(nil); err != nil {
stderr := err.Error()
if matched, _ := regexp.MatchString(".*Remote branch .* not found in upstream origin.*", stderr); matched {
return git.ErrBranchNotExist{
@ -92,7 +92,7 @@ func (t *TemporaryUploadRepository) Init() error {
// SetDefaultIndex sets the git index to our HEAD
func (t *TemporaryUploadRepository) SetDefaultIndex() error {
if _, err := git.NewCommand(t.ctx, "read-tree", "HEAD").RunInDir(t.basePath); err != nil {
if _, _, err := git.NewCommand(t.ctx, "read-tree", "HEAD").RunStdString(&git.RunOpts{Dir: t.basePath}); err != nil {
return fmt.Errorf("SetDefaultIndex: %v", err)
}
return nil
@ -111,11 +111,10 @@ func (t *TemporaryUploadRepository) LsFiles(filenames ...string) ([]string, erro
}
if err := git.NewCommand(t.ctx, cmdArgs...).
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: t.basePath,
Stdout: stdOut,
Stderr: stdErr,
Run(&git.RunOpts{
Dir: t.basePath,
Stdout: stdOut,
Stderr: stdErr,
}); err != nil {
log.Error("Unable to run git ls-files for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String())
err = fmt.Errorf("Unable to run git ls-files for temporary repo of: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String())
@ -144,12 +143,11 @@ func (t *TemporaryUploadRepository) RemoveFilesFromIndex(filenames ...string) er
}
if err := git.NewCommand(t.ctx, "update-index", "--remove", "-z", "--index-info").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: t.basePath,
Stdin: stdIn,
Stdout: stdOut,
Stderr: stdErr,
Run(&git.RunOpts{
Dir: t.basePath,
Stdin: stdIn,
Stdout: stdOut,
Stderr: stdErr,
}); err != nil {
log.Error("Unable to update-index for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String())
return fmt.Errorf("Unable to update-index for temporary repo: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String())
@ -163,12 +161,11 @@ func (t *TemporaryUploadRepository) HashObject(content io.Reader) (string, error
stdErr := new(bytes.Buffer)
if err := git.NewCommand(t.ctx, "hash-object", "-w", "--stdin").
RunWithContext(&git.RunContext{
Timeout: -1,
Dir: t.basePath,
Stdin: content,
Stdout: stdOut,
Stderr: stdErr,
Run(&git.RunOpts{
Dir: t.basePath,
Stdin: content,
Stdout: stdOut,
Stderr: stdErr,
}); err != nil {
log.Error("Unable to hash-object to temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String())
return "", fmt.Errorf("Unable to hash-object to temporary repo: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String())
@ -179,7 +176,7 @@ func (t *TemporaryUploadRepository) HashObject(content io.Reader) (string, error
// AddObjectToIndex adds the provided object hash to the index with the provided mode and path
func (t *TemporaryUploadRepository) AddObjectToIndex(mode, objectHash, objectPath string) error {
if _, err := git.NewCommand(t.ctx, "update-index", "--add", "--replace", "--cacheinfo", mode, objectHash, objectPath).RunInDir(t.basePath); err != nil {
if _, _, err := git.NewCommand(t.ctx, "update-index", "--add", "--replace", "--cacheinfo", mode, objectHash, objectPath).RunStdString(&git.RunOpts{Dir: t.basePath}); err != nil {
stderr := err.Error()
if matched, _ := regexp.MatchString(".*Invalid path '.*", stderr); matched {
return models.ErrFilePathInvalid{
@ -195,7 +192,7 @@ func (t *TemporaryUploadRepository) AddObjectToIndex(mode, objectHash, objectPat
// WriteTree writes the current index as a tree to the object db and returns its hash
func (t *TemporaryUploadRepository) WriteTree() (string, error) {
stdout, err := git.NewCommand(t.ctx, "write-tree").RunInDir(t.basePath)
stdout, _, err := git.NewCommand(t.ctx, "write-tree").RunStdString(&git.RunOpts{Dir: t.basePath})
if err != nil {
log.Error("Unable to write tree in temporary repo: %s(%s): Error: %v", t.repo.FullName(), t.basePath, err)
return "", fmt.Errorf("Unable to write-tree in temporary repo for: %s Error: %v", t.repo.FullName(), err)
@ -213,7 +210,7 @@ func (t *TemporaryUploadRepository) GetLastCommitByRef(ref string) (string, erro
if ref == "" {
ref = "HEAD"
}
stdout, err := git.NewCommand(t.ctx, "rev-parse", ref).RunInDir(t.basePath)
stdout, _, err := git.NewCommand(t.ctx, "rev-parse", ref).RunStdString(&git.RunOpts{Dir: t.basePath})
if err != nil {
log.Error("Unable to get last ref for %s in temporary repo: %s(%s): Error: %v", ref, t.repo.FullName(), t.basePath, err)
return "", fmt.Errorf("Unable to rev-parse %s in temporary repo for: %s Error: %v", ref, t.repo.FullName(), err)
@ -300,13 +297,12 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(parent string, author, co
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
if err := git.NewCommand(t.ctx, args...).
RunWithContext(&git.RunContext{
Env: env,
Timeout: -1,
Dir: t.basePath,
Stdin: messageBytes,
Stdout: stdout,
Stderr: stderr,
Run(&git.RunOpts{
Env: env,
Dir: t.basePath,
Stdin: messageBytes,
Stdout: stdout,
Stderr: stderr,
}); err != nil {
log.Error("Unable to commit-tree in temporary repo: %s (%s) Error: %v\nStdout: %s\nStderr: %s",
t.repo.FullName(), t.basePath, err, stdout, stderr)
@ -357,7 +353,7 @@ func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) {
var finalErr error
if err := git.NewCommand(t.ctx, "diff-index", "--src-prefix=\\a/", "--dst-prefix=\\b/", "--cached", "-p", "HEAD").
RunWithContext(&git.RunContext{
Run(&git.RunOpts{
Timeout: 30 * time.Second,
Dir: t.basePath,
Stdout: stdoutWriter,

@ -111,7 +111,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
if stdout, _, err := git.NewCommand(txCtx,
"clone", "--bare", oldRepoPath, repoPath).
SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", opts.BaseRepo.FullName(), repo.FullName())).
RunWithContextBytes(&git.RunContext{Timeout: 10 * time.Minute}); err != nil {
RunStdBytes(&git.RunOpts{Timeout: 10 * time.Minute}); err != nil {
log.Error("Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v", repo, opts.BaseRepo, stdout, err)
return fmt.Errorf("git clone: %v", err)
}
@ -120,9 +120,9 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
return fmt.Errorf("checkDaemonExportOK: %v", err)
}
if stdout, err := git.NewCommand(txCtx, "update-server-info").
if stdout, _, err := git.NewCommand(txCtx, "update-server-info").
SetDescription(fmt.Sprintf("ForkRepository(git update-server-info): %s", repo.FullName())).
RunInDir(repoPath); err != nil {
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v", repo, stdout, err)
return fmt.Errorf("git update-server-info: %v", err)
}

@ -81,7 +81,7 @@ func InitWiki(ctx context.Context, repo *repo_model.Repository) error {
return fmt.Errorf("InitRepository: %v", err)
} else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil {
return fmt.Errorf("createDelegateHooks: %v", err)
} else if _, err = git.NewCommand(ctx, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(repo.WikiPath()); err != nil {
} else if _, _, err = git.NewCommand(ctx, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: repo.WikiPath()}); err != nil {
return fmt.Errorf("unable to set default wiki branch to master: %v", err)
}
return nil