来探讨下git工作流下golang项目的version信息该如何处理比较符合标准

之前自己写的几个简单的小工具都是没有把version信息注入到编译出来的文件里,发布版本多了后也无法溯源了.想着有必要看下这方面的知识了.

观察现有的一些

之前我博客docker panic那次事故就是根据docker info里的containerd的commit id找到了相关的代码来回溯.我们先看看各个项目的version信息

$ docker version
Client: Docker Engine - Community
 Version:           19.03.2
 API version:       1.40
 Go version:        go1.12.8
 Git commit:        6a30dfc
 Built:             Thu Aug 29 05:28:55 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.2
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.8
  Git commit:       6a30dfc
  Built:            Thu Aug 29 05:27:34 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.10
  GitCommit:        b34a5c8af56e510852c35414db4c1f4fa6172339
 runc:
  Version:          1.0.0-rc8+dev
  GitCommit:        3e425f80a8c931f88e6d94a8c831b9d5aa481657
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
$ etcd --version
etcd Version: 3.3.13
Git SHA: 98d3084
Go Version: go1.10.8
Go OS/Arch: linux/amd64
$ kubectl version -o json
{
  "clientVersion": {
    "major": "1",
    "minor": "13",
    "gitVersion": "v1.13.12",
    "gitCommit": "a8b52209ee172232b6db7a6e0ce2adc77458829f",
    "gitTreeState": "clean",
    "buildDate": "2019-10-15T12:12:15Z",
    "goVersion": "go1.11.13",
    "compiler": "gc",
    "platform": "linux/amd64"
  },
  "serverVersion": {
    "major": "1",
    "minor": "13",
    "gitVersion": "v1.13.12",
    "gitCommit": "a8b52209ee172232b6db7a6e0ce2adc77458829f",
    "gitTreeState": "clean",
    "buildDate": "2019-10-15T12:04:30Z",
    "goVersion": "go1.11.13",
    "compiler": "gc",
    "platform": "linux/amd64"
  }
}

如何注入

对比下都有如下信息:

  • version
  • go version
  • arch info and os
  • git commit id
  • build date
makefile
go build -ldflags
包名.变量名

市面上很多都是单独整了个version文件,直接从里面cat的.实际都是master代码测试完美了后发布tag,tag触发release.可以根据tag号做版本号来外部注入.总的来说就是k8s这方面最规范.去看它的源码.

从k8s源码学习

staging/src/k8s.io/component-base/version/version.go
staging/src/k8s.io/component-base/version/base.go
hack/lib/init.sh

version脚本里逻辑可能对于非运维看比较麻烦,简单说下上面version信息:

Major1.18.21Minor1.18.218GitVersion$release-dirtyGitCommitGitTreeState

个人实现

我简单说下现在我推荐的逻辑判断:

git=(git --work-tree "${KUBE_ROOT}") #后面使用git命令用:"${git[@]}"
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
HEAD=$("${git[@]}" rev-parse "HEAD^{commit}")
if [ -n "$TAG" ]; then
  TAG_COMMITID=$("${git[@]}" rev-parse $TAG 2>/dev/null)
  if [ "$?" -ne 0 ];then
      echo no such tag: $TAG
      exit 1
  fi
else #默认取最新的tag
  TAG_COMMITID=$("${git[@]}" rev-list --tags --max-count=1)
  TAG=$("${git[@]}" describe --tags ${TAG_COMMITID})
fi
"${git[@]}" checkout $TAG 2>/dev/null
BUILD_VERSION=${TAG}
if [ -z "$("${git[@]}" status --porcelain 2>/dev/null)" ];then
  GIT_TREE_STATE='clean'
else
  GIT_TREE_STATE='dirty'
fi
if [ "${HEAD}" != "${TAG_COMMITID}" ];then
  #tag的基础上改动,所以tag版本号-dirty
  BUILD_VERSION+="-dirty"
  COMMIT_ID=${HEAD}
else
  COMMIT_ID=${TAG_COMMITID}
fi
"${git[@]}" checkout $HEAD 2>/dev/null

整个细节性都在我github上