Repository: kubernetes-sigs/controller-runtime

Issue:
setup-envtest: add version option to print installed version
I want to make sure the correct version is installed without having to re-install it every time,
currently --help does not how the version that is installed though

Discussion:

Solution patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 058362b5..67c9b98b 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -14,6 +14,8 @@ jobs:
     name: Upload binaries to release
     runs-on: ubuntu-latest
     steps:
+    - name: Set env
+      run:  echo "RELEASE_TAG=${GITHUB_REF:10}" >> $GITHUB_ENV
     - name: Check out code
       uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2
     - name: Calculate go version
diff --git a/Makefile b/Makefile
index 5fbef45d..b656fa01 100644
--- a/Makefile
+++ b/Makefile
@@ -174,7 +174,7 @@ release-binary: $(RELEASE_DIR)
 		-v "$$(pwd):/workspace$(DOCKER_VOL_OPTS)" \
 		-w /workspace/tools/setup-envtest \
 		golang:$(GO_VERSION) \
-		go build -a -trimpath -ldflags "-extldflags '-static'" \
+		go build -a -trimpath -ldflags "-X 'sigs.k8s.io/controller-runtime/tools/setup-envtest/version.version=$(RELEASE_TAG)' -extldflags '-static'" \
 		-o ./out/$(RELEASE_BINARY) ./
 
 ## --------------------------------------
diff --git a/pkg/handler/enqueue_owner.go b/pkg/handler/enqueue_owner.go
index 80cb27c1..e8fc8eb4 100644
--- a/pkg/handler/enqueue_owner.go
+++ b/pkg/handler/enqueue_owner.go
@@ -48,7 +48,7 @@ type OwnerOption func(e enqueueRequestForOwnerInterface)
 //
 // - a handler.enqueueRequestForOwner EventHandler with an OwnerType of ReplicaSet and OnlyControllerOwner set to true.
 func EnqueueRequestForOwner(scheme *runtime.Scheme, mapper meta.RESTMapper, ownerType client.Object, opts ...OwnerOption) EventHandler {
-	return WithLowPriorityWhenUnchanged(TypedEnqueueRequestForOwner[client.Object](scheme, mapper, ownerType, opts...))
+	return TypedEnqueueRequestForOwner[client.Object](scheme, mapper, ownerType, opts...)
 }
 
 // TypedEnqueueRequestForOwner enqueues Requests for the Owners of an object.  E.g. the object that created
@@ -72,7 +72,7 @@ func TypedEnqueueRequestForOwner[object client.Object](scheme *runtime.Scheme, m
 	for _, opt := range opts {
 		opt(e)
 	}
-	return e
+	return WithLowPriorityWhenUnchanged(e)
 }
 
 // OnlyControllerOwner if provided will only look at the first OwnerReference with Controller: true.



Test patch:
diff --git a/pkg/handler/eventhandler_test.go b/pkg/handler/eventhandler_test.go
index 38f76dab..7cf5076e 100644
--- a/pkg/handler/eventhandler_test.go
+++ b/pkg/handler/eventhandler_test.go
@@ -798,6 +798,16 @@ var _ = Describe("Eventhandler", func() {
 					)
 				},
 			},
