Skip to content

Commit

Permalink
Export and cleanup scaffolding machinery
Browse files Browse the repository at this point in the history
- Export scaffolding machinery
- Reorganize scaffolding machinery that was in model
- Remove experimental pattern code (old plugin system)

Signed-off-by: Adrian Orive <[email protected]>
  • Loading branch information
Adirio committed Mar 2, 2021
1 parent 85c445e commit 8e56502
Show file tree
Hide file tree
Showing 142 changed files with 1,626 additions and 1,848 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ test-unit: ## Run the unit tests
.PHONY: test-coverage
test-coverage: ## Run unit tests creating the output to report coverage
- rm -rf *.out # Remove all coverage files if exists
go test -race -failfast -tags=integration -coverprofile=coverage-all.out -coverpkg="./pkg/cli/...,./pkg/config/...,./pkg/internal/...,./pkg/model/...,./pkg/plugin/...,./pkg/plugins/golang,./pkg/plugins/internal/..." ./pkg/...
go test -race -failfast -tags=integration -coverprofile=coverage-all.out -coverpkg="./pkg/cli/...,./pkg/config/...,./pkg/internal/...,./pkg/machinery/...,./pkg/model/...,./pkg/plugin/...,./pkg/plugins/golang" ./pkg/...

.PHONY: test-integration
test-integration: ## Run the integration tests
Expand Down
75 changes: 75 additions & 0 deletions pkg/machinery/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2020 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 machinery

import (
"fmt"
)

// This file contains the errors returned by the scaffolding machinery
// They are exported to be able to check which kind of error was returned

// ValidateError is a wrapper error that will be used for errors returned by RequiresValidation.Validate
type ValidateError struct {
error
}

// Unwrap implements Wrapper interface
func (e ValidateError) Unwrap() error {
return e.error
}

// SetTemplateDefaultsError is a wrapper error that will be used for errors returned by Template.SetTemplateDefaults
type SetTemplateDefaultsError struct {
error
}

// Unwrap implements Wrapper interface
func (e SetTemplateDefaultsError) Unwrap() error {
return e.error
}

// ModelAlreadyExistsError is returned if the file is expected not to exist but a previous model does
type ModelAlreadyExistsError struct {
path string
}

// Error implements error interface
func (e ModelAlreadyExistsError) Error() string {
return fmt.Sprintf("failed to create %s: model already exists", e.path)
}

// UnknownIfExistsActionError is returned if the if-exists-action is unknown
type UnknownIfExistsActionError struct {
path string
ifExistsAction IfExistsAction
}

// Error implements error interface
func (e UnknownIfExistsActionError) Error() string {
return fmt.Sprintf("unknown behavior if file exists (%d) for %s", e.ifExistsAction, e.path)
}

// FileAlreadyExistsError is returned if the file is expected not to exist but it does
type FileAlreadyExistsError struct {
path string
}

// Error implements error interface
func (e FileAlreadyExistsError) Error() string {
return fmt.Sprintf("failed to create %s: file already exists", e.path)
}
48 changes: 48 additions & 0 deletions pkg/machinery/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright 2020 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 machinery

import (
"errors"
"path/filepath"

. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
)

var _ = Describe("Errors", func() {
var (
path = filepath.Join("path", "to", "file")
testErr = errors.New("test error")
)

DescribeTable("should contain the wrapped error",
func(err error) {
Expect(errors.Is(err, testErr)).To(BeTrue())
},
Entry("for validate errors", ValidateError{testErr}),
Entry("for set template defaults errors", SetTemplateDefaultsError{testErr}),
)

// NOTE: the following test increases coverage
It("should print a descriptive error message", func() {
Expect(ModelAlreadyExistsError{path}.Error()).To(ContainSubstring("model already exists"))
Expect(UnknownIfExistsActionError{path, -1}.Error()).To(ContainSubstring("unknown behavior if file exists"))
Expect(FileAlreadyExistsError{path}.Error()).To(ContainSubstring("file already exists"))
})
})
16 changes: 8 additions & 8 deletions pkg/model/file/file.go → pkg/machinery/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,30 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package file
package machinery

