Skip to content

Commit de80fc7

Browse files
committed
add -incminor
1 parent 91fae3e commit de80fc7

5 files changed

Lines changed: 430 additions & 27 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ Usage of gitsemver:
5050
write Go source with PkgName and PkgVersion
5151
-incpatch
5252
increment the patch level and create a new tag
53+
-incminor
54+
increment the minor level and create a new tag
5355
-name string
5456
override the Go PkgName, default is to use last portion of module in go.mod
5557
-nofetch
@@ -76,6 +78,8 @@ $ gitsemver
7678
v1.2.3-main.456
7779
$ gitsemver -incpatch
7880
v1.2.4
81+
$ gitsemver -incminor
82+
v1.3.0
7983
```
8084

8185
#### Generate a go package file with version information

internal/gitsemver/versioninfo.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,53 @@ func (vi *VersionInfo) IncPatch() string {
132132
return vi.Tag
133133
}
134134

135+
// IncMinor increments the minor level of the version, returning the new tag.
136+
func (vi *VersionInfo) IncMinor() string {
137+
baseTag := vi.Tag
138+
// Ignore prerelease/build suffixes when incrementing the minor level.
139+
if idx := strings.IndexAny(baseTag, "-+"); idx > -1 {
140+
if core := baseTag[:idx]; isSemverTag(core) {
141+
baseTag = core
142+
}
143+
}
144+
if !isSemverTag(baseTag) {
145+
vi.SameTree = true
146+
return vi.Tag
147+
}
148+
hasVPrefix := strings.HasPrefix(baseTag, "v")
149+
core := strings.TrimPrefix(baseTag, "v")
150+
parts := strings.Split(core, ".")
151+
major := parts[0]
152+
minor := 0
153+
var err error
154+
if len(parts) > 1 {
155+
if minor, err = strconv.Atoi(parts[1]); err != nil {
156+
vi.SameTree = true
157+
return vi.Tag
158+
}
159+
}
160+
hasPatch := len(parts) >= 3
161+
prefix := ""
162+
if hasVPrefix {
163+
prefix = "v"
164+
}
165+
for {
166+
minor++
167+
if len(parts) == 1 {
168+
vi.Tag = prefix + major + "." + strconv.Itoa(minor)
169+
} else if hasPatch {
170+
vi.Tag = prefix + major + "." + strconv.Itoa(minor) + ".0"
171+
} else {
172+
vi.Tag = prefix + major + "." + strconv.Itoa(minor)
173+
}
174+
if !vi.HasTag(vi.Tag) {
175+
break
176+
}
177+
}
178+
vi.SameTree = true
179+
return vi.Tag
180+
}
181+
135182
func CleanBranch(branch string) string {
136183
// SemVer pre-release identifiers only allow [0-9A-Za-z-].
137184
branch = reNonSemVerPreRelease.ReplaceAllString(branch, "-")

internal/gitsemver/versioninfo_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,69 @@ func Test_VersionInfo_IncPatch_OverflowPatchLevel(t *testing.T) {
137137
}
138138
}
139139

140+
func Test_VersionInfo_IncMinor_Mappings(t *testing.T) {
141+
tests := []struct {
142+
in string
143+
want string
144+
}{
145+
{in: "v1", want: "v1.1"},
146+
{in: "v1.2", want: "v1.3"},
147+
{in: "v1.2.3", want: "v1.3.0"},
148+
}
149+
for _, tt := range tests {
150+
vi := &gitsemver.VersionInfo{Tag: tt.in}
151+
if got := vi.IncMinor(); got != tt.want {
152+
t.Fatalf("IncMinor(%q): expected %q, got %q", tt.in, tt.want, got)
153+
}
154+
if !vi.SameTree {
155+
t.Fatalf("IncMinor(%q): expected SameTree=true", tt.in)
156+
}
157+
}
158+
}
159+
160+
func Test_VersionInfo_IncMinor_PrereleaseTag(t *testing.T) {
161+
vi := &gitsemver.VersionInfo{Tag: "v1.2.3-rc.1"}
162+
if got := vi.IncMinor(); got != "v1.3.0" {
163+
t.Fatalf("expected v1.3.0, got %q", got)
164+
}
165+
if !vi.SameTree {
166+
t.Fatal("expected SameTree=true")
167+
}
168+
}
169+
170+
func Test_VersionInfo_IncMinor_AvoidsEquivalentPrefixCollisions(t *testing.T) {
171+
vi := &gitsemver.VersionInfo{
172+
Tag: "v1.2.3",
173+
Tags: []gitsemver.GitTag{
174+
{Tag: "v1.3.0"},
175+
{Tag: "1.4.0"},
176+
},
177+
}
178+
if got := vi.IncMinor(); got != "v1.5.0" {
179+
t.Fatalf("expected v1.5.0, got %q", got)
180+
}
181+
}
182+
183+
func Test_VersionInfo_IncMinor_InvalidTagNoLoop(t *testing.T) {
184+
vi := &gitsemver.VersionInfo{Tag: "not-a-semver-tag"}
185+
if got := vi.IncMinor(); got != "not-a-semver-tag" {
186+
t.Fatalf("expected unchanged tag, got %q", got)
187+
}
188+
if !vi.SameTree {
189+
t.Fatal("expected SameTree=true for unchanged non-semver tag")
190+
}
191+
}
192+
193+
func Test_VersionInfo_IncMinor_OverflowMinorLevel(t *testing.T) {
194+
vi := &gitsemver.VersionInfo{Tag: "v1.9999999999999999999999999"}
195+
if got := vi.IncMinor(); got != "v1.9999999999999999999999999" {
196+
t.Fatalf("expected unchanged overflow minor tag, got %q", got)
197+
}
198+
if !vi.SameTree {
199+
t.Fatal("expected SameTree=true for unchanged overflow tag")
200+
}
201+
}
202+
140203
func Test_CleanBranch(t *testing.T) {
141204
isEqual(t, "branch-with-dots", gitsemver.CleanBranch("-branch.with..dots"))
142205
isEqual(t, "gitlab-branch", gitsemver.CleanBranch("gitlab---branch"))

main.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ var (
8383
flagNoFetch = flag.Bool("nofetch", false, "don't fetch remote tags")
8484
flagNoNewline = flag.Bool("nonewline", false, "don't print a newline after the output")
8585
flagIncPatch = flag.Bool("incpatch", false, "increment the patch level and create a new tag")
86+
flagIncMinor = flag.Bool("incminor", false, "increment the minor level and create a new tag")
8687
flagBranch = flag.Bool("branch", false, "print the current branch name")
8788
flagVersion = flag.Bool("version", false, "print the version of gitsemver and exit")
8889
)
@@ -125,16 +126,24 @@ func mainfn() int {
125126
if err == nil {
126127
var vi gitsemver.VersionInfo
127128
if vi, err = vs.GetVersion(repoDir); err == nil {
128-
if *flagIncPatch {
129+
if *flagIncPatch && *flagIncMinor {
130+
err = errors.New("cannot use both -incpatch and -incminor")
131+
}
132+
if err == nil && (*flagIncPatch || *flagIncMinor) {
129133
var clean bool
130134
if clean, err = vs.Git.CleanStatus(repoDir, true); err == nil {
131-
if !clean {
132-
err = errors.New("cannot use -incpatch with uncommitted changes")
133-
} else {
134-
createTag = vi.IncPatch()
135+
if clean {
136+
if *flagIncPatch {
137+
createTag = vi.IncPatch()
138+
}
139+
if *flagIncMinor {
140+
createTag = vi.IncMinor()
141+
}
135142
if testMode {
136143
createTag = ""
137144
}
145+
} else {
146+
err = errors.New("cannot bump version with uncommitted changes")
138147
}
139148
}
140149
}

0 commit comments

Comments
 (0)