Skip to content

Commit 8246dc0

Browse files
authored
Add debug log output for execGit. (#25)
1 parent 279bad8 commit 8246dc0

File tree

5 files changed

+83
-45
lines changed

5 files changed

+83
-45
lines changed

cmd/services/main.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import (
77
"os"
88

99
"github.com/mitchellh/go-homedir"
10-
"github.com/rhd-gitops-example/services/pkg/avancement"
11-
"github.com/rhd-gitops-example/services/pkg/git"
1210
"github.com/tcnksm/go-gitconfig"
1311
"github.com/urfave/cli/v2"
12+
13+
"github.com/rhd-gitops-example/services/pkg/avancement"
14+
"github.com/rhd-gitops-example/services/pkg/git"
1415
)
1516

1617
const (
@@ -22,6 +23,7 @@ const (
2223
cacheDirFlag = "cache-dir"
2324
nameFlag = "commit-name"
2425
emailFlag = "commit-email"
26+
debugFlag = "debug"
2527
)
2628

2729
var (
@@ -32,6 +34,13 @@ var (
3234
EnvVars: []string{"GITHUB_TOKEN"},
3335
Required: true,
3436
},
37+
&cli.BoolFlag{
38+
Name: debugFlag,
39+
Usage: "additional debug logging output",
40+
EnvVars: []string{"DEBUG_SERVICES"},
41+
Value: false,
42+
Required: false,
43+
},
3544
}
3645

3746
promoteFlags = []cli.Flag{
@@ -103,6 +112,7 @@ func promoteAction(c *cli.Context) error {
103112
toRepo := c.String(toFlag)
104113
service := c.String(serviceFlag)
105114
newBranchName := c.String(branchNameFlag)
115+
debug := c.Bool(debugFlag)
106116

107117
cacheDir, err := homedir.Expand(c.String(cacheDirFlag))
108118
if err != nil {
@@ -113,7 +123,7 @@ func promoteAction(c *cli.Context) error {
113123
if err != nil {
114124
return fmt.Errorf("unable to establish credentials: %w", err)
115125
}
116-
return avancement.New(cacheDir, author).Promote(service, fromRepo, toRepo, newBranchName)
126+
return avancement.New(cacheDir, author, avancement.WithDebug(debug)).Promote(service, fromRepo, toRepo, newBranchName)
117127
}
118128

119129
func newAuthor(c *cli.Context) (*git.Author, error) {

pkg/avancement/service_manager.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,43 @@ type ServiceManager struct {
1818
author *git.Author
1919
clientFactory scmClientFactory
2020
repoFactory repoFactory
21+
debug bool
2122
}
2223

2324
const (
2425
defaultCommitMsg = "this is a commit"
2526
)
2627

2728
type scmClientFactory func(token string) *scm.Client
28-
type repoFactory func(url, localPath string) (git.Repo, error)
29+
type repoFactory func(url, localPath string, debug bool) (git.Repo, error)
30+
type serviceOpt func(*ServiceManager)
2931

3032
// New creates and returns a new ServiceManager.
3133
//
3234
// The cacheDir used to checkout the source and destination repos.
3335
// The token is used to create a Git token
34-
func New(cacheDir string, author *git.Author) *ServiceManager {
35-
return &ServiceManager{
36+
func New(cacheDir string, author *git.Author, opts ...serviceOpt) *ServiceManager {
37+
sm := &ServiceManager{
3638
cacheDir: cacheDir,
3739
author: author,
3840
clientFactory: git.CreateGitHubClient,
39-
repoFactory: func(url, localPath string) (git.Repo, error) {
40-
r, err := git.NewRepository(url, localPath)
41+
repoFactory: func(url, localPath string, debug bool) (git.Repo, error) {
42+
r, err := git.NewRepository(url, localPath, debug)
4143
return git.Repo(r), err
4244
},
4345
}
46+
for _, o := range opts {
47+
o(sm)
48+
}
49+
return sm
50+
}
51+
52+
// WithDebug is a service option that configures the ServiceManager for
53+
// additional debugging.
54+
func WithDebug(f bool) serviceOpt {
55+
return func(sm *ServiceManager) {
56+
sm.debug = f
57+
}
4458
}
4559

4660
// TODO: make this a command-line parameter defaulting to "master"
@@ -115,13 +129,13 @@ func (s *ServiceManager) cloneRepo(repoURL, branch string) (git.Repo, error) {
115129
if err != nil {
116130
return nil, err
117131
}
118-
repo, err := s.repoFactory(repoURL, path.Join(s.cacheDir, encode(repoURL, branch)))
132+
repo, err := s.repoFactory(repoURL, path.Join(s.cacheDir, encode(repoURL, branch)), s.debug)
119133
if err != nil {
120134
return nil, fmt.Errorf("failed to create repo for URL %s: %w", repoURL, err)
121135
}
122136
err = repo.Clone()
123137
if err != nil {
124-
return nil, fmt.Errorf("failed to clone repo %s: %w", repoURL, err)
138+
return nil, err
125139
}
126140
return repo, nil
127141
}

pkg/avancement/service_manager_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestPromoteWithSuccess(t *testing.T) {
2828
}
2929
sm := New("tmp", author)
3030
sm.clientFactory = fakeClientFactory
31-
sm.repoFactory = func(url, _ string) (git.Repo, error) {
31+
sm.repoFactory = func(url, _ string, _ bool) (git.Repo, error) {
3232
return git.Repo(repos[url]), nil
3333
}
3434
devRepo.AddFiles("/services/my-service/base/config/myfile.yaml")

pkg/git/repository.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package git
22

33
import (
4+
"bytes"
45
"fmt"
56
"io"
7+
"log"
68
"net/url"
79
"os"
810
"os/exec"
@@ -17,18 +19,20 @@ type Repository struct {
1719
LocalPath string
1820
RepoURL string
1921
repoName string
22+
debug bool
23+
logger func(fmt string, v ...interface{})
2024
}
2125

2226
// NewRepository creates and returns a local cache of an upstream repository.
2327
//
2428
// The repoURL should be of the form https://github.com/myorg/myrepo.
2529
// The path should be a local directory where the contents are cloned to.
26-
func NewRepository(repoURL, localPath string) (*Repository, error) {
30+
func NewRepository(repoURL, localPath string, debug bool) (*Repository, error) {
2731
name, err := repoName(repoURL)
2832
if err != nil {
2933
return nil, err
3034
}
31-
return &Repository{LocalPath: localPath, RepoURL: repoURL, repoName: name}, nil
35+
return &Repository{LocalPath: localPath, RepoURL: repoURL, repoName: name, logger: log.Printf}, nil
3236
}
3337

3438
func (g *Repository) repoPath(extras ...string) string {
@@ -41,17 +45,18 @@ func (r *Repository) Clone() error {
4145
if err != nil {
4246
return fmt.Errorf("error creating the cache dir %s: %w", r.LocalPath, err)
4347
}
44-
_, err = execGit(r.LocalPath, nil, "clone", r.RepoURL)
48+
out, err := r.execGit(r.LocalPath, nil, "clone", r.RepoURL)
49+
log.Printf("%s\n", out)
4550
return err
4651
}
4752

4853
func (r *Repository) Checkout(branch string) error {
49-
_, err := execGit(r.repoPath(), nil, "checkout", branch)
54+
_, err := r.execGit(r.repoPath(), nil, "checkout", branch)
5055
return err
5156
}
5257

5358
func (r *Repository) CheckoutAndCreate(branch string) error {
54-
_, err := execGit(r.repoPath(), nil, "checkout", "-b", branch)
59+
_, err := r.execGit(r.repoPath(), nil, "checkout", "-b", branch)
5560
return err
5661
}
5762

@@ -91,29 +96,38 @@ func (r *Repository) CopyFile(src, dst string) error {
9196
}
9297

9398
func (r *Repository) StageFiles(filenames ...string) error {
94-
_, err := execGit(r.repoPath(), nil, append([]string{"add"}, filenames...)...)
99+
_, err := r.execGit(r.repoPath(), nil, append([]string{"add"}, filenames...)...)
95100
return err
96101
}
97102

98103
func (r *Repository) Commit(msg string, author *Author) error {
99104
args := []string{"commit", "-m", msg}
100-
_, err := execGit(r.repoPath(), envFromAuthor(author), args...)
105+
_, err := r.execGit(r.repoPath(), envFromAuthor(author), args...)
101106
return err
102107
}
103108

104109
func (r *Repository) Push(branchName string) error {
105110
args := []string{"push", "origin", branchName}
106-
_, err := execGit(r.repoPath(), nil, args...)
111+
_, err := r.execGit(r.repoPath(), nil, args...)
107112
return err
108113
}
109114

110-
func execGit(workingDir string, env []string, args ...string) ([]byte, error) {
115+
func (r *Repository) execGit(workingDir string, env []string, args ...string) ([]byte, error) {
111116
cmd := exec.Command("git", args...)
112117
if env != nil {
113118
cmd.Env = append(os.Environ(), env...)
114119
}
115120
cmd.Dir = workingDir
116-
return cmd.Output()
121+
var b bytes.Buffer
122+
cmd.Stdout = &b
123+
cmd.Stderr = &b
124+
err := cmd.Run()
125+
out := b.Bytes()
126+
// TODO: more sophisticated logging.
127+
if err != nil && r.debug {
128+
r.logger("DEBUG: %s\n", out)
129+
}
130+
return out, err
117131
}
118132

119133
// TODO: this probably needs specialisation for GitLab URLs.

pkg/git/repository_test.go

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package git
22

33
import (
4+
"fmt"
45
"io/ioutil"
56
"net/url"
67
"os"
@@ -43,7 +44,7 @@ func TestRepoName(t *testing.T) {
4344
func TestCloneCreatesDirectory(t *testing.T) {
4445
tempDir, cleanup := makeTempDir(t)
4546
defer cleanup()
46-
r, err := NewRepository(testRepository, path.Join(tempDir, "path"))
47+
r, err := NewRepository(testRepository, path.Join(tempDir, "path"), false)
4748
assertNoError(t, err)
4849
err = r.Clone()
4950
assertNoError(t, err)
@@ -69,24 +70,6 @@ func TestClone(t *testing.T) {
6970
}
7071
}
7172

72-
/* TestCheckout relates to earlier behaviour that dealt with branches within repos. We can revisit this.
73-
func TestCheckout(t *testing.T) {
74-
r, cleanup := cloneTestRepository(t)
75-
defer cleanup()
76-
77-
err := r.Checkout("updated-version")
78-
assertNoError(t, err)
79-
80-
contents, err := ioutil.ReadFile(path.Join(r.LocalPath, "env-staging/service-a/deployment.txt"))
81-
assertNoError(t, err)
82-
83-
want := "This is an updated version of this file.\n"
84-
if diff := cmp.Diff(want, string(contents)); diff != "" {
85-
t.Fatalf("failed to read file: %s", diff)
86-
}
87-
}
88-
*/
89-
9073
func TestWalk(t *testing.T) {
9174
r, cleanup := cloneTestRepository(t)
9275
defer cleanup()
@@ -201,7 +184,7 @@ func TestStageFiles(t *testing.T) {
201184
err = r.StageFiles("services/service-a/new-file.txt")
202185
assertNoError(t, err)
203186

204-
out := assertExecGit(t, r.repoPath("services/service-a"), "status", "--porcelain")
187+
out := assertExecGit(t, r, r.repoPath("services/service-a"), "status", "--porcelain")
205188
want := "A services/service-a/new-file.txt\n"
206189
if diff := cmp.Diff(want, string(out)); diff != "" {
207190
t.Fatalf("file status not modified: %s", diff)
@@ -225,7 +208,7 @@ func TestCommit(t *testing.T) {
225208
err = r.Commit("this is a test commit", &Author{Name: "Test User", Email: "[email protected]"})
226209
assertNoError(t, err)
227210

228-
out := strings.Split(string(assertExecGit(t, r.repoPath("services/service-a"), "log", "-n", "1")), "\n")
211+
out := strings.Split(string(assertExecGit(t, r, r.repoPath("services/service-a"), "log", "-n", "1")), "\n")
229212
want := []string{"Author: Test User <[email protected]>", " this is a test commit"}
230213
if diff := cmp.Diff(want, out, cmpopts.IgnoreSliceElements(func(s string) bool {
231214
return strings.HasPrefix(s, "commit") || strings.HasPrefix(s, "Date:") || s == ""
@@ -234,6 +217,23 @@ func TestCommit(t *testing.T) {
234217
}
235218
}
236219

220+
func TestExecGit(t *testing.T) {
221+
r, cleanup := cloneTestRepository(t)
222+
r.debug = true
223+
captured := ""
224+
r.logger = func(f string, v ...interface{}) {
225+
captured = fmt.Sprintf(f, v...)
226+
}
227+
defer cleanup()
228+
_, err := r.execGit(r.repoPath(), nil, "unknown")
229+
test.AssertErrorMatch(t, "exit status 1", err)
230+
231+
want := "DEBUG: git: 'unknown' is not a git command. See 'git --help'."
232+
if strings.TrimSpace(captured) != want {
233+
t.Fatalf("execGit debug log failed: got %s, want %s", captured, want)
234+
}
235+
}
236+
237237
func TestPush(t *testing.T) {
238238
if authToken() == "" {
239239
t.Skip("no auth token to push the branch upstream")
@@ -255,7 +255,7 @@ func TestPush(t *testing.T) {
255255

256256
func cloneTestRepository(t *testing.T) (*Repository, func()) {
257257
tempDir, cleanup := makeTempDir(t)
258-
r, err := NewRepository(authenticatedURL(t), tempDir)
258+
r, err := NewRepository(authenticatedURL(t), tempDir, false)
259259
assertNoError(t, err)
260260
err = r.Clone()
261261
assertNoError(t, err)
@@ -282,9 +282,9 @@ func makeTempDir(t *testing.T) (string, func()) {
282282
}
283283
}
284284

285-
func assertExecGit(t *testing.T, gitPath string, args ...string) []byte {
285+
func assertExecGit(t *testing.T, r *Repository, gitPath string, args ...string) []byte {
286286
t.Helper()
287-
out, err := execGit(gitPath, nil, args...)
287+
out, err := r.execGit(gitPath, nil, args...)
288288
if err != nil {
289289
t.Fatalf("assertExecGit failed: %s (%s)", err, out)
290290
}

0 commit comments

Comments
 (0)