Go 的版本自动化

作者: caixw
修改时间:

一般情况下,我会在发布程序时把编译的时期附在版本号里,按照 semver 的规则,一个版本号会是这样子:0.1.2+20161129,前三个字符相对来说改动比较少,但是最后的日期一天一变,如果采用手动改变代码中常的方式,就比较得麻烦。所以我会使用 shell 和 go build 命令的 ldflags 参数相结合,在每次编译时,自动更新这个个变量。

下面是一段简单的代码,用来作为示例,除了编译日期之外,还指定了一个 commit hash,用于记录最后的提交 ID:

 1// Copyright 2016 by caixw, All rights reserved.
 2// Use of this source code is governed by a MIT
 3// license that can be found in the LICENSE file.
 4
 5package main
 6
 7import (
 8    "flag"
 9)
10
11const mainVersion = "1.2.3"
12
13var (
14    buildDate  string
15    commitHash string
16)
17
18func main() {
19    v := flag.Bool("v", false, "显示版本号")
20    flag.Parse()
21
22    if *v {
23        version := mainVersion
24        if len(buildDate) > 0 {
25            version += "+" + buildDate
26        }
27        fmt.Println("version:", version)
28
29        if len(commitHash) > 0 {
30            fmt.Println("git commit hash:", commitHash)
31        }
32        return
33    }
34
35    // TODO
36}

下面是相对应的一个简单 shell 脚本,用于编译代码:

1# 获取两个参数变量,等号两端不要有空格
2buildDate=$(date -u '+%Y%m%d')
3hash=$(git rev-parse HEAD)
4
5go build  -ldflags "-X main.buildDate=${buildDate} -X main.commitHash=${hash}"

执行 ./main,将会输出类似以下内容:

1version:1.2.3+20161129
2git commit hash: 8b3632a2451edcd175939de6581315b9dde0fbd7

关于 ldflags 参数:

  • 不能修改常量,只能是变量;
  • 变量可以小写;
  • 若不是 main 包,则需要指定全路径:go build -ldflags="-X github.com/caixw/gobuild/vars.xxx=$(date -u '+%Y%m%d')"
  • 可以同时指定多个,采用 "-X importpath.name=xxx -X importpath.name=XXX" 的形式。

本作品采用署名 4.0 国际 (CC BY 4.0)进行许可。

唯一链接:https://caixw.io/posts/2016/go-auto-versioning.html