Control de versiones de creación automática de aplicaciones
¿Es posible incrementar automáticamente un número de versión menor cada vez que se compila una aplicación Go?
Me gustaría establecer un número de versión dentro de mi programa, con una sección de incremento automático:
$ myapp -version
MyApp version 0.5.132
Siendo 0.5 el número de versión que configuré y 132 un valor que se incrementa automáticamente cada vez que se compila el binario.
¿Es esto posible en Go?
El vinculador Go ( enlace de herramienta go ) tiene una opción para establecer el valor de una variable de cadena no inicializada:
-X importpath.name=value Set the value of the string variable in importpath named name to
valor. Tenga en cuenta que antes de Go 1.5 esta opción tenía dos argumentos separados. Ahora se necesita un argumento dividido en el primer signo =.
Como parte de su proceso de compilación, puede configurar una variable de cadena de versión usando esto. Puede pasar esto a través de la go
herramienta usando -ldflags
. Por ejemplo, dado el siguiente archivo fuente:
package main
import "fmt"
var xyz string
func main() {
fmt.Println(xyz)
}
Entonces:
$ go run -ldflags "-X main.xyz=abc" main.go
abc
Para establecer main.minversion
la fecha y hora de construcción al construir:
go build -ldflags "-X main.minversion=`date -u +.%Y%m%d.%H%M%S`" service.go
Si compila sin inicializar main.minversion
de esta manera, contendrá la cadena vacía.
Úselo ldflags
para establecer variables en el main
paquete:
Con archivo main.go
:
package main
import "fmt"
var (
version string
build string
)
func main() {
fmt.Println("version=", version)
fmt.Println("build=", build)
}
Entonces corre:
go run \
-ldflags "-X main.version=1.0.0 -X main.build=12082019" \
main.go
Construir:
go build -o mybinary \
-ldflags "-X main.version=1.0.0 -X 'main.build=$(date)'" \
main.go
Úselo ldflags
para establecer una variable en un non-main
paquete:
Con archivo config.go
:
package config
import "fmt"
var (
Version string
)
func LogVersion() {
fmt.Println("version=", Version)
}
También necesitarás el archivo main.go
:
package main
import (
"fmt"
"github.com/user/repo/config"
}
func main() {
config.LogVersion()
}
Primero construye tu binario:
go build -o mybinary main.go
Encuentre la ruta completa del nombre de la variable que desea configurar:
go tool nm <path_to_binary> | grep Version
Ejecute y construya el binario nuevamente pero con 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
Inspirado en https://github.com/golang/go/wiki/GcToolchainTricks#incluyendo-build-information-in-the-executable
Además, si está utilizando goreleaser
, lea esto https://goreleaser.com/cookbooks/using-main.version/?h=ldflag#using-the-mainversion-ldflag :
GoReleaser establece tres ldflags por defecto:
main.version: Etiqueta de Git actual
main.commit: SHA de confirmación de git actual
main.date: Fecha según RFC3339
Si quieres ver esto en acción: https://github.com/hoto/fuzzy-repo-finder/blob/master/pkg/config/config.go
Además me gustaría publicar un pequeño ejemplo de cómo usar git y 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
El archivo make creará dos ejecutables. Uno está ejecutando la función uno, el otro tomará la función dos como entrada principal:
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]()
}
Entonces simplemente ejecuta:
make
Conseguirás:
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
Tuve problemas para usar el -ldflags
parámetro al crear mi proyecto de biblioteca y aplicación de línea de comandos mixta, así que terminé usando un destino Makefile para generar un archivo fuente de Go que contiene la versión de mi aplicación y la fecha de compilación:
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)
En mi init()
método, hago esto:
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()
}
Sin embargo, si desea un número de compilación que aumenta atómicamente en lugar de una fecha de compilación, probablemente necesitará crear un archivo local que contenga el último número de compilación. Su Makefile leería el contenido del archivo en una variable, lo incrementaría, lo insertaría en el version.go
archivo en lugar de la fecha y escribiría el nuevo número de compilación en el archivo.