mirror of
				https://github.com/therootcompany/go-gitver.git
				synced 2025-10-31 04:32:49 +00:00 
			
		
		
		
	WIP, nae nae
This commit is contained in:
		
							parent
							
								
									e4a0e9576b
								
							
						
					
					
						commit
						60debf802f
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,5 @@ | |||||||
|  | generated-version.go | ||||||
|  | 
 | ||||||
| # ---> Go | # ---> Go | ||||||
| # Binaries for programs and plugins | # Binaries for programs and plugins | ||||||
| *.exe | *.exe | ||||||
|  | |||||||
							
								
								
									
										70
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								README.md
									
									
									
									
									
								
							| @ -1,3 +1,71 @@ | |||||||
| # git-version.go | # git-version.go | ||||||
| 
 | 
 | ||||||
| Use git tags to add semver to your go package. | Use git tags to add semver to your go package. | ||||||
|  | 
 | ||||||
|  | >     Goal: Either use an exact version like v1.0.0 | ||||||
|  | >           or translate the git version like v1.0.0-4-g0000000 | ||||||
|  | >           to a semver like v1.0.1-pre4+g0000000 | ||||||
|  | > | ||||||
|  | >           Fail gracefully when git repo isn't available. | ||||||
|  | 
 | ||||||
|  | # Demo | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | go run git.rootprojects.org/root/go-gitver | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # 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 -mod=vendor git.rootprojects.org/root/go-gitver | ||||||
|  | 
 | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import "fmt" | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  |   GitRev = "0000000" | ||||||
|  |   GitVersion = "v0.0.0-pre0+g0000000" | ||||||
|  |   GitTimestamp = "0000-00-00T00:00:00+0000" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  |   fmt.Println(GitRev) | ||||||
|  |   fmt.Println(GitVersion) | ||||||
|  |   fmt.Println(GitTimestamp) | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Behind the curtain | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | git describe --tags --dirty --always | ||||||
|  | # v1.0.0 | ||||||
|  | # v1.0.0-1 | ||||||
|  | 
 | ||||||
|  | git log --format='format:%cI' -n 1 --since=(git describe --tags --dirty --always) | ||||||
|  | git rev-parse HEAD | ||||||
|  | ``` | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								examples/basic/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								examples/basic/main.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | //go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver | ||||||
|  | 
 | ||||||
|  | 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) | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								examples/basic/tools/tools.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								examples/basic/tools/tools.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | // build +tools | ||||||
|  | 
 | ||||||
|  | // This is a dummy package for build tooling | ||||||
|  | package tools | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	_ "git.rootprojects.org/root/go-gitver" | ||||||
|  | ) | ||||||
							
								
								
									
										166
									
								
								gitver.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								gitver.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | |||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"go/format" | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | 	"os/exec" | ||||||
|  | 	"regexp" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | 	"text/template" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var exitCode int | ||||||
|  | var exactVer *regexp.Regexp | ||||||
|  | var gitVer *regexp.Regexp | ||||||
|  | var verFile = "generated-version.go" | ||||||
|  | 
 | ||||||
|  | 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+)-)?(dirty|g)`) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  | 	args := os.Args[1:] | ||||||
|  | 	for i := range args { | ||||||
|  | 		arg := args[i] | ||||||
|  | 		if "-f" == arg || "--fail" == arg { | ||||||
|  | 			exitCode = 1 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	desc, err := gitDesc() | ||||||
|  | 	if nil != err { | ||||||
|  | 		log.Fatalf("Failed to get git version: %s\n", err) | ||||||
|  | 		os.Exit(exitCode) | ||||||
|  | 	} | ||||||
|  | 	rev := gitRev() | ||||||
|  | 	ver := semVer(desc) | ||||||
|  | 	ts, err := gitTimestamp(desc) | ||||||
|  | 	if nil != err { | ||||||
|  | 		fmt.Println("badtimes", err) // TODO remove | ||||||
|  | 		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 | ||||||
|  | 	var buf bytes.Buffer | ||||||
|  | 	if err := versionTpl.Execute(&buf, v); nil != err { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Format | ||||||
|  | 	src, err := format.Source(buf.Bytes()) | ||||||
|  | 	if nil != err { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Write to disk (in the Current Working Directory) | ||||||
|  | 	f, err := os.Create(verFile) | ||||||
|  | 	if nil != err { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	if _, err := f.Write(src); nil != err { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	if err := f.Close(); nil != 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]) | ||||||
|  | 	} | ||||||
|  | 	return ver | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func gitTimestamp(desc string) (time.Time, error) { | ||||||
|  | 	args := strings.Split(fmt.Sprintf("git show %s --format='format:%%cI' --no-patch", desc), " ") | ||||||
|  | 	cmd := exec.Command(args[0], args[1:]...) | ||||||
|  | 	out, err := cmd.CombinedOutput() | ||||||
|  | 	fmt.Printf("foo:\n%#v\n", args) | ||||||
|  | 	fmt.Printf("bar:\n%s\n", strings.Join(args, " ")) | ||||||
|  | 	fmt.Println("baz:\n", string(out), err) | ||||||
|  | 	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. | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	GitRev = "{{ .GitRev }}" | ||||||
|  | 	GitVersion = "{{ .Version }}" | ||||||
|  | 	GitTimestamp = "{{ .Timestamp }}" | ||||||
|  | } | ||||||
|  | `)) | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user