Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring and cleanup in preparation for changing namespaces #2139

Merged
merged 44 commits into from
Mar 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
f750ab2
Delegate IsPreview() to wrapped local reference
theunrepentantgeek Feb 27, 2022
13a9dda
Include version prefix explicitly in LocalPackageReference
theunrepentantgeek Feb 25, 2022
076c9e9
Explicitly pass version reference to constructor of LocalPackageRefer…
theunrepentantgeek Feb 28, 2022
163ebe2
Tolerate prefix already being present in tests
theunrepentantgeek Feb 28, 2022
eb23dab
Create WithPackageReference() method on TypeName
theunrepentantgeek Feb 28, 2022
07bdaf6
Fail fast if a stage purges all type definitions by error
theunrepentantgeek Feb 28, 2022
2b3ce0c
Use test.MakeLocalPackageReference() more consistently
theunrepentantgeek Feb 28, 2022
8528921
Update golden files in functions package
theunrepentantgeek Feb 28, 2022
3c11058
Update golden files in testcases project
theunrepentantgeek Feb 28, 2022
d4b56f1
Fix test root identification
theunrepentantgeek Feb 28, 2022
78da3d7
Fix package reference used for customization types
theunrepentantgeek Mar 1, 2022
2879835
Remove dependency of CreateStorageTypes on the conversion graph
theunrepentantgeek Mar 1, 2022
133841c
Include reason in TypeMatcher errors
theunrepentantgeek Mar 1, 2022
6684087
Code gardening TypeTransformer
theunrepentantgeek Mar 1, 2022
0eb3c5f
Remove prefix from TypeTransforms configuration
theunrepentantgeek Mar 1, 2022
cdc06cd
Change return type of StoragePackageReference.Local()
theunrepentantgeek Mar 2, 2022
55b803e
Change Add() to varidic for convenience
theunrepentantgeek Mar 2, 2022
12c6b2d
Change ConversionGraph to build from existing references only
theunrepentantgeek Mar 2, 2022
d592687
Update pipeline and tests for revised dependencies
theunrepentantgeek Mar 3, 2022
813312d
Move requisite checks into pipeline.State and pipeline.Stage
theunrepentantgeek Mar 3, 2022
8cfd55b
Add Copy() to StringSet
theunrepentantgeek Mar 3, 2022
a5c0430
Update tests to use RunTestPipeline()
theunrepentantgeek Mar 3, 2022
bda9611
Suppress JSON tests on types with no properties
theunrepentantgeek Mar 3, 2022
721906d
Update stage_test.go
theunrepentantgeek Mar 4, 2022
c56b302
Add context to panic while generating functions
theunrepentantgeek Mar 4, 2022
a213644
Add AsSlice() to TypeDefinitionSet
theunrepentantgeek Mar 6, 2022
aaae496
Move pipeline verification into stages
theunrepentantgeek Mar 6, 2022
58dedbf
Allow golden tests to handle multiple files for export
theunrepentantgeek Mar 6, 2022
0d7cad0
Update documentation of pipeline stages
theunrepentantgeek Mar 6, 2022
7e2b2c1
Update golden files
theunrepentantgeek Mar 6, 2022
8243138
Update documentation
theunrepentantgeek Mar 6, 2022
cdb6196
Centralize function generation through method that annotates panics
theunrepentantgeek Mar 9, 2022
8b84771
Fix incorrect namespace `vcustomizations`
theunrepentantgeek Mar 10, 2022
2f1f1ee
Improve doc comment
theunrepentantgeek Mar 10, 2022
a0bea96
Restore functions into golden files
theunrepentantgeek Mar 10, 2022
56f8147
Panic if things go very strange
theunrepentantgeek Mar 10, 2022
767df26
Fix error message
theunrepentantgeek Mar 10, 2022
9c03f08
Update golden tests
theunrepentantgeek Mar 10, 2022
c376299
Fix lint issues
theunrepentantgeek Mar 10, 2022
f636543
Update Crossplane configuration
theunrepentantgeek Mar 10, 2022
6d5dfec
Go fmt
theunrepentantgeek Mar 10, 2022
4ba23c1
Add comment about post-requisites
theunrepentantgeek Mar 10, 2022
994b8c6
Address PR feedback
theunrepentantgeek Mar 10, 2022
d8c8b0e
Fix stupid copy-paste error
theunrepentantgeek Mar 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/hugo/content/contributing/generator-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ One reason for this is to allow the creation of multiple pipelines (currently we

Pipeline stages are instances of `pipeline.Stage`. Each has a factory method that returns a `pipeline.Stage` instance. In operation, each accepts a `pipeline.State` containing the current object model and transforms it into a new state, that is passed to the next stage in turn. If a stage returns an error, the pipeline run is aborted.

New stages should use the `MakeStage()` function. You'll see some older stages that predate a structural change use the deprecated `MakeLegacyStage()` factory instead; these older stages are slowly being migrated and `MakeLegacyStage()` will be deleted when this is complete.
New stages should use the `NewStage()` function. You'll see some older stages that predate a structural change use the deprecated `NewLegacyStage()` factory instead; these older stages are slowly being migrated and `NewLegacyStage()` will be deleted when this is complete.

## Code Generation

Expand Down
4 changes: 2 additions & 2 deletions hack/crossplane/azure-crossplane.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ typeTransformers:
property: Copy
ifType:
group: deploymenttemplate
version: v1alpha1api20190401
version: "2019-04-01"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: Can this just be 2019-04-01? Does it need the quotes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs the quotes, else it seems to get interpreted as a date.

name: ResourceCopy
optional: true
remove: true
Expand All @@ -142,7 +142,7 @@ typeTransformers:
property: Copy
ifType:
group: definitions
version: v1alpha1api
version: "*"
name: ResourceCopy
optional: true
remove: true
Expand Down
4 changes: 2 additions & 2 deletions v2/azure-arm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ typeTransformers:
property: Copy
ifType:
group: deploymenttemplate
version: v1alpha1api20190401
version: "2019-04-01"
name: ResourceCopy
optional: true
remove: true
Expand All @@ -190,7 +190,7 @@ typeTransformers:
property: Copy
ifType:
group: definitions
version: v1alpha1api
version: "*"
name: ResourceCopy
optional: true
remove: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ func (i InterfaceImplementer) AsDeclarations(
})

