231 votes

Versioning automatique des applications

Est-il possible d'incrémenter automatiquement un numéro de version mineure à chaque fois qu'une application Go est compilée ?

Je voudrais définir un numéro de version dans mon programme, avec une section d'auto-incrémentation :

$ myapp -version
MyApp version 0.5.132

Étant 0.5 le numéro de version que j'ai défini, et 132 une valeur qui s'incrémente automatiquement à chaque fois que le binaire est compilé.

Est-ce possible en Go ?

377voto

axw Points 2630

Le linker Go ( lien vers l'outil ) a une option pour définir la valeur d'une variable chaîne non initialisée :

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

valeur. Notez qu'avant Go 1.5, cette option prenait deux arguments séparés. Maintenant, elle prend un argument séparé sur le premier signe =.

Dans le cadre de votre processus de construction, vous pouvez définir une variable de chaîne de version en utilisant ceci. Vous pouvez la faire passer par la fonction go outil utilisant -ldflags . Par exemple, étant donné le fichier source suivant :

package main

import "fmt"

var xyz string

func main() {
    fmt.Println(xyz)
}

Ensuite :

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

Afin d'établir main.minversion à la date et à l'heure de construction lors de la construction :

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

Si vous compilez sans initialiser main.minversion de cette manière, il contiendra la chaîne vide.

4 votes

Cette valeur sera-t-elle sauvegardée dans le binaire si j'utilise la fonction go bouild au lieu de go run ?

6 votes

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

0 votes

Cela ne semble pas fonctionner pour moi dans Go 1.1.1 : $ go run -ldflags "-X main.xyz abc" main.go -> go run: no go files listed

41voto

Hoto Points 395

Utilisez ldflags pour définir des variables dans main paquet :

Avec dossier main.go :

package main

import "fmt"

var (
    version string
    build   string
)

func main() {
    fmt.Println("version=", version)
    fmt.Println("build=", build)
}

Alors cours :

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

Construire :

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

Utilisez ldflags pour définir une variable dans un non-main paquet :

Avec dossier config.go :

package config

import "fmt"

var (
    Version string
)

func LogVersion() {
    fmt.Println("version=", Version)
}

Vous aurez également besoin du fichier main.go :

package main

import (
    "fmt"
    "github.com/user/repo/config"
}

func main() {
    config.LogVersion()
}

Construisez d'abord votre binaire :

go build -o mybinary main.go 

Trouvez le chemin complet du nom de la variable que vous voulez définir :

go tool nm <path_to_binary> | grep Version

Exécutez et construisez à nouveau le binaire mais avec l'option 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     

Inspiré par https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable


De même, si vous utilisez goreleaser alors lisez ceci https://goreleaser.com/environment/#using-the-mainversion :

Par défaut, GoReleaser définit trois ldflags :

main.version : Balise Git actuelle
main.commit : Git commit actuel SHA
main.date : Date selon RFC3339


Si vous voulez voir ça en action : https://github.com/hoto/fuzzy-repo-finder/blob/master/pkg/config/config.go

34voto

LITERADIX Points 102

En outre, je voudrais poster un petit exemple d'utilisation de git et d'un 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

Le fichier make va créer deux exécutables. L'un exécute la fonction 1, l'autre prendra la fonction 2 comme entrée principale :

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]()

}

Alors, courez :

make

Vous aurez :

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

28voto

pegli Points 91

J'ai eu du mal à utiliser le -ldflags lors de la construction de mon projet mixte d'application et de bibliothèque en ligne de commande, j'ai donc fini par utiliser une cible Makefile pour générer un fichier source Go contenant la version de mon application et la date de construction :

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)

Dans mon init() méthode, je fais ça :

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()
}

Si vous vouliez un numéro de build augmentant de façon atomique au lieu d'une date de build, cependant, vous auriez probablement besoin de créer un fichier local contenant le dernier numéro de build. Votre Makefile lira le contenu du fichier dans une variable, l'incrémentera, l'insérera dans la variable version.go au lieu de la date, et réécrire le nouveau numéro de construction dans le fichier.

2 votes

Bonne solution. Cependant, je pense avoir trouvé la raison des problèmes liés à -ldflags. Si le fichier contenant la variable mise à jour par -X n'est pas touché, alors la compilation ne se déclenche pas et vous avez une ancienne version dans le binaire. Ma solution a été de toucher un petit fichier contenant uniquement la variable qui est réinitialisée via -ldflags "-X ...".

13voto

Ostati Points 654

Sous Windows OS, donnez le programme ci-dessous

package main

import "fmt"

var (
    version string
    date    string
)

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

Vous pouvez construire en utilisant

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%"

Le format de la date suppose votre environnement echo %date% est Fri 07/22/2016 et echo %time% est 16:21:52.88

Alors la sortie sera : version=0.0.1, date=2016-07-22T16:21:52

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X