From 38230fc518abc5183322f4943ea621a785645ea4 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Mon, 28 Aug 2023 11:54:27 -0500 Subject: [PATCH 1/2] Use pversion to retrieve buildtime information --- Dockerfile | 3 + cmd/pinniped/cmd/version.go | 47 ++++++-- cmd/pinniped/cmd/version_test.go | 83 ++++++++++++-- go.mod | 2 +- hack/get-ldflags.sh | 9 +- hack/lib/version.sh | 102 ----------------- hack/prepare-for-integration-tests.sh | 8 +- internal/concierge/apiserver/apiserver.go | 6 +- internal/concierge/server/server.go | 6 +- internal/pversion/version.go | 83 ++++++++++++++ internal/pversion/version_test.go | 127 +++++++++++++++++++++ internal/supervisor/apiserver/apiserver.go | 6 +- internal/supervisor/server/server.go | 4 +- 13 files changed, 346 insertions(+), 140 deletions(-) delete mode 100644 hack/lib/version.sh create mode 100644 internal/pversion/version.go create mode 100644 internal/pversion/version_test.go diff --git a/Dockerfile b/Dockerfile index 0c5a0652..e8d9ba12 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,9 @@ WORKDIR /work COPY . . ARG GOPROXY +ARG KUBE_GIT_VERSION +ENV KUBE_GIT_VERSION=$KUBE_GIT_VERSION + # Build the executable binary (CGO_ENABLED=0 means static linking) # Pass in GOCACHE (build cache) and GOMODCACHE (module cache) so they # can be re-used between image builds. diff --git a/cmd/pinniped/cmd/version.go b/cmd/pinniped/cmd/version.go index 7f144f4e..f0b221f7 100644 --- a/cmd/pinniped/cmd/version.go +++ b/cmd/pinniped/cmd/version.go @@ -1,13 +1,16 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package cmd import ( + "encoding/json" "fmt" "github.com/spf13/cobra" - "k8s.io/component-base/version" + "sigs.k8s.io/yaml" + + "go.pinniped.dev/internal/pversion" ) //nolint:gochecknoinits @@ -15,14 +18,44 @@ func init() { rootCmd.AddCommand(newVersionCommand()) } +//nolint:gochecknoglobals +var ( + output = new(string) + // getBuildInfo can be overwritten by tests. + getBuildInfo = pversion.Get +) + func newVersionCommand() *cobra.Command { - return &cobra.Command{ - RunE: func(cmd *cobra.Command, _ []string) error { - fmt.Fprintf(cmd.OutOrStdout(), "%#v\n", version.Get()) - return nil - }, + c := &cobra.Command{ + RunE: runner, Args: cobra.NoArgs, // do not accept positional arguments for this command Use: "version", Short: "Print the version of this Pinniped CLI", } + c.Flags().StringVarP(output, "output", "o", "", "one of 'yaml' or 'json'") + return c +} + +func runner(cmd *cobra.Command, _ []string) error { + buildVersion := getBuildInfo() + + switch { + case output == nil || *output == "": + _, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", buildVersion.GitVersion) + case *output == "json": + bytes, err := json.MarshalIndent(buildVersion, "", " ") + if err != nil { + return err + } + _, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", bytes) + case *output == "yaml": + bytes, err := yaml.Marshal(buildVersion) + if err != nil { + return err + } + _, _ = fmt.Fprint(cmd.OutOrStdout(), string(bytes)) + default: + return fmt.Errorf("'%s' is not a valid option for output", *output) + } + return nil } diff --git a/cmd/pinniped/cmd/version_test.go b/cmd/pinniped/cmd/version_test.go index dc9c5d30..d423eac7 100644 --- a/cmd/pinniped/cmd/version_test.go +++ b/cmd/pinniped/cmd/version_test.go @@ -1,4 +1,4 @@ -// Copyright 2020 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package cmd @@ -9,8 +9,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + apimachineryversion "k8s.io/apimachinery/pkg/version" "go.pinniped.dev/internal/here" + "go.pinniped.dev/internal/pversion" ) var ( @@ -19,8 +21,8 @@ var ( version \[flags\] Flags: - -h, --help help for version - + -h, --help help for version + -o, --output string one of 'yaml' or 'json' `) knownGoodHelpRegexpForVersion = here.Doc(` @@ -30,24 +32,55 @@ var ( version \[flags\] Flags: - -h, --help help for version + -h, --help help for version + -o, --output string one of 'yaml' or 'json' `) - emptyVersionRegexp = `version.Info{Major:"", Minor:"", GitVersion:".*", GitCommit:".*", GitTreeState:"", BuildDate:".*", GoVersion:".*", Compiler:".*", Platform:".*/.*"}` + jsonRegexp = here.Doc(`{ + "major": "\d*", + "minor": "\d*", + "gitVersion": "i am a version for json output", + "gitCommit": ".*", + "gitTreeState": ".*", + "buildDate": ".*", + "goVersion": ".*", + "compiler": ".*", + "platform": ".*/.*" +}`) + + yamlRegexp = here.Doc(`buildDate: ".*" +compiler: .* +gitCommit: .* +gitTreeState: .* +gitVersion: i am a version for yaml output +goVersion: .* +major: "\d*" +minor: "\d*" +platform: .*/.* +`) ) func TestNewVersionCmd(t *testing.T) { + t.Cleanup(func() { + getBuildInfo = pversion.Get + }) + tests := []struct { name string args []string + vars string + getBuildInfo func() apimachineryversion.Info wantError bool wantStdoutRegexp string wantStderrRegexp string }{ { - name: "no flags", - args: []string{}, - wantStdoutRegexp: emptyVersionRegexp + "\n", + name: "no flags", + args: []string{}, + getBuildInfo: func() apimachineryversion.Info { + return apimachineryversion.Info{GitVersion: "v55.66.44"} + }, + wantStdoutRegexp: "v55.66.44\n", }, { name: "help flag passed", @@ -61,10 +94,44 @@ func TestNewVersionCmd(t *testing.T) { wantStderrRegexp: `Error: unknown command "tuna" for "version"`, wantStdoutRegexp: knownGoodUsageRegexpForVersion, }, + { + name: "json output", + args: []string{"--output", "json"}, + getBuildInfo: func() apimachineryversion.Info { + return apimachineryversion.Info{ + GitVersion: "i am a version for json output", + Platform: "a/b", + } + }, + wantStdoutRegexp: jsonRegexp, + }, + { + name: "yaml output", + args: []string{"--output", "yaml"}, + getBuildInfo: func() apimachineryversion.Info { + return apimachineryversion.Info{ + GitVersion: "i am a version for yaml output", + Platform: "c/d", + } + }, + wantStdoutRegexp: yamlRegexp, + }, + { + name: "incorrect output", + args: []string{"--output", "foo"}, + wantError: true, + wantStderrRegexp: `Error: 'foo' is not a valid option for output`, + wantStdoutRegexp: knownGoodUsageRegexpForVersion, + }, } + for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { + if tt.getBuildInfo != nil { + getBuildInfo = tt.getBuildInfo + } + cmd := newVersionCommand() require.NotNil(t, cmd) diff --git a/go.mod b/go.mod index b70f1dd0..dfd7f8fe 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/chromedp/cdproto v0.0.0-20230828023241-f357fd93b5d6 github.com/chromedp/chromedp v0.9.2 github.com/coreos/go-oidc/v3 v3.6.0 + github.com/coreos/go-semver v0.3.1 github.com/creack/pty v1.1.18 github.com/davecgh/go-spew v1.1.1 github.com/felixge/httpsnoop v1.0.3 @@ -67,7 +68,6 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chromedp/sysutil v1.0.0 // indirect github.com/coreos/go-oidc v2.2.1+incompatible // indirect - github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cristalhq/jwt/v4 v4.0.2 // indirect diff --git a/hack/get-ldflags.sh b/hack/get-ldflags.sh index 4364559d..d6c3705d 100755 --- a/hack/get-ldflags.sh +++ b/hack/get-ldflags.sh @@ -1,13 +1,8 @@ #!/usr/bin/env bash -# Copyright 2020 the Pinniped contributors. All Rights Reserved. +# Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 set -euo pipefail -ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" - -KUBE_ROOT="${ROOT}" # required by `hack/lib/version.sh` -source "${ROOT}/hack/lib/version.sh" - -kube::version::ldflags +echo "-X 'go.pinniped.dev/internal/pversion.gitVersion=$KUBE_GIT_VERSION'" diff --git a/hack/lib/version.sh b/hack/lib/version.sh deleted file mode 100644 index 233d4ff9..00000000 --- a/hack/lib/version.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2014 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. - -# -# This has been changed from kube's default version.sh to expect KUBE_GIT_VERSION to be set -# by the caller. If it is set, it must be a semver version number, and it will be included -# in the result. If it is not set, then defaults indicating that the version is unknown will -# be included in the result. -# -# These changes are to allow the CI build steps to set the version number at build time -# without using the original behavior of this script, which was to look at previous git -# tags to guess the version number. -# - -kube::version::get_version_vars() { - local git=(git --work-tree "${KUBE_ROOT}") - - if [[ -n ${KUBE_GIT_COMMIT-} ]] || KUBE_GIT_COMMIT=$("${git[@]}" rev-parse "HEAD^{commit}" 2>/dev/null); then - if [[ -z ${KUBE_GIT_TREE_STATE-} ]]; then - # Check if the tree is dirty. default to dirty - if git_status=$("${git[@]}" status --porcelain 2>/dev/null) && [[ -z ${git_status} ]]; then - KUBE_GIT_TREE_STATE="clean" - else - KUBE_GIT_TREE_STATE="dirty" - fi - fi - - # If KUBE_GIT_VERSION is supplied - if [[ -n "${KUBE_GIT_VERSION:-""}" ]]; then - - # If KUBE_GIT_VERSION is not a valid Semantic Version, then refuse to build. - if ! [[ "${KUBE_GIT_VERSION}" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then - echo "KUBE_GIT_VERSION should be a valid Semantic Version starting with a \"v\". Current value: ${KUBE_GIT_VERSION}" - echo "Please see more details here: https://semver.org" - exit 1 - fi - - if [[ "${KUBE_GIT_VERSION}" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?([-].*)?([+].*)?$ ]]; then - KUBE_GIT_MAJOR=${BASH_REMATCH[1]} - KUBE_GIT_MINOR=${BASH_REMATCH[2]} - fi - - else - # KUBE_GIT_VERSION was not supplied - # These values need to pass the validation in k8s.io/component-base/metrics: - # https://github.com/kubernetes/component-base/blob/v0.20.5/metrics/version_parser.go#L28-L50 - KUBE_GIT_VERSION='v0.0.0' - KUBE_GIT_MAJOR='0' - KUBE_GIT_MINOR='0' - fi - fi -} - -# Prints the value that needs to be passed to the -ldflags parameter of go build -# in order to set the Kubernetes based on the git tree status. -# IMPORTANT: if you update any of these, also update the lists in -# pkg/version/def.bzl and hack/print-workspace-status.sh. -kube::version::ldflags() { - kube::version::get_version_vars - - local -a ldflags - function add_ldflag() { - local key=${1} - local val=${2} - # If you update these, also update the list component-base/version/def.bzl. - ldflags+=( - "-X 'k8s.io/client-go/pkg/version.${key}=${val}'" - "-X 'k8s.io/component-base/version.${key}=${val}'" - ) - } - - add_ldflag "buildDate" "$(date ${SOURCE_DATE_EPOCH:+"--date=@${SOURCE_DATE_EPOCH}"} -u +'%Y-%m-%dT%H:%M:%SZ')" - if [[ -n ${KUBE_GIT_COMMIT-} ]]; then - add_ldflag "gitCommit" "${KUBE_GIT_COMMIT}" - add_ldflag "gitTreeState" "${KUBE_GIT_TREE_STATE}" - fi - - if [[ -n ${KUBE_GIT_VERSION-} ]]; then - add_ldflag "gitVersion" "${KUBE_GIT_VERSION}" - fi - - if [[ -n ${KUBE_GIT_MAJOR-} && -n ${KUBE_GIT_MINOR-} ]]; then - add_ldflag "gitMajor" "${KUBE_GIT_MAJOR}" - add_ldflag "gitMinor" "${KUBE_GIT_MINOR}" - fi - - # The -ldflags parameter takes a single string, so join the output. - echo "${ldflags[*]-}" -} diff --git a/hack/prepare-for-integration-tests.sh b/hack/prepare-for-integration-tests.sh index c76c959f..5db8ec97 100755 --- a/hack/prepare-for-integration-tests.sh +++ b/hack/prepare-for-integration-tests.sh @@ -206,12 +206,12 @@ registry_repo_tag="${registry_repo}:${tag}" if [[ "$do_build" == "yes" ]]; then # Rebuild the code if [[ "$dockerfile_path" != "" ]]; then - log_note "Docker building the app with dockerfile $dockerfile_path..." - DOCKER_BUILDKIT=1 docker build . --tag "$registry_repo_tag" --file "$dockerfile_path" + log_note "Docker building the app with dockerfile $dockerfile_path and KUBE_GIT_VERSION=$KUBE_GIT_VERSION" + DOCKER_BUILDKIT=1 docker build . --tag "$registry_repo_tag" --file "$dockerfile_path" --build-arg "KUBE_GIT_VERSION=$KUBE_GIT_VERSION" else - log_note "Docker building the app..." + log_note "Docker building the app with KUBE_GIT_VERSION=$KUBE_GIT_VERSION" # DOCKER_BUILDKIT=1 is optional on MacOS but required on linux. - DOCKER_BUILDKIT=1 docker build . --tag "$registry_repo_tag" + DOCKER_BUILDKIT=1 docker build . --tag "$registry_repo_tag" --build-arg "KUBE_GIT_VERSION=$KUBE_GIT_VERSION" fi fi diff --git a/internal/concierge/apiserver/apiserver.go b/internal/concierge/apiserver/apiserver.go index 02fb89f7..5fa743b0 100644 --- a/internal/concierge/apiserver/apiserver.go +++ b/internal/concierge/apiserver/apiserver.go @@ -1,4 +1,4 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package apiserver @@ -14,11 +14,11 @@ import ( "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" - "k8s.io/client-go/pkg/version" "go.pinniped.dev/internal/controllerinit" "go.pinniped.dev/internal/issuer" "go.pinniped.dev/internal/plog" + "go.pinniped.dev/internal/pversion" "go.pinniped.dev/internal/registry/credentialrequest" "go.pinniped.dev/internal/registry/whoamirequest" ) @@ -59,7 +59,7 @@ func (c *Config) Complete() CompletedConfig { &c.ExtraConfig, } - versionInfo := version.Get() + versionInfo := pversion.Get() completedCfg.GenericConfig.Version = &versionInfo return CompletedConfig{completedConfig: &completedCfg} diff --git a/internal/concierge/server/server.go b/internal/concierge/server/server.go index e4df17ce..ee446c42 100644 --- a/internal/concierge/server/server.go +++ b/internal/concierge/server/server.go @@ -19,7 +19,6 @@ import ( openapinamer "k8s.io/apiserver/pkg/endpoints/openapi" genericapiserver "k8s.io/apiserver/pkg/server" genericoptions "k8s.io/apiserver/pkg/server/options" - "k8s.io/client-go/pkg/version" "k8s.io/client-go/rest" conciergeopenapi "go.pinniped.dev/generated/latest/client/concierge/openapi" @@ -37,6 +36,7 @@ import ( "go.pinniped.dev/internal/issuer" "go.pinniped.dev/internal/kubeclient" "go.pinniped.dev/internal/plog" + "go.pinniped.dev/internal/pversion" "go.pinniped.dev/internal/registry/credentialrequest" ) @@ -266,13 +266,13 @@ func main() error { // Dump out the time since compile (mostly useful for benchmarking our local development cycle latency). var timeSinceCompile time.Duration - if buildDate, err := time.Parse(time.RFC3339, version.Get().BuildDate); err == nil { + if buildDate, err := time.Parse(time.RFC3339, pversion.Get().BuildDate); err == nil { timeSinceCompile = time.Since(buildDate).Round(time.Second) } plog.Always("Running concierge", "user-agent", rest.DefaultKubernetesUserAgent(), - "version", versionInfo(version.Get()), + "version", versionInfo(pversion.Get()), "time-since-build", timeSinceCompile, ) diff --git a/internal/pversion/version.go b/internal/pversion/version.go new file mode 100644 index 00000000..089b4cdf --- /dev/null +++ b/internal/pversion/version.go @@ -0,0 +1,83 @@ +// Copyright 2023 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package pversion + +import ( + "fmt" + "runtime" + "runtime/debug" + "strings" + + "github.com/coreos/go-semver/semver" + apimachineryversion "k8s.io/apimachinery/pkg/version" + k8sstrings "k8s.io/utils/strings" +) + +// readBuildInfo is meant to be overwritten by tests. +// +//nolint:gochecknoglobals // these are swapped during unit tests. +var readBuildInfo = debug.ReadBuildInfo + +// gitVersion is set using a linker flag +// -ldflags "-X 'go.pinniped.dev/internal/pversion.gitVersion=v9.8.7'" +// (or set for unit tests). +// +//nolint:gochecknoglobals // these are swapped during unit tests. +var gitVersion string + +// Get returns the overall codebase version. It's for detecting +// what code a binary was built from. +// +// This function is very similar to the function defined in k8s.io/component-base (version/version.go) +// but is designed to work with golang's VCS build-time information. +// +// See: +// - https://github.com/kubernetes/component-base/blob/v0.28.0/version/version.go#L26-L42 +// - https://tip.golang.org/doc/go1.18#go-version +func Get() apimachineryversion.Info { + info := apimachineryversion.Info{ + Major: "0", + Minor: "0", + GitVersion: "v0.0.0", + GitTreeState: "dirty", + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } + + gitVersionWithoutLeadingV := gitVersion + if strings.HasPrefix(gitVersion, "v") { + gitVersionWithoutLeadingV, _ = strings.CutPrefix(gitVersion, "v") + } + + gitVersionSemver, err := semver.NewVersion(gitVersionWithoutLeadingV) + if err == nil && gitVersionSemver != nil { + info.GitVersion = gitVersion + info.Major = fmt.Sprintf("%d", gitVersionSemver.Major) + info.Minor = fmt.Sprintf("%d", gitVersionSemver.Minor) + } + + if debugBuildInfo, ok := readBuildInfo(); ok { + for _, buildSetting := range debugBuildInfo.Settings { + switch buildSetting.Key { + case "vcs.revision": + info.GitCommit = buildSetting.Value + case "vcs.time": + info.BuildDate = buildSetting.Value + case "vcs.modified": + if buildSetting.Value == "false" { + info.GitTreeState = "clean" + } + } + } + } + + if info.GitVersion == "v0.0.0" && info.GitCommit != "" { + info.GitVersion += fmt.Sprintf("-%s-%s", + k8sstrings.ShortenString(info.GitCommit, 8), + info.GitTreeState) + } + + return info +} diff --git a/internal/pversion/version_test.go b/internal/pversion/version_test.go new file mode 100644 index 00000000..a3a6e8c6 --- /dev/null +++ b/internal/pversion/version_test.go @@ -0,0 +1,127 @@ +// Copyright 2023 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package pversion + +import ( + "fmt" + "runtime" + "runtime/debug" + "testing" + + "github.com/stretchr/testify/require" + apimachineryversion "k8s.io/apimachinery/pkg/version" +) + +func TestGet(t *testing.T) { + originalGitVersion := gitVersion + t.Cleanup(func() { + gitVersion = originalGitVersion + readBuildInfo = debug.ReadBuildInfo + }) + + t.Run("when readBuildInfo() returns not ok", func(t *testing.T) { + gitVersion = "" + readBuildInfo = func() (info *debug.BuildInfo, ok bool) { + return nil, false + } + + info := apimachineryversion.Info{ + Major: "0", + Minor: "0", + GitVersion: "v0.0.0", + GitTreeState: "dirty", + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } + require.Equal(t, info, Get()) + }) + + t.Run("when readBuildInfo() returns ok", func(t *testing.T) { + gitVersion = "9.8.7" + readBuildInfo = func() (info *debug.BuildInfo, ok bool) { + buildInfo := debug.BuildInfo{ + Settings: []debug.BuildSetting{ + {Key: "vcs.revision", Value: "revision-value"}, + {Key: "vcs.time", Value: "time-value"}, + {Key: "vcs.modified", Value: "anything but 'true'"}, + {Key: "other", Value: "ignored"}, + }, + } + return &buildInfo, true + } + + expected := apimachineryversion.Info{ + Major: "9", + Minor: "8", + GitVersion: "9.8.7", + GitCommit: "revision-value", + GitTreeState: "dirty", + BuildDate: "time-value", + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } + + require.Equal(t, expected, Get()) + }) + + t.Run("when readBuildInfo() returns ok but gitVersion is not provided", func(t *testing.T) { + gitVersion = "" + readBuildInfo = func() (info *debug.BuildInfo, ok bool) { + buildInfo := debug.BuildInfo{ + Settings: []debug.BuildSetting{ + {Key: "vcs.revision", Value: "384850953501b7d66d466b4ca4d13a81bc54a7c3"}, + {Key: "vcs.time", Value: "time-value"}, + {Key: "vcs.modified", Value: "anything but 'true'"}, + {Key: "other", Value: "ignored"}, + }, + } + return &buildInfo, true + } + + expected := apimachineryversion.Info{ + Major: "0", + Minor: "0", + GitVersion: "v0.0.0-38485095-dirty", + GitCommit: "384850953501b7d66d466b4ca4d13a81bc54a7c3", + GitTreeState: "dirty", + BuildDate: "time-value", + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } + + require.Equal(t, expected, Get()) + }) + + t.Run("when gitVersion is complex", func(t *testing.T) { + gitVersion = "v1.2.3-abc123" + readBuildInfo = func() (info *debug.BuildInfo, ok bool) { + buildInfo := debug.BuildInfo{ + Settings: []debug.BuildSetting{ + {Key: "vcs.revision", Value: "abc123"}, + {Key: "vcs.time", Value: "time-value"}, + {Key: "vcs.modified", Value: "false"}, + {Key: "other", Value: "ignored"}, + }, + } + return &buildInfo, true + } + + expected := apimachineryversion.Info{ + Major: "1", + Minor: "2", + GitVersion: "v1.2.3-abc123", + GitCommit: "abc123", + GitTreeState: "clean", + BuildDate: "time-value", + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } + + require.Equal(t, expected, Get()) + }) +} diff --git a/internal/supervisor/apiserver/apiserver.go b/internal/supervisor/apiserver/apiserver.go index 4bae4803..5c0a4c9a 100644 --- a/internal/supervisor/apiserver/apiserver.go +++ b/internal/supervisor/apiserver/apiserver.go @@ -1,4 +1,4 @@ -// Copyright 2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package apiserver @@ -17,11 +17,11 @@ import ( "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/client-go/pkg/version" configv1alpha1clientset "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/typed/config/v1alpha1" "go.pinniped.dev/internal/controllerinit" "go.pinniped.dev/internal/plog" + "go.pinniped.dev/internal/pversion" "go.pinniped.dev/internal/registry/clientsecretrequest" ) @@ -61,7 +61,7 @@ func (c *Config) Complete() CompletedConfig { &c.ExtraConfig, } - versionInfo := version.Get() + versionInfo := pversion.Get() completedCfg.GenericConfig.Version = &versionInfo return CompletedConfig{completedConfig: &completedCfg} diff --git a/internal/supervisor/server/server.go b/internal/supervisor/server/server.go index 250c53e9..6f9b152a 100644 --- a/internal/supervisor/server/server.go +++ b/internal/supervisor/server/server.go @@ -33,7 +33,6 @@ import ( kubeinformers "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/client-go/pkg/version" "k8s.io/client-go/rest" aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" "k8s.io/utils/clock" @@ -66,6 +65,7 @@ import ( "go.pinniped.dev/internal/oidc/provider" "go.pinniped.dev/internal/oidc/provider/manager" "go.pinniped.dev/internal/plog" + "go.pinniped.dev/internal/pversion" "go.pinniped.dev/internal/secret" "go.pinniped.dev/internal/supervisor/apiserver" supervisorscheme "go.pinniped.dev/internal/supervisor/scheme" @@ -681,7 +681,7 @@ func main() error { // return an error instead of plog.Fatal to allow defer stat plog.Always("Running supervisor", "user-agent", rest.DefaultKubernetesUserAgent(), - "version", versionInfo(version.Get()), + "version", versionInfo(pversion.Get()), "arguments", os.Args, ) From 2dcc149fee5d274ff0185fb924272cb09b2fdc71 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Mon, 28 Aug 2023 12:14:14 -0500 Subject: [PATCH 2/2] Split off helper function --- internal/pversion/version.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/pversion/version.go b/internal/pversion/version.go index 089b4cdf..40132591 100644 --- a/internal/pversion/version.go +++ b/internal/pversion/version.go @@ -73,11 +73,15 @@ func Get() apimachineryversion.Info { } } - if info.GitVersion == "v0.0.0" && info.GitCommit != "" { + ensureFakeDevVersion(&info) + + return info +} + +func ensureFakeDevVersion(info *apimachineryversion.Info) { + if info != nil && info.GitVersion == "v0.0.0" && info.GitCommit != "" { info.GitVersion += fmt.Sprintf("-%s-%s", k8sstrings.ShortenString(info.GitCommit, 8), info.GitTreeState) } - - return info }