Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bazel: inject git version information into version.cc #23303

Merged
merged 3 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ build --action_env=CXXFLAGS=-Wno-int-conversion
build --host_action_env=CFLAGS=-Wno-int-conversion
build --action_env=CFLAGS=-Wno-int-conversion

build --keep_going

# prevent actions and tests from using the network. anything that needs to
# opt-out (e.g. a network test) can use `tags=["requires-network"]`.
build --sandbox_default_allow_network=false

# prevent certain environment variables (e.g. PATH and LD_LIBRARY_PATH) from
# leaking into the build.
build --incompatible_strict_action_env

# =================================
# Sanitizer
# =================================
Expand Down Expand Up @@ -70,20 +80,7 @@ build:release --config=secure
build:release --copt -mllvm --copt -inline-threshold=2500
build:release --linkopt=-flto

build --keep_going

# prevent actions and tests from using the network. anything that needs to
# opt-out (e.g. a network test) can use `tags=["requires-network"]`.
build --sandbox_default_allow_network=false

# prevent certain environment variables (e.g. PATH and LD_LIBRARY_PATH) from
# leaking into the build.
build --incompatible_strict_action_env

# disabling until we are able to address the issue with GHA checkout into
# container resulting in a Git repository that doesn't seems to cause errors
# https://github.com/actions/checkout/issues/363
#build --workspace_status_command=bazel/workspace_status.sh
rockwotj marked this conversation as resolved.
Show resolved Hide resolved
build:stamp --stamp --workspace_status_command=./bazel/stamp_vars.sh

# =================================
# Testing
Expand Down
38 changes: 38 additions & 0 deletions bazel/stamp_vars.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash

set -eo pipefail

# What is this file?
# This allows us to inject external variables into our Bazel build.
# Care must be taken when modifying this, as incorrect usage could
# cause bazel to invalidate the cache too often.
#
# To RTFM, see: https://bazel.build/docs/user-manual#workspace-status-command
#
# Bazel only runs this when --config=stamp is used. At that point bazel invokes
# this script to generate key-value information that represents the status of the
# workspace. The output should be like
#
# KEY1 VALUE1
# KEY2 VALUE2
#
# If the script exits with non-zero code, the build will fail.
#
# Note that keys starting with "STABLE_" are part of the stable set, which if
# changed, invalidate any stampted targets (which by default is only binaries
# if the --stamp flag is passed to bazel, otherwise nothing). Keys which do
# not start with "STABLE_" are part of the volatile set, which will be used
# but do not invalidate stamped targets.

git_rev=$(git rev-parse HEAD)
echo "STABLE_GIT_COMMIT ${git_rev}"

git_tag=$(git describe --always --abbrev=0 --match='v*')
echo "STABLE_GIT_LATEST_TAG ${git_tag}"

# Check whether there are any uncommitted changes
if git diff-index --quiet HEAD --; then
echo "STABLE_GIT_TREE_DIRTY "
else
echo "STABLE_GIT_TREE_DIRTY -dirty"
fi
14 changes: 0 additions & 14 deletions bazel/workspace_status.sh

This file was deleted.

53 changes: 39 additions & 14 deletions src/v/version/BUILD
Original file line number Diff line number Diff line change
@@ -1,26 +1,51 @@
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("//bazel:build.bzl", "redpanda_cc_library")
load(":expand_with_stamp_vars.bzl", "expand_with_stamp_vars")

# TODO(bazel) https://redpandadata.atlassian.net/browse/CORE-5568 there is some
# learning and bits to create to properly get the version embedded. however, we
# don't want to block all progress (there are, unfortunatley, a lot of uses in
# the tree of redpanda_version) until that is addressed. so instead we'll fill
# in fake version information in the bazel build until CORE-5568 is resolved.
# Our python binary used to parse the workspace_status output and expand a template with those variables.
py_binary(
name = "stamper",
srcs = ["stamper.py"],
)

