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

feat: expose version values via bazel_binaries.versions #132

Merged
merged 4 commits into from
Mar 16, 2023
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
9 changes: 8 additions & 1 deletion WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,23 @@ buildifier_prebuilt_register_toolchains()

# MARK: - Integration Tests

load(
"//:bazel_versions.bzl",
"CURRENT_BAZEL_VERSION",
"OTHER_BAZEL_VERSIONS",
"SUPPORTED_BAZEL_VERSIONS",
)
load("//bazel_integration_test/bzlmod:workspace_bazel_binaries.bzl", "workspace_bazel_binaries")

# This is only necessary while rules_bazel_integration_test switches back and
# forth between WORKSPACE repositories and bzlmod repositories.
workspace_bazel_binaries(
name = "bazel_binaries",
current_version = CURRENT_BAZEL_VERSION,
other_versions = OTHER_BAZEL_VERSIONS,
rbt_repo_name = "",
)

load("//:bazel_versions.bzl", "SUPPORTED_BAZEL_VERSIONS")
load("//bazel_integration_test:defs.bzl", "bazel_binaries")

bazel_binaries(versions = SUPPORTED_BAZEL_VERSIONS)
3 changes: 1 addition & 2 deletions bazel_integration_test/bzlmod/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
load("@bazel_binaries//:defs.bzl", "bazel_binaries")
load("@cgrindel_bazel_starlib//bzlformat:defs.bzl", "bzlformat_pkg")
load("//:bazel_versions.bzl", "CURRENT_BAZEL_VERSION")
load(
"//bazel_integration_test:defs.bzl",
"bazel_integration_test",
Expand Down Expand Up @@ -28,7 +27,7 @@ sh_binary(
bazel_integration_test(
name = "e2e_test",
bazel_binaries = bazel_binaries,
bazel_version = CURRENT_BAZEL_VERSION,
bazel_version = bazel_binaries.versions.current,
# Override the default tags. Let this run with bazel test //...
tags = [],
test_runner = ":e2e_test_runner",
Expand Down
92 changes: 77 additions & 15 deletions bazel_integration_test/bzlmod/bazel_binaries.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Implementation for bzlmod `bazel_binaries`."""

load("@cgrindel_bazel_starlib//bzllib:defs.bzl", "lists")
load(
"//bazel_integration_test/private:bazel_binaries.bzl",
_bazel_binary_repo_rule = "bazel_binary",
Expand All @@ -11,31 +12,56 @@ load("//bazel_integration_test/private:no_deps_utils.bzl", "no_deps_utils")
_BAZEL_BINARIES_HELPER_DEFS_BZL = """load("@{rbt_repo_name}//bazel_integration_test/bzlmod:bazel_binary_utils.bzl", "bazel_binary_utils")

def _label(version):
return bazel_binary_utils.label(_VERSIONS, version, lambda x: Label(x))
return bazel_binary_utils.label(_VERSION_TO_REPO, version, lambda x: Label(x))

_VERSIONS = {versions}
_VERSION_TO_REPO = {version_to_repo}

_versions = struct(
current = "{current_version}",
other = {other_versions},
all = {all_versions}
)

bazel_binaries = struct(
label = _label,
versions = _versions,
)
"""

def _bazel_binaries_helper_impl(repository_ctx):
current_version = repository_ctx.attr.current_version
version_to_repo = repository_ctx.attr.version_to_repo
if current_version == "":
fail("A current version must be specified.")
if version_to_repo.get(current_version) == None:
fail("""\
The specified current version ({}) is not in the `version_to_repo` dict.\
""".format(current_version))

all_versions = sorted(version_to_repo.keys())
other_versions = [v for v in all_versions if v != current_version]
repository_ctx.file("defs.bzl", _BAZEL_BINARIES_HELPER_DEFS_BZL.format(
versions = repository_ctx.attr.versions,
version_to_repo = repository_ctx.attr.version_to_repo,
rbt_repo_name = repository_ctx.attr.rbt_repo_name,
current_version = current_version,
other_versions = other_versions,
all_versions = all_versions,
))
repository_ctx.file("WORKSPACE")
repository_ctx.file("BUILD.bazel")

_bazel_binaries_helper = repository_rule(
implementation = _bazel_binaries_helper_impl,
attrs = {
"current_version": attr.string(
doc = "The value to be used as the current version.",
mandatory = True,
),
"rbt_repo_name": attr.string(
doc = "The name of the rules_bazel_integration_test repo.",
mandatory = True,
),
"versions": attr.string_dict(
"version_to_repo": attr.string_dict(
doc = "A mapping of version number/reference to repository name.",
mandatory = True,
),
Expand All @@ -45,39 +71,72 @@ _bazel_binaries_helper = repository_rule(

# MARK: - bazel_binaries Extension

def _version_info(version, type, current):
return struct(
version = version,
repo_name = no_deps_utils.bazel_binary_repo_name(version),
type = type,
current = current,
)

_version_types = struct(
string = "string",
label = "label",
)

def _declare_bazel_binary(download):
if download.version != "" and download.version_file != None:
fail("""\
A bazel_binary.download can only have one of the following: \
version, version_file.\
""")
if download.version != "":
version = download.version
repo_name = no_deps_utils.bazel_binary_repo_name(version)
_bazel_binary_repo_rule(name = repo_name, version = version)
vi = _version_info(
version = download.version,
type = _version_types.string,
current = download.current,
)
_bazel_binary_repo_rule(name = vi.repo_name, version = vi.version)
else:
version = str(download.version_file)
repo_name = no_deps_utils.bazel_binary_repo_name(version)
vi = _version_info(
version = str(download.version_file),
type = _version_types.label,
current = download.current,
)
_bazel_binary_repo_rule(
name = repo_name,
name = vi.repo_name,
version_file = download.version_file,
)
return (version, repo_name)
return vi

def _bazel_binaries_impl(module_ctx):
rbt_repo_name = "rules_bazel_integration_test"
version_to_repo = {}
version_infos = []
for mod in module_ctx.modules:
for download in mod.tags.download:
version, repo_name = _declare_bazel_binary(download)
version_to_repo[version] = repo_name
vi = _declare_bazel_binary(download)
version_infos.append(vi)
for rbt_repo in mod.tags.rbt_repo:
rbt_repo_name = rbt_repo.name

if len(version_infos) == 0:
fail("No versions were specified.")

version_to_repo = {vi.version: vi.repo_name for vi in version_infos}
current_vi = lists.find(version_infos, lambda x: x.current)
if current_vi == None:
current_vi = lists.find(
version_infos,
lambda x: x.type == _version_types.label,
)
if current_vi == None:
current_vi = version_infos[0]

_bazel_binaries_helper(
name = "bazel_binaries",
versions = version_to_repo,
version_to_repo = version_to_repo,
rbt_repo_name = rbt_repo_name,
current_version = current_vi.version,
)

_rbt_repo_tag = tag_class(
Expand All @@ -95,6 +154,9 @@ this tag class is `rules_bazel_integration_test`.\

_download_tag = tag_class(
attrs = {
"current": attr.bool(
doc = "Designate this version as the current version.",
),
"version": attr.string(
doc = """\
The Bazel version to download as a valid Bazel semantic version string.\
Expand Down
7 changes: 1 addition & 6 deletions bazel_integration_test/bzlmod/bazel_binary_utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@ def _repo_name(version_to_repo_name, version):
if len(version_to_repo_name) == 0:
# Fallback to original behavior.
return no_deps_utils.bazel_binary_repo_name(version)
if no_deps_utils.is_version_file(version):
if not version.startswith("@"):
version = "@@{}".format(version)
version_str = str(Label(version))
else:
version_str = version
version_str = no_deps_utils.normalize_version(version)
repo_name = version_to_repo_name.get(version_str, None)
if repo_name == None:
fail("""\
Expand Down
22 changes: 22 additions & 0 deletions bazel_integration_test/bzlmod/workspace_bazel_binaries.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,43 @@

_BAZEL_BINARIES_HELPER_DEFS_BZL = """load("@{rbt_repo_name}//bazel_integration_test/private:integration_test_utils.bzl", "integration_test_utils")

_versions = struct(
current = "{current_version}",
other = {other_versions},
all = {all_versions}
)

bazel_binaries = struct(
label = integration_test_utils.bazel_binary_label,
versions = _versions,
)
"""

def _workspace_bazel_binaries_impl(repository_ctx):
current_version = repository_ctx.attr.current_version
if current_version == "":
fail("A current version must be specified.")
other_versions = repository_ctx.attr.other_versions
all_versions = sorted([current_version] + other_versions)
repository_ctx.file("defs.bzl", _BAZEL_BINARIES_HELPER_DEFS_BZL.format(
rbt_repo_name = repository_ctx.attr.rbt_repo_name,
current_version = current_version,
other_versions = other_versions,
all_versions = all_versions,
))
repository_ctx.file("WORKSPACE")
repository_ctx.file("BUILD.bazel")

workspace_bazel_binaries = repository_rule(
implementation = _workspace_bazel_binaries_impl,
attrs = {
"current_version": attr.string(
doc = "The current version.",
mandatory = True,
),
"other_versions": attr.string_list(
doc = "The other versions",
),
"rbt_repo_name": attr.string(
doc = "The name of the rules_bazel_integration_test repo.",
default = "rules_bazel_integration_test",
Expand Down
2 changes: 1 addition & 1 deletion bazel_integration_test/private/integration_test_utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def _bazel_integration_test_name(name, version):
"""
return "{name}_bazel_{version}".format(
name = name,
version = no_deps_utils.normalize_version(version),
version = no_deps_utils.format_version_for_label(version),
)

def _bazel_integration_test_names(name, versions = []):
Expand Down
16 changes: 13 additions & 3 deletions bazel_integration_test/private/no_deps_utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ def _bazel_binary_repo_name(version):
A `string` that is suitable for use as a repository name.
"""
return "build_bazel_bazel_{version}".format(
version = _normalize_version(version),
version = _format_version_for_label(version),
)

def _normalize_version(version):
def _format_version_for_label(version):
"""Normalizes a version string such that it can be used as part of a label.

Args:
Expand Down Expand Up @@ -58,9 +58,19 @@ def _is_version_file(version):
def _bazel_binary_label(repo_name):
return "@{repo_name}//:bazel_binary".format(repo_name = repo_name)

def _normalize_version(version):
if _is_version_file(version):
if not version.startswith("@"):
version = "@@{}".format(version)
version_str = str(Label(version))
else:
version_str = version
return version_str

no_deps_utils = struct(
bazel_binary_repo_name = _bazel_binary_repo_name,
bazel_binary_label = _bazel_binary_label,
bazel_binary_repo_name = _bazel_binary_repo_name,
format_version_for_label = _format_version_for_label,
is_version_file = _is_version_file,
normalize_version = _normalize_version,
semantic_version_to_name = _semantic_version_to_name,
Expand Down
4 changes: 2 additions & 2 deletions doc/rules_and_macros_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ default test runner is provided by the `default_test_runner` macro.
| <a id="bazel_integration_test-env"></a>env | Optional. A dictionary of <code>strings</code>. Specifies additional environment variables to be passed to the test. | <code>{}</code> |
| <a id="bazel_integration_test-env_inherit"></a>env_inherit | Optional. Override the env_inherit values passed to the test. Only do this if you understand what needs to be passed along. Most folks will want to use <code>additional_env_inherit</code> to pass additional env_inherit values. | <code>["SUDO_ASKPASS", "HOME", "CC"]</code> |
| <a id="bazel_integration_test-additional_env_inherit"></a>additional_env_inherit | Optional. Specify additional <code>env_inherit</code> values that should be passed to the test. | <code>[]</code> |
| <a id="bazel_integration_test-bazel_binaries"></a>bazel_binaries | <p align="center"> - </p> | <code>None</code> |
| <a id="bazel_integration_test-bazel_binaries"></a>bazel_binaries | Optional for WORKSPACE loaded repositories. Required for repositories that enable bzlmod. The value for this parameter is loaded by adding <code>load("@bazel_binaries//:defs.bzl", "bazel_binaries")</code> to your build file. | <code>None</code> |
| <a id="bazel_integration_test-kwargs"></a>kwargs | additional attributes like timeout and visibility | none |


Expand Down Expand Up @@ -78,7 +78,7 @@ Macro that defines a set Bazel integration tests each executed with a different
| <a id="bazel_integration_tests-timeout"></a>timeout | A valid Bazel timeout value. https://docs.bazel.build/versions/main/test-encyclopedia.html#role-of-the-test-runner | <code>"long"</code> |
| <a id="bazel_integration_tests-env_inherit"></a>env_inherit | Optional. Override the env_inherit values passed to the test. Only do this if you understand what needs to be passed along. Most folks will want to use <code>additional_env_inherit</code> to pass additional env_inherit values. | <code>["SUDO_ASKPASS", "HOME", "CC"]</code> |
| <a id="bazel_integration_tests-additional_env_inherit"></a>additional_env_inherit | Optional. Specify additional <code>env_inherit</code> values that should be passed to the test. | <code>[]</code> |
| <a id="bazel_integration_tests-bazel_binaries"></a>bazel_binaries | <p align="center"> - </p> | <code>None</code> |
| <a id="bazel_integration_tests-bazel_binaries"></a>bazel_binaries | Optional for WORKSPACE loaded repositories. Required for repositories that enable bzlmod. The value for this parameter is loaded by adding <code>load("@bazel_binaries//:defs.bzl", "bazel_binaries")</code> to your build file. | <code>None</code> |
| <a id="bazel_integration_tests-kwargs"></a>kwargs | additional attributes like timeout and visibility | none |


Expand Down
13 changes: 6 additions & 7 deletions examples/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
load("@bazel_binaries//:defs.bzl", "bazel_binaries")
load("@cgrindel_bazel_starlib//bzlformat:defs.bzl", "bzlformat_pkg")
load("//:bazel_versions.bzl", "CURRENT_BAZEL_VERSION", "OTHER_BAZEL_VERSIONS")
load(
"//bazel_integration_test:defs.bzl",
"bazel_integration_test",
Expand All @@ -22,7 +21,7 @@ default_test_runner(
bazel_integration_test(
name = "simple_test",
bazel_binaries = bazel_binaries,
bazel_version = CURRENT_BAZEL_VERSION,
bazel_version = bazel_binaries.versions.current,
test_runner = ":simple_test_runner",
workspace_files = integration_test_utils.glob_workspace_files("simple") + [
"//:shared_bazelrc_files",
Expand All @@ -37,7 +36,7 @@ bazel_integration_tests(
# buildifier: disable=duplicated-name
name = "simple_test",
bazel_binaries = bazel_binaries,
bazel_versions = OTHER_BAZEL_VERSIONS,
bazel_versions = bazel_binaries.versions.other,
test_runner = ":simple_test_runner",
workspace_files = integration_test_utils.glob_workspace_files("simple") + [
"//:shared_bazelrc_files",
Expand All @@ -61,7 +60,7 @@ default_test_runner(
bazel_integration_test(
name = "custom_test_runner_test",
bazel_binaries = bazel_binaries,
bazel_version = CURRENT_BAZEL_VERSION,
bazel_version = bazel_binaries.versions.current,
# GH120: Enable the custom_test_runner test once swift_bazel supports
# bzlmod.
target_compatible_with = select({
Expand Down Expand Up @@ -93,7 +92,7 @@ sh_binary(
bazel_integration_test(
name = "use_create_scratch_dir_test",
bazel_binaries = bazel_binaries,
bazel_version = CURRENT_BAZEL_VERSION,
bazel_version = bazel_binaries.versions.current,
test_runner = ":use_create_scratch_dir_test_runner",
workspace_files = integration_test_utils.glob_workspace_files("simple") + [
"//:local_repository_files",
Expand All @@ -116,7 +115,7 @@ sh_binary(
bazel_integration_test(
name = "dynamic_workspace_test",
bazel_binaries = bazel_binaries,
bazel_version = CURRENT_BAZEL_VERSION,
bazel_version = bazel_binaries.versions.current,
test_runner = ":dynamic_workspace_test_runner",
)

Expand All @@ -139,7 +138,7 @@ test_suite(
":dynamic_workspace_test",
] + integration_test_utils.bazel_integration_test_names(
"simple_test",
OTHER_BAZEL_VERSIONS,
bazel_binaries.versions.other,
),
visibility = ["//:__subpackages__"],
)
3 changes: 1 addition & 2 deletions release/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ load(
"release_archive",
"update_readme",
)
load("//:bazel_versions.bzl", "CURRENT_BAZEL_VERSION")
load(
"//bazel_integration_test:defs.bzl",
"bazel_integration_test",
Expand Down Expand Up @@ -76,6 +75,6 @@ sh_binary(
bazel_integration_test(
name = "archive_test",
bazel_binaries = bazel_binaries,
bazel_version = CURRENT_BAZEL_VERSION,
bazel_version = bazel_binaries.versions.current,
test_runner = ":archive_test_runner",
)
Loading