for _, f := range functions {
result = append(result, f.AsFunc(codeGenerationContext, typeName))
decl := generateMethodDeclForFunction(typeName, f, codeGenerationContext)
result = append(result, decl)
}
}

Expand Down
57 changes: 31 additions & 26 deletions v2/tools/generator/internal/astmodel/local_package_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,26 @@ type LocalPackageReference struct {
localPathPrefix string
group string
version string
versionPrefix string
}

var (
_ PackageReference = LocalPackageReference{}
_ fmt.Stringer = LocalPackageReference{}
)

const generatorVersionPrefix string = "v1alpha1api"
const GeneratorVersionPrefix string = "v1alpha1api"

// MakeLocalPackageReference Creates a new local package reference from a group and version
func MakeLocalPackageReference(prefix string, group string, version string) LocalPackageReference {
func MakeLocalPackageReference(prefix string, group string, versionPrefix string, version string) LocalPackageReference {
return LocalPackageReference{
localPathPrefix: prefix,
group: group,
version: version,
versionPrefix: versionPrefix,
version: sanitizePackageName(version),
}
}

// CreateLocalPackageNameFromVersion transforms a version string (2018-06-01) into a package
// name (v1alpha1api20180601)
func CreateLocalPackageNameFromVersion(version string) string {
return generatorVersionPrefix + sanitizePackageName(version)
}

// sanitizePackageName removes all non-alphanum characters and converts to lower case
func sanitizePackageName(input string) string {
var builder []rune = make([]rune, 0, len(input))

for _, r := range input {
if unicode.IsLetter(r) || unicode.IsNumber(r) {
builder = append(builder, unicode.ToLower(rune(r)))
}
}

return string(builder)
}

// LocalPathPrefix returns the prefix (everything up to the group name)
func (pr LocalPackageReference) LocalPathPrefix() string {
return pr.localPathPrefix
Expand All @@ -65,17 +48,17 @@ func (pr LocalPackageReference) Group() string {

// Version returns the version of this local reference
func (pr LocalPackageReference) Version() string {
return pr.version
return pr.versionPrefix + pr.version
}

// PackageName returns the package name of this reference
func (pr LocalPackageReference) PackageName() string {
return pr.version
return pr.Version()
}

// PackagePath returns the fully qualified package path
func (pr LocalPackageReference) PackagePath() string {
url := pr.localPathPrefix + "/" + pr.group + "/" + pr.version
url := pr.localPathPrefix + "/" + pr.group + "/" + pr.PackageName()
return url
}

Expand All @@ -87,6 +70,7 @@ func (pr LocalPackageReference) Equals(ref PackageReference) bool {

if other, ok := ref.(LocalPackageReference); ok {
return pr.localPathPrefix == other.localPathPrefix &&
pr.versionPrefix == other.versionPrefix &&
pr.version == other.version &&
pr.group == other.group
}
Expand All @@ -100,10 +84,18 @@ func (pr LocalPackageReference) String() string {
}

// IsPreview returns true if this package reference is a preview
// We don't check the version prefix (which contains the version of the generator) as that may contain alpha or beta
// even if the ARM version is not preview.
func (pr LocalPackageReference) IsPreview() bool {
return containsPreviewVersionLabel(strings.ToLower(pr.version))
}

// WithVersionPrefix returns a new LocalPackageReference with a different version prefix
func (pr LocalPackageReference) WithVersionPrefix(prefix string) LocalPackageReference {
pr.versionPrefix = prefix
return pr
}

// IsLocalPackageReference returns true if the supplied reference is a local one
func IsLocalPackageReference(ref PackageReference) bool {
_, ok := ref.(LocalPackageReference)
Expand All @@ -112,5 +104,18 @@ func IsLocalPackageReference(ref PackageReference) bool {

// GroupVersion returns the group and version of this local reference.
func (pr LocalPackageReference) GroupVersion() (string, string, bool) {
return pr.group, pr.version, true
return pr.group, pr.Version(), true
}

// sanitizePackageName removes all non-alphanumeric characters and converts to lower case
func sanitizePackageName(input string) string {
var builder = make([]rune, 0, len(input))

for _, r := range input {
if unicode.IsLetter(r) || unicode.IsNumber(r) {
builder = append(builder, unicode.ToLower(r))
}
}

return string(builder)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,30 @@ import (
)

func makeTestLocalPackageReference(group string, version string) LocalPackageReference {
return MakeLocalPackageReference("github.com/Azure/azure-service-operator/v2/api", group, version)
// We use a fixed path and version prefixes to ensure consistency across testing
return MakeLocalPackageReference("github.com/Azure/azure-service-operator/v2/api", group, "v", version)
}

func TestMakeLocalPackageReference_GivenGroupAndPackage_ReturnsInstanceWithProperties(t *testing.T) {
t.Parallel()

cases := []struct {
name string
group string
pkg string
name string
group string
version string
pkg string
}{
{"Networking", "microsoft.networking", "v20200901"},
{"Batch (new)", "microsoft.batch", "v20200901"},
{"Batch (old)", "microsoft.batch", "v20150101"},
{"Networking", "microsoft.networking", "2020-09-01", "v20200901"},
{"Batch (new)", "microsoft.batch", "2020-09-01", "v20200901"},
{"Batch (old)", "microsoft.batch", "2015-01-01", "v20150101"},
}
for _, c := range cases {
c := c
t.Run(c.name, func(t *testing.T) {
t.Parallel()
g := NewGomegaWithT(t)

ref := makeTestLocalPackageReference(c.group, c.pkg)
ref := makeTestLocalPackageReference(c.group, c.version)
grp := ref.Group()
pkg := ref.PackageName()

Expand All @@ -49,24 +51,28 @@ func TestLocalPackageReferences_ReturnExpectedProperties(t *testing.T) {
cases := []struct {
name string
group string
version string
pkg string
expectedPath string
}{
{
"Networking",
"microsoft.networking",
"2020-09-01",
"v20200901",
"github.com/Azure/azure-service-operator/v2/api/microsoft.networking/v20200901",
},
{
"Batch (new)",
"microsoft.batch",
"2020-09-01",
"v20200901",
"github.com/Azure/azure-service-operator/v2/api/microsoft.batch/v20200901",
},
{
"Batch (old)",
"microsoft.batch",
"2015-01-01",
"v20150101",
"github.com/Azure/azure-service-operator/v2/api/microsoft.batch/v20150101",
},
Expand All @@ -77,7 +83,7 @@ func TestLocalPackageReferences_ReturnExpectedProperties(t *testing.T) {
t.Parallel()
g := NewGomegaWithT(t)

ref := makeTestLocalPackageReference(c.group, c.pkg)
ref := makeTestLocalPackageReference(c.group, c.version)
grp := ref.Group()
g.Expect(ref.PackageName()).To(Equal(c.pkg))
g.Expect(ref.PackagePath()).To(Equal(c.expectedPath))
Expand Down Expand Up @@ -144,9 +150,7 @@ func TestLocalPackageReferenceIsPreview(t *testing.T) {
t.Parallel()
g := NewGomegaWithT(t)

ref := makeTestLocalPackageReference(
"microsoft.storage",
CreateLocalPackageNameFromVersion(c.version))
ref := makeTestLocalPackageReference("microsoft.storage", c.version)

g.Expect(ref.IsPreview()).To(Equal(c.isPreview))
})
Expand Down
11 changes: 10 additions & 1 deletion v2/tools/generator/internal/astmodel/object_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func (objectType *ObjectType) generateMethodDecls(codeGenerationContext *CodeGen
var result []dst.Decl

for _, f := range objectType.Functions() {
funcDef := f.AsFunc(codeGenerationContext, typeName)
funcDef := generateMethodDeclForFunction(typeName, f, codeGenerationContext)
result = append(result, funcDef)
}

Expand Down Expand Up @@ -453,6 +453,15 @@ func (objectType *ObjectType) WithFunction(function Function) *ObjectType {
return result
}

// WithoutFunctions creates a new ObjectType with no functions (useful for testing)
func (objectType *ObjectType) WithoutFunctions() *ObjectType {
// Create a copy to preserve immutability
result := objectType.copy()
result.functions = make(map[string]Function)

return result
}

// WithInterface creates a new ObjectType that's a copy with an interface implementation attached
func (objectType *ObjectType) WithInterface(iface *InterfaceImplementation) *ObjectType {
// Create a copy of objectType to preserve immutability
Expand Down
9 changes: 1 addition & 8 deletions v2/tools/generator/internal/astmodel/package_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,15 +266,8 @@ func (v *versionComparer) isPreviewVersionLabel(identifier string) (int, bool) {
// special set, and if so returns its true. If the passed identifier does not contain one,
// returns false.
func containsPreviewVersionLabel(identifier string) bool {
// Work out where the API version starts in the identifier
// (We don't want to return preview just because the operator itself is in preview)
startOfAPIVersion := 0
if strings.HasPrefix(identifier, generatorVersionPrefix) {
startOfAPIVersion = len(generatorVersionPrefix)
}

for _, id := range previewVersionLabels {
if strings.LastIndex(identifier, id) > startOfAPIVersion {
if strings.LastIndex(identifier, id) > 0 {
theunrepentantgeek marked this conversation as resolved.
Show resolved Hide resolved
return true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestPropertyReference_IsEmpty_ReturnsExpectedResult(t *testing.T) {
func TestPropertyReference_String_ReturnsExpectedResult(t *testing.T) {
t.Parallel()
g := NewGomegaWithT(t)
pkg := makeTestLocalPackageReference("Demo", "v1")
pkg := makeTestLocalPackageReference("Demo", "1")
declaringType := MakeTypeName(pkg, "Person")
property := PropertyName("FullName")

Expand Down
31 changes: 30 additions & 1 deletion v2/tools/generator/internal/astmodel/resource_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,15 @@ func (resource *ResourceType) WithFunction(function Function) *ResourceType {
return result
}

// WithoutFunctions creates a new Resource with no functions (useful for testing)
func (resource *ResourceType) WithoutFunctions() *ResourceType {
// Create a copy to preserve immutability
result := resource.copy()
result.functions = make(map[string]Function)

return result
}

// WithTestCase creates a new Resource that's a copy with an additional test case included
func (resource *ResourceType) WithTestCase(testcase TestCase) *ResourceType {
result := resource.copy()
Expand Down Expand Up @@ -596,7 +605,7 @@ func (resource *ResourceType) generateMethodDecls(codeGenerationContext *CodeGen
var result []dst.Decl

for _, f := range resource.Functions() {
funcDef := f.AsFunc(codeGenerationContext, typeName)
funcDef := generateMethodDeclForFunction(typeName, f, codeGenerationContext)
result = append(result, funcDef)
}

Expand Down Expand Up @@ -717,3 +726,23 @@ func (resource *ResourceType) WriteDebugDescription(builder *strings.Builder, de
resource.status.WriteDebugDescription(builder, definitions)
builder.WriteString("]")
}

// generateMethodDeclForFunction generates the AST for a function; if a panic occurs, the identity of the type and
// function being generated will be wrapped around the existing panic details to aid in debugging.
func generateMethodDeclForFunction(
typeName TypeName,
f Function,
codeGenerationContext *CodeGenerationContext) *dst.FuncDecl {

defer func() {
if err := recover(); err != nil {
panic(fmt.Sprintf(
"generating method declaration for %s.%s: %s",
typeName.Name(),
f.Name(),
err))
}
}()

return f.AsFunc(codeGenerationContext, typeName)
}
Loading