// IfExistsAction determines what to do if the scaffold file already exists
type IfExistsAction int

const (
// Skip skips the file and moves to the next one
Skip IfExistsAction = iota
// SkipFile skips the file and moves to the next one
SkipFile IfExistsAction = iota

// Error returns an error and stops processing
Error

// Overwrite truncates and overwrites the existing file
Overwrite
// OverwriteFile truncates and overwrites the existing file
OverwriteFile
)

// File describes a file that will be written
type File struct {
// Path is the file to write
Path string `json:"path,omitempty"`
Path string

// Contents is the generated output
Contents string `json:"contents,omitempty"`
Contents string

// IfExistsAction determines what to do if the file exists
IfExistsAction IfExistsAction `json:"ifExistsAction,omitempty"`
IfExistsAction IfExistsAction
}
11 changes: 5 additions & 6 deletions pkg/model/file/funcmap.go → pkg/machinery/funcmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package file
package machinery

import (
"fmt"
Expand All @@ -39,10 +39,9 @@ func isEmptyString(s string) bool {
}

// hashFNV will generate a random string useful for generating a unique string
func hashFNV(s string) (string, error) {
func hashFNV(s string) string {
hasher := fnv.New32a()
if _, err := hasher.Write([]byte(s)); err != nil {
return "", err
}
return fmt.Sprintf("%x", hasher.Sum(nil)), nil
// Hash.Write never returns an error
_, _ = hasher.Write([]byte(s))
return fmt.Sprintf("%x", hasher.Sum(nil))
}
45 changes: 45 additions & 0 deletions pkg/machinery/funcmap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
Copyright 2021 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 machinery

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
)

var _ = Describe("funcmap functions", func() {
Context("isEmptyString", func() {
It("should return true for empty strings", func() {
Expect(isEmptyString("")).To(BeTrue())
})

DescribeTable("should return false for any other string",
func(str string) { Expect(isEmptyString(str)).To(BeFalse()) },
Entry(`for "a"`, "a"),
Entry(`for "1"`, "1"),
Entry(`for "-"`, "-"),
Entry(`for "."`, "."),
)
})

Context("hashFNV", func() {
It("should hash the input", func() {
Expect(hashFNV("test")).To(Equal("afd071e5"))
})
})
})
66 changes: 66 additions & 0 deletions pkg/machinery/injector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Copyright 2021 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 machinery

import (
"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
)

// injector is used to inject certain fields to file templates.
type injector struct {
// config stores the project configuration.
config config.Config

// boilerplate is the copyright comment added at the top of scaffolded files.
boilerplate string

// resource contains the information of the API that is being scaffolded.
resource *resource.Resource
}

// injectInto injects fields from the universe into the builder
func (i injector) injectInto(builder Builder) {
// Inject project configuration
if i.config != nil {
if builderWithDomain, hasDomain := builder.(HasDomain); hasDomain {
builderWithDomain.InjectDomain(i.config.GetDomain())
}
if builderWithRepository, hasRepository := builder.(HasRepository); hasRepository {
builderWithRepository.InjectRepository(i.config.GetRepository())
}
if builderWithProjectName, hasProjectName := builder.(HasProjectName); hasProjectName {
builderWithProjectName.InjectProjectName(i.config.GetProjectName())
}
if builderWithMultiGroup, hasMultiGroup := builder.(HasMultiGroup); hasMultiGroup {
builderWithMultiGroup.InjectMultiGroup(i.config.IsMultiGroup())
}
if builderWithComponentConfig, hasComponentConfig := builder.(HasComponentConfig); hasComponentConfig {
builderWithComponentConfig.InjectComponentConfig(i.config.IsComponentConfig())
}
}
// Inject boilerplate
if builderWithBoilerplate, hasBoilerplate := builder.(HasBoilerplate); hasBoilerplate {
builderWithBoilerplate.InjectBoilerplate(i.boilerplate)
}
// Inject resource
if i.resource != nil {
if builderWithResource, hasResource := builder.(HasResource); hasResource {
builderWithResource.InjectResource(i.resource)
}
}
}
Loading

0 comments on commit 8e56502

Please sign in to comment.