Rewrite compile tests from BazelProtoCommonTest to Starlark. This is using rules_analysis for testing. The tests are super fast (cca. 1s for all of the to run). The tests work either with a redirect (calling native rule) or with actual implementation in the protobuf repository. PiperOrigin-RevId: 651748083pull/18339/head
parent
d9fb893ba7
commit
dc17de7c7b
6 changed files with 556 additions and 0 deletions
@ -0,0 +1,3 @@ |
|||||||
|
load(":proto_common_compile_tests.bzl", "proto_common_compile_test_suite") |
||||||
|
|
||||||
|
proto_common_compile_test_suite(name = "proto_common_compile_test_suite") |
@ -0,0 +1,361 @@ |
|||||||
|
"""Tests for `proto_common.compile` function.""" |
||||||
|
|
||||||
|
load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") |
||||||
|
load("@rules_testing//lib:truth.bzl", "matching") |
||||||
|
load("@rules_testing//lib:util.bzl", "util") |
||||||
|
load("//bazel:proto_library.bzl", "proto_library") |
||||||
|
load("//bazel/tests/testdata:compile_rule.bzl", "compile_rule") |
||||||
|
|
||||||
|
protocol_compiler = "/protoc" |
||||||
|
|
||||||
|
def proto_common_compile_test_suite(name): |
||||||
|
util.helper_target( |
||||||
|
proto_library, |
||||||
|
name = "simple_proto", |
||||||
|
srcs = ["A.proto"], |
||||||
|
) |
||||||
|
test_suite( |
||||||
|
name = name, |
||||||
|
tests = [ |
||||||
|
_test_compile_basic, |
||||||
|
_test_compile_noplugin, |
||||||
|
_test_compile_with_plugin_output, |
||||||
|
_test_compile_with_directory_plugin_output, |
||||||
|
_test_compile_additional_args, |
||||||
|
_test_compile_additional_tools, |
||||||
|
_test_compile_additional_tools_no_plugin, |
||||||
|
_test_compile_additional_inputs, |
||||||
|
_test_compile_resource_set, |
||||||
|
_test_compile_protoc_opts, |
||||||
|
_test_compile_direct_generated_protos, |
||||||
|
_test_compile_indirect_generated_protos, |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Verifies basic usage of `proto_common.compile`. |
||||||
|
def _test_compile_basic(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_basic_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_basic_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.argv().contains_exactly_predicates( |
||||||
|
[ |
||||||
|
matching.str_endswith(protocol_compiler), |
||||||
|
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||||
|
matching.equals_wrapper("-I."), |
||||||
|
matching.str_endswith("/A.proto"), |
||||||
|
], |
||||||
|
) |
||||||
|
action.mnemonic().equals("MyMnemonic") |
||||||
|
|
||||||
|
# Verifies usage of proto_common.generate_code with no plugin specified by toolchain. |
||||||
|
def _test_compile_noplugin(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
toolchain = "//bazel/tests/testdata:toolchain_noplugin", |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_noplugin_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_noplugin_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.argv().contains_exactly_predicates( |
||||||
|
[ |
||||||
|
matching.str_endswith(protocol_compiler), |
||||||
|
matching.equals_wrapper("-I."), |
||||||
|
matching.str_endswith("/A.proto"), |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Verifies usage of `proto_common.compile` with `plugin_output` parameter set to file. |
||||||
|
def _test_compile_with_plugin_output(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
plugin_output = "single", |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_with_plugin_output_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_with_plugin_output_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.argv().contains_exactly_predicates( |
||||||
|
[ |
||||||
|
matching.str_endswith(protocol_compiler), |
||||||
|
matching.str_matches("--java_out=param1,param2:b*-out/*/test_compile_with_plugin_output_compile"), |
||||||
|
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||||
|
matching.equals_wrapper("-I."), |
||||||
|
matching.str_endswith("/A.proto"), |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Verifies usage of `proto_common.compile` with `plugin_output` parameter set to file. |
||||||
|
def _test_compile_with_directory_plugin_output(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
plugin_output = "multiple", |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_with_directory_plugin_output_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_with_directory_plugin_output_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.argv().contains_exactly_predicates( |
||||||
|
[ |
||||||
|
matching.str_endswith(protocol_compiler), |
||||||
|
matching.str_matches("--java_out=param1,param2:b*-out/*/bin"), |
||||||
|
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||||
|
matching.equals_wrapper("-I."), |
||||||
|
matching.str_endswith("/A.proto"), |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Verifies usage of `proto_common.compile` with `additional_args` parameter |
||||||
|
def _test_compile_additional_args(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
additional_args = ["--a", "--b"], |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_additional_args_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_additional_args_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.argv().contains_exactly_predicates( |
||||||
|
[ |
||||||
|
matching.str_endswith(protocol_compiler), |
||||||
|
matching.equals_wrapper("--a"), |
||||||
|
matching.equals_wrapper("--b"), |
||||||
|
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||||
|
matching.equals_wrapper("-I."), |
||||||
|
matching.str_endswith("/A.proto"), |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Verifies usage of `proto_common.compile` with `additional_tools` parameter |
||||||
|
def _test_compile_additional_tools(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
additional_tools = [ |
||||||
|
"//bazel/tests/testdata:_tool1", |
||||||
|
"//bazel/tests/testdata:_tool2", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_additional_tools_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_additional_tools_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.inputs().contains_at_least_predicates( |
||||||
|
[ |
||||||
|
matching.file_basename_equals("_tool1"), |
||||||
|
matching.file_basename_equals("_tool2"), |
||||||
|
matching.file_basename_equals("plugin"), |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Verifies usage of `proto_common.compile` with `additional_tools` parameter and no plugin on the toolchain. |
||||||
|
def _test_compile_additional_tools_no_plugin(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
additional_tools = [ |
||||||
|
"//bazel/tests/testdata:_tool1", |
||||||
|
"//bazel/tests/testdata:_tool2", |
||||||
|
], |
||||||
|
toolchain = "//bazel/tests/testdata:toolchain_noplugin", |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_additional_tools_no_plugin_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_additional_tools_no_plugin_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.inputs().contains_at_least_predicates( |
||||||
|
[ |
||||||
|
matching.file_basename_equals("_tool1"), |
||||||
|
matching.file_basename_equals("_tool2"), |
||||||
|
], |
||||||
|
) |
||||||
|
action.inputs().not_contains_predicate(matching.file_basename_equals("plugin")) |
||||||
|
|
||||||
|
# Verifies usage of `proto_common.compile` with `additional_inputs` parameter. |
||||||
|
def _test_compile_additional_inputs(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
additional_inputs = ["input1.txt", "input2.txt"], |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_additional_inputs_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_additional_inputs_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.inputs().contains_at_least_predicates( |
||||||
|
[ |
||||||
|
matching.file_basename_equals("input1.txt"), |
||||||
|
matching.file_basename_equals("input2.txt"), |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Verifies usage of `proto_common.compile` with `additional_tools` parameter and no plugin on the toolchain. |
||||||
|
def _test_compile_resource_set(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
use_resource_set = True, |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_resource_set_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_resource_set_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") # @unused |
||||||
|
# We can't check the specification of the resource set, but we at least verify analysis passes |
||||||
|
|
||||||
|
# Verifies `--protocopts` are passed to command line. |
||||||
|
def _test_compile_protoc_opts(name): |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = ":simple_proto", |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
config_settings = {"//command_line_option:protocopt": ["--foo", "--bar"]}, |
||||||
|
impl = _test_compile_protoc_opts_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_protoc_opts_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.argv().contains_exactly_predicates( |
||||||
|
[ |
||||||
|
matching.str_endswith(protocol_compiler), |
||||||
|
matching.equals_wrapper("--foo"), |
||||||
|
matching.equals_wrapper("--bar"), |
||||||
|
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||||
|
matching.equals_wrapper("-I."), |
||||||
|
matching.str_endswith("/A.proto"), |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Verifies `proto_common.compile`> correctly handles direct generated `.proto` files. |
||||||
|
def _test_compile_direct_generated_protos(name): |
||||||
|
util.helper_target(native.genrule, name = name + "_generate_G", cmd = "", outs = ["G.proto"]) |
||||||
|
util.helper_target( |
||||||
|
proto_library, |
||||||
|
name = name + "_directly_generated_proto", |
||||||
|
srcs = ["A.proto", "G.proto"], |
||||||
|
) |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = name + "_directly_generated_proto", |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_direct_generated_protos_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_direct_generated_protos_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.argv().contains_exactly_predicates( |
||||||
|
[ |
||||||
|
matching.str_endswith(protocol_compiler), |
||||||
|
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||||
|
matching.str_matches("-Ib*-out/*/*"), |
||||||
|
matching.equals_wrapper("-I."), |
||||||
|
matching.str_endswith("/A.proto"), |
||||||
|
matching.str_matches("*-out/*/*/*/G.proto"), |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
# Verifies usage of `proto_common.compile` with `plugin_output` parameter |
||||||
|
def _test_compile_indirect_generated_protos(name): |
||||||
|
util.helper_target(native.genrule, name = "_generate_h", srcs = ["A.txt"], cmd = "", outs = ["H.proto"]) |
||||||
|
util.helper_target(proto_library, name = "_generated_proto", srcs = ["H.proto"]) |
||||||
|
util.helper_target( |
||||||
|
proto_library, |
||||||
|
name = name + "_indirectly_generated_proto", |
||||||
|
srcs = ["A.proto"], |
||||||
|
deps = [":_generated_proto"], |
||||||
|
) |
||||||
|
util.helper_target( |
||||||
|
compile_rule, |
||||||
|
name = name + "_compile", |
||||||
|
proto_dep = name + "_indirectly_generated_proto", |
||||||
|
) |
||||||
|
|
||||||
|
analysis_test( |
||||||
|
name = name, |
||||||
|
target = name + "_compile", |
||||||
|
impl = _test_compile_indirect_generated_protos_impl, |
||||||
|
) |
||||||
|
|
||||||
|
def _test_compile_indirect_generated_protos_impl(env, target): |
||||||
|
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||||
|
action.argv().contains_exactly_predicates( |
||||||
|
[ |
||||||
|
matching.str_endswith(protocol_compiler), |
||||||
|
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||||
|
matching.str_matches("-Ib*-out/*/*"), |
||||||
|
matching.equals_wrapper("-I."), |
||||||
|
matching.str_endswith("/A.proto"), |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,130 @@ |
|||||||
|
package(default_visibility = ["//visibility:public"]) |
||||||
|
|
||||||
|
proto_lang_toolchain( |
||||||
|
name = "toolchain", |
||||||
|
blacklisted_protos = [":denied"], |
||||||
|
command_line = "--java_out=param1,param2:$(OUT)", |
||||||
|
mnemonic = "MyMnemonic", |
||||||
|
plugin = ":plugin", |
||||||
|
plugin_format_flag = "--plugin=%s", |
||||||
|
progress_message = "Progress Message %{label}", |
||||||
|
runtime = ":runtime", |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
proto_lang_toolchain( |
||||||
|
name = "toolchain_noplugin", |
||||||
|
blacklisted_protos = [":denied"], |
||||||
|
command_line = "--java_out=param1,param2:$(OUT)", |
||||||
|
mnemonic = "MyMnemonic", |
||||||
|
progress_message = "Progress Message %{label}", |
||||||
|
runtime = ":runtime", |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_binary( |
||||||
|
name = "plugin", |
||||||
|
srcs = ["plugin.cc"], |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_library( |
||||||
|
name = "runtime", |
||||||
|
srcs = ["runtime.cc"], |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
filegroup( |
||||||
|
name = "descriptors", |
||||||
|
srcs = [ |
||||||
|
"descriptor.proto", |
||||||
|
"metadata.proto", |
||||||
|
], |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
filegroup( |
||||||
|
name = "any", |
||||||
|
srcs = ["any.proto"], |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
filegroup( |
||||||
|
name = "something", |
||||||
|
srcs = ["something.proto"], |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
proto_library( |
||||||
|
name = "mixed", |
||||||
|
srcs = [ |
||||||
|
":descriptors", |
||||||
|
":something", |
||||||
|
], |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
proto_library( |
||||||
|
name = "denied", |
||||||
|
srcs = [ |
||||||
|
":any", |
||||||
|
":descriptors", |
||||||
|
], |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_binary( |
||||||
|
name = "_tool1", |
||||||
|
srcs = ["tool1.cc"], |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_binary( |
||||||
|
name = "_tool2", |
||||||
|
srcs = ["tool2.cc"], |
||||||
|
tags = [ |
||||||
|
"manual", |
||||||
|
"nobuilder", |
||||||
|
"notap", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,50 @@ |
|||||||
|
"""Testing function for proto_common module""" |
||||||
|
|
||||||
|
load("//bazel/common:proto_common.bzl", "proto_common") |
||||||
|
|
||||||
|
def _resource_set_callback(_os, inputs_size): |
||||||
|
return {"memory": 25 + 0.15 * inputs_size, "cpu": 1} |
||||||
|
|
||||||
|
def _impl(ctx): |
||||||
|
outfile = ctx.actions.declare_file(ctx.attr.name) |
||||||
|
kwargs = {} |
||||||
|
if ctx.attr.plugin_output == "single": |
||||||
|
kwargs["plugin_output"] = outfile.path |
||||||
|
elif ctx.attr.plugin_output == "multiple": |
||||||
|
kwargs["plugin_output"] = ctx.bin_dir.path |
||||||
|
elif ctx.attr.plugin_output == "wrong": |
||||||
|
kwargs["plugin_output"] = ctx.bin_dir.path + "///" |
||||||
|
if ctx.attr.additional_args: |
||||||
|
additional_args = ctx.actions.args() |
||||||
|
additional_args.add_all(ctx.attr.additional_args) |
||||||
|
kwargs["additional_args"] = additional_args |
||||||
|
if ctx.files.additional_tools: |
||||||
|
kwargs["additional_tools"] = ctx.files.additional_tools |
||||||
|
if ctx.files.additional_inputs: |
||||||
|
kwargs["additional_inputs"] = depset(ctx.files.additional_inputs) |
||||||
|
if ctx.attr.use_resource_set: |
||||||
|
kwargs["resource_set"] = _resource_set_callback |
||||||
|
if ctx.attr.progress_message: |
||||||
|
kwargs["experimental_progress_message"] = ctx.attr.progress_message |
||||||
|
proto_common.compile( |
||||||
|
ctx.actions, |
||||||
|
ctx.attr.proto_dep[ProtoInfo], |
||||||
|
ctx.attr.toolchain[proto_common.ProtoLangToolchainInfo], |
||||||
|
[outfile], |
||||||
|
**kwargs |
||||||
|
) |
||||||
|
return [DefaultInfo(files = depset([outfile]))] |
||||||
|
|
||||||
|
compile_rule = rule( |
||||||
|
_impl, |
||||||
|
attrs = { |
||||||
|
"proto_dep": attr.label(), |
||||||
|
"plugin_output": attr.string(), |
||||||
|
"toolchain": attr.label(default = ":toolchain"), |
||||||
|
"additional_args": attr.string_list(), |
||||||
|
"additional_tools": attr.label_list(cfg = "exec"), |
||||||
|
"additional_inputs": attr.label_list(allow_files = True), |
||||||
|
"use_resource_set": attr.bool(), |
||||||
|
"progress_message": attr.string(), |
||||||
|
}, |
||||||
|
) |
Loading…
Reference in new issue