Skip to content

Commit b01fee8

Browse files
committed
improve error handling
1 parent 1bc1819 commit b01fee8

File tree

7 files changed

+343
-161
lines changed

7 files changed

+343
-161
lines changed

pkg/errgitexec.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package gitsemver
2+
3+
import (
4+
"strconv"
5+
)
6+
7+
type errGitExec struct {
8+
git string
9+
args []string
10+
err error
11+
stderr string
12+
}
13+
14+
var ErrGitExec = &errGitExec{}
15+
16+
func NewErrGitExec(git string, args []string, err error, stderr string) error {
17+
return &errGitExec{
18+
git: git,
19+
args: args,
20+
err: err,
21+
stderr: stderr,
22+
}
23+
}
24+
25+
func (err *errGitExec) Error() string {
26+
var b []byte
27+
if err.git != "" {
28+
b = append(b, err.git...)
29+
for _, arg := range err.args {
30+
b = append(b, ' ')
31+
b = strconv.AppendQuote(b, arg)
32+
}
33+
b = append(b, ": "...)
34+
}
35+
if len(err.stderr) > 0 {
36+
b = append(b, err.stderr...)
37+
} else if err.err != nil {
38+
b = append(b, err.err.Error()...)
39+
}
40+
return string(b)
41+
}
42+
43+
func (err *errGitExec) Is(other error) bool {
44+
return other == ErrGitExec
45+
}
46+
47+
func (err *errGitExec) Unwrap() error {
48+
return err.err
49+
}

pkg/errgitexec_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package gitsemver
2+
3+
import (
4+
"errors"
5+
"os"
6+
"testing"
7+
)
8+
9+
func Test_errGitExec_Error(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
git string
13+
args []string
14+
err error
15+
stderr string
16+
want string
17+
}{
18+
{
19+
name: "nil",
20+
git: "",
21+
args: nil,
22+
err: nil,
23+
stderr: "",
24+
want: "",
25+
},
26+
{
27+
name: "os.ErrNotExist",
28+
git: "_nope_",
29+
args: nil,
30+
err: os.ErrNotExist,
31+
stderr: "",
32+
want: "_nope_: " + os.ErrNotExist.Error(),
33+
},
34+
}
35+
for _, tt := range tests {
36+
t.Run(tt.name, func(t *testing.T) {
37+
err := &errGitExec{
38+
git: tt.git,
39+
args: tt.args,
40+
err: tt.err,
41+
stderr: tt.stderr,
42+
}
43+
if got := err.Error(); got != tt.want {
44+
t.Errorf("errGitExec.Error() = \n got %q\nwant %q\n", got, tt.want)
45+
}
46+
if !errors.Is(err, ErrGitExec) {
47+
t.Error("not ErrGitExec")
48+
}
49+
if uw := errors.Unwrap(err); uw != tt.err {
50+
t.Errorf("unwrap = \n got %#v\nwant %#v\n", uw, tt.err)
51+
}
52+
})
53+
}
54+
}

pkg/gitsemver.go

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

33
import (
4+
"errors"
45
"fmt"
56
"io"
67
"strconv"
@@ -74,13 +75,14 @@ func (vs *GitSemVer) Debug(f string, args ...any) {
7475
}
7576
}
7677

