fix: set nogo flags as universal (#4623)
**What type of PR is this?**
Bug fix
**What does this PR do? Why is it needed?**
This ensure the nogo flag doesn't get wiped when transitioning to an
exec config when --incompatible_exclude_starlark_flags_from_exec_config
is set.
Without this change, a cycle shows up in the dependencies when the
option is set.
Fixes #4620
(thanks @fmeum for the diagnosis!)
diff --git a/MODULE.bazel b/MODULE.bazel
index 83965b6..b517e41 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -7,7 +7,7 @@
# The custom repo_name is used to prevent our bazel_features polyfill for WORKSPACE builds from
# conflicting with the real bazel_features repo.
bazel_dep(name = "bazel_features", version = "1.36.0", repo_name = "io_bazel_rules_go_bazel_features")
-bazel_dep(name = "bazel_skylib", version = "1.2.0")
+bazel_dep(name = "bazel_skylib", version = "1.8.1")
bazel_dep(name = "platforms", version = "1.1.0")
bazel_dep(name = "rules_proto", version = "7.0.2")
bazel_dep(name = "protobuf", version = "29.0", repo_name = "com_google_protobuf")
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock
index 5fa9af9..34fee1b 100644
--- a/MODULE.bazel.lock
+++ b/MODULE.bazel.lock
@@ -40,7 +40,8 @@
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
"https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d",
"https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
- "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953",
+ "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6",
+ "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/source.json": "7ebaefba0b03efe59cac88ed5bbc67bcf59a3eff33af937345ede2a38b2d368a",
"https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
"https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
"https://bcr.bazel.build/modules/gazelle/0.45.0/MODULE.bazel": "ecd19ebe9f8e024e1ccffb6d997cc893a974bcc581f1ae08f386bdd448b10687",
diff --git a/go/private/BUILD.bazel b/go/private/BUILD.bazel
index abe5c36..0bf46bf 100644
--- a/go/private/BUILD.bazel
+++ b/go/private/BUILD.bazel
@@ -165,6 +165,7 @@
bool_setting(
name = "bootstrap_nogo",
build_setting_default = False,
+ scope = "universal",
visibility = ["//visibility:public"],
)
@@ -174,6 +175,7 @@
bool_setting(
name = "request_nogo",
build_setting_default = True,
+ scope = "universal",
visibility = ["//visibility:public"],
)
diff --git a/go/private/repositories.bzl b/go/private/repositories.bzl
index eb2e7f8..865c41f 100644
--- a/go/private/repositories.bzl
+++ b/go/private/repositories.bzl
@@ -51,12 +51,11 @@
wrapper(
http_archive,
name = "bazel_skylib",
- # 1.6.1, latest as of 2024-05-20
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.6.1/bazel-skylib-1.6.1.tar.gz",
- "https://github.com/bazelbuild/bazel-skylib/releases/download/1.6.1/bazel-skylib-1.6.1.tar.gz",
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.8.1/bazel-skylib-1.8.1.tar.gz",
+ "https://github.com/bazelbuild/bazel-skylib/releases/download/1.8.1/bazel-skylib-1.8.1.tar.gz",
],
- sha256 = "9f38886a40548c6e96c106b752f242130ee11aaa068a56ba7e56f4511f33e4f2",
+ sha256 = "51b5105a760b353773f904d2bbc5e664d0987fbaf22265164de65d43e910d8ac",
strip_prefix = "",
)
diff --git a/tests/core/nogo/exec_config/BUILD.bazel b/tests/core/nogo/exec_config/BUILD.bazel
new file mode 100644
index 0000000..f8ee3ea
--- /dev/null
+++ b/tests/core/nogo/exec_config/BUILD.bazel
@@ -0,0 +1,6 @@
+load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
+
+go_bazel_test(
+ name = "exec_config_test",
+ srcs = ["exec_config_test.go"],
+)
diff --git a/tests/core/nogo/exec_config/exec_config_test.go b/tests/core/nogo/exec_config/exec_config_test.go
new file mode 100644
index 0000000..5e3dde7
--- /dev/null
+++ b/tests/core/nogo/exec_config/exec_config_test.go
@@ -0,0 +1,88 @@
+// Copyright 2026 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package exec_config_test
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/bazelbuild/rules_go/go/tools/bazel_testing"
+)
+
+func TestMain(m *testing.M) {
+ bazel_testing.TestMain(m, bazel_testing.Args{
+ Main: `
+-- BUILD.bazel --
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "nogo")
+
+nogo(
+ name = "my_nogo",
+ vet = True,
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "lib",
+ srcs = ["lib.go"],
+ importpath = "example.com/lib",
+)
+
+-- lib.go --
+package lib
+
+func Hello() string {
+ return "hello"
+}
+`,
+ ModuleFileSuffix: `
+go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")
+go_sdk.nogo(nogo = "//:my_nogo")
+`,
+ })
+}
+
+// TestNoCycleWithExcludedStarlarkFlags is a regression test for the nogo
+// bootstrapping cycle that reappears when Starlark flags are excluded from the
+// exec configuration.
+//
+// Every Go target depends on the nogo binary (cfg = "exec"), and the nogo
+// binary is itself built from Go libraries that depend on nogo. rules_go breaks
+// this cycle with the //go/private:bootstrap_nogo flag, which go_tool_transition
+// sets to True when building nogo so that nogo's own dependencies resolve the
+// nogo alias to a noop instead of the real binary.
+//
+// Under --incompatible_exclude_starlark_flags_from_exec_config, that flag would
+// be reset to its default across the cfg = "exec" edge into nogo's
+// dependencies, re-activating nogo on them and reintroducing the cycle. Marking
+// bootstrap_nogo (and request_nogo) with scope = "universal" exempts them from
+// that reset, which is what this test guards.
+func TestNoCycleWithExcludedStarlarkFlags(t *testing.T) {
+ const flag = "--incompatible_exclude_starlark_flags_from_exec_config"
+ err := bazel_testing.RunBazel("build", "//:lib", flag)
+ if err == nil {
+ return // Build succeeded: no cycle.
+ }
+
+ // The flag only exists on Bazel 8+. On older versions, skip rather than
+ // fail so the test stays green across the supported Bazel matrix.
+ if strings.Contains(err.Error(), "Unrecognized option: "+flag) {
+ t.Skipf("Bazel does not support %s; skipping", flag)
+ }
+
+ if strings.Contains(err.Error(), "cycle in dependency graph") {
+ t.Fatalf("nogo bootstrapping cycle reintroduced by %s:\n%s", flag, err)
+ }
+ t.Fatalf("unexpected build failure: %s", err)
+}