What is the best way one would go about injecting build metadata such as the current git sha (and whether the tree was dirty) into the binary?
An example is kubectl:
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.3", GitCommit:"d2835416544f298c919e2ead3be3d0864b52323b", GitTreeState:"clean", BuildDate:"2018-02-09T21:51:54Z", GoVersion:"go1.9.4", Compiler:"gc", Platform:"darwin/amd64"}
In vanilla go, I'd probably just run git status on the repository, but bazel workspaces are isolated from the original source, so this method would not work.
Either way, thanks a lot for maintaining rules_go! It's been great building Go binaries with Bazel.
Sorry for the slow response -- was out of the office for a long weekend.
We do have some support for injecting build metadata via link stamping. See Defines and stamping for the full documentation.
To quickly summarize, you can set the x_defs attribute in go_binary or go_library. It's a dictionary which maps global variable names to values to be set by the linker. The values may be constants or they can come from a script that Bazel executes before the build.
For example, you can have a script that discovers the current git commit and associates it with a variable:
#!/bin/bash
echo STABLE_GIT_COMMIT $(git rev-parse HEAD)
You can use the variable in x_defs like this:
go_binary(
name = "cmd",
srcs = ["main.go"],
deps = ["//version:go_default_library"],
x_defs = {"example.com/repo/version.Version": "{STABLE_GIT_COMMIT}"},
)
You need to tell Bazel about this script (perhaps in an rc file somewhere)
$ bazel build --workspace_status_command=./status.sh //:cmd
thank you so much! I will give this a try :)
@jayconrod is there a way to get the version from a static file instead? I have a VERSION file next to every main.go and I currently use make to pass the contents of the file to the go linker. The problem with --workspace_status_command is that it will apply to all builds. Is there a way to get the version out of the VERSION file within the BUILD.bazel without any external options?
@kalbasit Sure, I can think of a couple ways to do that.
.bzl file approach: Create a file called version.bzl that just defines some global variables. This should be easy to generate or update with a script.
VERSION = "1.2.3"
You can use these in your BUILD.bazel file:
load("//:version.bzl", "VERSION")
go_binary(
name = "cmd",
srcs = ["main.go"],
deps = ["//version:go_default_library"],
x_defs = {"example.com/repo/version.Version": VERSION},
)
generated code approach: You could use a small program that reads VERSION and writes out a version.go file that gets compiled into your binary. With this approach, you wouldn't use x_defs at all. See Rules for general information on writing rules. Also Executing a binary for an example.
this is awesome, thx @jayconrod!!
Most helpful comment
Sorry for the slow response -- was out of the office for a long weekend.
We do have some support for injecting build metadata via link stamping. See Defines and stamping for the full documentation.
To quickly summarize, you can set the
x_defsattribute ingo_binaryorgo_library. It's a dictionary which maps global variable names to values to be set by the linker. The values may be constants or they can come from a script that Bazel executes before the build.For example, you can have a script that discovers the current git commit and associates it with a variable:
You can use the variable in
x_defslike this:You need to tell Bazel about this script (perhaps in an rc file somewhere)