@@ -2,6 +2,7 @@ package main
2
2
3
3
import (
4
4
"fmt"
5
+ "log"
5
6
"os"
6
7
"os/exec"
7
8
"regexp"
@@ -13,39 +14,79 @@ import (
13
14
var (
14
15
// describeRegexp parses the count and revision part of the “git describe --long” output.
15
16
describeRegexp = regexp .MustCompile (`-\d+-g([0-9a-f]+)\s*$` )
17
+
18
+ // semverRegexp checks if a string is a valid Go semver,
19
+ // from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
20
+ // with leading "v" added.
21
+ semverRegexp = regexp .MustCompile (`^v(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` )
16
22
)
17
23
18
24
// TODO: also support other VCS
19
- func pkgVersionFromGit (gitdir string ) (string , error ) {
20
- cmd := exec .Command ("git" , "describe" , "--exact-match" , "--tags" )
25
+ func pkgVersionFromGit (gitdir string , forcePrerelease bool ) (version string , hasRelease , isRelease bool , err error ) {
26
+ var latestTag string
27
+ var commitsAhead int
28
+
29
+ // Find @latest version tag (whether annotated or not)
30
+ cmd := exec .Command ("git" , "describe" , "--abbrev=0" , "--tags" )
21
31
cmd .Dir = gitdir
22
- if tag , err := cmd .Output (); err == nil {
23
- version := strings .TrimSpace (string (tag ))
24
- if strings .HasPrefix (version , "v" ) {
25
- version = version [1 :]
32
+ if out , err := cmd .Output (); err == nil {
33
+ latestTag = strings .TrimSpace (string (out ))
34
+ hasRelease = true
35
+ log .Printf ("Found latest tag %q" , latestTag )
36
+
37
+ if ! semverRegexp .MatchString (latestTag ) {
38
+ log .Printf ("WARNING: Latest tag %q is not a valid SemVer version\n " , latestTag )
39
+ // TODO: Enforce strict sementic versioning with leading "v"?
40
+ }
41
+
42
+ // Count number of commits since @latest version
43
+ cmd = exec .Command ("git" , "rev-list" , "--count" , latestTag + "..HEAD" )
44
+ cmd .Dir = gitdir
45
+ out , err := cmd .Output ()
46
+ if err != nil {
47
+ return "" , true , false , err
48
+ }
49
+ commitsAhead , err = strconv .Atoi (strings .TrimSpace (string (out )))
50
+ if err != nil {
51
+ return "" , true , false , err
52
+ }
53
+
54
+ if commitsAhead == 0 {
55
+ // Equivalent to "git describe --exact-match --tags"
56
+ log .Printf ("Latest tag %q matches master" , latestTag )
57
+ } else {
58
+ log .Printf ("INFO: master is ahead of %q by %v commits" , latestTag , commitsAhead )
59
+ }
60
+
61
+ version = strings .TrimPrefix (latestTag , "v" )
62
+ isRelease = true
63
+
64
+ if forcePrerelease {
65
+ log .Printf ("INFO: Force packaging master (prerelease) as requested by user" )
66
+ } else {
67
+ return version , hasRelease , isRelease , nil
26
68
}
27
- return version , nil
28
69
}
29
70
71
+ // Packaging @master (prerelease)
72
+
73
+ // 1.0~rc1 < 1.0 < 1.0+b1, as per
74
+ // https://www.debian.org/doc/manuals/maint-guide/first.en.html#namever
75
+ mainVer := "0.0~"
76
+ if hasRelease {
77
+ mainVer = version + "+"
78
+ }
79
+
80
+ // Find committer date, UNIX timestamp
30
81
cmd = exec .Command ("git" , "log" , "--pretty=format:%ct" , "-n1" )
31
82
cmd .Dir = gitdir
32
83
lastCommitUnixBytes , err := cmd .Output ()
33
84
if err != nil {
34
- return "" , err
85
+ return "" , hasRelease , isRelease , err
35
86
}
36
87
lastCommitUnix , err := strconv .ParseInt (strings .TrimSpace (string (lastCommitUnixBytes )), 0 , 64 )
37
88
if err != nil {
38
- return "" , err
39
- }
40
-
41
- // Find the most recent tag (whether annotated or not)
42
- cmd = exec .Command ("git" , "describe" , "--abbrev=0" , "--tags" )
43
- cmd .Dir = gitdir
44
- // 1.0~rc1 < 1.0 < 1.0+b1, as per
45
- // https://www.debian.org/doc/manuals/maint-guide/first.en.html#namever
46
- lastTag := "0.0~"
47
- if lastTagBytes , err := cmd .Output (); err == nil {
48
- lastTag = strings .TrimPrefix (strings .TrimSpace (string (lastTagBytes )), "v" ) + "+"
89
+ return "" , hasRelease , isRelease , err
49
90
}
50
91
51
92
// This results in an output like 4.10.2-232-g9f107c8
@@ -60,19 +101,19 @@ func pkgVersionFromGit(gitdir string) (string, error) {
60
101
cmd .Stderr = os .Stderr
61
102
revparseBytes , err := cmd .Output ()
62
103
if err != nil {
63
- return "" , err
104
+ return "" , hasRelease , isRelease , err
64
105
}
65
106
lastCommitSha = strings .TrimSpace (string (revparseBytes ))
66
107
} else {
67
108
submatches := describeRegexp .FindSubmatch (describeBytes )
68
109
if submatches == nil {
69
- return "" , fmt .Errorf ("git describe output %q does not match expected format" , string (describeBytes ))
110
+ return "" , hasRelease , isRelease , fmt .Errorf ("git describe output %q does not match expected format" , string (describeBytes ))
70
111
}
71
112
lastCommitSha = string (submatches [1 ])
72
113
}
73
- version : = fmt .Sprintf ("%sgit%s.%s" ,
74
- lastTag ,
114
+ version = fmt .Sprintf ("%sgit%s.%s" ,
115
+ mainVer ,
75
116
time .Unix (lastCommitUnix , 0 ).UTC ().Format ("20060102" ),
76
117
lastCommitSha )
77
- return version , nil
118
+ return version , hasRelease , isRelease , nil
78
119
}
0 commit comments