249 lines
5.4 KiB
Markdown
249 lines
5.4 KiB
Markdown
# git-version.go
|
|
|
|
Use **git tags** to add [**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).
|
|
|
|
```txt
|
|
Goals:
|
|
|
|
1. Use an exact `git tag` version, like v1.0.0, when clean
|
|
2. Translate the `git describe` version (v1.0.0-4-g0000000)
|
|
to semver (v1.0.1-pre4+g0000000) in between releases
|
|
3. Note when `dirty` (and have build timestamp)
|
|
|
|
Fail gracefully when git repo isn't available.
|
|
```
|
|
|
|
# How it works
|
|
|
|
1. You define the fallback version and version printing in `main.go`:
|
|
|
|
```
|
|
package main
|
|
|
|
var (
|
|
GitRev = "0000000"
|
|
GitVersion = "v0.0.0-pre0+0000000"
|
|
GitTimestamp = "0000-00-00T00:00:00+0000"
|
|
)
|
|
|
|
func main() {
|
|
if (len(os.Args) > 1 && "version" === os.Args[1]) {
|
|
fmt.Println("My version is", GitVersion, "created at", GitTimestamp)
|
|
}
|
|
// ...
|
|
}
|
|
```
|
|
|
|
2. You `go generate` or `go run git.rootprojects.org/root/go-gitver` to generate `xversion.go`:
|
|
|
|
```
|
|
package main
|
|
|
|
func init() {
|
|
GitRev = "0921ed1e"
|
|
GitVersion = "v1.1.2"
|
|
GitTimestamp = "2019-07-01T02:32:58-06:00"
|
|
}
|
|
```
|
|
|
|
# Demo
|
|
|
|
Generate an `xversion.go` file:
|
|
|
|
```bash
|
|
go run git.rootprojects.org/root/go-gitver
|
|
cat xversion.go
|
|
```
|
|
|
|
```go
|
|
// Code generated by go generate; DO NOT EDIT.
|
|
package main
|
|
|
|
func init() {
|
|
GitRev = "6dace8255b52e123297a44629bc32c015add310a"
|
|
GitVersion = "v1.1.4-pre2+g6dace82"
|
|
GitTimestamp = "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 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
|
|
|
|
```
|
|
|
|
Add a file that imports go-gitver (for versioning)
|
|
|
|
```go
|
|
// +build tools
|
|
|
|
package example
|
|
|
|
import _ "git.rootprojects.org/root/go-gitver"
|
|
```
|
|
|
|
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 --fail
|
|
|
|
```
|
|
|
|
```bash
|
|
go run -mod=vendor git.rootprojects.org/root/go-gitver version
|
|
```
|
|
|
|
# Usage
|
|
|
|
See `examples/basic`
|
|
|
|
1. Create a `tools` package in your project
|
|
2. Guard it against regular builds with `// +build tools`
|
|
3. Include `_ "git.rootprojects.org/root/go-gitver"` in the imports
|
|
4. Declare `var GitRev, GitVersion, GitTimestamp string` in your `package main`
|
|
5. Include `//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver` as well
|
|
|
|
`tools/tools.go`:
|
|
|
|
```go
|
|
// +build tools
|
|
|
|
// This is a dummy package for build tooling
|
|
package tools
|
|
|
|
import (
|
|
_ "git.rootprojects.org/root/go-gitver"
|
|
)
|
|
```
|
|
|
|
`main.go`:
|
|
|
|
```go
|
|
//go:generate go run git.rootprojects.org/root/go-gitver --fail
|
|
|
|
package main
|
|
|
|
import "fmt"
|
|
|
|
var (
|
|
GitRev = "0000000"
|
|
GitVersion = "v0.0.0-pre0+0000000"
|
|
GitTimestamp = "0000-00-00T00:00:00+0000"
|
|
)
|
|
|
|
func main() {
|
|
fmt.Println(GitRev)
|
|
fmt.Println(GitVersion)
|
|
fmt.Println(GitTimestamp)
|
|
}
|
|
```
|
|
|
|
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 --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" 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.
|
|
|
|
Shows the git tag + description. Assumes that you're using the semver format `v1.0.0` for your base tags.
|
|
|
|
```bash
|
|
git describe --tags --dirty --always
|
|
# v1.0.0
|
|
# v1.0.0-1-g0000000
|
|
# v1.0.0-dirty
|
|
```
|
|
|
|
Show the commit date (when the commit made it into the current tree).
|
|
Internally we use the current date when the working tree is dirty.
|
|
|
|
```bash
|
|
git show v1.0.0-1-g0000000 --format=%cd --date=format:%Y-%m-%dT%H:%M:%SZ%z --no-patch
|
|
# 2010-01-01T20:30:00Z-0600
|
|
# fatal: ambiguous argument 'v1.0.0-1-g0000000-dirty': unknown revision or path not in the working tree.
|
|
```
|
|
|
|
Shows the most recent commit.
|
|
|
|
```bash
|
|
git rev-parse HEAD
|
|
# 0000000000000000000000000000000000000000
|
|
```
|
|
|
|
# Errors
|
|
|
|
### cannot find package "."
|
|
|
|
```txt
|
|
package git.rootprojects.org/root/go-gitver: cannot find package "." in:
|
|
/Users/me/go-example/vendor/git.rootprojects.org/root/go-gitver
|
|
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
|
|
```
|