Skip to content

Commit 3b7b70a

Browse files
committed
cmd/gcbuilder: Convert to Cobra-based CLI
Signed-off-by: Stephen Augustus <[email protected]>
1 parent 5da57bc commit 3b7b70a

File tree

5 files changed

+210
-92
lines changed

5 files changed

+210
-92
lines changed

cmd/gcbuilder/BUILD.bazel

+18-15
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
11
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
22

3-
go_library(
4-
name = "go_default_library",
5-
srcs = ["main.go"],
6-
importpath = "k8s.io/release/cmd/gcbuilder",
7-
visibility = ["//visibility:private"],
8-
deps = ["//pkg/gcp/build:go_default_library"],
9-
)
10-
11-
go_binary(
12-
name = "gcbuilder",
13-
embed = [":go_default_library"],
14-
visibility = ["//visibility:public"],
15-
)
16-
173
filegroup(
184
name = "package-srcs",
195
srcs = glob(["**"]),
@@ -23,7 +9,24 @@ filegroup(
239

2410
filegroup(
2511
name = "all-srcs",
26-
srcs = [":package-srcs"],
12+
srcs = [
13+
":package-srcs",
14+
"//cmd/gcbuilder/cmd:all-srcs",
15+
],
2716
tags = ["automanaged"],
2817
visibility = ["//visibility:public"],
2918
)
19+
20+
go_library(
21+
name = "go_default_library",
22+
srcs = ["main.go"],
23+
importpath = "k8s.io/release/cmd/gcbuilder",
24+
visibility = ["//visibility:private"],
25+
deps = ["//cmd/gcbuilder/cmd:go_default_library"],
26+
)
27+
28+
go_binary(
29+
name = "gcbuilder",
30+
embed = [":go_default_library"],
31+
visibility = ["//visibility:public"],
32+
)

cmd/gcbuilder/cmd/BUILD.bazel

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
2+
3+
go_library(
4+
name = "go_default_library",
5+
srcs = ["root.go"],
6+
importpath = "k8s.io/release/cmd/gcbuilder/cmd",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"//pkg/gcp/build:go_default_library",
10+
"//pkg/log:go_default_library",
11+
"@com_github_sirupsen_logrus//:go_default_library",
12+
"@com_github_spf13_cobra//:go_default_library",
13+
],
14+
)
15+
16+
go_test(
17+
name = "go_default_test",
18+
srcs = ["root_test.go"],
19+
embed = [":go_default_library"],
20+
deps = ["@com_github_stretchr_testify//require:go_default_library"],
21+
)
22+
23+
filegroup(
24+
name = "package-srcs",
25+
srcs = glob(["**"]),
26+
tags = ["automanaged"],
27+
visibility = ["//visibility:private"],
28+
)
29+
30+
filegroup(
31+
name = "all-srcs",
32+
srcs = [":package-srcs"],
33+
tags = ["automanaged"],
34+
visibility = ["//visibility:public"],
35+
)

cmd/gcbuilder/cmd/root.go

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
Copyright 2019 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 cmd
18+
19+
import (
20+
"os"
21+
"path"
22+
"path/filepath"
23+
"strings"
24+
25+
"github.com/sirupsen/logrus"
26+
"github.com/spf13/cobra"
27+
28+
"k8s.io/release/pkg/gcp/build"
29+
"k8s.io/release/pkg/log"
30+
)
31+
32+
// rootCmd represents the base command when called without any subcommands
33+
var rootCmd = &cobra.Command{
34+
Use: "gcbuilder",
35+
Short: "gcbuilder",
36+
PersistentPreRunE: initLogging,
37+
RunE: func(cmd *cobra.Command, args []string) error {
38+
return run()
39+
},
40+
}
41+
42+
type rootOptions struct {
43+
logLevel string
44+
}
45+
46+
var (
47+
rootOpts = &rootOptions{}
48+
buildOpts = &build.Options{}
49+
)
50+
51+
// Execute adds all child commands to the root command and sets flags appropriately.
52+
// This is called by main.main(). It only needs to happen once to the rootCmd.
53+
func Execute() {
54+
if err := rootCmd.Execute(); err != nil {
55+
logrus.Fatal(err)
56+
}
57+
}
58+
59+
func init() {
60+
rootCmd.PersistentFlags().StringVar(&buildOpts.ConfigDir, "config-dir", "", "Configuration directory")
61+
rootCmd.PersistentFlags().StringVar(&buildOpts.BuildDir, "build-dir", "", "If provided, this directory will be uploaded as the source for the Google Cloud Build run.")
62+
rootCmd.PersistentFlags().StringVar(&buildOpts.CloudbuildFile, "gcb-config", "cloudbuild.yaml", "If provided, this will be used as the name of the Google Cloud Build config file.")
63+
rootCmd.PersistentFlags().StringVar(&buildOpts.LogDir, "log-dir", "", "If provided, build logs will be sent to files in this directory instead of to stdout/stderr.")
64+
rootCmd.PersistentFlags().StringVar(&buildOpts.ScratchBucket, "scratch-bucket", "", "The complete GCS path for Cloud Build to store scratch files (sources, logs).")
65+
rootCmd.PersistentFlags().StringVar(&buildOpts.Project, "project", "", "If specified, use a non-default GCP project.")
66+
rootCmd.PersistentFlags().BoolVar(&buildOpts.AllowDirty, "allow-dirty", false, "If true, allow pushing dirty builds.")
67+
rootCmd.PersistentFlags().BoolVar(&buildOpts.NoSource, "no-source", false, "If true, no source will be uploaded with this build.")
68+
rootCmd.PersistentFlags().StringVar(&buildOpts.Variant, "variant", "", "If specified, build only the given variant. An error if no variants are defined.")
69+
rootCmd.PersistentFlags().StringVar(&buildOpts.EnvPassthrough, "env-passthrough", "", "Comma-separated list of specified environment variables to be passed to GCB as substitutions with an _ prefix. If the variable doesn't exist, the substitution will exist but be empty.")
70+
rootCmd.PersistentFlags().StringVar(&rootOpts.logLevel, "log-level", "info", "the logging verbosity, either 'panic', 'fatal', 'error', 'warn', 'warning', 'info', 'debug' or 'trace'")
71+
72+
buildOpts.ConfigDir = strings.TrimSuffix(buildOpts.ConfigDir, "/")
73+
}
74+
75+
// TODO: Clean up error handling
76+
func run() error {
77+
if buildOpts.ConfigDir == "" {
78+
logrus.Fatal("expected a config directory to be provided")
79+
}
80+
81+
if bazelWorkspace := os.Getenv("BUILD_WORKSPACE_DIRECTORY"); bazelWorkspace != "" {
82+
if err := os.Chdir(bazelWorkspace); err != nil {
83+
logrus.Fatalf("Failed to chdir to bazel workspace (%s): %v", bazelWorkspace, err)
84+
}
85+
}
86+
87+
if buildOpts.BuildDir == "" {
88+
buildOpts.BuildDir = buildOpts.ConfigDir
89+
}
90+
91+
logrus.Infof("Build directory: %s\n", buildOpts.BuildDir)
92+
93+
// Canonicalize the config directory to be an absolute path.
94+
// As we're about to cd into the build directory, we need a consistent way to reference the config files
95+
// when the config directory is not the same as the build directory.
96+
absConfigDir, absErr := filepath.Abs(buildOpts.ConfigDir)
97+
if absErr != nil {
98+
logrus.Fatalf("Could not resolve absolute path for config directory: %v", absErr)
99+
}
100+
101+
buildOpts.ConfigDir = absConfigDir
102+
buildOpts.CloudbuildFile = path.Join(buildOpts.ConfigDir, buildOpts.CloudbuildFile)
103+
104+
configDirErr := buildOpts.ValidateConfigDir()
105+
if configDirErr != nil {
106+
logrus.Fatalf("Could not validate config directory: %v", configDirErr)
107+
}
108+
109+
logrus.Infof("Config directory: %s\n", buildOpts.ConfigDir)
110+
111+
logrus.Infof("cd-ing to build directory: %s\n", buildOpts.BuildDir)
112+
if err := os.Chdir(buildOpts.BuildDir); err != nil {
113+
logrus.Fatalf("Failed to chdir to build directory (%s): %v", buildOpts.BuildDir, err)
114+
}
115+
116+
errors := build.RunBuildJobs(buildOpts)
117+
if len(errors) != 0 {
118+
logrus.Fatalf("Failed to run some build jobs: %v", errors)
119+
}
120+
logrus.Info("Finished.")
121+
122+
return nil
123+
}
124+
125+
func initLogging(*cobra.Command, []string) error {
126+
return log.SetupGlobalLogger(rootOpts.logLevel)
127+
}

cmd/gcbuilder/cmd/root_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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 cmd
18+
19+
import (
20+
"testing"
21+
22+
"github.com/stretchr/testify/require"
23+
)
24+
25+
func TestRootCommand(t *testing.T) {
26+
err := rootCmd.Execute()
27+
require.Nil(t, err)
28+
}

cmd/gcbuilder/main.go

+2-77
Original file line numberDiff line numberDiff line change
@@ -16,83 +16,8 @@ limitations under the License.
1616

1717
package main
1818

19-
import (
20-
"flag"
21-
"fmt"
22-
"log"
23-
"os"
24-
"path"
25-
"path/filepath"
26-
"strings"
27-
28-
"k8s.io/release/pkg/gcp/build"
29-
)
30-
31-
func parseFlags() build.Options {
32-
o := build.Options{}
33-
flag.StringVar(&o.BuildDir, "build-dir", "", "If provided, this directory will be uploaded as the source for the Google Cloud Build run.")
34-
flag.StringVar(&o.CloudbuildFile, "gcb-config", "cloudbuild.yaml", "If provided, this will be used as the name of the Google Cloud Build config file.")
35-
flag.StringVar(&o.LogDir, "log-dir", "", "If provided, build logs will be sent to files in this directory instead of to stdout/stderr.")
36-
flag.StringVar(&o.ScratchBucket, "scratch-bucket", "", "The complete GCS path for Cloud Build to store scratch files (sources, logs).")
37-
flag.StringVar(&o.Project, "project", "", "If specified, use a non-default GCP project.")
38-
flag.BoolVar(&o.AllowDirty, "allow-dirty", false, "If true, allow pushing dirty builds.")
39-
flag.BoolVar(&o.NoSource, "no-source", false, "If true, no source will be uploaded with this build.")
40-
flag.StringVar(&o.Variant, "variant", "", "If specified, build only the given variant. An error if no variants are defined.")
41-
flag.StringVar(&o.EnvPassthrough, "env-passthrough", "", "Comma-separated list of specified environment variables to be passed to GCB as substitutions with an _ prefix. If the variable doesn't exist, the substitution will exist but be empty.")
42-
43-
flag.Parse()
44-
45-
if flag.NArg() < 1 {
46-
_, _ = fmt.Fprintln(os.Stderr, "expected a config directory to be provided")
47-
os.Exit(1)
48-
}
49-
50-
o.ConfigDir = strings.TrimSuffix(flag.Arg(0), "/")
51-
52-
return o
53-
}
19+
import "k8s.io/release/cmd/gcbuilder/cmd"
5420

5521
func main() {
56-
o := parseFlags()
57-
58-
if bazelWorkspace := os.Getenv("BUILD_WORKSPACE_DIRECTORY"); bazelWorkspace != "" {
59-
if err := os.Chdir(bazelWorkspace); err != nil {
60-
log.Fatalf("Failed to chdir to bazel workspace (%s): %v", bazelWorkspace, err)
61-
}
62-
}
63-
64-
if o.BuildDir == "" {
65-
o.BuildDir = o.ConfigDir
66-
}
67-
68-
log.Printf("Build directory: %s\n", o.BuildDir)
69-
70-
// Canonicalize the config directory to be an absolute path.
71-
// As we're about to cd into the build directory, we need a consistent way to reference the config files
72-
// when the config directory is not the same as the build directory.
73-
absConfigDir, absErr := filepath.Abs(o.ConfigDir)
74-
if absErr != nil {
75-
log.Fatalf("Could not resolve absolute path for config directory: %v", absErr)
76-
}
77-
78-
o.ConfigDir = absConfigDir
79-
o.CloudbuildFile = path.Join(o.ConfigDir, o.CloudbuildFile)
80-
81-
configDirErr := o.ValidateConfigDir()
82-
if configDirErr != nil {
83-
log.Fatalf("Could not validate config directory: %v", configDirErr)
84-
}
85-
86-
log.Printf("Config directory: %s\n", o.ConfigDir)
87-
88-
log.Printf("cd-ing to build directory: %s\n", o.BuildDir)
89-
if err := os.Chdir(o.BuildDir); err != nil {
90-
log.Fatalf("Failed to chdir to build directory (%s): %v", o.BuildDir, err)
91-
}
92-
93-
errors := build.RunBuildJobs(&o)
94-
if len(errors) != 0 {
95-
log.Fatalf("Failed to run some build jobs: %v", errors)
96-
}
97-
log.Println("Finished.")
22+
cmd.Execute()
9823
}

0 commit comments

Comments
 (0)