Application auto build versioning

后端 未结 6 798
情话喂你
情话喂你 2020-11-28 00:25

Is it possible to increment a minor version number automatically each time a Go app is compiled?

I would like to set a version number inside my program, with an auto

相关标签:
6条回答
  • 2020-11-28 00:32

    Additionally I would like to post a small example how to use git and a makefile:

    --- Makefile ----
    
    # This how we want to name the binary output
    BINARY=gomake
    
    # These are the values we want to pass for VERSION and BUILD
    # git tag 1.0.1
    # git commit -am "One more change after the tags"
    VERSION=`git describe --tags`
    BUILD=`date +%FT%T%z`
    
    # Setup the -ldflags option for go build here, interpolate the variable values
    LDFLAGS_f1=-ldflags "-w -s -X main.Version=${VERSION} -X main.Build=${BUILD} -X main.Entry=f1"
    LDFLAGS_f2=-ldflags "-w -s -X main.Version=${VERSION} -X main.Build=${BUILD} -X main.Entry=f2"
    
    # Builds the project
    build:
        go build ${LDFLAGS_f1} -o ${BINARY}_f1
        go build ${LDFLAGS_f2} -o ${BINARY}_f2
    
    # Installs our project: copies binaries
    install:
        go install ${LDFLAGS_f1}
    
    # Cleans our project: deletes binaries
    clean:
        if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi
    
    .PHONY: clean install
    

    The make file will create two executables. One is executing function one, the other will take function two as main entry:

    package main
    
    import (
            "fmt"
    )
    
    var (
    
            Version string
            Build   string
            Entry   string
    
            funcs = map[string]func() {
                    "f1":functionOne,"f2":functionTwo,
            }
    
    )
    
    func functionOne() {
        fmt.Println("This is function one")
    }
    
    func functionTwo() {
        fmt.Println("This is function two")
    }
    
    func main() {
    
            fmt.Println("Version: ", Version)
            fmt.Println("Build Time: ", Build)
    
        funcs[Entry]()
    
    }
    

    Then just run:

    make
    

    You will get:

    mab@h2470988:~/projects/go/gomake/3/gomake$ ls -al
    total 2020
    drwxrwxr-x 3 mab mab    4096 Sep  7 22:41 .
    drwxrwxr-x 3 mab mab    4096 Aug 16 10:00 ..
    drwxrwxr-x 8 mab mab    4096 Aug 17 16:40 .git
    -rwxrwxr-x 1 mab mab 1023488 Sep  7 22:41 gomake_f1
    -rwxrwxr-x 1 mab mab 1023488 Sep  7 22:41 gomake_f2
    -rw-rw-r-- 1 mab mab     399 Aug 16 10:21 main.go
    -rw-rw-r-- 1 mab mab     810 Sep  7 22:41 Makefile
    mab@h2470988:~/projects/go/gomake/3/gomake$ ./gomake_f1
    Version:  1.0.1-1-gfb51187
    Build Time:  2016-09-07T22:41:38+0200
    This is function one
    mab@h2470988:~/projects/go/gomake/3/gomake$ ./gomake_f2
    Version:  1.0.1-1-gfb51187
    Build Time:  2016-09-07T22:41:39+0200
    This is function two
    
    0 讨论(0)
  • 2020-11-28 00:34

    I had trouble using the -ldflags parameter when building my mixed command-line app and library project, so I ended up using a Makefile target to generate a Go source file containing my app's version and the build date:

    BUILD_DATE := `date +%Y-%m-%d\ %H:%M`
    VERSIONFILE := cmd/myapp/version.go
    
    gensrc:
        rm -f $(VERSIONFILE)
        @echo "package main" > $(VERSIONFILE)
        @echo "const (" >> $(VERSIONFILE)
        @echo "  VERSION = \"1.0\"" >> $(VERSIONFILE)
        @echo "  BUILD_DATE = \"$(BUILD_DATE)\"" >> $(VERSIONFILE)
        @echo ")" >> $(VERSIONFILE)
    

    In my init() method, I do this:

    flag.Usage = func() {
        fmt.Fprintf(os.Stderr, "%s version %s\n", os.Args[0], VERSION)
        fmt.Fprintf(os.Stderr, "built %s\n", BUILD_DATE)
        fmt.Fprintln(os.Stderr, "usage:")
        flag.PrintDefaults()
    }
    

    If you wanted an atomically-increasing build number instead of a build date, however, you would probably need to create a local file that contained the last build number. Your Makefile would read the file contents into a variable, increment it, insert it in the version.go file instead of the date, and write the new build number back to the file.

    0 讨论(0)
  • 2020-11-28 00:49

    On Windows OS given the program below

    package main
    
    import "fmt"
    
    var (
        version string
        date    string
    )
    
    func main() {
        fmt.Printf("version=%s, date=%s", version, date)
    }
    

    You can build using

    go build -ldflags "-X main.version=0.0.1 -X main.date=%date:~10,4%-%date:~4,2%-%date:~7,2%T%time:~0,2%:%time:~3,2%:%time:~6,2%"
    

    Date format assumes your environment echo %date% is Fri 07/22/2016 and echo %time% is 16:21:52.88

    Then the output will be: version=0.0.1, date=2016-07-22T16:21:52

    0 讨论(0)
  • 2020-11-28 00:51

    The Go linker (go tool link) has an option to set the value of an uninitialised string variable:

    -X importpath.name=value
      Set the value of the string variable in importpath named name to
    

    value. Note that before Go 1.5 this option took two separate arguments. Now it takes one argument split on the first = sign.

    As part of your build process, you could set a version string variable using this. You can pass this through the go tool using -ldflags. For example, given the following source file:

    package main
    
    import "fmt"
    
    var xyz string
    
    func main() {
        fmt.Println(xyz)
    }
    

    Then:

    $ go run -ldflags "-X main.xyz=abc" main.go
    abc
    

    In order to set main.minversion to the build date and time when building:

    go build -ldflags "-X main.minversion=`date -u +.%Y%m%d.%H%M%S`" service.go
    

    If you compile without initializing main.minversion in this way, it will contain the empty string.

    0 讨论(0)
  • 2020-11-28 00:51

    to use multi -ldflags:

    $ go build -ldflags "-X name1=value1 -X name2=value2" -o path/to/output
    
    0 讨论(0)
  • 2020-11-28 00:56

    Use ldflags to set variables in main package:

    With file main.go:

    package main
    
    import "fmt"
    
    var (
        version string
        build   string
    )
    
    func main() {
        fmt.Println("version=", version)
        fmt.Println("build=", build)
    }
    

    Then run:

    go run \
      -ldflags "-X main.version=1.0.0 -X main.build=12082019" \ 
      main.go
    

    Build:

    go build -o mybinary \
      -ldflags "-X main.version=1.0.0 -X 'main.build=$(date)'" \ 
      main.go
    

    Use ldflags to set variable in a non-main package:

    With file config.go:

    package config
    
    import "fmt"
    
    var (
        Version string
    )
    
    func LogVersion() {
        fmt.Println("version=", Version)
    }
    

    You will also need file main.go:

    package main
    
    import (
        "fmt"
        "github.com/user/repo/config"
    }
    
    func main() {
        config.LogVersion()
    }
    

    Build your binary first:

    go build -o mybinary main.go 
    

    Find the full path of variable name you want to set:

    go tool nm <path_to_binary> | grep Version
    

    Run and build the binary again but with the ldflags:

    go run \
      -ldflags "-X github.com/user/repo/config.Version=1.0.0" \
      main.go --version       
    
    
    go build -o mybinary \
      -ldflags "-X github.com/user/repo/config.Version=1.0.0" \
      main.go     
    

    Inspired by https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable


    Also if you are using goreleaser then read this https://goreleaser.com/environment/#using-the-mainversion :

    Default wise GoReleaser sets three ldflags:

    main.version: Current Git tag
    main.commit: Current git commit SHA
    main.date: Date according RFC3339


    If you want to see this in action: https://github.com/hoto/fuzzy-repo-finder/blob/master/pkg/config/config.go

    0 讨论(0)
提交回复
热议问题