Skip to content

Commit dc3a2f5

Browse files
authored
Merge pull request #632 from droot/feature/scaffolding-v2
Simplified Scaffolding based on the builder pattern
2 parents fe626f8 + 5dbed55 commit dc3a2f5

File tree

94 files changed

+2618
-352
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+2618
-352
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test/*.tgz filter=lfs diff=lfs merge=lfs -text

.travis.yml

+6
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ go:
99

1010
git:
1111
depth: 3
12+
lfs_skip_smudge: true
1213

1314
go_import_path: sigs.k8s.io/kubebuilder
1415

1516
before_install:
1617
- go get -u github.com/golang/dep/cmd/dep
18+
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install git-lfs ; fi
19+
20+
before_script:
21+
- git lfs install
22+
- git lfs pull
1723

1824
# Install must be set to prevent default `go get` to run.
1925
# The dependencies have already been vendored by `dep` so

CONTRIBUTING.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Kubernetes projects require that you sign a Contributor License Agreement (CLA)
77
Please see https://git.k8s.io/community/CLA.md for more info.
88

99
## Contributing steps
10-
10+
1. Setup [Git LFS plugin](https://git-lfs.github.com/)
1111
1. Submit an issue describing your proposed change to the repo in question.
1212
1. The [repo owners](OWNERS) will respond to your issue promptly.
1313
1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above).
@@ -16,6 +16,10 @@ Please see https://git.k8s.io/community/CLA.md for more info.
1616

1717
## How to build kubebuilder locally
1818

19+
1. Setup Git LFS
20+
Install the git-lfs plugin using the instructions from [git-lfs](https://git-lfs.github.com/) page.
21+
Once installed, run `git lfs install` in your repo to setup git lfs hooks.
22+
1923
1. Build
2024
```sh
2125
$ go build -o /output/path/kubebuilder ./cmd

Makefile

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env bash
2+
3+
# Copyright 2019 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
#
18+
# Makefile with some common workflow for dev, build and test
19+
#
20+
21+
all: build test
22+
23+
.PHONY: build test
24+
25+
build:
26+
go build -o bin/kubebuilder ./cmd
27+
28+
generate:
29+
./generated_golden.sh
30+
31+
test:
32+
go test -v ./cmd/... ./pkg/...
33+

cmd/api.go

+48-85
Original file line numberDiff line numberDiff line change
@@ -22,111 +22,94 @@ import (
2222
"log"
2323
"os"
2424
"os/exec"
25-
"path/filepath"
26-
"strings"
2725

2826
"github.com/spf13/cobra"
2927
flag "github.com/spf13/pflag"
3028

3129
"sigs.k8s.io/kubebuilder/cmd/util"
3230
"sigs.k8s.io/kubebuilder/pkg/scaffold"
33-
"sigs.k8s.io/kubebuilder/pkg/scaffold/controller"
34-
"sigs.k8s.io/kubebuilder/pkg/scaffold/input"
35-
"sigs.k8s.io/kubebuilder/pkg/scaffold/resource"
31+
"sigs.k8s.io/kubebuilder/pkg/scaffold/v1/resource"
3632
)
3733

3834
type apiOptions struct {
39-
r *resource.Resource
40-
resourceFlag, controllerFlag *flag.Flag
41-
doResource, doController, doMake bool
35+
apiScaffolder scaffold.API
36+
resourceFlag, controllerFlag *flag.Flag
37+
38+
// runMake indicates whether to run make or not after scaffolding APIs
39+
runMake bool
4240
}
4341

44-
// APICmd represents the resource command
42+
func (o *apiOptions) bindCmdFlags(cmd *cobra.Command) {
43+
cmd.Flags().BoolVar(&o.runMake, "make", true,
44+
"if true, run make after generating files")
45+
cmd.Flags().BoolVar(&o.apiScaffolder.DoResource, "resource", true,
46+
"if set, generate the resource without prompting the user")
47+
o.resourceFlag = cmd.Flag("resource")
48+
cmd.Flags().BoolVar(&o.apiScaffolder.DoController, "controller", true,
49+
"if set, generate the controller without prompting the user")
50+
o.controllerFlag = cmd.Flag("controller")
51+
o.apiScaffolder.Resource = resourceForFlags(cmd.Flags())
52+
}
53+
54+
// resourceForFlags registers flags for Resource fields and returns the Resource
55+
func resourceForFlags(f *flag.FlagSet) *resource.Resource {
56+
r := &resource.Resource{}
57+
f.StringVar(&r.Kind, "kind", "", "resource Kind")
58+
f.StringVar(&r.Group, "group", "", "resource Group")
59+
f.StringVar(&r.Version, "version", "", "resource Version")
60+
f.BoolVar(&r.Namespaced, "namespaced", true, "resource is namespaced")
61+
f.BoolVar(&r.CreateExampleReconcileBody, "example", true,
62+
"if true an example reconcile body should be written while scaffolding a resource.")
63+
return r
64+
}
4565

66+
// APICmd represents the resource command
4667
func (o *apiOptions) runAddAPI() {
4768
dieIfNoProject()
4869

4970
reader := bufio.NewReader(os.Stdin)
5071
if !o.resourceFlag.Changed {
5172
fmt.Println("Create Resource under pkg/apis [y/n]?")
52-
o.doResource = util.Yesno(reader)
73+
o.apiScaffolder.DoResource = util.Yesno(reader)
5374
}
5475

5576
if !o.controllerFlag.Changed {
5677
fmt.Println("Create Controller under pkg/controller [y/n]?")
57-
o.doController = util.Yesno(reader)
78+
o.apiScaffolder.DoController = util.Yesno(reader)
5879
}
5980

60-
if o.r.Group == "" {
61-
log.Fatalf("Must specify --group")
62-
}
63-
if o.r.Version == "" {
64-
log.Fatalf("Must specify --version")
65-
}
66-
if o.r.Kind == "" {
67-
log.Fatalf("Must specify --kind")
81+
if err := o.apiScaffolder.Validate(); err != nil {
82+
log.Fatalln(err)
6883
}
6984

7085
fmt.Println("Writing scaffold for you to edit...")
7186

72-
r := o.r
73-
if o.doResource {
74-
fmt.Println(filepath.Join("pkg", "apis", r.Group, r.Version,
75-
fmt.Sprintf("%s_types.go", strings.ToLower(r.Kind))))
76-
fmt.Println(filepath.Join("pkg", "apis", r.Group, r.Version,
77-
fmt.Sprintf("%s_types_test.go", strings.ToLower(r.Kind))))
78-
79-
err := (&scaffold.Scaffold{}).Execute(input.Options{},
80-
&resource.Register{Resource: r},
81-
&resource.Types{Resource: r},
82-
&resource.VersionSuiteTest{Resource: r},
83-
&resource.TypesTest{Resource: r},
84-
&resource.Doc{Resource: r},
85-
&resource.Group{Resource: r},
86-
&resource.AddToScheme{Resource: r},
87-
&resource.CRDSample{Resource: r},
88-
)
89-
if err != nil {
90-
log.Fatal(err)
91-
}
92-
} else {
93-
// disable generation of example reconcile body if not scaffolding resource
94-
// because this could result in a fork-bomb of k8s resources where watching a
95-
// deployment, replicaset etc. results in generating deployment which
96-
// end up generating replicaset, pod etc recursively.
97-
r.CreateExampleReconcileBody = false
87+
if err := o.apiScaffolder.Scaffold(); err != nil {
88+
log.Fatal(err)
9889
}
9990

100-
if o.doController {
101-
fmt.Println(filepath.Join("pkg", "controller", strings.ToLower(r.Kind),
102-
fmt.Sprintf("%s_controller.go", strings.ToLower(r.Kind))))
103-
fmt.Println(filepath.Join("pkg", "controller", strings.ToLower(r.Kind),
104-
fmt.Sprintf("%s_controller_test.go", strings.ToLower(r.Kind))))
105-
106-
err := (&scaffold.Scaffold{}).Execute(input.Options{},
107-
&controller.Controller{Resource: r},
108-
&controller.AddController{Resource: r},
109-
&controller.Test{Resource: r},
110-
&controller.SuiteTest{Resource: r},
111-
)
112-
if err != nil {
113-
log.Fatal(err)
114-
}
91+
if err := o.postScaffold(); err != nil {
92+
log.Fatal(err)
11593
}
94+
}
11695

117-
if o.doMake {
96+
func (o *apiOptions) postScaffold() error {
97+
if o.runMake {
11898
fmt.Println("Running make...")
11999
cm := exec.Command("make") // #nosec
120100
cm.Stderr = os.Stderr
121101
cm.Stdout = os.Stdout
122102
if err := cm.Run(); err != nil {
123-
log.Fatal(err)
103+
return fmt.Errorf("error running make: %v", err)
124104
}
125105
}
106+
return nil
126107
}
127108

128109
func newAPICommand() *cobra.Command {
129-
o := apiOptions{}
110+
options := apiOptions{
111+
apiScaffolder: scaffold.API{},
112+
}
130113

131114
apiCmd := &cobra.Command{
132115
Use: "create api",
@@ -158,19 +141,11 @@ After the scaffold is written, api will run make on the project.
158141
make run
159142
`,
160143
Run: func(cmd *cobra.Command, args []string) {
161-
o.runAddAPI()
144+
options.runAddAPI()
162145
},
163146
}
164147

165-
apiCmd.Flags().BoolVar(&o.doMake, "make", true,
166-
"if true, run make after generating files")
167-
apiCmd.Flags().BoolVar(&o.doResource, "resource", true,
168-
"if set, generate the resource without prompting the user")
169-
o.resourceFlag = apiCmd.Flag("resource")
170-
apiCmd.Flags().BoolVar(&o.doController, "controller", true,
171-
"if set, generate the controller without prompting the user")
172-
o.controllerFlag = apiCmd.Flag("controller")
173-
o.r = ResourceForFlags(apiCmd.Flags())
148+
options.bindCmdFlags(apiCmd)
174149

175150
return apiCmd
176151
}
@@ -181,15 +156,3 @@ func dieIfNoProject() {
181156
log.Fatalf("Command must be run from a directory containing %s", "PROJECT")
182157
}
183158
}
184-
185-
// ResourceForFlags registers flags for Resource fields and returns the Resource
186-
func ResourceForFlags(f *flag.FlagSet) *resource.Resource {
187-
r := &resource.Resource{}
188-
f.StringVar(&r.Kind, "kind", "", "resource Kind")
189-
f.StringVar(&r.Group, "group", "", "resource Group")
190-
f.StringVar(&r.Version, "version", "", "resource Version")
191-
f.BoolVar(&r.Namespaced, "namespaced", true, "resource is namespaced")
192-
f.BoolVar(&r.CreateExampleReconcileBody, "example", true,
193-
"if true an example reconcile body should be written while scaffolding a resource.")
194-
return r
195-
}

0 commit comments

Comments
 (0)