1
0
mirror of https://github.com/therootcompany/go-gitver.git synced 2024-11-16 17:08:59 +00:00

Compare commits

..

24 Commits

Author SHA1 Message Date
1638772379
docs: fix typo 2023-01-18 14:10:35 -07:00
752451d77b
fix typo 2021-04-15 02:15:55 -06:00
3409d5f2e4 update examples 2020-10-12 14:46:35 -06:00
cfbbc73f48 complete transition to v2 2020-10-12 14:42:55 -06:00
1ee983f56d add v2 to go.mod 2020-10-10 16:33:22 -06:00
a745735392 add GoDoc link 2020-10-10 16:16:08 -06:00
b667843a2b v2.0.0-pre1: make compatible with GoReleaser 2020-10-10 16:13:09 -06:00
37c1fd4b56 fix typos in example fmt.Printf 2020-09-12 08:57:44 +00:00
a45a154eaf shorter example string 2020-07-17 02:55:32 +00:00
d5c2342f76 clarify usage 2020-07-17 02:52:49 +00:00
6dace8255b whitespace fix 2020-07-17 02:46:24 +00:00
82ec670e8a made README more clear 2020-07-17 02:46:03 +00:00
d4628bd751 fail softly, as documented 2019-07-08 14:36:22 -06:00
a3af8e6c5b v1.1.2 2019-07-01 02:33:28 -06:00
0921ed1e60 separate ExecAndParse, bugfix source format 2019-07-01 02:32:19 -06:00
039b465b75 add common issue 2019-06-21 00:47:42 -06:00
ef45a8a999 bump version 2019-06-21 00:19:55 -06:00
0b8c2d86df v1.1.1: update docs, template conditionals 2019-06-21 00:18:07 -06:00
639a7e246f update markdown syntax 2019-06-21 00:08:45 -06:00
2da59efd62 update syntax highlighting 2019-06-21 00:07:27 -06:00
84130f846a v1.1.0: better docs, examples, and options 2019-06-21 00:02:09 -06:00
9f05e2304c rename outfile xversion.go to lower init() priority, add outfile option 2019-06-21 00:01:02 -06:00
47b8ec43ae fix docs, add more docs, allow different package name 2019-06-20 23:27:41 -06:00
f104a3155f v1.0.0: get version from git, or fail gracefully 2019-06-20 22:55:24 -06:00
26 changed files with 702 additions and 160 deletions

7
.gitignore vendored
View File

