Skip to content

Commit 334c899

Browse files
authored
Improve git log for debugging (#24095)
1 parent 985f76d commit 334c899

File tree

3 files changed

+48
-59
lines changed

3 files changed

+48
-59
lines changed

modules/git/command.go

+31-23
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const DefaultLocale = "C"
4040

4141
// Command represents a command with its subcommands or arguments.
4242
type Command struct {
43-
name string
43+
prog string
4444
args []string
4545
parentContext context.Context
4646
desc string
@@ -49,10 +49,28 @@ type Command struct {
4949
}
5050

5151
func (c *Command) String() string {
52-
if len(c.args) == 0 {
53-
return c.name
52+
return c.toString(false)
53+
}
54+
55+
func (c *Command) toString(sanitizing bool) string {
56+
// WARNING: this function is for debugging purposes only. It's much better than old code (which only joins args with space),
57+
// It's impossible to make a simple and 100% correct implementation of argument quoting for different platforms.
58+
debugQuote := func(s string) string {
59+
if strings.ContainsAny(s, " `'\"\t\r\n") {
60+
return fmt.Sprintf("%q", s)
61+
}
62+
return s
63+
}
64+
a := make([]string, 0, len(c.args)+1)
65+
a = append(a, debugQuote(c.prog))
66+
for _, arg := range c.args {
67+
if sanitizing && (strings.Contains(arg, "://") && strings.Contains(arg, "@")) {
68+
a = append(a, debugQuote(util.SanitizeCredentialURLs(arg)))
69+
} else {
70+
a = append(a, debugQuote(arg))
71+
}
5472
}
55-
return fmt.Sprintf("%s %s", c.name, strings.Join(c.args, " "))
73+
return strings.Join(a, " ")
5674
}
5775

5876
// NewCommand creates and returns a new Git Command based on given command and arguments.
@@ -67,7 +85,7 @@ func NewCommand(ctx context.Context, args ...internal.CmdArg) *Command {
6785
cargs = append(cargs, string(arg))
6886
}
6987
return &Command{
70-
name: GitExecutable,
88+
prog: GitExecutable,
7189
args: cargs,
7290
parentContext: ctx,
7391
globalArgsLength: len(globalCommandArgs),
@@ -82,7 +100,7 @@ func NewCommandContextNoGlobals(ctx context.Context, args ...internal.CmdArg) *C
82100
cargs = append(cargs, string(arg))
83101
}
84102
return &Command{
85-
name: GitExecutable,
103+
prog: GitExecutable,
86104
args: cargs,
87105
parentContext: ctx,
88106
}
@@ -250,28 +268,18 @@ func (c *Command) Run(opts *RunOpts) error {
250268
}
251269

252270
if len(opts.Dir) == 0 {
253-
log.Debug("%s", c)
271+
log.Debug("git.Command.Run: %s", c)
254272
} else {
255-
log.Debug("%s: %v", opts.Dir, c)
273+
log.Debug("git.Command.RunDir(%s): %s", opts.Dir, c)
256274
}
257275

258276
desc := c.desc
259277
if desc == "" {
260-
args := c.args[c.globalArgsLength:]
261-
var argSensitiveURLIndexes []int
262-
for i, arg := range c.args {
263-
if strings.Contains(arg, "://") && strings.Contains(arg, "@") {
264-
argSensitiveURLIndexes = append(argSensitiveURLIndexes, i)
265-
}
266-
}
267-
if len(argSensitiveURLIndexes) > 0 {
268-
args = make([]string, len(c.args))
269-
copy(args, c.args)
270-
for _, urlArgIndex := range argSensitiveURLIndexes {
271-
args[urlArgIndex] = util.SanitizeCredentialURLs(args[urlArgIndex])
272-
}
278+
if opts.Dir == "" {
279+
desc = fmt.Sprintf("git: %s", c.toString(true))
280+
} else {
281+
desc = fmt.Sprintf("git(dir:%s): %s", opts.Dir, c.toString(true))
273282
}
274-
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir)
275283
}
276284

277285
var ctx context.Context
@@ -285,7 +293,7 @@ func (c *Command) Run(opts *RunOpts) error {
285293
}
286294
defer finished()
287295

288-
cmd := exec.CommandContext(ctx, c.name, c.args...)
296+
cmd := exec.CommandContext(ctx, c.prog, c.args...)
289297
if opts.Env == nil {
290298
cmd.Env = os.Environ()
291299
} else {

modules/git/command_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,11 @@ func TestGitArgument(t *testing.T) {
5252
assert.True(t, isSafeArgumentValue("x"))
5353
assert.False(t, isSafeArgumentValue("-x"))
5454
}
55+
56+
func TestCommandString(t *testing.T) {
57+
cmd := NewCommandContextNoGlobals(context.Background(), "a", "-m msg", "it's a test", `say "hello"`)
58+
assert.EqualValues(t, cmd.prog+` a "-m msg" "it's a test" "say \"hello\""`, cmd.String())
59+
60+
cmd = NewCommandContextNoGlobals(context.Background(), "url: https://a:b@c/")
61+
assert.EqualValues(t, cmd.prog+` "url: https://sanitized-credential@c/"`, cmd.toString(true))
62+
}

modules/git/repo.go

+9-36
Original file line numberDiff line numberDiff line change
@@ -209,49 +209,22 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
209209
} else {
210210
cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, opts.Remote, opts.Force, opts.Mirror))
211211
}
212-
var outbuf, errbuf strings.Builder
213212

214-
if opts.Timeout == 0 {
215-
opts.Timeout = -1
216-
}
217-
218-
err := cmd.Run(&RunOpts{
219-
Env: opts.Env,
220-
Timeout: opts.Timeout,
221-
Dir: repoPath,
222-
Stdout: &outbuf,
223-
Stderr: &errbuf,
224-
})
213+
stdout, stderr, err := cmd.RunStdString(&RunOpts{Env: opts.Env, Timeout: opts.Timeout, Dir: repoPath})
225214
if err != nil {
226-
if strings.Contains(errbuf.String(), "non-fast-forward") {
227-
return &ErrPushOutOfDate{
228-
StdOut: outbuf.String(),
229-
StdErr: errbuf.String(),
230-
Err: err,
231-
}
232-
} else if strings.Contains(errbuf.String(), "! [remote rejected]") {
233-
err := &ErrPushRejected{
234-
StdOut: outbuf.String(),
235-
StdErr: errbuf.String(),
236-
Err: err,
237-
}
215+
if strings.Contains(stderr, "non-fast-forward") {
216+
return &ErrPushOutOfDate{StdOut: stdout, StdErr: stderr, Err: err}
217+
} else if strings.Contains(stderr, "! [remote rejected]") {
218+
err := &ErrPushRejected{StdOut: stdout, StdErr: stderr, Err: err}
238219
err.GenerateMessage()
239220
return err
240-
} else if strings.Contains(errbuf.String(), "matches more than one") {
241-
err := &ErrMoreThanOne{
242-
StdOut: outbuf.String(),
243-
StdErr: errbuf.String(),
244-
Err: err,
245-
}
246-
return err
221+
} else if strings.Contains(stderr, "matches more than one") {
222+
return &ErrMoreThanOne{StdOut: stdout, StdErr: stderr, Err: err}
247223
}
224+
return fmt.Errorf("push failed: %w - %s\n%s", err, stderr, stdout)
248225
}
249226

250-
if errbuf.Len() > 0 && err != nil {
251-
return fmt.Errorf("%w - %s", err, errbuf.String())
252-
}
253-
254-
return err
227+
return nil
255228
}
256229

257230
// GetLatestCommitTime returns time for latest commit in repository (across all branches)

0 commit comments

Comments
 (0)