77-
func (vs *GitSemVer) getTreeHash(repo, tag string) (gt GitTag) {
78+
func (vs *GitSemVer) getTreeHash(repo, tag string) (gt GitTag, err error) {
7879
for i := range vs.tags {
7980
if vs.tags[i].Tag == tag {
80-
return vs.tags[i]
81+
return vs.tags[i], nil
8182
}
8283
}
83-
if commit, tree := vs.Git.GetHashes(repo, tag); commit != "" && tree != "" {
84+
var commit, tree string
85+
if commit, tree, err = vs.Git.GetHashes(repo, tag); commit != "" && tree != "" && err == nil {
8486
gt.Tag = tag
8587
gt.Commit = commit
8688
gt.Tree = tree
@@ -89,56 +91,75 @@ func (vs *GitSemVer) getTreeHash(repo, tag string) (gt GitTag) {
8991
return
9092
}
9193

92-
func (vs *GitSemVer) examineTags(repo string) {
93-
vs.cleanstatus = vs.Git.CleanStatus(repo)
94-
headHashes := vs.getTreeHash(repo, "HEAD")
95-
vs.Debug("treehash %s: HEAD (clean: %v)\n", headHashes.Tree, vs.cleanstatus)
96-
for _, testtag := range vs.Git.GetTags(repo) {
97-
tagtreehashes := vs.getTreeHash(repo, testtag)
98-
if tagtreehashes.Tree != "" {
99-
vs.Debug("treehash %s: %q\n", tagtreehashes.Tree, testtag)
100-
if vs.cleanstatus && tagtreehashes.Tree == headHashes.Tree {
101-
return
94+
func (vs *GitSemVer) examineTags(repo string) (err error) {
95+
if vs.cleanstatus, err = vs.Git.CleanStatus(repo); err == nil {
96+
var headHashes GitTag
97+
if headHashes, err = vs.getTreeHash(repo, "HEAD"); err == nil {
98+
vs.Debug("treehash %s: HEAD (clean: %v)\n", headHashes.Tree, vs.cleanstatus)
99+
var tags []string
100+
if tags, err = vs.Git.GetTags(repo); err == nil {
101+
for _, testtag := range tags {
102+
var tagtreehashes GitTag
103+
if tagtreehashes, err = vs.getTreeHash(repo, testtag); err == nil {
104+
if tagtreehashes.Tree != "" {
105+
vs.Debug("treehash %s: %q\n", tagtreehashes.Tree, testtag)
106+
if vs.cleanstatus && tagtreehashes.Tree == headHashes.Tree {
107+
return
108+
}
109+
}
110+
}
111+
}
102112
}
103113
}
104114
}
115+
return
105116
}
106117

107118
// GetTag returns the semver git version tag matching the current tree, or
108119
// the closest semver tag if none match exactly. It also returns a bool
109120
// that is true if the tree hashes match and there are no uncommitted changes.
110-
func (vs *GitSemVer) GetTag(repo string) (string, bool) {
111-
vs.examineTags(repo)
112-
if tag := strings.TrimSpace(vs.Env.Getenv("CI_COMMIT_TAG")); tag != "" {
113-
return tag, true
114-
}
115-
head := vs.getTreeHash(repo, "HEAD")
116-
for _, gt := range vs.tags {
117-
if gt.Tag != "HEAD" && gt.Tree == head.Tree {
118-
return gt.Tag, vs.cleanstatus
121+
func (vs *GitSemVer) GetTag(repo string) (tag string, match bool, err error) {
122+
if tag = strings.TrimSpace(vs.Env.Getenv("CI_COMMIT_TAG")); tag != "" {
123+
return tag, true, nil
124+
}
125+
tag = "v0.0.0"
126+
if err = vs.examineTags(repo); err == nil {
127+
var head GitTag
128+
if head, err = vs.getTreeHash(repo, "HEAD"); err == nil {
129+
for _, gt := range vs.tags {
130+
if gt.Tag != "HEAD" && gt.Tree == head.Tree {
131+
return gt.Tag, vs.cleanstatus, nil
132+
}
133+
}
119134
}
120-
}
121-
if tag := vs.Git.GetClosestTag(repo, "HEAD"); tag != "" {
122-
found := vs.getTreeHash(repo, tag)
123-
for _, gt := range vs.tags {
124-
if gt.Tag != "HEAD" && gt.Tree == found.Tree {
125-
found = gt
126-
break
135+
var closeToHEAD string
136+
if closeToHEAD, err = vs.Git.GetClosestTag(repo, "HEAD"); closeToHEAD != "" {
137+
var found GitTag
138+
if found, err = vs.getTreeHash(repo, closeToHEAD); err == nil {
139+
for _, gt := range vs.tags {
140+
if gt.Tag != "HEAD" && gt.Tree == found.Tree {
141+
found = gt
142+
break
143+
}
144+
}
145+
vs.Debug("treehash %s: %q is closest to HEAD\n", found.Tree, found.Tag)
146+
return found.Tag, vs.cleanstatus && (found.Tree == head.Tree), nil
127147
}
128148
}
129-
vs.Debug("treehash %s: %q is closest to HEAD\n", found.Tree, found.Tag)
130-
return found.Tag, vs.cleanstatus && (found.Tree == head.Tree)
131149
}
132-
return "v0.0.0", false
150+
return
133151
}
134152

135-
func (vs *GitSemVer) getBranchGitHub(repo string) (branchName string) {
153+
func (vs *GitSemVer) getBranchGitHub(repo string) (branchName string, err error) {
136154
if branchName = strings.TrimSpace(vs.Env.Getenv("GITHUB_BASE_REF")); branchName == "" {
137155
if branchName = strings.TrimSpace(vs.Env.Getenv("GITHUB_REF_NAME")); branchName != "" {
138156
if strings.TrimSpace(vs.Env.Getenv("GITHUB_REF_TYPE")) == "tag" {
139-
for _, branchName = range vs.Git.GetBranchesFromTag(repo, branchName) {
140-
if vs.IsReleaseBranch(branchName) {
141-
break
157+
var branches []string
158+
if branches, err = vs.Git.GetBranchesFromTag(repo, branchName); err == nil {
159+
for _, branchName = range branches {
160+
if vs.IsReleaseBranch(branchName) {
161+
return
162+
}
142163
}
143164
}
144165
}
@@ -147,12 +168,15 @@ func (vs *GitSemVer) getBranchGitHub(repo string) (branchName string) {
147168
return
148169
}
149170

150-
func (vs *GitSemVer) getBranchGitLab(repo string) (branchName string) {
171+
func (vs *GitSemVer) getBranchGitLab(repo string) (branchName string, err error) {
151172
if branchName = strings.TrimSpace(vs.Env.Getenv("CI_COMMIT_REF_NAME")); branchName != "" {
152173
if strings.TrimSpace(vs.Env.Getenv("CI_COMMIT_TAG")) == branchName {
153-
for _, branchName = range vs.Git.GetBranchesFromTag(repo, branchName) {
154-
if vs.IsReleaseBranch(branchName) {
155-
break
174+
var branches []string
175+
if branches, err = vs.Git.GetBranchesFromTag(repo, branchName); err == nil {
176+
for _, branchName = range branches {
177+
if vs.IsReleaseBranch(branchName) {
178+
return
179+
}
156180
}
157181
}
158182
}
@@ -165,10 +189,10 @@ func (vs *GitSemVer) getBranchGitLab(repo string) (branchName string) {
165189
// branch name in the build system or Git. If no branch name
166190
// can be found (for example, in detached HEAD state),
167191
// then an empty string is returned.
168-
func (vs *GitSemVer) GetBranch(repo string) (branchName string) {
169-
if branchName = vs.Git.GetBranch(repo); branchName == "" {
170-
if branchName = vs.getBranchGitHub(repo); branchName == "" {
171-
branchName = vs.getBranchGitLab(repo)
192+
func (vs *GitSemVer) GetBranch(repo string) (branchName string, err error) {
193+
if branchName, err = vs.Git.GetBranch(repo); branchName == "" {
194+
if branchName, err = vs.getBranchGitHub(repo); branchName == "" {
195+
branchName, err = vs.getBranchGitLab(repo)
172196
}
173197
}
174198
return
@@ -177,10 +201,10 @@ func (vs *GitSemVer) GetBranch(repo string) (branchName string) {
177201
// GetBuild returns the build counter. This is taken from the CI system if available,
178202
// otherwise the Git commit count is used. Returns an empty string if no reasonable build
179203
// counter can be found.
180-
func (vs *GitSemVer) GetBuild(repo string) (build string) {
204+
func (vs *GitSemVer) GetBuild(repo string) (build string, err error) {
181205
if build = strings.TrimSpace(vs.Env.Getenv("CI_PIPELINE_IID")); build == "" {
182206
if build = strings.TrimSpace(vs.Env.Getenv("GITHUB_RUN_NUMBER")); build == "" {
183-
build = vs.Git.GetBuild(repo)
207+
build, err = vs.Git.GetBuild(repo)
184208
}
185209
}
186210
return
@@ -189,9 +213,12 @@ func (vs *GitSemVer) GetBuild(repo string) (build string) {
189213
// GetVersion returns a VersionInfo for the source code in the Git repository.
190214
func (vs *GitSemVer) GetVersion(repo string) (vi VersionInfo, err error) {
191215
if repo, err = vs.Git.CheckGitRepo(repo); err == nil {
192-
if vi.Tag, vi.SameTree = vs.GetTag(repo); vi.Tag != "" {
193-
vi.Build = vs.GetBuild(repo)
194-
vi.Branch = vs.GetBranch(repo)
216+
if vi.Tag, vi.SameTree, err = vs.GetTag(repo); vi.Tag != "" && err == nil {
217+
var e error
218+
vi.Build, e = vs.GetBuild(repo)
219+
err = errors.Join(err, e)
220+
vi.Branch, e = vs.GetBranch(repo)
221+
err = errors.Join(err, e)
195222
vi.IsRelease = vs.IsReleaseBranch(vi.Branch)
196223
vi.Tags = vs.tags
197224
}

0 commit comments

Comments
 (0)