m/cli/metroctl: add multiplatform metroctl target

This adds a target which builds metroctl for multiple platforms. Because
this target will be built with "bazel test //...", we no longer need to
explicitly test building metroctl for various platforms in CI.

Building fails with --config=race; I added a target_compatible_with so
the target is skipped in this case.

Change-Id: Ib747233bc8442af5f947d35289d36ddd147b7953
Reviewed-on: https://review.monogon.dev/c/monogon/+/4439
Tested-by: Jenkins CI
Reviewed-by: Tim Windelschmidt <tim@monogon.tech>
diff --git a/build/ci/jenkins-presubmit.groovy b/build/ci/jenkins-presubmit.groovy
index c658133..59d7c60 100644
--- a/build/ci/jenkins-presubmit.groovy
+++ b/build/ci/jenkins-presubmit.groovy
@@ -22,10 +22,6 @@
                         echo "Gerrit change: ${GERRIT_CHANGE_URL}"
                         sh "git clean -fdx -e '/bazel-*'"
                         sh "JENKINS_NODE_COOKIE=dontKillMe tools/bazel --bazelrc=.bazelrc.ci test //..."
-                        sh "JENKINS_NODE_COOKIE=dontKillMe tools/bazel --bazelrc=.bazelrc.ci build  --//metropolis/cli/metroctl:buildkind=lite --platforms=@io_bazel_rules_go//go/toolchain:darwin_arm64 //metropolis/cli/metroctl"
-                        sh "JENKINS_NODE_COOKIE=dontKillMe tools/bazel --bazelrc=.bazelrc.ci build  --//metropolis/cli/metroctl:buildkind=lite --platforms=@io_bazel_rules_go//go/toolchain:darwin_amd64 //metropolis/cli/metroctl"
-                        sh "JENKINS_NODE_COOKIE=dontKillMe tools/bazel --bazelrc=.bazelrc.ci build  --//metropolis/cli/metroctl:buildkind=lite --platforms=@io_bazel_rules_go//go/toolchain:windows_arm64 //metropolis/cli/metroctl"
-                        sh "JENKINS_NODE_COOKIE=dontKillMe tools/bazel --bazelrc=.bazelrc.ci build  --//metropolis/cli/metroctl:buildkind=lite --platforms=@io_bazel_rules_go//go/toolchain:windows_amd64 //metropolis/cli/metroctl"
                         sh "JENKINS_NODE_COOKIE=dontKillMe tools/bazel --bazelrc=.bazelrc.ci test --config dbg //..."
                         sh "JENKINS_NODE_COOKIE=dontKillMe tools/bazel --bazelrc=.bazelrc.ci test --config race //..."
                     }
diff --git a/build/platforms/def.bzl b/build/platforms/def.bzl
new file mode 100644
index 0000000..2e4796a
--- /dev/null
+++ b/build/platforms/def.bzl
@@ -0,0 +1,36 @@
+def _multiplatform_transition_impl(_, attr):
+    return [
+        {"//command_line_option:platforms": str(platform)}
+        for platform in attr.platforms
+    ]
+
+_multiplatform_transition = transition(
+    implementation = _multiplatform_transition_impl,
+    inputs = [],
+    outputs = ["//command_line_option:platforms"],
+)
+
+def _multiplatform_transition_filegroup_impl(ctx):
+    files = [src[DefaultInfo].files for src in ctx.attr.srcs]
+    runfiles = ctx.runfiles().merge_all([src[DefaultInfo].default_runfiles for src in ctx.attr.srcs])
+    return [DefaultInfo(
+        files = depset(transitive = files),
+        runfiles = runfiles,
+    )]
+
+multiplatform_transition_filegroup = rule(
+    _multiplatform_transition_filegroup_impl,
+    attrs = {
+        "platforms": attr.label_list(
+            providers = [platform_common.PlatformInfo],
+            mandatory = True,
+            doc = "The target platforms to transition the srcs.",
+        ),
+        "srcs": attr.label_list(
+            cfg = _multiplatform_transition,
+            mandatory = True,
+            doc = "The input to be transitioned to the target platforms.",
+        ),
+    },
+    doc = "Transitions the srcs to use the provided platforms. The filegroup will contain artifacts for all target platforms.",
+)
diff --git a/metropolis/cli/metroctl/BUILD.bazel b/metropolis/cli/metroctl/BUILD.bazel
index f300f44..b280aea 100644
--- a/metropolis/cli/metroctl/BUILD.bazel
+++ b/metropolis/cli/metroctl/BUILD.bazel
@@ -1,6 +1,7 @@
 load("@aspect_bazel_lib//lib:transitions.bzl", "platform_transition_filegroup")
 load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+load("//build/platforms:def.bzl", "multiplatform_transition_filegroup")
 load(":defs.bzl", "buildkind")
 
 buildkind(
@@ -150,3 +151,29 @@
     embed = [":metroctl_lib"],
     visibility = ["//metropolis:__subpackages__"],
 )
+
+config_setting(
+    name = "race_enabled",
+    flag_values = {"@io_bazel_rules_go//go/config:race": "True"},
+)
+
+# This target serves as a test that metroctl can be built for all listed
+# platforms.
+multiplatform_transition_filegroup(
+    name = "metroctl_lite_all_platforms",
+    srcs = [":metroctl_lite"],
+    platforms = [
+        "//build/platforms:linux_x86_64",
+        "//build/platforms:linux_aarch64",
+        "@io_bazel_rules_go//go/toolchain:darwin_amd64",
+        "@io_bazel_rules_go//go/toolchain:darwin_arm64",
+        "@io_bazel_rules_go//go/toolchain:windows_amd64",
+        "@io_bazel_rules_go//go/toolchain:windows_arm64",
+    ],
+    target_compatible_with = select({
+        # We can't build this with race enabled because
+        # we don't have a C toolchain for all platforms.
+        ":race_enabled": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    }),
+)