Skip to content

Commit 79cac1e

Browse files
committed
add -debug and use git status
1 parent df9337c commit 79cac1e

File tree

7 files changed

+94
-15
lines changed

7 files changed

+94
-15
lines changed

main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var (
2828
flagGit = flag.String("git", "git", "path to Git executable")
2929
flagOut = flag.String("out", "", "write to file instead of stdout (relative paths are relative to repo)")
3030
flagName = flag.String("name", "", "override the Go PkgName, default is to use last portion of module in go.mod")
31+
flagDebug = flag.Bool("debug", false, "write debug info to stderr")
3132
flagGoPackage = flag.Bool("gopackage", false, "write Go source with PkgName and PkgVersion")
3233
flagNoFetch = flag.Bool("nofetch", false, "don't fetch remote tags")
3334
flagNoNewline = flag.Bool("nonewline", false, "don't print a newline after the output")
@@ -42,6 +43,9 @@ func mainfn() int {
4243

4344
vs, err := gitsemver.New(*flagGit)
4445
if err == nil {
46+
if *flagDebug {
47+
vs.DebugOut = os.Stderr
48+
}
4549
var createTag string
4650
if repoDir, err = vs.Git.CheckGitRepo(repoDir); err == nil {
4751
if !*flagNoFetch {

main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func TestMainError(t *testing.T) {
3535
}
3636
flag.Parse()
3737
*flagOut = "/proc/.nonexistant"
38+
*flagDebug = true
3839
*flagIncPatch = true
3940
main()
4041
}

pkg/gitsemver.go

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package gitsemver
22

33
import (
4+
"fmt"
5+
"io"
46
"strconv"
57
"strings"
68
)
79

810
type GitSemVer struct {
9-
Git Gitter // Git
10-
Env Environment // environment
11+
Git Gitter // Git
12+
Env Environment // environment
13+
DebugOut io.Writer // if nit nil, write debug output here
1114
}
1215

1316
// New returns a GitSemVer ready to examine
@@ -62,27 +65,49 @@ func (vs *GitSemVer) IsReleaseBranch(branchName string) bool {
6265
return false
6366
}
6467

68+
// Debug writes debugging output to DebugOut if it's not nil.
69+
func (vs *GitSemVer) Debug(f string, args ...any) {
70+
if vs.DebugOut != nil {
71+
_, _ = fmt.Fprintf(vs.DebugOut, f, args...)
72+
}
73+
}
74+
6575
// GetTag returns the semver git version tag matching the current tree, or
66-
// the closest semver tag if none match.
76+
// the closest semver tag if none match exactly. It also returns a bool
77+
// that is true if the tree hashes match and there are no uncommitted changes.
6778
func (vs *GitSemVer) GetTag(repo string) (string, bool) {
6879
if tag := strings.TrimSpace(vs.Env.Getenv("CI_COMMIT_TAG")); tag != "" {
6980
return tag, true
7081
}
71-
if currtreehash := vs.Git.GetCurrentTreeHash(repo); currtreehash != "" {
82+
treehashes := map[string]string{}
83+
cleanstatus := vs.Git.CleanStatus(repo)
84+
currtreehash := vs.Git.GetCurrentTreeHash(repo)
85+
if currtreehash != "" {
86+
vs.Debug("treehash %s: HEAD (clean: %v)\n", currtreehash, cleanstatus)
7287
for _, testtag := range vs.Git.GetTags(repo) {
7388
tagtreehash := vs.Git.GetTreeHash(repo, testtag)
89+
if _, ok := treehashes[tagtreehash]; !ok {
90+
treehashes[tagtreehash] = testtag
91+
}
92+
vs.Debug("treehash %s: %q\n", tagtreehash, testtag)
7493
if tagtreehash == currtreehash {
75-
return testtag, true
94+
return testtag, cleanstatus
7695
}
7796
}
7897
}
7998
if tag := vs.Git.GetClosestTag(repo, "HEAD"); tag != "" {
80-
return tag, false
99+
tagtreehash := vs.Git.GetTreeHash(repo, tag)
100+
if lasttag, ok := treehashes[tagtreehash]; ok {
101+
tag = lasttag
102+
}
103+
vs.Debug("treehash %s: %q is closest to HEAD\n", tagtreehash, tag)
104+
return tag, cleanstatus && (tagtreehash == currtreehash)
81105
}
82106
return "v0.0.0", false
83107
}
84108

85109
func (vs *GitSemVer) getBranchGitHub(repo string) (branchName string) {
110+
//
86111
if branchName = strings.TrimSpace(vs.Env.Getenv("GITHUB_REF_NAME")); branchName != "" {
87112
if strings.TrimSpace(vs.Env.Getenv("GITHUB_REF_TYPE")) == "tag" {
88113
for _, branchName = range vs.Git.GetBranchesFromTag(repo, branchName) {

pkg/gitsemver_test.go

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

33
import (
4+
"bytes"
45
"testing"
56

67
gitsemver "github.com/linkdata/gitsemver/pkg"
@@ -27,12 +28,14 @@ func Test_NewVersionStringer_FailsWithBadBinary(t *testing.T) {
2728
}
2829

2930
func isEqual[T comparable](t *testing.T, a, b T) {
31+
t.Helper()
3032
if a != b {
3133
t.Errorf("%v != %v", a, b)
3234
}
3335
}
3436

3537
func isTrue(t *testing.T, v bool) {
38+
t.Helper()
3639
if !v {
3740
t.Error(v)
3841
}
@@ -242,3 +245,16 @@ func Test_VersionStringer_GetVersionDetachedHEAD(t *testing.T) {
242245
}
243246
isEqual(t, "v2.0.0", vi.Version())
244247
}
248+
249+
func TestGitSemVer_Debug(t *testing.T) {
250+
vs, err := gitsemver.New("git")
251+
if err != nil {
252+
t.Error(err)
253+
}
254+
var buf bytes.Buffer
255+
vs.DebugOut = &buf
256+
vs.Debug("foo")
257+
if x := buf.String(); x != "foo" {
258+
t.Error(x)
259+
}
260+
}

pkg/gitter.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,25 @@ type Gitter interface {
3838
DeleteTag(repo, tag string) (err error)
3939
// PushTag pushes the given tag to the origin. Does nothing if tag is empty.
4040
PushTag(repo, tag string) (err error)
41+
// CleanStatus returns true if there are no uncommitted changes in the repo
42+
CleanStatus(repo string) bool
4143
}
4244

4345
type DefaultGitter string
4446

47+
func (dg DefaultGitter) execKeepError(args ...string) (err error) {
48+
var b []byte
49+
b, err = exec.Command(string(dg), args...).CombinedOutput() /* #nosec G204 */
50+
if err != nil {
51+
errText := err.Error()
52+
if s := strings.TrimSpace(string(b)); s != "" {
53+
errText = s
54+
}
55+
err = fmt.Errorf("%s %s: %q", string(dg), strings.Join(args, " "), errText)
56+
}
57+
return
58+
}
59+
4560
func NewDefaultGitter(gitBin string) (gitter Gitter, err error) {
4661
if gitBin, err = exec.LookPath(gitBin); err == nil {
4762
gitter = DefaultGitter(gitBin)
@@ -122,7 +137,7 @@ func (dg DefaultGitter) GetTreeHash(repo, tag string) string {
122137

123138
// GetClosestTag returns the closest semver tag for the given commit hash.
124139
func (dg DefaultGitter) GetClosestTag(repo, commit string) (tag string) {
125-
_ = exec.Command(string(dg), "-C", repo, "fetch", "--unshallow").Run() //#nosec G204
140+
_ = exec.Command(string(dg), "-C", repo, "fetch", "--unshallow", "--tags").Run() //#nosec G204
126141
if b, _ := exec.Command(string(dg), "-C", repo, "describe", "--tags", "--match=v[0-9]*", "--match=[0-9]*", "--abbrev=0", commit).Output(); len(b) > 0 /* #nosec G204 */ {
127142
return strings.TrimSpace(string(b))
128143
}
@@ -183,25 +198,26 @@ func (dg DefaultGitter) FetchTags(repo string) (err error) {
183198

184199
func (dg DefaultGitter) CreateTag(repo, tag string) (err error) {
185200
if tag != "" {
186-
err = exec.Command(string(dg), "-C", repo, "tag", tag).Run() /* #nosec G204 */
201+
err = dg.execKeepError("-C", repo, "tag", tag)
187202
}
188203
return
189204
}
190205

191206
func (dg DefaultGitter) DeleteTag(repo, tag string) (err error) {
192207
if tag != "" {
193-
err = exec.Command(string(dg), "-C", repo, "tag", "-d", tag).Run() /* #nosec G204 */
208+
err = dg.execKeepError("-C", repo, "tag", "-d", tag)
194209
}
195210
return
196211
}
197212

198213
func (dg DefaultGitter) PushTag(repo, tag string) (err error) {
199214
if tag != "" {
200-
var b []byte
201-
b, err = exec.Command(string(dg), "-C", repo, "push", "origin", tag).CombinedOutput() /* #nosec G204 */
202-
if err != nil {
203-
err = fmt.Errorf("%w: %s", err, strings.TrimSpace(string(b)))
204-
}
215+
err = dg.execKeepError("-C", repo, "push", "origin", tag)
205216
}
206217
return
207218
}
219+
220+
func (dg DefaultGitter) CleanStatus(repo string) bool {
221+
b, _ := exec.Command(string(dg), "-C", repo, "status", "--untracked-files=no", "--porcelain").Output() /* #nosec G204 */
222+
return len(strings.TrimSpace(string(b))) == 0
223+
}

pkg/gitter_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,19 @@ func Test_DefaultGitter_PushTag(t *testing.T) {
221221
err = dg.PushTag(".", "test-tag")
222222
if err == nil {
223223
t.Error("no error")
224+
} else {
225+
t.Log(err)
224226
}
225-
t.Log(err)
227+
}
226228

229+
func Test_DefaultGitter_CleanStatus(t *testing.T) {
230+
dg, err := gitsemver.NewDefaultGitter("git")
231+
if err != nil {
232+
t.Error(err)
233+
}
234+
if !dg.CleanStatus(".") {
235+
t.Log("git status reports uncommitted changes")
236+
} else {
237+
t.Log("git status reports clean")
238+
}
227239
}

pkg/mockgitter_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type MockGitter struct {
3838
branch string
3939
treehash string
4040
TopTag string
41+
dirty bool
4142
}
4243

4344
func (mg *MockGitter) CheckGitRepo(dir string) (repo string, err error) {
@@ -150,4 +151,8 @@ func (mg *MockGitter) PushTag(repo, tag string) (err error) {
150151
return
151152
}
152153

154+
func (mg *MockGitter) CleanStatus(repo string) bool {
155+
return !mg.dirty
156+
}
157+
153158
var _ gitsemver.Gitter = &MockGitter{}

0 commit comments

Comments
 (0)