summaryrefslogtreecommitdiffstatshomepage
path: root/version.go
blob: de9bd8753b6d0b82a803e9031fc96167b3ec066c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package main

import (
	"errors"
	"fmt"
	"runtime/debug"
	"strings"

	"github.com/git-bug/git-bug/commands"
	"golang.org/x/mod/semver"
)

var (
	version = "undefined"
)

// getVersion returns a string representing the version information defined when
// the binary was built, or a sane default indicating a local build. a string is
// always returned. an error may be returned along with the string in the event
// that we detect a local build but are unable to get build metadata.
//
// TODO: support validation of the version (that it's a real version)
// TODO: support notifying the user if their version is out of date
func getVersion() (string, error) {
	var arch string
	var commit string
	var modified bool
	var platform string

	var v strings.Builder

	// this supports overriding the default version if the deprecated var used
	// for setting the exact version for releases is supplied. we are doing this
	// in order to give downstream package maintainers a longer window to
	// migrate.
	//
	// TODO: 0.12.0: remove support for old build tags
	if version == "undefined" && commands.GitExactTag != "" {
		version = commands.GitExactTag
	}

	// automatically add the v prefix if it's missing
	if version != "undefined" && !strings.HasPrefix(version, "v") {
		version = fmt.Sprintf("v%s", version)
	}

	// reset the version string to undefined if it is invalid
	if ok := semver.IsValid(version); !ok {
		version = "undefined"
	}

	v.WriteString(version)

	info, ok := debug.ReadBuildInfo()
	if !ok {
		v.WriteString(fmt.Sprintf(" (no build info)\n"))
		return v.String(), errors.New("unable to read build metadata")
	}

	for _, kv := range info.Settings {
		switch kv.Key {
		case "GOOS":
			platform = kv.Value
		case "GOARCH":
			arch = kv.Value
		case "vcs.modified":
			if kv.Value == "true" {
				modified = true
			}
		case "vcs.revision":
			commit = kv.Value
		}
	}

	if commit != "" {
		v.WriteString(fmt.Sprintf(" %.12s", commit))
	}

	if modified {
		v.WriteString("/dirty")
	}

	v.WriteString(fmt.Sprintf(" %s", info.GoVersion))

	if platform != "" {
		v.WriteString(fmt.Sprintf(" %s", platform))
	}

	if arch != "" {
		v.WriteString(fmt.Sprintf(" %s", arch))
	}

	return fmt.Sprint(v.String(), "\n"), nil
}