Skip to content

Commit

Permalink
Allow specifying a specific version
Browse files Browse the repository at this point in the history
This works better with tools that want you to pass in the version
number, instead of automatically incrementing it based on what's in
the file. An example of this is in a Makefile where I want to do four
different things with the same version number - it's difficult to
get the version number from this program and then pass it all of the
places it's needed, it's easier to just pass it in and use everywhere.

Updates the successful output to be only the new version number and
a newline. Refactors the code to be more modular and adds a new
SetInFile method for setting a given version number in a file.
  • Loading branch information
kevinburke committed Feb 22, 2018
1 parent 50edb79 commit 34aa0b0
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 44 deletions.
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ STATICCHECK := $(shell command -v staticcheck)
install:
go install ./...

test:
lint:
ifndef STATICCHECK
go get -u honnef.co/go/tools/cmd/staticcheck
endif
go vet ./...
staticcheck ./...

test: lint
go test -race ./... -timeout 1s

release: install test
Expand Down
86 changes: 58 additions & 28 deletions lib/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,46 +132,76 @@ func changeVersion(vtype VersionType, value string) (*Version, error) {
return version, nil
}

// BumpInFile finds a constant named VERSION, version, or Version in the file
// with the given filename, increments the version per the given VersionType,
// and writes the file back to disk. Returns the incremented Version object.
func BumpInFile(vtype VersionType, filename string) (*Version, error) {
fset := token.NewFileSet()
parsedFile, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
if err != nil {
return nil, err
}
for _, decl := range parsedFile.Decls {
func findBasicLit(file *ast.File) (*ast.BasicLit, error) {
for _, decl := range file.Decls {
switch gd := decl.(type) {
case *ast.GenDecl:
if gd.Tok != token.CONST {
continue
}
spec, _ := gd.Specs[0].(*ast.ValueSpec)
if strings.ToUpper(spec.Names[0].Name) == "VERSION" {
value, _ := spec.Values[0].(*ast.BasicLit)
if value.Kind != token.STRING {
value, ok := spec.Values[0].(*ast.BasicLit)
if !ok || value.Kind != token.STRING {
return nil, fmt.Errorf("VERSION is not a string, was %#v\n", value.Value)
}
version, err := changeVersion(vtype, value.Value)
if err != nil {
return nil, err
}
value.Value = fmt.Sprintf("\"%s\"", version.String())
f, err := os.Create(filename)
if err != nil {
return nil, err
}
cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
err = cfg.Fprint(f, fset, parsedFile)
if err != nil {
return nil, err
}
return version, nil
return value, nil
}
default:
continue
}
}
return nil, fmt.Errorf("No VERSION const found in %s", filename)
return nil, errors.New("bump_version: No version const found")
}

func writeFile(filename string, fset *token.FileSet, file *ast.File) error {
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
return cfg.Fprint(f, fset, file)
}

func changeInFile(filename string, f func(*ast.BasicLit) error) error {
fset := token.NewFileSet()
parsedFile, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
if err != nil {
return err
}
lit, err := findBasicLit(parsedFile)
if err != nil {
return fmt.Errorf("No Version const found in %s", filename)
}
if err := f(lit); err != nil {
return err
}
writeErr := writeFile(filename, fset, parsedFile)
return writeErr
}

// SetInFile sets the version in filename to newVersion.
func SetInFile(newVersion *Version, filename string) error {
return changeInFile(filename, func(lit *ast.BasicLit) error {
lit.Value = fmt.Sprintf("\"%s\"", newVersion.String())
return nil
})
}

// BumpInFile finds a constant named VERSION, version, or Version in the file
// with the given filename, increments the version per the given VersionType,
// and writes the file back to disk. Returns the incremented Version object.
func BumpInFile(vtype VersionType, filename string) (*Version, error) {
var version *Version
err := changeInFile(filename, func(lit *ast.BasicLit) error {
var err error
version, err = changeVersion(vtype, lit.Value)
if err != nil {
return err
}
lit.Value = fmt.Sprintf("\"%s\"", version.String())
return nil
})
return version, err
}
55 changes: 40 additions & 15 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"flag"
"fmt"
"log"
"os"
"os/exec"

Expand All @@ -13,36 +12,62 @@ import (
const VERSION = "1.2"

func usage() {
fmt.Fprintf(os.Stderr, "Usage: bump_version <major|minor|patch> <filename>\n")
fmt.Fprintf(os.Stderr, "Usage: bump_version [--version=<version>] [<major|minor|patch>] <filename>\n")
flag.PrintDefaults()
}

// runCommand execs the given command and exits if it fails.
func runCommand(binary string, args ...string) {
out, err := exec.Command(binary, args...).CombinedOutput()
if err != nil {
log.Fatalf("Error when running command: %s.\nOutput was:\n%s", err.Error(), string(out))
fmt.Fprintf(os.Stderr, "Error when running command: %s.\nOutput was:\n%s", err.Error(), string(out))
os.Exit(2)
}
}

var vsn = flag.String("version", "", "Set this version in the file (don't increment whatever version is present)")

func main() {
flag.Usage = usage
flag.Parse()
args := flag.Args()
if len(args) != 2 {
usage()
os.Exit(2)
}
versionTypeStr := args[0]
filename := args[1]

version, err := bump_version.BumpInFile(bump_version.VersionType(versionTypeStr), filename)
if err != nil {
log.Fatal(err)
var filename string
var version *bump_version.Version
if *vsn != "" {
// no "minor"
if len(args) != 1 {
flag.Usage()
return
}
var err error
version, err = bump_version.Parse(*vsn)
if err != nil {
os.Stderr.WriteString(err.Error())
os.Exit(2)
}
filename = args[0]
setErr := bump_version.SetInFile(version, filename)
if setErr != nil {
os.Stderr.WriteString(setErr.Error() + "\n")
os.Exit(2)
}
} else {
fmt.Fprintf(os.Stderr, "Bumped version to %s\n", version)
if len(args) != 2 {
flag.Usage()
return
}
versionTypeStr := args[0]
filename = args[1]

var err error
version, err = bump_version.BumpInFile(bump_version.VersionType(versionTypeStr), filename)
if err != nil {
os.Stderr.WriteString(err.Error() + "\n")
os.Exit(2)
}
}
runCommand("git", "add", filename)
runCommand("git", "commit", "-m", version.String())
runCommand("git", "tag", version.String(), "--annotate", "--message", version.String())
fmt.Fprintf(os.Stderr, "Added new commit and tagged version %s.\n", version)
os.Stdout.WriteString(version.String() + "\n")
}

0 comments on commit 34aa0b0

Please sign in to comment.