+			{
+				name: "TypedEnqueueRequestForOwner",
+				handler: func() handler.EventHandler {
+					return handler.TypedEnqueueRequestForOwner[client.Object](
+						scheme.Scheme,
+						mapper,
+						&corev1.Pod{},
+					)
+				},
+			},
 			{
 				name: "Funcs",
 				handler: func() handler.EventHandler {
diff --git a/tools/setup-envtest/main.go b/tools/setup-envtest/main.go
index 3121e206..7eb5ec43 100644
--- a/tools/setup-envtest/main.go
+++ b/tools/setup-envtest/main.go
@@ -184,6 +184,9 @@ Commands:
 		reads a .tar.gz file from stdin and expand it into the store.
 		must have a concrete version and platform.
 
+	version:
+		list the installed version of setup-envtest.
+
 Versions:
 
 	Versions take the form of a small subset of semver selectors.
@@ -256,7 +259,6 @@ Environment Variables:
 		version = flag.Arg(1)
 	}
 	env := setupEnv(globalLog, version)
-
 	// perform our main set of actions
 	switch action := flag.Arg(0); action {
 	case "use":
@@ -274,6 +276,8 @@ Environment Variables:
 			Input:       os.Stdin,
 			PrintFormat: printFormat,
 		}.Do(env)
+	case "version":
+		workflows.Version{}.Do(env)
 	default:
 		flag.Usage()
 		envp.Exit(2, "unknown action %q", action)
diff --git a/tools/setup-envtest/version/version.go b/tools/setup-envtest/version/version.go
new file mode 100644
index 00000000..58e7e309
--- /dev/null
+++ b/tools/setup-envtest/version/version.go
@@ -0,0 +1,21 @@
+package version
+
+import "runtime/debug"
+
+// Version to be set using ldflags:
+// -ldflags "-X sigs.k8s.io/controller-tools/pkg/version.version=v1.0.0"
+// falls back to module information is unse
+var version = ""
+
+// Version returns the version of the main module
+func Version() string {
+	if version != "" {
+		return version
+	}
+	info, ok := debug.ReadBuildInfo()
+	if !ok || info == nil || info.Main.Version == "" {
+		// binary has not been built with module support or doesn't contain a version.
+		return "(unknown)"
+	}
+	return info.Main.Version
+}
diff --git a/tools/setup-envtest/version/version_suite_test.go b/tools/setup-envtest/version/version_suite_test.go
new file mode 100644
index 00000000..99c623e8
--- /dev/null
+++ b/tools/setup-envtest/version/version_suite_test.go
@@ -0,0 +1,27 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+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 version
+
+import (
+	"testing"
+
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+)
+
+func TestVersioning(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "Test Version Suite")
+}
diff --git a/tools/setup-envtest/version/version_test.go b/tools/setup-envtest/version/version_test.go
new file mode 100644
index 00000000..4178cac8
--- /dev/null
+++ b/tools/setup-envtest/version/version_test.go
@@ -0,0 +1,54 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+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 version
+
+import (
+	"runtime/debug"
+
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+)
+
+var _ = Describe("TestVersion", func() {
+
+	info, ok := debug.ReadBuildInfo()
+	Expect(ok).To(BeTrue())
+	tests := map[string]struct {
+		version  string
+		expected string
+	}{
+		"empty returns build info": {
+			version:  "",
+			expected: info.Main.Version,
+		},
+		"set to a value returns it": {
+			version:  "1.2.3",
+			expected: "1.2.3",
+		},
+	}
+	for name, tc := range tests {
+		It("Version set to "+name, func() {
+			versionBackup := version
+			defer func() {
+				version = versionBackup
+			}()
+			version = tc.version
+			result := Version()
+			Expect(result).To(Equal(tc.expected))
+		})
+	}
+})
diff --git a/tools/setup-envtest/workflows/workflows.go b/tools/setup-envtest/workflows/workflows.go
index fdabd995..fb9123d2 100644
--- a/tools/setup-envtest/workflows/workflows.go
+++ b/tools/setup-envtest/workflows/workflows.go
@@ -5,11 +5,13 @@ package workflows
 
 import (
 	"context"
+	"fmt"
 	"io"
 
 	"github.com/go-logr/logr"
 
 	envp "sigs.k8s.io/controller-runtime/tools/setup-envtest/env"
+	"sigs.k8s.io/controller-runtime/tools/setup-envtest/version"
 )
 
 // Use is a workflow that prints out information about stored
@@ -85,3 +87,12 @@ func (f Sideload) Do(env *envp.Env) {
 	env.Sideload(ctx, f.Input)
 	env.PrintInfo(f.PrintFormat)
 }
+
+// Version is the workflow that shows the current binary version
+// of setup-envtest.
+type Version struct{}
+
+// Do executes the workflow.
+func (v Version) Do(env *envp.Env) {
+	fmt.Fprintf(env.Out, "setup-envtest version: %s\n", version.Version())
+}
diff --git a/tools/setup-envtest/workflows/workflows_test.go b/tools/setup-envtest/workflows/workflows_test.go
index 27d4ec67..435ae242 100644
--- a/tools/setup-envtest/workflows/workflows_test.go
+++ b/tools/setup-envtest/workflows/workflows_test.go
@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"io/fs"
 	"path/filepath"
+	"runtime/debug"
 	"sort"
 	"strings"
 
@@ -443,4 +444,16 @@ var _ = Describe("Workflows", func() {
 			Expect(string(outContents)).To(HavePrefix(expectedPrefix), "should have the debugging prefix")
 		})
 	})
+
+	Describe("version", func() {
+		It("should print out the version if the RELEASE_TAG is empty", func() {
+			v := wf.Version{}
+			v.Do(env)
+			info, ok := debug.ReadBuildInfo()
+			Expect(ok).To(BeTrue())
+			Expect(out.String()).ToNot(BeEmpty())
+			Expect(out.String()).To(Equal(fmt.Sprintf("setup-envtest version: %s\n", info.Main.Version)))
+		})
+	})
+
 })