Skip to content

Commit 31ebcaa

Browse files
authored
Merge pull request #2061 from fabriziopandini/add-version-package
✨clusterctl: add version command
2 parents 2f74797 + 94376dd commit 31ebcaa

File tree

5 files changed

+237
-4
lines changed

5 files changed

+237
-4
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ ifeq ($(SELINUX_ENABLED),1)
8585
DOCKER_VOL_OPTS?=:z
8686
endif
8787

88+
# Set build time variables including version details
89+
LDFLAGS := $(shell hack/version.sh)
90+
8891
all: test manager clusterctl
8992

9093
help: ## Display this help
@@ -133,7 +136,7 @@ managers: ## Build all managers
133136

134137
.PHONY: clusterctl
135138
clusterctl: ## Build clusterctl binary
136-
go build -o bin/clusterctl sigs.k8s.io/cluster-api/cmd/clusterctl
139+
go build -ldflags "$(LDFLAGS)" -o bin/clusterctl sigs.k8s.io/cluster-api/cmd/clusterctl
137140

138141
$(KUSTOMIZE): $(TOOLS_DIR)/go.mod # Build kustomize from tools folder.
139142
cd $(TOOLS_DIR); go build -tags=tools -o $(BIN_DIR)/kustomize sigs.k8s.io/kustomize/kustomize/v3

