Skip to content

Commit 41e071c

Browse files
committed
feat: release command
1 parent 1cd52b2 commit 41e071c

File tree

5 files changed

+267
-9
lines changed

5 files changed

+267
-9
lines changed

cmd/release/release.go

Lines changed: 244 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,260 @@ package release
33
import (
44
"flag"
55
"fmt"
6+
"log"
7+
"strconv"
8+
"strings"
9+
10+
survey "github.com/AlecAivazis/survey/v2"
11+
clog "github.com/barelyhuman/commitlog/log"
12+
"github.com/go-git/go-git/v5"
13+
"github.com/go-git/go-git/v5/plumbing"
14+
"github.com/go-git/go-git/v5/plumbing/object"
615
)
716

817
var releaseCmd *flag.FlagSet
18+
var major *bool
19+
var minor *bool
20+
var patch *bool
21+
var beta *string
22+
var tag *string
23+
24+
var semverPrompt = &survey.Select{
25+
Message: "Choose a semver version:",
26+
Options: []string{"major", "minor", "patch", "none"},
27+
Default: "none",
28+
}
29+
30+
var betaPrompt = &survey.Confirm{
31+
Message: "Is it a beta release?",
32+
}
33+
34+
var betaSuffixPrompt = &survey.Input{
35+
Message: "Enter the exiting beta suffix, will be also used for the any beta suffix?",
36+
Default: "beta",
37+
}
38+
39+
// TagVersion - struct holding the broken down tag
40+
type TagVersion struct {
41+
major string
42+
minor string
43+
patch string
44+
beta string
45+
isBeta bool
46+
}
947

1048
// Install - add flags and other options
1149
func Install() {
1250
releaseCmd = flag.NewFlagSet("release", flag.ExitOnError)
13-
releaseCmd.Bool("-major", false, "If release is a major one, will increment the x.0.0 ")
14-
releaseCmd.Bool("-minor", false, "If release is a minor one, will increment the 0.x.0 ")
15-
releaseCmd.Bool("-patch", false, "If release is a patch, will increment the 0.0.x ")
16-
releaseCmd.Bool("-beta", false, "If the release is a beta, to add/increment tag by `-beta.x`")
17-
releaseCmd.String("-tag", "", "The Tag to be taken as base")
51+
major = releaseCmd.Bool("major", false, "If release is a major one, will increment the x.0.0 ")
52+
minor = releaseCmd.Bool("minor", false, "If release is a minor one, will increment the 0.x.0 ")
53+
patch = releaseCmd.Bool("patch", false, "If release is a patch, will increment the 0.0.x ")
54+
beta = releaseCmd.String("beta", "beta", "If the release is a beta, to add/increment tag with `-beta.x` or mentioned string")
55+
tag = releaseCmd.String("tag", "", "The Tag to be taken as base")
1856
}
1957