# These are our defaults, it uses the same format as the values printed in //bazel:workspace_status.sh
# If not using --config=stamp, then these will be the values in version.cc
write_file(
name = "nostamp_variables",
out = "nostamp_variables.txt",
content = [
"STABLE_GIT_LATEST_TAG 0.0.0-dev",
"STABLE_GIT_COMMIT 0000000000000000000000000000000000000000",
"STABLE_GIT_TREE_DIRTY ",
],
)

# Convert from a CMake template, to a template that works with Python's built-in string.Template
expand_template(
name = "version_template",
out = "version.in.bazel.cc",
substitutions = {
"@GIT_VER@": "${STABLE_GIT_LATEST_TAG}",
"@GIT_SHA1@": "${STABLE_GIT_COMMIT}",
"@GIT_CLEAN_DIRTY@": "${STABLE_GIT_TREE_DIRTY}",
},
template = "version.cc.in",
)

genrule(
# Use our custom rule to inject the variables from workspace_status.sh or our default if the
# workspace_status wasn't used.
expand_with_stamp_vars(
name = "version_cc",
srcs = ["version.cc.in"],
outs = ["version.cc"],
cmd_bash = """
sed -e 's/@GIT_VER@/1.0.0/g' \
-e 's/@GIT_SHA1@/0000000000000000000000000000000000000000/g' \
-e 's/@GIT_CLEAN_DIRTY@//g' $< > $@
""",
out = "version.cc",
defaults_file = ":nostamp_variables",
template = ":version_template",
)

redpanda_cc_library(
name = "version",
srcs = [
"version.cc",
":version_cc",
],
hdrs = [
"version.h",
Expand Down
53 changes: 53 additions & 0 deletions src/v/version/expand_with_stamp_vars.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""
A rule to expand a file using variables from the workspace status command.

The template is a python format, so we can expand things like {STABLE_GIT_COMMIT}
to the current commmit. Provide a `defaults_file` to file in defaults if the build
is not stamped (ie. dev builds).
"""

def _expand_with_stamp_vars(ctx):
ctx.actions.run(
outputs = [ctx.outputs.out],
inputs = [ctx.file.defaults_file, ctx.file.template, ctx.info_file],
tools = [ctx.executable._tool],
executable = ctx.executable._tool,
arguments = [
"--template",
ctx.file.template.path,
"--variables",
ctx.file.defaults_file.path,
ctx.info_file.path,
"--output",
ctx.outputs.out.path,
],
mnemonic = "ExpandStampVars",
use_default_shell_env = False,
)
return DefaultInfo(
files = depset([ctx.outputs.out]),
runfiles = ctx.runfiles(files = [ctx.outputs.out]),
)

expand_with_stamp_vars = rule(
implementation = _expand_with_stamp_vars,
attrs = {
"_tool": attr.label(
executable = True,
allow_files = True,
cfg = "exec",
default = Label("//src/v/version:stamper"),
),
"template": attr.label(
allow_single_file = True,
mandatory = True,
),
"defaults_file": attr.label(
allow_single_file = True,
mandatory = True,
),
"out": attr.output(
mandatory = True,
),
},
)
41 changes: 41 additions & 0 deletions src/v/version/stamper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env python3

# Copyright 2024 Redpanda Data, Inc.
#
# Use of this software is governed by the Business Source License
# included in the file licenses/BSL.md
#
# As of the Change Date specified in that file, in accordance with
# the Business Source License, use of this software will be governed
# by the Apache License, Version 2.0

from string import Template
from pathlib import Path


def substitute(args):
variables = {}
for var_file in args.variables:
vars_text = Path(var_file).read_text()
for line in vars_text.splitlines():
if not line.strip():
continue
(key, val) = line.split(" ", maxsplit=1)
variables[key] = val
tmpl = Template(Path(args.template).read_text())
expanded = tmpl.substitute(**variables)
Path(args.output).write_text(expanded)


def main():
import argparse

parser = argparse.ArgumentParser(description="version stamper")
parser.add_argument("--template", required=True)
parser.add_argument("--output", required=True)
parser.add_argument("--variables", nargs=2)
substitute(parser.parse_args())


if __name__ == '__main__':
main()