cmd/clusterctl/cmd/config_providers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ var configProvidersCmd = &cobra.Command{
6565
clusterctl config provider aws:v0.4.1 -o yaml`),
6666

6767
RunE: func(cmd *cobra.Command, args []string) error {
68-
if !(cpo.output == "" || cpo.output == "yaml" || cpo.output == "text") {
68+
if !(cpo.output == "" || cpo.output == "yaml" || cpo.output == "text") { //nolint goconst
6969
return errors.New("please provide a valid output. Supported values are [ text, yaml ]")
7070
}
7171

cmd/clusterctl/cmd/version.go

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2019 The Kubernetes Authors.
2+
Copyright 2020 The Kubernetes Authors.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -16,4 +16,68 @@ limitations under the License.
1616

1717
package cmd
1818

19-
// TODO: version command
19+
import (
20+
"encoding/json"
21+
"fmt"
22+
23+
"github.com/pkg/errors"
24+
"github.com/spf13/cobra"
25+
"sigs.k8s.io/cluster-api/cmd/version"
26+
"sigs.k8s.io/yaml"
27+
)
28+
29+
// Version provides the version information of clusterctl
30+
type Version struct {
31+
ClientVersion *version.Info `json:"clusterctl"`
32+
}
33+
34+
type versionOptions struct {
35+
output string
36+
}
37+
38+
var vo = &versionOptions{}
39+
40+
var versionCmd = &cobra.Command{
41+
Use: "version",
42+
Short: "Print version of clustectl",
43+
Args: cobra.ExactArgs(0),
44+
RunE: func(cmd *cobra.Command, args []string) error {
45+
return runVersion()
46+
},
47+
}
48+
49+
func init() {
50+
versionCmd.Flags().StringVarP(&vo.output, "output", "o", "", "Output format; available options are 'yaml', 'json' and 'short'")
51+
52+
RootCmd.AddCommand(versionCmd)
53+
}
54+
55+
func runVersion() error {
56+
clientVersion := version.Get()
57+
v := Version{
58+
ClientVersion: &clientVersion,
59+
}
60+
61+
switch vo.output {
62+
case "":
63+
fmt.Printf("clusterctl version: %#v\n", v.ClientVersion)
64+
case "short":
65+
fmt.Printf("%s\n", v.ClientVersion.GitVersion)
66+
case "yaml":
67+
y, err := yaml.Marshal(&v)
68+
if err != nil {
69+
return err
70+
}
71+
fmt.Print(string(y))
72+
case "json":
73+
y, err := json.MarshalIndent(&v, "", " ")
74+
if err != nil {
75+
return err
76+
}
77+
fmt.Println(string(y))
78+
default:
79+
return errors.Errorf("invalid output format: %s", vo.output)
80+
}
81+
82+
return nil
83+
}

cmd/version/version.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package version
18+
19+
import (
20+
"fmt"
21+
"runtime"
22+
)
23+
24+
var (
25+
gitMajor string // major version, always numeric
26+
gitMinor string // minor version, numeric possibly followed by "+"
27+
gitVersion string // semantic version, derived by build scripts
28+
gitCommit string // sha1 from git, output of $(git rev-parse HEAD)
29+
gitTreeState string // state of git tree, either "clean" or "dirty"
30+
buildDate string // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
31+
)
32+
33+
type Info struct {
34+
Major string `json:"major,omitempty"`
35+
Minor string `json:"minor,omitempty"`
36+
GitVersion string `json:"gitVersion,omitempty"`
37+
GitCommit string `json:"gitCommit,omitempty"`
38+
GitTreeState string `json:"gitTreeState,omitempty"`
39+
BuildDate string `json:"buildDate,omitempty"`
40+
GoVersion string `json:"goVersion,omitempty"`
41+
Compiler string `json:"compiler,omitempty"`
42+
Platform string `json:"platform,omitempty"`
43+
}
44+
45+
func Get() Info {
46+
return Info{
47+
Major: gitMajor,
48+
Minor: gitMinor,
49+
GitVersion: gitVersion,
50+
GitCommit: gitCommit,
51+
GitTreeState: gitTreeState,
52+
BuildDate: buildDate,
53+
GoVersion: runtime.Version(),
54+
Compiler: runtime.Compiler,
55+
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
56+
}
57+
}
58+
59+
// String returns info as a human-friendly version string.
60+
func (info Info) String() string {
61+
return info.GitVersion
62+
}

hack/version.sh

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env bash
2+
# Copyright 2020 The Kubernetes Authors.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
set -o errexit
17+
set -o nounset
18+
set -o pipefail
19+
20+
version::get_version_vars() {
21+
# shellcheck disable=SC1083
22+
GIT_COMMIT="$(git rev-parse HEAD^{commit})"
23+
24+
if git_status=$(git status --porcelain 2>/dev/null) && [[ -z ${git_status} ]]; then
25+
GIT_TREE_STATE="clean"
26+
else
27+
GIT_TREE_STATE="dirty"
28+
fi
29+
30+
# stolen from k8s.io/hack/lib/version.sh
31+
# Use git describe to find the version based on tags.
32+
if GIT_VERSION=$(git describe --tags --abbrev=14 2>/dev/null); then
33+
# This translates the "git describe" to an actual semver.org
34+
# compatible semantic version that looks something like this:
35+
# v1.1.0-alpha.0.6+84c76d1142ea4d
36+
#
37+
# TODO: We continue calling this "git version" because so many
38+
# downstream consumers are expecting it there.
39+
# shellcheck disable=SC2001
40+
DASHES_IN_VERSION=$(echo "${GIT_VERSION}" | sed "s/[^-]//g")
41+
if [[ "${DASHES_IN_VERSION}" == "---" ]] ; then
42+
# We have distance to subversion (v1.1.0-subversion-1-gCommitHash)
43+
# shellcheck disable=SC2001
44+
GIT_VERSION=$(echo "${GIT_VERSION}" | sed "s/-\([0-9]\{1,\}\)-g\([0-9a-f]\{14\}\)$/.\1\-\2/")
45+
elif [[ "${DASHES_IN_VERSION}" == "--" ]] ; then
46+
# We have distance to base tag (v1.1.0-1-gCommitHash)
47+
# shellcheck disable=SC2001
48+
GIT_VERSION=$(echo "${GIT_VERSION}" | sed "s/-g\([0-9a-f]\{14\}\)$/-\1/")
49+
fi
50+
if [[ "${GIT_TREE_STATE}" == "dirty" ]]; then
51+
# git describe --dirty only considers changes to existing files, but
52+
# that is problematic since new untracked .go files affect the build,
53+
# so use our idea of "dirty" from git status instead.
54+
GIT_VERSION+="-dirty"
55+
fi
56+
57+
58+
# Try to match the "git describe" output to a regex to try to extract
59+
# the "major" and "minor" versions and whether this is the exact tagged
60+
# version or whether the tree is between two tagged versions.
61+
if [[ "${GIT_VERSION}" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?([-].*)?([+].*)?$ ]]; then
62+
GIT_MAJOR=${BASH_REMATCH[1]}
63+
GIT_MINOR=${BASH_REMATCH[2]}
64+
fi
65+
66+
# If GIT_VERSION is not a valid Semantic Version, then refuse to build.
67+
if ! [[ "${GIT_VERSION}" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
68+
echo "GIT_VERSION should be a valid Semantic Version. Current value: ${GIT_VERSION}"
69+
echo "Please see more details here: https://semver.org"
70+
exit 1
71+
fi
72+
fi
73+
74+
GIT_RELEASE_TAG=$(git describe --abbrev=0 --tags)
75+
GIT_RELEASE_COMMIT=$(git rev-list -n 1 "${GIT_RELEASE_TAG}")
76+
}
77+
78+
# stolen from k8s.io/hack/lib/version.sh and modified
79+
# Prints the value that needs to be passed to the -ldflags parameter of go build
80+
version::ldflags() {
81+
version::get_version_vars
82+
83+
local -a ldflags
84+
function add_ldflag() {
85+
local key=${1}
86+
local val=${2}
87+
ldflags+=(
88+
"-X 'sigs.k8s.io/cluster-api/cmd/version.${key}=${val}'"
89+
)
90+
}
91+
92+
add_ldflag "buildDate" "$(date ${SOURCE_DATE_EPOCH:+"--date=@${SOURCE_DATE_EPOCH}"} -u +'%Y-%m-%dT%H:%M:%SZ')"
93+
add_ldflag "gitCommit" "${GIT_COMMIT}"
94+
add_ldflag "gitTreeState" "${GIT_TREE_STATE}"
95+
add_ldflag "gitMajor" "${GIT_MAJOR}"
96+
add_ldflag "gitMinor" "${GIT_MINOR}"
97+
add_ldflag "gitVersion" "${GIT_VERSION}"
98+
add_ldflag "gitReleaseCommit" "${GIT_RELEASE_COMMIT}"
99+
100+
# The -ldflags parameter takes a single string, so join the output.
101+
echo "${ldflags[*]-}"
102+
}
103+
104+
version::ldflags

0 commit comments

Comments
 (0)