@ -1,4 +1,9 @@
generated-version.go xversion.go
zversion.go
/go-gitver
hello
examples/*/*.sum
# ---> Go # ---> Go
# Binaries for programs and plugins # Binaries for programs and plugins

1
.prettierrc Normal file
View File

@ -0,0 +1 @@
{}

216
README.md
View File

@ -1,17 +1,154 @@
# git-version.go # [Go GitVer](https://git.rootprojects.org/root/go-gitver)
Use git tags to add semver to your go package. Use **git tags** to add (GoReleaser-compatible) [**semver**](https://semver.org/)
to your go package in under 150
[lines of code](https://git.rootprojects.org/root/go-gitver/src/branch/master/gitver/gitver.go).
> Goal: Either use an exact version like v1.0.0 ```txt
> or translate the git version like v1.0.0-4-g0000000 Goals:
> to a semver like v1.0.1-pre4+g0000000
> 1. Use an exact `git tag` version, like v1.0.0, when clean
> Fail gracefully when git repo isn't available. 2. Translate the `git describe` version (v1.0.0-4-g0000000)
to semver (1.0.1-pre4+g0000000) in between releases
3. Note when `dirty` (and have build timestamp)
Fail gracefully when git repo isn't available.
```
# GoDoc
See <https://pkg.go.dev/git.rootprojects.org/root/go-gitver/v2>.
# How it works
1. You define the fallback version and version printing in `main.go`:
```go
//go:generate go run git.rootprojects.org/root/go-gitver/v2
package main
import (
"fmt"
"strings"
)
var (
commit = "0000000"
version = "0.0.0-pre0+0000000"
date = "0000-00-00T00:00:00+0000"
)
func main() {
if (len(os.Args) > 1 && "version" == strings.TrimLeft(os.Args[1], "-")) {
fmt.Printf("Foobar v%s (%s) %s\n", version, commit[:7], date)
}
// ...
}
```
2. You `go generate` or `go run git.rootprojects.org/root/go-gitver/v2` to generate `xversion.go`:
```go
package main
func init() {
commit = "0921ed1e"
version = "1.1.2"
date = "2019-07-01T02:32:58-06:00"
}
```
# Demo # Demo
Generate an `xversion.go` file:
```bash ```bash
go run git.rootprojects.org/root/go-gitver go run git.rootprojects.org/root/go-gitver/v2
cat xversion.go
```
```go
// Code generated by go generate; DO NOT EDIT.
package main
func init() {
commit = "6dace8255b52e123297a44629bc32c015add310a"
version = "1.1.4-pre2+g6dace82"
date = "2020-07-16T20:48:15-06:00"
}
```
<small>**Note**: The file is named `xversion.go` by default so that the
generated file's `init()` will come later, and thus take priority, over
most other files.</small>
See `go-gitver`s self-generated version:
```bash
go run git.rootprojects.org/root/go-gitver/v2 version
```
```txt
6dace8255b52e123297a44629bc32c015add310a
v1.1.4-pre2+g6dace82
2020-07-16T20:48:15-06:00
```
# QuickStart
Add this to the top of your main file, so that it runs with `go generate`:
```go
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver/v2
```
Add a file that imports go-gitver (for versioning)
```go
// +build tools
package example
import _ "git.rootprojects.org/root/go-gitver/v2"
```
Change you build instructions to be something like this:
```bash
go mod vendor
go generate -mod=vendor ./...
go build -mod=vendor -o example cmd/example/*.go
```
You don't have to use `-mod=vendor`, but I highly recommend it (just `go mod tidy; go mod vendor` to start).
# Options
```txt
version print version and exit
--fail exit with non-zero status code on failure
--package <name> will set the package name
--outfile <name> will replace `xversion.go` with the given file path
```
ENVs
```bash
# Alias for --fail
GITVER_FAIL=true
```
For example:
```go
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver/v2 --fail
```
```bash
go run -mod=vendor git.rootprojects.org/root/go-gitver/v2 version
``` ```
# Usage # Usage
@ -19,47 +156,65 @@ go run git.rootprojects.org/root/go-gitver
See `examples/basic` See `examples/basic`
1. Create a `tools` package in your project 1. Create a `tools` package in your project
2. Guard it against regular builds with `// build +tools` 2. Guard it against regular builds with `// +build tools`
3. Include `_ "git.rootprojects.org/root/go-gitver"` in the imports 3. Include `_ "git.rootprojects.org/root/go-gitver/v2"` in the imports
4. Declare `var GitRev, GitVersion, GitTimestamp string` in your `package main` 4. Declare `var commit, version, date string` in your `package main`
5. Include `//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver` as well 5. Include `//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver/v2` as well
`tools/tools.go`: `tools/tools.go`:
```go ```go
// build +tools // +build tools
// This is a dummy package for build tooling // This is a dummy package for build tooling
package tools package tools
import ( import (
_ "git.rootprojects.org/root/go-gitver" _ "git.rootprojects.org/root/go-gitver/v2"
) )
``` ```
`main.go`: `main.go`:
```go ```go
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver //go:generate go run git.rootprojects.org/root/go-gitver/v2 --fail
package main package main
import "fmt" import "fmt"
var ( var (
GitRev = "0000000" commit = "0000000"
GitVersion = "v0.0.0-pre0+g0000000" version = "0.0.0-pre0+0000000"
GitTimestamp = "0000-00-00T00:00:00+0000" date = "0000-00-00T00:00:00+0000"
) )
func main() { func main() {
fmt.Println(GitRev) fmt.Println(commit)
fmt.Println(GitVersion) fmt.Println(version)
fmt.Println(GitTimestamp) fmt.Println(date)
} }
``` ```
# Behind the curtain If you're using `go mod vendor` (which I highly recommend that you do),
you'd modify the `go:generate` ever so slightly:
```go
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver/v2 --fail
```
The only reason I didn't do that in the example is that I'd be included
the repository in itself and that would be... weird.
# Why a tools package?
> import "git.rootprojects.org/root/go-gitver/v2" is a program, not an importable package
Having a tools package with a build tag that you don't use is a nice way to add exact
versions of a command package used for tooling to your `go.mod` with `go mod tidy`,
without getting the error above.
# git: behind the curtain
These are the commands that are used under the hood to produce the versions. These are the commands that are used under the hood to produce the versions.
@ -87,3 +242,20 @@ Shows the most recent commit.
git rev-parse HEAD git rev-parse HEAD
# 0000000000000000000000000000000000000000 # 0000000000000000000000000000000000000000
``` ```
# Errors
### cannot find package "."
```txt
package git.rootprojects.org/root/go-gitver/v2: cannot find package "." in:
/Users/me/go-example/vendor/git.rootprojects.org/root/go-gitver/v2
cmd/example/example.go:1: running "go": exit status 1
```
You forgot to update deps and re-vendor:
```bash
go mod tidy
go mod vendor
```

32
examples/basic/README.md Normal file
View File

@ -0,0 +1,32 @@
# Example
Prints the version or a nice message
# Build
Typically the developer would perform these steps
and then commit the results (`go.mod`, `go.sum`, `vendor`).
However, since this is an example within the project directory,
that seemed a little redundant.
```bash
go mod tidy
go mod vendor
```
These are the instructions that someone cloning the repo might use.
```bash
go generate -mod=vendor ./...
go build -mod=vendor -o hello *.go
./hello
./hello --version
```
Note: If the source is distributed in a non-git tarball then
`version-generated.go` will not be output, and whatever
version info is in `package main` will remain as-is.
If you would prefer the build process to fail (i.e. in a CI/CD pipeline),
you can set the environment variable `GITVER_FAIL=true`.

5
examples/basic/go.mod Normal file
View File

@ -0,0 +1,5 @@
module example.com/hello
go 1.12
require git.rootprojects.org/root/go-gitver/v2 v2.0.2

View File

@ -1,17 +1,28 @@
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver //go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver/v2 --fail
package main package main
import "fmt" import (
"flag"
"fmt"
)
var ( var (
GitRev = "0000000" commit = "0000000"
GitVersion = "v0.0.0-pre0+0000000" version = "0.0.0-pre0+0000000"
GitTimestamp = "0000-00-00T00:00:00+0000" date = "0000-00-00T00:00:00+0000"
) )
func main() { func main() {
fmt.Println(GitRev) showVersion := flag.Bool("version", false, "Print version and exit")
fmt.Println(GitVersion) flag.Parse()
fmt.Println(GitTimestamp)
if *showVersion {
fmt.Println(commit)
fmt.Println(version)
fmt.Println(date)
return
}
fmt.Println("Hello, World!")
} }

View File

@ -1,8 +1,8 @@
// build +tools // +build tools
// This is a dummy package for build tooling // This is a dummy package for build tooling
package tools package tools
import ( import (
_ "git.rootprojects.org/root/go-gitver" _ "git.rootprojects.org/root/go-gitver/v2"
) )

View File

@ -0,0 +1,25 @@
# Example
Prints the version or a nice message
# Doesn't have a separate tools package
This is just like `examples/basic`,
but it uses a normal file with a build tag
rather than a tools package.
See `examples/basic` for more details.
# Demo
```bash
go mod tidy
go mod vendor
```
```bash
go generate -mod=vendor ./...
go build -mod=vendor -o hello *.go
./hello
./hello --version
```

5
examples/no-tools/go.mod Normal file
View File

@ -0,0 +1,5 @@
module example.com/hello
go 1.12
require git.rootprojects.org/root/go-gitver/v2 v2.0.2

28
examples/no-tools/main.go Normal file
View File

@ -0,0 +1,28 @@
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver/v2 --fail
package main
import (
"flag"
"fmt"
)
var (
commit = "0000000"
version = "0.0.0-pre0+0000000"
date = "0000-00-00T00:00:00+0000"
)
func main() {
showVersion := flag.Bool("version", false, "Print version and exit")
flag.Parse()
if *showVersion {
fmt.Println(commit)
fmt.Println(version)
fmt.Println(date)
return
}
fmt.Println("Hello, World!")
}

View File

@ -0,0 +1,6 @@
// +build tools
// This is a dummy file for build tooling
package main
import _ "git.rootprojects.org/root/go-gitver/v2"

View File

@ -0,0 +1,24 @@
# Example
Prints the version or a nice message
# Doesn't have a separate tools package
This is just like `examples/sub-package` except that its `//go:generate` is in `main.go`
and it outputs `./version/zversion.go` instead of `xversion.go`.
See `examples/basic` for more details.
# Demo
```bash
go mod tidy
go mod vendor
```
```bash
go generate -mod=vendor ./...
go build -mod=vendor -o hello *.go
./hello
./hello --version
```

View File

@ -0,0 +1,5 @@
module example.com/hello
go 1.12
require git.rootprojects.org/root/go-gitver/v2 v2.0.2

View File

@ -0,0 +1,24 @@
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver/v2 --package version --outfile ./version/zversion.go
package main
import (
"flag"
"fmt"
"example.com/hello/version"
)
func main() {
showVersion := flag.Bool("version", false, "Print version and exit")
flag.Parse()
if *showVersion {
fmt.Println(version.Commit())
fmt.Println(version.Version())
fmt.Println(version.Date())
return
}
fmt.Println("Hello, World!")
}

View File

@ -0,0 +1,8 @@
// +build tools
// This is a dummy package for build tooling
package tools
import (
_ "git.rootprojects.org/root/go-gitver/v2"
)

View File

@ -0,0 +1,22 @@
package version
var (
commit = "0000000"
version = "0.0.0-pre0+0000000"
date = "0000-00-00T00:00:00+0000"
)
// Commit returns the git commit reference
func Commit() string {
return commit
}
// Version returns the git version, without the leading 'v'
func Version() string {
return version
}
// Date returns the ISO-formatted date string
func Date() string {
return date
}

View File

@ -0,0 +1,24 @@
# Example
Prints the version or a nice message
# Put version in its own packge
This is just like `examples/basic`,
but it uses the package name `version` instead of `main`.
See `examples/basic` for more details.
# Demo
```bash
go mod tidy
go mod vendor
```
```bash
go generate -mod=vendor ./...
go build -mod=vendor -o hello *.go
./hello
./hello --version
```

View File

@ -0,0 +1,5 @@
module example.com/hello
go 1.12
require git.rootprojects.org/root/go-gitver/v2 v2.0.2

View File

@ -0,0 +1,22 @@
package main
import (
"flag"
"fmt"
"example.com/hello/version"
)
func main() {
showVersion := flag.Bool("version", false, "Print version and exit")
flag.Parse()
if *showVersion {
fmt.Println(version.Commit())
fmt.Println(version.Version())
fmt.Println(version.Date())
return
}
fmt.Println("Hello, World!")
}

View File

@ -0,0 +1,8 @@
// +build tools
// This is a dummy package for build tooling
package tools
import (
_ "git.rootprojects.org/root/go-gitver/v2"
)

View File

@ -0,0 +1,24 @@
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver/v2 --package version
package version
var (
commit = "0000000"
version = "0.0.0-pre0+0000000"
date = "0000-00-00T00:00:00+0000"
)
// Commit returns the git commit reference
func Commit() string {
return commit
}
// Version returns the git version, without the leading 'v'
func Version() string {
return version
}
// Date returns the ISO-formatted date string
func Date() string {
return date
}

168
gitver.go
View File

@ -1,78 +1,71 @@
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver/v2
package main package main
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"go/format" "go/format"
"log"
"os" "os"
"os/exec"
"regexp"
"strconv"
"strings"
"text/template" "text/template"
"time" "time"
"git.rootprojects.org/root/go-gitver/v2/gitver"
) )
var commit, version, date string
var exitCode int var exitCode int
var exactVer *regexp.Regexp var verFile = "xversion.go"
var gitVer *regexp.Regexp
var verFile = "generated-version.go"
var (
GitRev = "0000000"
GitVersion = "v0.0.0-pre0+g0000000"
GitTimestamp = "0000-00-00T00:00:00+0000"
)
func init() {
// exactly vX.Y.Z (go-compatible semver)
exactVer = regexp.MustCompile(`^v\d+\.\d+\.\d+$`)
// vX.Y.Z-n-g0000000 git post-release, semver prerelease
// vX.Y.Z-dirty git post-release, semver prerelease
gitVer = regexp.MustCompile(`^(v\d+\.\d+)\.(\d+)(-(\d+))?(-(g[0-9a-f]+))?(-(dirty))?`)
}
func main() { func main() {
pkg := "main"
args := os.Args[1:] args := os.Args[1:]
for i := range args { for i := range args {
arg := args[i] arg := args[i]
if "-f" == arg || "--fail" == arg { if "-f" == arg || "--fail" == arg {
exitCode = 1 exitCode = 1
} else if ("--outfile" == arg || "-o" == arg) && len(args) > i+1 {
verFile = args[i+1]
args[i+1] = ""
} else if "--package" == arg && len(args) > i+1 {
pkg = args[i+1]
args[i+1] = ""
} else if "-V" == arg || "version" == arg || "-version" == arg || "--version" == arg { } else if "-V" == arg || "version" == arg || "-version" == arg || "--version" == arg {
fmt.Println(GitRev) fmt.Println(commit)
fmt.Println(GitVersion) fmt.Println(version)
fmt.Println(GitTimestamp) fmt.Println(date)
os.Exit(0) os.Exit(0)
} }
} }
if "" != os.Getenv("GITVER_FAIL") && "false" != os.Getenv("GITVER_FAIL") {
exitCode = 1
}
desc, err := gitDesc() v, err := gitver.ExecAndParse()
if nil != err { if nil != err {
log.Fatalf("Failed to get git version: %s\n", err) fmt.Fprintf(os.Stderr, "Failed to get git version: %s\n", err)
if exitCode > 0 {
os.Exit(exitCode) os.Exit(exitCode)
} }
rev := gitRev() v = &gitver.Versions{
ver := semVer(desc) Timestamp: time.Now(),
ts, err := gitTimestamp(desc)
if nil != err {
ts = time.Now()
} }
v := struct {
Timestamp string
Version string
GitRev string
}{
Timestamp: ts.Format(time.RFC3339),
Version: ver,
GitRev: rev,
} }
// Create or overwrite the go file from template // Create or overwrite the go file from template
var buf bytes.Buffer var buf bytes.Buffer
if err := versionTpl.Execute(&buf, v); nil != err { if err := versionTpl.Execute(&buf, struct {
Package string
Timestamp string
Version string
Commit string
}{
Package: pkg,
Timestamp: v.Timestamp.Format(time.RFC3339),
Version: v.Version,
Commit: v.Rev,
}); nil != err {
panic(err) panic(err)
} }
@ -93,92 +86,19 @@ func main() {
if err := f.Close(); nil != err { if err := f.Close(); nil != err {
panic(err) panic(err)
} }
}
func gitDesc() (string, error) {
args := strings.Split("git describe --tags --dirty --always", " ")
cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if nil != err {
// Don't panic, just carry on
//out = []byte("v0.0.0-0-g0000000")
return "", err
}
return strings.TrimSpace(string(out)), nil
}
func gitRev() string {
args := strings.Split("git rev-parse HEAD", " ")
cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if nil != err {
fmt.Fprintf(os.Stderr,
"\nUnexpected Error\n\n"+
"Please open an issue at https://git.rootprojects.org/root/go-gitver/issues/new \n"+
"Please include the following:\n\n"+
"Command: %s\n"+
"Output: %s\n"+
"Error: %s\n"+
"\nPlease and Thank You.\n\n", strings.Join(args, " "), out, err)
os.Exit(exitCode)
}
return strings.TrimSpace(string(out))
}
func semVer(desc string) string {
var ver string
if exactVer.MatchString(desc) {
// v1.0.0
ver = desc
} else if gitVer.MatchString(desc) {
// ((v1.0).(0)-(1))
vers := gitVer.FindStringSubmatch(desc)
patch, err := strconv.Atoi(vers[2])
if nil != err {
fmt.Fprintf(os.Stderr,
"\nUnexpected Error\n\n"+
"Please open an issue at https://git.rootprojects.org/root/go-gitver/issues/new \n"+
"Please include the following:\n\n"+
"git description: %s\n"+
"RegExp: %#v\n"+
"Error: %s\n"+
"\nPlease and Thank You.\n\n", desc, gitVer, err)
os.Exit(exitCode)
}
// v1.0.1-pre1
ver = fmt.Sprintf("%s.%d-pre%s", vers[1], patch+1, vers[4])
fmt.Println(desc, vers)
if "dirty" == vers[8] {
//if strings.Contains(desc, "dirty") {
ver += "+dirty"
}
}
return ver
}
func gitTimestamp(desc string) (time.Time, error) {
args := []string{
"git",
"show", desc,
"--format=%cd",
"--date=format:%Y-%m-%dT%H:%M:%SZ%z",
"--no-patch",
}
cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if nil != err {
// a dirty desc was probably used
return time.Time{}, err
}
return time.Parse(time.RFC3339, strings.TrimSpace(string(out)))
} }
var versionTpl = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT. var versionTpl = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT.
package main package {{ .Package }}
func init() { func init() {
GitRev = "{{ .GitRev }}" {{ if .Commit -}}
GitVersion = "{{ .Version }}" commit = "{{ .Commit }}"
GitTimestamp = "{{ .Timestamp }}" {{ end -}}
{{ if .Version -}}
version = "{{ .Version }}"
{{ end -}}
date = "{{ .Timestamp }}"
} }
`)) `))

154
gitver/gitver.go Normal file
View File

@ -0,0 +1,154 @@
package gitver
import (
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
"time"
)
var exactVer *regexp.Regexp
var gitVer *regexp.Regexp
func init() {
// exactly vX.Y.Z (go-compatible semver)
exactVer = regexp.MustCompile(`^v\d+\.\d+\.\d+$`)
// vX.Y.Z-n-g0000000 git post-release, semver prerelease
// vX.Y.Z-dirty git post-release, semver prerelease
gitVer = regexp.MustCompile(`^(v\d+\.\d+)\.(\d+)(-(\d+))?(-(g[0-9a-f]+))?(-(dirty))?`)
}
// Versions describes the various version properties
type Versions struct {
Timestamp time.Time
Version string
Rev string
}
// ExecAndParse will run git and parse the output
func ExecAndParse() (*Versions, error) {
desc, err := gitDesc()
if nil != err {
return nil, err
}
rev, err := gitRev()
if nil != err {
return nil, err
}
ver, err := semVer(desc)
if nil != err {
return nil, err
}
ts, err := gitTimestamp(desc)
if nil != err {
ts = time.Now()
}
return &Versions{
Timestamp: ts,
Version: ver,
Rev: rev,
}, nil
}
func gitDesc() (string, error) {
args := strings.Split("git describe --tags --dirty --always", " ")
cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if nil != err {
// Don't panic, just carry on
//out = []byte("0.0.0-0-g0000000")
return "", err
}
return strings.TrimSpace(string(out)), nil
}
func gitRev() (string, error) {
args := strings.Split("git rev-parse HEAD", " ")
cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if nil != err {
return "", fmt.Errorf("\nUnexpected Error\n\n"+
"Please open an issue at https://git.rootprojects.org/root/go-gitver/issues/new \n"+
"Please include the following:\n\n"+
"Command: %s\n"+
"Output: %s\n"+
"Error: %s\n"+
"\nPlease and Thank You.\n\n", strings.Join(args, " "), out, err)
}
return strings.TrimSpace(string(out)), nil
}
func semVer(desc string) (string, error) {
if exactVer.MatchString(desc) {
// v1.0.0
return strings.TrimPrefix(desc, "v"), nil
}
if !gitVer.MatchString(desc) {
return "", nil
}
// (v1.0).(0)(-(1))(-(g0000000))(-(dirty))
vers := gitVer.FindStringSubmatch(desc)
patch, err := strconv.Atoi(vers[2])
if nil != err {
return "", fmt.Errorf("\nUnexpected Error\n\n"+
"Please open an issue at https://git.rootprojects.org/root/go-gitver/issues/new \n"+
"Please include the following:\n\n"+
"git description: %s\n"+
"RegExp: %#v\n"+
"Error: %s\n"+
"\nPlease and Thank You.\n\n", desc, gitVer, err)
}
// v1.0.1-pre1
// v1.0.1-pre1+g0000000
// v1.0.1-pre0+dirty
// v1.0.1-pre0+g0000000-dirty
if "" == vers[4] {
vers[4] = "0"
}
ver := fmt.Sprintf("%s.%d-pre%s", vers[1], patch+1, vers[4])
if "" != vers[6] || "dirty" == vers[8] {
ver += "+"
if "" != vers[6] {
ver += vers[6]
if "" != vers[8] {
ver += "-"
}
}
ver += vers[8]
}
return strings.TrimPrefix(ver, "v"), nil
}
func gitTimestamp(desc string) (time.Time, error) {
// Other options:
//
// Commit Date
// git log -1 --format=%cd --date=format:%Y-%m-%dT%H:%M:%SZ%z
//
// Author Date
// git log -1 --format=%ad --date=format:%Y-%m-%dT%H:%M:%SZ%z
//
// I think I chose this because it would account for dirty-ness better... maybe?
args := []string{
"git",
"show", desc,
"--format=%cd",
"--date=format:%Y-%m-%dT%H:%M:%SZ%z",
"--no-patch",
}
cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if nil != err {
// a dirty desc was probably used
return time.Time{}, err
}
return time.Parse(time.RFC3339, strings.TrimSpace(string(out)))
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module git.rootprojects.org/root/go-gitver/v2
go 1.12

0
go.sum Normal file
View File

9
version.go Normal file
View File

@ -0,0 +1,9 @@
package main
// use recently generated version info as a fallback
// for when git isn't present (i.e. go run <url>)
func init() {
commit = "37c1fd4b5694fd62c9f0d6ad1df47d938accbeec"
version = "2.0.0-pre1-dirty"
date = "2020-10-10T16:05:59-06:00"
}