2058
// Run - execute the command
2159
func Run(args []string) {
60+
61+
var tagToUse = *tag
62+
63+
isBeta := needsQuestionnaire(args)
2264
releaseCmd.Parse(args)
23-
fmt.Println("Note: The release command is not yet implemented")
65+
66+
if tagToUse == "" {
67+
tagToUse = getTagString()
68+
}
69+
70+
createRelease(tagToUse, *major, *minor, *patch, *beta, isBeta)
71+
}
72+
73+
// needsQuestionnaire - Check semver and beta if no args were supplied
74+
func needsQuestionnaire(args []string) bool {
75+
var semver string
76+
var isBeta bool
77+
78+
if len(args) < 1 {
79+
err := survey.AskOne(semverPrompt, &semver)
80+
if err != nil {
81+
fmt.Println(err.Error())
82+
return false
83+
}
84+
85+
err = survey.AskOne(betaPrompt, &isBeta)
86+
if err != nil {
87+
fmt.Println(err.Error())
88+
return false
89+
}
90+
91+
err = survey.AskOne(betaSuffixPrompt, beta)
92+
if err != nil {
93+
fmt.Println(err.Error())
94+
return false
95+
}
96+
97+
switch semver {
98+
case "major":
99+
*major = true
100+
break
101+
case "minor":
102+
*minor = true
103+
break
104+
case "patch":
105+
*patch = true
106+
break
107+
}
108+
}
109+
110+
return isBeta
111+
}
112+
113+
func createRelease(tagString string, increaseMajor bool, increaseMinor bool, increasePatch bool, betaSuffix string, isBeta bool) {
114+
version, hasV := breakTag(tagString)
115+
releaseTagString := ""
116+
117+
majorAsInt, err := strconv.ParseInt(version.major, 10, 32)
118+
if err != nil {
119+
log.Fatal("Error converting to number on version.major", version)
120+
}
121+
minorAsInt, err := strconv.ParseInt(version.minor, 10, 32)
122+
if err != nil {
123+
log.Fatal("Error converting to number on version.minor", version)
124+
}
125+
patchAsInt, err := strconv.ParseInt(version.patch, 10, 32)
126+
if err != nil {
127+
log.Fatal("Error converting to number on version.patch", version)
128+
}
129+
betaAsInt, err := strconv.ParseInt(version.beta, 10, 32)
130+
if err != nil {
131+
log.Fatal("Error converting to number on version.beta", version)
132+
}
133+
134+
if hasV {
135+
releaseTagString += "v"
136+
}
137+
138+
if increaseMajor {
139+
majorAsInt++
140+
}
141+
142+
if increaseMinor {
143+
minorAsInt++
144+
}
145+
146+
if increasePatch {
147+
patchAsInt++
148+
}
149+
150+
releaseTagString += fmt.Sprintf("%d.%d.%d", majorAsInt, minorAsInt, patchAsInt)
151+
152+
if isBeta {
153+
betaAsInt++
154+
releaseTagString += fmt.Sprintf("-%s.%d", betaSuffix, betaAsInt)
155+
}
156+
157+
fmt.Println(releaseTagString)
158+
159+
isConfirmed := confirmRelease(releaseTagString)
160+
161+
if !isConfirmed {
162+
return
163+
}
164+
165+
repo := clog.OpenRepository(".")
166+
167+
setTag(repo, releaseTagString)
168+
}
169+
170+
func tagExists(tag string, r *git.Repository) bool {
171+
tagFoundErr := "tag was found"
172+
tags, err := r.TagObjects()
173+
if err != nil {
174+
log.Printf("get tags error: %s", err)
175+
return false
176+
}
177+
res := false
178+
err = tags.ForEach(func(t *object.Tag) error {
179+
if t.Name == tag {
180+
res = true
181+
return fmt.Errorf(tagFoundErr)
182+
}
183+
return nil
184+
})
185+
if err != nil && err.Error() != tagFoundErr {
186+
log.Printf("iterate tags error: %s", err)
187+
return false
188+
}
189+
return res
190+
}
191+
192+
func setTag(r *git.Repository, tag string) (bool, error) {
193+
if tagExists(tag, r) {
194+
log.Printf("tag %s already exists", tag)
195+
return false, nil
196+
}
197+
log.Printf("Set tag %s", tag)
198+
h, err := r.Head()
199+
if err != nil {
200+
log.Printf("get HEAD error: %s", err)
201+
return false, err
202+
}
203+
204+
_, err = r.CreateTag(tag, h.Hash(), &git.CreateTagOptions{
205+
Message: tag,
206+
})
207+
208+
if err != nil {
209+
log.Printf("create tag error: %s", err)
210+
return false, err
211+
}
212+
213+
return true, nil
214+
}
215+
216+
func confirmRelease(tag string) bool {
217+
var confirm bool
218+
219+
confirmReleasePrompt := &survey.Confirm{
220+
Message: "Do you want me to create the following tag: " + tag + " ?",
221+
}
222+
223+
err := survey.AskOne(confirmReleasePrompt, &confirm)
224+
225+
if err != nil {
226+
log.Fatalln(err)
227+
}
228+
return confirm
229+
}
230+
231+
func breakTag(tagString string) (*TagVersion, bool) {
232+
hasV := false
233+
version := &TagVersion{}
234+
tagSplits := strings.Split(tagString, ".")
235+
236+
version.major = tagSplits[0]
237+
version.minor = tagSplits[1]
238+
version.patch = tagSplits[2]
239+
version.beta = tagSplits[3]
240+
241+
// Check if the major version has the letter `v` in the tag
242+
if len(version.major) > 1 && strings.Contains(version.major, "v") {
243+
version.major = version.major[len("v"):]
244+
hasV = true
245+
}
246+
247+
if len(version.patch) > 1 && strings.Contains(version.patch, "-"+*beta) {
248+
version.patch = strings.Replace(version.patch, "-"+*beta, "", -1)
249+
}
250+
251+
return version, hasV
252+
}
253+
254+
func getTagString() string {
255+
currentRepository := clog.OpenRepository(".")
256+
var tagRef *plumbing.Reference
257+
if *tag == "" {
258+
tagRef, _, _ = clog.GetLatestTagFromRepository(currentRepository)
259+
}
260+
onlyTag := tagRef.Name().Short()
261+
return onlyTag
24262
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ module github.com/barelyhuman/commitlog
33
go 1.15
44

55
require (
6+
github.com/AlecAivazis/survey/v2 v2.2.8
67
github.com/go-git/go-git/v5 v5.2.0
78
)

go.sum

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
github.com/AlecAivazis/survey v1.8.8 h1:Y4yypp763E8cbqb5RBqZhGgkCFLRFnbRBHrxnpMMsgQ=
2+
github.com/AlecAivazis/survey/v2 v2.2.8 h1:TgxCwybKdBckmC+/P9/5h49rw/nAHe/itZL0dgHs+Q0=
3+
github.com/AlecAivazis/survey/v2 v2.2.8/go.mod h1:9DYvHgXtiXm6nCn+jXnOXLKbH+Yo9u8fAS/SduGdoPk=
4+
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
15
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
26
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
37
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
@@ -16,17 +20,27 @@ github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod
1620
github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI=
1721
github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs=
1822
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
23+
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
1924
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
2025
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
2126
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
2227
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
2328
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
29+
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
30+
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
2431
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
2532
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
2633
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
2734
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
35+
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
2836
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
2937
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
38+
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
39+
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
40+
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
41+
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
42+
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
43+
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
3044
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
3145
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
3246
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@@ -35,22 +49,27 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
3549
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
3650
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
3751
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
52+
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
3853
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
3954
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
4055
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
4156
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
4257
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
58+
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
4359
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
4460
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
4561
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
4662
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
4763
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
4864
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
4965
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
66+
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5067
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
68+
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5169
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
5270
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5371
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
72+
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
5473
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
5574
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
5675
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

log/gitutils.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ func normalizeCommit(commitMessage string) string {
108108
return strings.TrimSuffix(message, "\n")
109109
}
110110

111-
// openRepository - open the git repository and return repository reference
112-
func openRepository(path string) *git.Repository {
111+
// OpenRepository - open the git repository and return repository reference
112+
func OpenRepository(path string) *git.Repository {
113113
r, err := git.PlainOpen(path)
114114
if err != nil {
115115
log.Fatal("Error opening Repository: ", err)

log/log.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func (container *logContainer) canAddToContainer(skip bool) bool {
137137

138138
// CommitLog - Generate commit log
139139
func CommitLog(path string, startCommitString string, endCommitString string, inclusionFlags string, skipClassification bool) (string, ErrMessage) {
140-
currentRepository := openRepository(path)
140+
currentRepository := OpenRepository(path)
141141
baseCommitReference, err := currentRepository.Head()
142142
var startHash, endHash *object.Commit
143143
var cIter object.CommitIter

0 commit comments

Comments
 (0)