diff --git a/hack/generator/pkg/codegen/code_generator.go b/hack/generator/pkg/codegen/code_generator.go index 699b0c94166..7f2a3274ea1 100644 --- a/hack/generator/pkg/codegen/code_generator.go +++ b/hack/generator/pkg/codegen/code_generator.go @@ -15,7 +15,6 @@ import ( "github.com/Azure/azure-service-operator/hack/generator/pkg/astmodel" "github.com/Azure/azure-service-operator/hack/generator/pkg/codegen/pipeline" - "github.com/Azure/azure-service-operator/hack/generator/pkg/codegen/storage" "github.com/Azure/azure-service-operator/hack/generator/pkg/config" ) @@ -79,9 +78,6 @@ func NewCodeGeneratorFromConfig(configuration *config.Configuration, idFactory a } func createAllPipelineStages(idFactory astmodel.IdentifierFactory, configuration *config.Configuration) []pipeline.Stage { - // graph keeps track of the conversions we need between different API & Storage versions - graph := storage.NewConversionGraph() - return []pipeline.Stage{ pipeline.LoadSchemaIntoTypes(idFactory, configuration, pipeline.DefaultSchemaLoader), @@ -158,9 +154,9 @@ func createAllPipelineStages(idFactory astmodel.IdentifierFactory, configuration // Create Storage types // TODO: For now only used for ARM pipeline.InjectOriginalVersionFunction(idFactory).UsedFor(pipeline.ARMTarget), - pipeline.CreateStorageTypes(graph).UsedFor(pipeline.ARMTarget), + pipeline.CreateStorageTypes().UsedFor(pipeline.ARMTarget), pipeline.InjectOriginalVersionProperty().UsedFor(pipeline.ARMTarget), - pipeline.InjectPropertyAssignmentFunctions(graph, idFactory).UsedFor(pipeline.ARMTarget), + pipeline.InjectPropertyAssignmentFunctions(idFactory).UsedFor(pipeline.ARMTarget), pipeline.InjectOriginalGVKFunction(idFactory).UsedFor(pipeline.ARMTarget), pipeline.SimplifyDefinitions(), @@ -194,17 +190,17 @@ func createAllPipelineStages(idFactory astmodel.IdentifierFactory, configuration func (generator *CodeGenerator) Generate(ctx context.Context) error { klog.V(1).Infof("Generator version: %v", pipeline.CombinedVersion()) - defs := make(astmodel.Types) + state := pipeline.NewState() for i, stage := range generator.pipeline { klog.V(0).Infof("%d/%d: %s", i+1, len(generator.pipeline), stage.Description()) // Defensive copy (in case the pipeline modifies its inputs) so that we can compare types in vs out - defsOut, err := stage.Run(ctx, defs.Copy()) + stateOut, err := stage.Run(ctx, state) if err != nil { return errors.Wrapf(err, "failed during pipeline stage %d/%d: %s", i+1, len(generator.pipeline), stage.Description()) } - defsAdded := defsOut.Except(defs) - defsRemoved := defs.Except(defsOut) + defsAdded := stateOut.Types().Except(state.Types()) + defsRemoved := state.Types().Except(stateOut.Types()) if len(defsAdded) > 0 && len(defsRemoved) > 0 { klog.V(1).Infof("Added %d, removed %d type definitions", len(defsAdded), len(defsRemoved)) @@ -214,7 +210,7 @@ func (generator *CodeGenerator) Generate(ctx context.Context) error { klog.V(1).Infof("Removed %d type definitions", len(defsRemoved)) } - defs = defsOut + state = stateOut } klog.Info("Finished") diff --git a/hack/generator/pkg/codegen/code_generator_test.go b/hack/generator/pkg/codegen/code_generator_test.go index c291f3f7919..229866a5759 100644 --- a/hack/generator/pkg/codegen/code_generator_test.go +++ b/hack/generator/pkg/codegen/code_generator_test.go @@ -66,7 +66,7 @@ func TestRemoveStages_PanicsForUnknownStage(t *testing.T) { } func MakeFakePipelineStage(id string) pipeline.Stage { - return pipeline.MakeStage( + return pipeline.MakeLegacyStage( id, "Stage "+id, func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { return types, nil }) diff --git a/hack/generator/pkg/codegen/golden_files_test.go b/hack/generator/pkg/codegen/golden_files_test.go index 9b43aba189f..9952eacb81a 100644 --- a/hack/generator/pkg/codegen/golden_files_test.go +++ b/hack/generator/pkg/codegen/golden_files_test.go @@ -72,7 +72,7 @@ func makeEmbeddedTestTypeDefinition() astmodel.TypeDefinition { } func injectEmbeddedStructType() pipeline.Stage { - return pipeline.MakeStage( + return pipeline.MakeLegacyStage( "injectEmbeddedStructType", "Injects an embedded struct into each object", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { @@ -194,7 +194,7 @@ func loadTestSchemaIntoTypes( path string) pipeline.Stage { source := configuration.SchemaURL - return pipeline.MakeStage( + return pipeline.MakeLegacyStage( "loadTestSchema", "Load and walk schema (test)", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { @@ -227,7 +227,7 @@ func loadTestSchemaIntoTypes( func exportPackagesTestPipelineStage(t *testing.T, testName string) pipeline.Stage { g := goldie.New(t) - return pipeline.MakeStage( + return pipeline.MakeLegacyStage( "exportTestPackages", "Export packages for test", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { @@ -272,7 +272,7 @@ func exportPackagesTestPipelineStage(t *testing.T, testName string) pipeline.Sta } func stripUnusedTypesPipelineStage() pipeline.Stage { - return pipeline.MakeStage( + return pipeline.MakeLegacyStage( "stripUnused", "Strip unused types for test", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { @@ -295,7 +295,7 @@ func stripUnusedTypesPipelineStage() pipeline.Stage { // TODO: we're hard-coding references, and even if we were sourcing them from Swagger // TODO: we have no way to give Swagger to the golden files tests currently. func addCrossResourceReferencesForTest(idFactory astmodel.IdentifierFactory) pipeline.Stage { - return pipeline.MakeStage( + return pipeline.MakeLegacyStage( "addCrossResourceReferences", "Add cross resource references for test", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/add_arm_conversion_interface.go b/hack/generator/pkg/codegen/pipeline/add_arm_conversion_interface.go index c0b9c1612dd..09132c99331 100644 --- a/hack/generator/pkg/codegen/pipeline/add_arm_conversion_interface.go +++ b/hack/generator/pkg/codegen/pipeline/add_arm_conversion_interface.go @@ -19,7 +19,7 @@ import ( // to all Kubernetes types. // The genruntime.ARMTransformer interface is used to convert from the Kubernetes type to the corresponding ARM type and back. func ApplyARMConversionInterface(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "applyArmConversionInterface", "Add ARM conversion interfaces to Kubernetes types", func(ctx context.Context, definitions astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/add_cross_resource_references.go b/hack/generator/pkg/codegen/pipeline/add_cross_resource_references.go index 424f6d7275c..102f9a8b54e 100644 --- a/hack/generator/pkg/codegen/pipeline/add_cross_resource_references.go +++ b/hack/generator/pkg/codegen/pipeline/add_cross_resource_references.go @@ -24,7 +24,7 @@ var armIDDescriptionRegex = regexp.MustCompile("(?i).*/subscriptions/.*?/resourc // AddCrossResourceReferences replaces cross resource references with genruntime.ResourceReference. func AddCrossResourceReferences(configuration *config.Configuration, idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "addCrossResourceReferences", "Replace cross-resource references with genruntime.ResourceReference", func(ctx context.Context, definitions astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/apply_export_filters.go b/hack/generator/pkg/codegen/pipeline/apply_export_filters.go index ce0024694cf..5c74adc9c8a 100644 --- a/hack/generator/pkg/codegen/pipeline/apply_export_filters.go +++ b/hack/generator/pkg/codegen/pipeline/apply_export_filters.go @@ -17,7 +17,7 @@ import ( // ApplyExportFilters creates a Stage to reduce our set of types for export func ApplyExportFilters(configuration *config.Configuration) Stage { - return MakeStage( + return MakeLegacyStage( "filterTypes", "Apply export filters to reduce the number of generated types", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/apply_kubernetes_resource_interface.go b/hack/generator/pkg/codegen/pipeline/apply_kubernetes_resource_interface.go index f5369f20938..f49db51870c 100644 --- a/hack/generator/pkg/codegen/pipeline/apply_kubernetes_resource_interface.go +++ b/hack/generator/pkg/codegen/pipeline/apply_kubernetes_resource_interface.go @@ -16,7 +16,7 @@ import ( // ApplyKubernetesResourceInterface ensures that every Resource implements the KubernetesResource interface func ApplyKubernetesResourceInterface(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "applyKubernetesResourceInterface", "Add the KubernetesResource interface to every resource", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/apply_property_rewrites.go b/hack/generator/pkg/codegen/pipeline/apply_property_rewrites.go index d51f95e50d4..767fdef5924 100644 --- a/hack/generator/pkg/codegen/pipeline/apply_property_rewrites.go +++ b/hack/generator/pkg/codegen/pipeline/apply_property_rewrites.go @@ -19,7 +19,7 @@ import ( // been "lowered" to objects. func ApplyPropertyRewrites(config *config.Configuration) Stage { - return MakeStage( + return MakeLegacyStage( "propertyRewrites", "Modify property types using configured transforms", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/assert_types_collection_valid.go b/hack/generator/pkg/codegen/pipeline/assert_types_collection_valid.go index 7e7649ae2f5..b0f053dd960 100644 --- a/hack/generator/pkg/codegen/pipeline/assert_types_collection_valid.go +++ b/hack/generator/pkg/codegen/pipeline/assert_types_collection_valid.go @@ -15,7 +15,7 @@ import ( // has TypeName's that are all reachable as well. This check fails if there is any TypeName that refers to a type that doesn't // exist. func AssertTypesCollectionValid() Stage { - return MakeStage( + return MakeLegacyStage( "assertTypesStructureValid", "Verify that all local TypeNames refer to a type", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/check_for_anytype.go b/hack/generator/pkg/codegen/pipeline/check_for_anytype.go index 644bfc4542f..ee4c88353a4 100644 --- a/hack/generator/pkg/codegen/pipeline/check_for_anytype.go +++ b/hack/generator/pkg/codegen/pipeline/check_for_anytype.go @@ -40,7 +40,7 @@ func checkForAnyType(description string, packages []string) Stage { expectedPackages[p] = struct{}{} } - return MakeStage( + return MakeLegacyStage( "rogueCheck", description, func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/check_for_anytype_test.go b/hack/generator/pkg/codegen/pipeline/check_for_anytype_test.go index 21e84c6977d..c8414116d24 100644 --- a/hack/generator/pkg/codegen/pipeline/check_for_anytype_test.go +++ b/hack/generator/pkg/codegen/pipeline/check_for_anytype_test.go @@ -27,6 +27,7 @@ func TestFindsAnyTypes(t *testing.T) { add := func(p astmodel.PackageReference, n string, t astmodel.Type) { defs.Add(astmodel.MakeTypeDefinition(astmodel.MakeTypeName(p, n), t)) } + // A couple of types in the same package... add(p1, "A", astmodel.AnyType) add(p1, "B", astmodel.NewObjectType().WithProperties( @@ -38,9 +39,11 @@ func TestFindsAnyTypes(t *testing.T) { // One that's fine. add(p3, "C", astmodel.NewArrayType(astmodel.IntType)) - results, err := FilterOutDefinitionsUsingAnyType(nil).action(context.Background(), defs) + state := NewState().WithTypes(defs) + stage := FilterOutDefinitionsUsingAnyType(nil) + finalState, err := stage.Run(context.Background(), state) - g.Expect(results).To(HaveLen(0)) + g.Expect(finalState).To(BeNil()) g.Expect(err).To(MatchError("AnyTypes found - add exclusions for: horo.logy/v20200730, road.train/v20200730")) } @@ -66,14 +69,16 @@ func TestIgnoresExpectedAnyTypePackages(t *testing.T) { add(p3, "C", astmodel.NewArrayType(astmodel.IntType)) exclusions := []string{"horo.logy/v20200730", "road.train/v20200730"} - results, err := FilterOutDefinitionsUsingAnyType(exclusions).action(context.Background(), defs) + + state := NewState().WithTypes(defs) + finalState, err := FilterOutDefinitionsUsingAnyType(exclusions).action(context.Background(), state) g.Expect(err).To(BeNil()) expected := make(astmodel.Types) expected.Add(astmodel.MakeTypeDefinition( astmodel.MakeTypeName(p3, "C"), astmodel.NewArrayType(astmodel.IntType), )) - g.Expect(results).To(Equal(expected)) + g.Expect(finalState.Types()).To(Equal(expected)) } func TestComplainsAboutUnneededExclusions(t *testing.T) { @@ -103,7 +108,10 @@ func TestComplainsAboutUnneededExclusions(t *testing.T) { "gamma.knife/v20200821", "road.train/v20200730", } - results, err := FilterOutDefinitionsUsingAnyType(exclusions).action(context.Background(), defs) - g.Expect(results).To(HaveLen(0)) + + state := NewState().WithTypes(defs) + stage := FilterOutDefinitionsUsingAnyType(exclusions) + finalState, err := stage.Run(context.Background(), state) + g.Expect(finalState).To(BeNil()) g.Expect(errors.Cause(err)).To(MatchError("no AnyTypes found in: gamma.knife/v20200821, people.vultures/20200821")) } diff --git a/hack/generator/pkg/codegen/pipeline/collapse_cross_group_refs.go b/hack/generator/pkg/codegen/pipeline/collapse_cross_group_refs.go index 30189e1e29c..1663fa64a51 100644 --- a/hack/generator/pkg/codegen/pipeline/collapse_cross_group_refs.go +++ b/hack/generator/pkg/codegen/pipeline/collapse_cross_group_refs.go @@ -16,7 +16,7 @@ import ( // CollapseCrossGroupReferences finds and removes references between API groups. This isn't particularly common // but does occur in a few instances, for example from Microsoft.Compute -> Microsoft.Compute.Extensions. func CollapseCrossGroupReferences() Stage { - return MakeStage( + return MakeLegacyStage( "collapseCrossGroupReferences", "Finds and removes cross group references", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/convert_allof_and_oneof_to_objects.go b/hack/generator/pkg/codegen/pipeline/convert_allof_and_oneof_to_objects.go index 9e98e16144f..425260b9f03 100644 --- a/hack/generator/pkg/codegen/pipeline/convert_allof_and_oneof_to_objects.go +++ b/hack/generator/pkg/codegen/pipeline/convert_allof_and_oneof_to_objects.go @@ -30,7 +30,7 @@ var ( // ConvertAllOfAndOneOfToObjects reduces the AllOfType and OneOfType to ObjectType func ConvertAllOfAndOneOfToObjects(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "allof-anyof-objects", "Convert allOf and oneOf to object types", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/create_arm_types.go b/hack/generator/pkg/codegen/pipeline/create_arm_types.go index f72fcf6e9f1..c68a0b8d041 100644 --- a/hack/generator/pkg/codegen/pipeline/create_arm_types.go +++ b/hack/generator/pkg/codegen/pipeline/create_arm_types.go @@ -18,7 +18,7 @@ import ( // CreateARMTypes walks the type graph and builds new types for communicating // with ARM func CreateARMTypes(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "createArmTypes", "Create types for interaction with ARM", func(ctx context.Context, definitions astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/create_storage_types.go b/hack/generator/pkg/codegen/pipeline/create_storage_types.go index aca9533ce38..025b6397156 100644 --- a/hack/generator/pkg/codegen/pipeline/create_storage_types.go +++ b/hack/generator/pkg/codegen/pipeline/create_storage_types.go @@ -19,11 +19,11 @@ const CreateStorageTypesStageId = "createStorageTypes" // CreateStorageTypes returns a pipeline stage that creates dedicated storage types for each resource and nested object. // Storage versions are created for *all* API versions to allow users of older versions of the operator to easily // upgrade. This is of course a bit odd for the first release, but defining the approach from day one is useful. -func CreateStorageTypes(conversionGraph *storage.ConversionGraph) Stage { +func CreateStorageTypes() Stage { result := MakeStage( CreateStorageTypesStageId, "Create storage versions of CRD types", - func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { + func(ctx context.Context, state *State) (*State, error) { // Predicate to isolate both resources and complex objects isPropertyContainer := func(def astmodel.TypeDefinition) bool { @@ -37,12 +37,13 @@ func CreateStorageTypes(conversionGraph *storage.ConversionGraph) Stage { } // Filter to the types we want to process - typesToConvert := types.Where(isPropertyContainer).Where(isNotARMType) + typesToConvert := state.Types().Where(isPropertyContainer).Where(isNotARMType) storageTypes := make(astmodel.Types) - typeConverter := storage.NewTypeConverter(types) + typeConverter := storage.NewTypeConverter(state.Types()) // Create storage variants + conversionGraph := storage.NewConversionGraph() for name, def := range typesToConvert { storageDef, err := typeConverter.ConvertDefinition(def) if err != nil { @@ -53,9 +54,10 @@ func CreateStorageTypes(conversionGraph *storage.ConversionGraph) Stage { conversionGraph.AddLink(name.PackageReference, storageDef.Name().PackageReference) } - result := types.Copy() - result.AddTypes(storageTypes) - return result, nil + types := state.Types().Copy() + types.AddTypes(storageTypes) + + return state.WithTypes(types).WithConversionGraph(conversionGraph), nil }) result.RequiresPrerequisiteStages(injectOriginalVersionFunctionStageId) diff --git a/hack/generator/pkg/codegen/pipeline/create_storage_types_test.go b/hack/generator/pkg/codegen/pipeline/create_storage_types_test.go index 6bd50f3484e..0c5f33622ae 100644 --- a/hack/generator/pkg/codegen/pipeline/create_storage_types_test.go +++ b/hack/generator/pkg/codegen/pipeline/create_storage_types_test.go @@ -12,7 +12,6 @@ import ( . "github.com/onsi/gomega" "github.com/Azure/azure-service-operator/hack/generator/pkg/astmodel" - "github.com/Azure/azure-service-operator/hack/generator/pkg/codegen/storage" "github.com/Azure/azure-service-operator/hack/generator/pkg/test" ) @@ -42,14 +41,13 @@ func TestCreateStorageTypes(t *testing.T) { types.AddAll(resourceV1, specV1, statusV1, resourceV2, specV2, statusV2, address2021) // Run the stage - - graph := storage.NewConversionGraph() - createStorageTypes := CreateStorageTypes(graph) + createStorageTypes := CreateStorageTypes() // Don't need a context when testing - finalTypes, err := createStorageTypes.Run(context.TODO(), types) + state := NewState() + finalState, err := createStorageTypes.Run(context.TODO(), state) g.Expect(err).To(Succeed()) - test.AssertPackagesGenerateExpectedCode(t, finalTypes, t.Name()) + test.AssertPackagesGenerateExpectedCode(t, finalState.Types(), t.Name()) } diff --git a/hack/generator/pkg/codegen/pipeline/crossplane_add_at_provider.go b/hack/generator/pkg/codegen/pipeline/crossplane_add_at_provider.go index 5ffc63f25ea..9b08e33295a 100644 --- a/hack/generator/pkg/codegen/pipeline/crossplane_add_at_provider.go +++ b/hack/generator/pkg/codegen/pipeline/crossplane_add_at_provider.go @@ -17,7 +17,7 @@ import ( // AddCrossplaneAtProvider adds an "AtProvider" property as the sole property in every resource status func AddCrossplaneAtProvider(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "addCrossplaneAtProviderProperty", "Add an 'AtProvider' property on every status", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/crossplane_add_embedded_resource_spec.go b/hack/generator/pkg/codegen/pipeline/crossplane_add_embedded_resource_spec.go index 2eab407b958..e9d800f9b2d 100644 --- a/hack/generator/pkg/codegen/pipeline/crossplane_add_embedded_resource_spec.go +++ b/hack/generator/pkg/codegen/pipeline/crossplane_add_embedded_resource_spec.go @@ -18,7 +18,7 @@ var CrossplaneRuntimeV1Alpha1Package = astmodel.MakeExternalPackageReference("gi // AddCrossplaneEmbeddedResourceSpec puts an embedded runtimev1alpha1.ResourceSpec on every spec type func AddCrossplaneEmbeddedResourceSpec(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "addCrossplaneEmbeddedResourceSpec", "Add an embedded runtimev1alpha1.ResourceSpec to every spec type", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/crossplane_add_embedded_resource_status.go b/hack/generator/pkg/codegen/pipeline/crossplane_add_embedded_resource_status.go index 11b3b321b86..ee239e9e891 100644 --- a/hack/generator/pkg/codegen/pipeline/crossplane_add_embedded_resource_status.go +++ b/hack/generator/pkg/codegen/pipeline/crossplane_add_embedded_resource_status.go @@ -16,7 +16,7 @@ import ( // AddCrossplaneEmbeddedResourceStatus puts an embedded runtimev1alpha1.ResourceStatus on every spec type func AddCrossplaneEmbeddedResourceStatus(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "addCrossplaneEmbeddedResourceStatus", "Add an embedded runtimev1alpha1.ResourceStatus to every status type", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/crossplane_add_for_provider.go b/hack/generator/pkg/codegen/pipeline/crossplane_add_for_provider.go index 067aeb8372f..a6255c9680a 100644 --- a/hack/generator/pkg/codegen/pipeline/crossplane_add_for_provider.go +++ b/hack/generator/pkg/codegen/pipeline/crossplane_add_for_provider.go @@ -18,7 +18,7 @@ import ( // and moves everything that was at the spec level down a level into the ForProvider type func AddCrossplaneForProvider(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "addCrossplaneForProviderProperty", "Add a 'ForProvider' property on every spec", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/crossplane_add_owner_properties.go b/hack/generator/pkg/codegen/pipeline/crossplane_add_owner_properties.go index 020a21311ad..ae87c2f8b63 100644 --- a/hack/generator/pkg/codegen/pipeline/crossplane_add_owner_properties.go +++ b/hack/generator/pkg/codegen/pipeline/crossplane_add_owner_properties.go @@ -17,7 +17,7 @@ import ( // AddCrossplaneOwnerProperties adds the 3-tuple of (xName, xNameRef, xNameSelector) for each owning resource func AddCrossplaneOwnerProperties(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "addCrossplaneOwnerProperties", "Add the 3-tuple of (xName, xNameRef, xNameSelector) for each owning resource", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/delete_generated_code.go b/hack/generator/pkg/codegen/pipeline/delete_generated_code.go index 5b205d6d980..4b21c1c652f 100644 --- a/hack/generator/pkg/codegen/pipeline/delete_generated_code.go +++ b/hack/generator/pkg/codegen/pipeline/delete_generated_code.go @@ -25,7 +25,7 @@ import ( // DeleteGeneratedCode creates a pipeline stage for cleanup of our output folder prior to generating files func DeleteGeneratedCode(outputFolder string) Stage { - return MakeStage( + return MakeLegacyStage( "deleteGenerated", "Delete generated code from "+outputFolder, func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/determine_resource_ownership.go b/hack/generator/pkg/codegen/pipeline/determine_resource_ownership.go index 2cf585eec6c..6dac1de1475 100644 --- a/hack/generator/pkg/codegen/pipeline/determine_resource_ownership.go +++ b/hack/generator/pkg/codegen/pipeline/determine_resource_ownership.go @@ -18,7 +18,7 @@ import ( const resourcesPropertyName = astmodel.PropertyName("Resources") func DetermineResourceOwnership(configuration *config.Configuration) Stage { - return MakeStage( + return MakeLegacyStage( "determineResourceOwnership", "Determine ARM resource relationships", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/ensure_type_has_arm_type.go b/hack/generator/pkg/codegen/pipeline/ensure_type_has_arm_type.go index 9fd74da6ca0..401ddb8831c 100644 --- a/hack/generator/pkg/codegen/pipeline/ensure_type_has_arm_type.go +++ b/hack/generator/pkg/codegen/pipeline/ensure_type_has_arm_type.go @@ -17,7 +17,7 @@ import ( // TODO: Wondering if we should have an even stronger version of this that asserts it for all types rather than just the top level? // EnsureARMTypeExistsForEveryResource performs a check ensuring that every Kubernetes resource spec/status has a corresponding ARM type func EnsureARMTypeExistsForEveryResource() Stage { - return MakeStage( + return MakeLegacyStage( "ensureArmTypeExistsForEveryType", "Check that an ARM type exists for both Spec and Status of each resource", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/export_controller_type_registrations.go b/hack/generator/pkg/codegen/pipeline/export_controller_type_registrations.go index aed0b563081..01f7cc0e705 100644 --- a/hack/generator/pkg/codegen/pipeline/export_controller_type_registrations.go +++ b/hack/generator/pkg/codegen/pipeline/export_controller_type_registrations.go @@ -17,7 +17,7 @@ import ( // ExportControllerResourceRegistrations creates a Stage to generate type registrations // for resources. func ExportControllerResourceRegistrations(outputPath string) Stage { - return MakeStage( + return MakeLegacyStage( "exportControllerResourceRegistrations", fmt.Sprintf("Export resource registrations to %q", outputPath), func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/export_generated_code.go b/hack/generator/pkg/codegen/pipeline/export_generated_code.go index 6e770f948e6..b8422ba7fc9 100644 --- a/hack/generator/pkg/codegen/pipeline/export_generated_code.go +++ b/hack/generator/pkg/codegen/pipeline/export_generated_code.go @@ -24,7 +24,7 @@ import ( // ExportPackages creates a Stage to export our generated code as a set of packages func ExportPackages(outputPath string) Stage { description := fmt.Sprintf("Export packages to %q", outputPath) - return MakeStage( + return MakeLegacyStage( "exportPackages", description, func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/flatten_properties.go b/hack/generator/pkg/codegen/pipeline/flatten_properties.go index d2275df1b0f..086033b7d5e 100644 --- a/hack/generator/pkg/codegen/pipeline/flatten_properties.go +++ b/hack/generator/pkg/codegen/pipeline/flatten_properties.go @@ -15,7 +15,7 @@ import ( ) func FlattenProperties() Stage { - return MakeStage("flattenProperties", "Apply flattening to properties marked for flattening", applyPropertyFlattening) + return MakeLegacyStage("flattenProperties", "Apply flattening to properties marked for flattening", applyPropertyFlattening) } func applyPropertyFlattening( diff --git a/hack/generator/pkg/codegen/pipeline/flatten_resources.go b/hack/generator/pkg/codegen/pipeline/flatten_resources.go index 973596b2674..497c101e187 100644 --- a/hack/generator/pkg/codegen/pipeline/flatten_resources.go +++ b/hack/generator/pkg/codegen/pipeline/flatten_resources.go @@ -15,7 +15,7 @@ import ( // FlattenResources flattens any resources directly inside other resources func FlattenResources() Stage { - return MakeStage( + return MakeLegacyStage( "flattenResources", "Flatten nested resource types", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/improve_resource_pluralization.go b/hack/generator/pkg/codegen/pipeline/improve_resource_pluralization.go index 8d5e5ca1cd1..00e495f6fbe 100644 --- a/hack/generator/pkg/codegen/pipeline/improve_resource_pluralization.go +++ b/hack/generator/pkg/codegen/pipeline/improve_resource_pluralization.go @@ -14,7 +14,7 @@ import ( // ImproveResourcePluralization improves pluralization for resources func ImproveResourcePluralization() Stage { - return MakeStage( + return MakeLegacyStage( "pluralizeNames", "Improve resource pluralization", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/inject_hub_function.go b/hack/generator/pkg/codegen/pipeline/inject_hub_function.go index 1a641b7efea..d69d2d1899f 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_hub_function.go +++ b/hack/generator/pkg/codegen/pipeline/inject_hub_function.go @@ -22,7 +22,7 @@ const InjectHubFunctionStageId = "injectHubFunction" // function so that it satisfies the required interface. func InjectHubFunction(idFactory astmodel.IdentifierFactory) Stage { - result := MakeStage( + result := MakeLegacyStage( InjectHubFunctionStageId, "Inject the function Hub() into each hub resource", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/inject_hub_function_test.go b/hack/generator/pkg/codegen/pipeline/inject_hub_function_test.go index d22750cf5d9..c9f13a1382a 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_hub_function_test.go +++ b/hack/generator/pkg/codegen/pipeline/inject_hub_function_test.go @@ -34,11 +34,12 @@ func TestInjectHubFunction_WhenResourceIsStorageVersion_GeneratesExpectedFile(t injectHubFunction := InjectHubFunction(idFactory) // Don't need a context when testing - finalTypes, err := injectHubFunction.Run(context.TODO(), types) + state := NewState().WithTypes(types) + finalState, err := injectHubFunction.Run(context.TODO(), state) g.Expect(err).To(Succeed()) - test.AssertPackagesGenerateExpectedCode(t, finalTypes, t.Name()) + test.AssertPackagesGenerateExpectedCode(t, finalState.Types(), t.Name()) } func TestInjectHubFunction_WhenResourceIsNotStorageVersion_GeneratesExpectedFile(t *testing.T) { @@ -57,9 +58,10 @@ func TestInjectHubFunction_WhenResourceIsNotStorageVersion_GeneratesExpectedFile injectHubFunction := InjectHubFunction(idFactory) // Don't need a context when testing - finalTypes, err := injectHubFunction.Run(context.TODO(), types) + state := NewState().WithTypes(types) + finalState, err := injectHubFunction.Run(context.TODO(), state) g.Expect(err).To(Succeed()) - test.AssertPackagesGenerateExpectedCode(t, finalTypes, t.Name()) + test.AssertPackagesGenerateExpectedCode(t, finalState.Types(), t.Name()) } diff --git a/hack/generator/pkg/codegen/pipeline/inject_original_gvk_function.go b/hack/generator/pkg/codegen/pipeline/inject_original_gvk_function.go index d8afe0b45e5..4c68b3d97d2 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_original_gvk_function.go +++ b/hack/generator/pkg/codegen/pipeline/inject_original_gvk_function.go @@ -23,7 +23,7 @@ const injectOriginalGVKFunctionId = "injectOriginalGVKFunction" // information needed to interact with ARM using the correct API version. func InjectOriginalGVKFunction(idFactory astmodel.IdentifierFactory) Stage { - stage := MakeStage( + stage := MakeLegacyStage( injectOriginalGVKFunctionId, "Inject the function OriginalGVK() into each Resource type", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/inject_original_gvk_function_test.go b/hack/generator/pkg/codegen/pipeline/inject_original_gvk_function_test.go index 36b0beec63f..455aa21ee69 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_original_gvk_function_test.go +++ b/hack/generator/pkg/codegen/pipeline/inject_original_gvk_function_test.go @@ -31,9 +31,10 @@ func TestInjectOriginalGVKFunction(t *testing.T) { injectOriginalVersion := InjectOriginalGVKFunction(idFactory) // Don't need a context when testing - finalTypes, err := injectOriginalVersion.Run(context.TODO(), types) + state := NewState().WithTypes(types) + finalState, err := injectOriginalVersion.Run(context.TODO(), state) g.Expect(err).To(Succeed()) - test.AssertPackagesGenerateExpectedCode(t, finalTypes, t.Name()) + test.AssertPackagesGenerateExpectedCode(t, finalState.Types(), t.Name()) } diff --git a/hack/generator/pkg/codegen/pipeline/inject_original_version_function.go b/hack/generator/pkg/codegen/pipeline/inject_original_version_function.go index fea37b6d2c4..f11e6f852e3 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_original_version_function.go +++ b/hack/generator/pkg/codegen/pipeline/inject_original_version_function.go @@ -24,7 +24,7 @@ const injectOriginalVersionFunctionStageId = "injectOriginalVersionFunction" // We run this stage before we create any storage types, ensuring only API versions get the function. func InjectOriginalVersionFunction(idFactory astmodel.IdentifierFactory) Stage { - stage := MakeStage( + stage := MakeLegacyStage( injectOriginalVersionFunctionStageId, "Inject the function OriginalVersion() into each Spec type", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/inject_original_version_function_test.go b/hack/generator/pkg/codegen/pipeline/inject_original_version_function_test.go index ee95a417ec0..8504a91354e 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_original_version_function_test.go +++ b/hack/generator/pkg/codegen/pipeline/inject_original_version_function_test.go @@ -31,9 +31,10 @@ func TestInjectOriginalVersionFunction(t *testing.T) { injectOriginalVersion := InjectOriginalVersionFunction(idFactory) // Don't need a context when testing - finalTypes, err := injectOriginalVersion.Run(context.TODO(), types) + state := NewState().WithTypes(types) + finalState, err := injectOriginalVersion.Run(context.TODO(), state) g.Expect(err).To(Succeed()) - test.AssertPackagesGenerateExpectedCode(t, finalTypes, t.Name()) + test.AssertPackagesGenerateExpectedCode(t, finalState.Types(), t.Name()) } diff --git a/hack/generator/pkg/codegen/pipeline/inject_original_version_property.go b/hack/generator/pkg/codegen/pipeline/inject_original_version_property.go index a7f4c4482cb..3acdd2255bc 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_original_version_property.go +++ b/hack/generator/pkg/codegen/pipeline/inject_original_version_property.go @@ -23,7 +23,7 @@ const InjectOriginalVersionPropertyId = "injectOriginalVersionProperty" // information needed to interact with ARM using the correct API version. func InjectOriginalVersionProperty() Stage { - stage := MakeStage( + stage := MakeLegacyStage( InjectOriginalVersionPropertyId, "Inject the property OriginalVersion into each Storage Spec type", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/inject_original_version_property_test.go b/hack/generator/pkg/codegen/pipeline/inject_original_version_property_test.go index d005ab6c0eb..fe7a92b1456 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_original_version_property_test.go +++ b/hack/generator/pkg/codegen/pipeline/inject_original_version_property_test.go @@ -31,11 +31,12 @@ func TestInjectOriginalVersionProperty_InjectsIntoSpec(t *testing.T) { injectOriginalProperty := InjectOriginalVersionProperty() // Don't need a context when testing - finalTypes, err := injectOriginalProperty.Run(context.TODO(), types) + state := NewState().WithTypes(types) + finalState, err := injectOriginalProperty.Run(context.TODO(), state) g.Expect(err).To(Succeed()) - test.AssertPackagesGenerateExpectedCode(t, finalTypes, t.Name()) + test.AssertPackagesGenerateExpectedCode(t, finalState.Types(), t.Name()) } func TestInjectOriginalVersionProperty_WhenOriginalVersionFunctionFound_DoesNotInjectIntoSpec(t *testing.T) { @@ -58,9 +59,10 @@ func TestInjectOriginalVersionProperty_WhenOriginalVersionFunctionFound_DoesNotI injectOriginalProperty := InjectOriginalVersionProperty() // Don't need a context when testing - finalTypes, err := injectOriginalProperty.Run(context.TODO(), types) + state := NewState().WithTypes(types) + finalState, err := injectOriginalProperty.Run(context.TODO(), state) g.Expect(err).To(Succeed()) - test.AssertPackagesGenerateExpectedCode(t, finalTypes, t.Name()) + test.AssertPackagesGenerateExpectedCode(t, finalState.Types(), t.Name()) } diff --git a/hack/generator/pkg/codegen/pipeline/inject_property_assignment_functions.go b/hack/generator/pkg/codegen/pipeline/inject_property_assignment_functions.go index d280e98a0f8..251b28d8b22 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_property_assignment_functions.go +++ b/hack/generator/pkg/codegen/pipeline/inject_property_assignment_functions.go @@ -23,15 +23,16 @@ const injectPropertyAssignmentFunctionsStageId = "injectPropertyAssignmentFuncti // InjectPropertyAssignmentFunctions injects property assignment functions AssignTo*() and AssignFrom*() into both // resources and object types. These functions do the heavy lifting of the conversions between versions of each type and // are the building blocks of the main CovertTo*() and ConvertFrom*() methods. -func InjectPropertyAssignmentFunctions(graph *storage.ConversionGraph, idFactory astmodel.IdentifierFactory) Stage { +func InjectPropertyAssignmentFunctions(idFactory astmodel.IdentifierFactory) Stage { stage := MakeStage( injectPropertyAssignmentFunctionsStageId, "Inject property assignment functions AssignFrom() and AssignTo() into resources and objects", - func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { + func(ctx context.Context, state *State) (*State, error) { + types := state.Types() result := types.Copy() - factory := NewPropertyAssignmentFunctionsFactory(graph, idFactory, types) + factory := NewPropertyAssignmentFunctionsFactory(state.ConversionGraph(), idFactory, types) for name, def := range types { _, ok := astmodel.AsFunctionContainer(def.Type()) @@ -44,7 +45,7 @@ func InjectPropertyAssignmentFunctions(graph *storage.ConversionGraph, idFactory klog.V(3).Infof("Injecting conversion functions into %s", name) // Find the definition we want to convert to/from - nextPackage, ok := graph.LookupTransition(name.PackageReference) + nextPackage, ok := state.ConversionGraph().LookupTransition(name.PackageReference) if !ok { // No next package, so nothing to do // (this is expected if we have the hub storage package) @@ -67,7 +68,7 @@ func InjectPropertyAssignmentFunctions(graph *storage.ConversionGraph, idFactory result[modified.Name()] = modified } - return result, nil + return state.WithTypes(result), nil }) // Needed to populate the conversion graph diff --git a/hack/generator/pkg/codegen/pipeline/inject_property_assignment_functions_test.go b/hack/generator/pkg/codegen/pipeline/inject_property_assignment_functions_test.go index 4224c45bbb2..52074b5cece 100644 --- a/hack/generator/pkg/codegen/pipeline/inject_property_assignment_functions_test.go +++ b/hack/generator/pkg/codegen/pipeline/inject_property_assignment_functions_test.go @@ -12,7 +12,6 @@ import ( . "github.com/onsi/gomega" "github.com/Azure/azure-service-operator/hack/generator/pkg/astmodel" - "github.com/Azure/azure-service-operator/hack/generator/pkg/codegen/storage" "github.com/Azure/azure-service-operator/hack/generator/pkg/test" ) @@ -42,17 +41,16 @@ func TestInjectPropertyAssignmentFunctions(t *testing.T) { types := make(astmodel.Types) types.AddAll(resourceV1, specV1, statusV1, resourceV2, specV2, statusV2, address2021) - graph := storage.NewConversionGraph() - // Run CreateStorageTypes first to populate the conversion graph - createStorageTypes := CreateStorageTypes(graph) - types, err := createStorageTypes.Run(context.TODO(), types) + createStorageTypes := CreateStorageTypes() + state := NewState().WithTypes(types) + initialState, err := createStorageTypes.Run(context.TODO(), state) g.Expect(err).To(Succeed()) // Now run our stage - injectFunctions := InjectPropertyAssignmentFunctions(graph, idFactory) - types, err = injectFunctions.Run(context.TODO(), types) + injectFunctions := InjectPropertyAssignmentFunctions(idFactory) + finalState, err := injectFunctions.Run(context.TODO(), initialState) g.Expect(err).To(Succeed()) - test.AssertPackagesGenerateExpectedCode(t, types, t.Name()) + test.AssertPackagesGenerateExpectedCode(t, finalState.Types(), t.Name()) } diff --git a/hack/generator/pkg/codegen/pipeline/json_serialization_test_cases.go b/hack/generator/pkg/codegen/pipeline/json_serialization_test_cases.go index 4bd59316045..b2f35710927 100644 --- a/hack/generator/pkg/codegen/pipeline/json_serialization_test_cases.go +++ b/hack/generator/pkg/codegen/pipeline/json_serialization_test_cases.go @@ -16,7 +16,7 @@ import ( func InjectJsonSerializationTests(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "jsonTestCases", "Add test cases to verify JSON serialization", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/load_schema.go b/hack/generator/pkg/codegen/pipeline/load_schema.go index bf5ef43289f..949af0d9acd 100644 --- a/hack/generator/pkg/codegen/pipeline/load_schema.go +++ b/hack/generator/pkg/codegen/pipeline/load_schema.go @@ -140,7 +140,7 @@ func LoadSchemaIntoTypes( schemaLoader schemaLoader) Stage { source := configuration.SchemaURL - return MakeStage( + return MakeLegacyStage( "loadSchema", "Load and walk schema", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/mark_storage_version.go b/hack/generator/pkg/codegen/pipeline/mark_storage_version.go index 45c92fd3d8a..92d5aba8046 100644 --- a/hack/generator/pkg/codegen/pipeline/mark_storage_version.go +++ b/hack/generator/pkg/codegen/pipeline/mark_storage_version.go @@ -19,7 +19,7 @@ const MarkStorageVersionStageId = "markStorageVersion" // MarkStorageVersion creates a Stage to mark a particular version as a storage version func MarkStorageVersion() Stage { - return MakeStage( + return MakeLegacyStage( MarkStorageVersionStageId, "Mark the latest version of each resource as the storage version", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/name_types_for_crd.go b/hack/generator/pkg/codegen/pipeline/name_types_for_crd.go index 61693421a4c..cb04e205b6c 100644 --- a/hack/generator/pkg/codegen/pipeline/name_types_for_crd.go +++ b/hack/generator/pkg/codegen/pipeline/name_types_for_crd.go @@ -17,7 +17,7 @@ import ( // NameTypesForCRD - for CRDs all inner enums and objects and validated types must be named, so we do it here func NameTypesForCRD(idFactory astmodel.IdentifierFactory) Stage { - return MakeStage( + return MakeLegacyStage( "nameTypes", "Name inner types for CRD", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/remove_embedded_resources.go b/hack/generator/pkg/codegen/pipeline/remove_embedded_resources.go index dcb9df543d8..297f185ddac 100644 --- a/hack/generator/pkg/codegen/pipeline/remove_embedded_resources.go +++ b/hack/generator/pkg/codegen/pipeline/remove_embedded_resources.go @@ -13,7 +13,7 @@ import ( ) func RemoveEmbeddedResources() Stage { - return MakeStage( + return MakeLegacyStage( "removeEmbeddedResources", "Remove properties that point to embedded resources. Only removes structural aspects of embedded resources, Id/ARMId references are retained.", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/remove_type_aliases.go b/hack/generator/pkg/codegen/pipeline/remove_type_aliases.go index 97f1b1c47ea..50e714cf721 100644 --- a/hack/generator/pkg/codegen/pipeline/remove_type_aliases.go +++ b/hack/generator/pkg/codegen/pipeline/remove_type_aliases.go @@ -19,7 +19,7 @@ import ( // RemoveTypeAliases creates a pipeline stage removing type aliases func RemoveTypeAliases() Stage { - return MakeStage( + return MakeLegacyStage( "removeAliases", "Remove type aliases", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/replace_anytype_with_json.go b/hack/generator/pkg/codegen/pipeline/replace_anytype_with_json.go index e5aadce2970..97c9bca262f 100644 --- a/hack/generator/pkg/codegen/pipeline/replace_anytype_with_json.go +++ b/hack/generator/pkg/codegen/pipeline/replace_anytype_with_json.go @@ -31,7 +31,7 @@ var ( ) func ReplaceAnyTypeWithJSON() Stage { - return MakeStage( + return MakeLegacyStage( "replaceAnyTypeWithJSON", "Replace properties using interface{} with arbitrary JSON", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/replace_anytype_with_json_test.go b/hack/generator/pkg/codegen/pipeline/replace_anytype_with_json_test.go index 612065fdb7c..48903c29a20 100644 --- a/hack/generator/pkg/codegen/pipeline/replace_anytype_with_json_test.go +++ b/hack/generator/pkg/codegen/pipeline/replace_anytype_with_json_test.go @@ -31,18 +31,19 @@ func TestReplacingAnyTypes(t *testing.T) { ), )) - results, err := ReplaceAnyTypeWithJSON().action(context.Background(), defs) - + state := NewState().WithTypes(defs) + finalState, err := ReplaceAnyTypeWithJSON().action(context.Background(), state) g.Expect(err).To(BeNil()) - a := results[aName] + finalTypes := finalState.Types() + a := finalTypes[aName] expectedType := astmodel.MakeTypeName( astmodel.MakeExternalPackageReference("k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"), "JSON", ) g.Expect(a.Type()).To(Equal(expectedType)) - bDef := results[bName] + bDef := finalTypes[bName] bProp, found := bDef.Type().(*astmodel.ObjectType).Property("Field2") g.Expect(found).To(BeTrue()) g.Expect(bProp.PropertyType()).To(Equal(expectedType)) @@ -71,7 +72,8 @@ func TestReplacingMapMapInterface(t *testing.T) { ), )) - results, err := ReplaceAnyTypeWithJSON().action(context.Background(), defs) + state := NewState().WithTypes(defs) + finalState, err := ReplaceAnyTypeWithJSON().action(context.Background(), state) g.Expect(err).To(BeNil()) @@ -84,7 +86,8 @@ func TestReplacingMapMapInterface(t *testing.T) { ), ) - aDef := results[aName] + finalTypes := finalState.Types() + aDef := finalTypes[aName] aProp, found := aDef.Type().(*astmodel.ObjectType).Property("Maps") g.Expect(found).To(BeTrue()) g.Expect(aProp.PropertyType()).To(Equal(expectedType)) diff --git a/hack/generator/pkg/codegen/pipeline/report_type_versions.go b/hack/generator/pkg/codegen/pipeline/report_type_versions.go index f7013946fd9..07b731e1069 100644 --- a/hack/generator/pkg/codegen/pipeline/report_type_versions.go +++ b/hack/generator/pkg/codegen/pipeline/report_type_versions.go @@ -23,7 +23,7 @@ import ( // ReportOnTypesAndVersions creates a pipeline stage that removes any wrapper types prior to actual code generation func ReportOnTypesAndVersions(configuration *config.Configuration) Stage { - return MakeStage( + return MakeLegacyStage( "reportTypesAndVersions", "Generate reports on types and versions in each package", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/simplify_definitions.go b/hack/generator/pkg/codegen/pipeline/simplify_definitions.go index 68a3d39653b..8cdf68e4607 100644 --- a/hack/generator/pkg/codegen/pipeline/simplify_definitions.go +++ b/hack/generator/pkg/codegen/pipeline/simplify_definitions.go @@ -16,7 +16,7 @@ import ( // SimplifyDefinitions creates a pipeline stage that removes any wrapper types prior to actual code generation func SimplifyDefinitions() Stage { - return MakeStage( + return MakeLegacyStage( "simplifyDefinitions", "Flatten definitions by removing wrapper types", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/stage.go b/hack/generator/pkg/codegen/pipeline/stage.go index 4b444d45b31..c428cd19087 100644 --- a/hack/generator/pkg/codegen/pipeline/stage.go +++ b/hack/generator/pkg/codegen/pipeline/stage.go @@ -24,7 +24,7 @@ type Stage struct { // Description of the stage to use when logging description string // Stage implementation - action func(context.Context, astmodel.Types) (astmodel.Types, error) + action func(context.Context, *State) (*State, error) // Tag used for filtering targets []Target // Identifiers for other stages that must be completed before this one @@ -37,7 +37,7 @@ type Stage struct { func MakeStage( id string, description string, - action func(context.Context, astmodel.Types) (astmodel.Types, error)) Stage { + action func(context.Context, *State) (*State, error)) Stage { return Stage{ id: id, description: description, @@ -45,6 +45,26 @@ func MakeStage( } } +// MakeLegacyStage is a legacy constructor for creating a new pipeline stage that's ready for execution +// DO NOT USE THIS FOR ANY NEW STAGES - it's kept for compatibility with an older style of pipeline stages that will be +// migrated to the new style over time. +func MakeLegacyStage( + id string, + description string, + action func(context.Context, astmodel.Types) (astmodel.Types, error)) Stage { + return MakeStage( + id, + description, + func(ctx context.Context, state *State) (*State, error) { + types, err := action(ctx, state.Types()) + if err != nil { + return nil, err + } + + return state.WithTypes(types), nil + }) +} + // HasId returns true if this stage has the specified id, false otherwise func (stage *Stage) HasId(id string) bool { return stage.id == id @@ -118,8 +138,8 @@ func (stage *Stage) Description() string { } // Run is used to execute the action associated with this stage -func (stage *Stage) Run(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { - return stage.action(ctx, types) +func (stage *Stage) Run(ctx context.Context, state *State) (*State, error) { + return stage.action(ctx, state) } // CheckPrerequisites returns an error if the prerequisites of this stage have not been met diff --git a/hack/generator/pkg/codegen/pipeline/state.go b/hack/generator/pkg/codegen/pipeline/state.go new file mode 100644 index 00000000000..7113d006770 --- /dev/null +++ b/hack/generator/pkg/codegen/pipeline/state.go @@ -0,0 +1,62 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +package pipeline + +import ( + "github.com/Azure/azure-service-operator/hack/generator/pkg/astmodel" + "github.com/Azure/azure-service-operator/hack/generator/pkg/codegen/storage" +) + +// State is an immutable instance that captures the information being passed along the pipeline +type State struct { + types astmodel.Types // set of types generated so far + conversionGraph *storage.ConversionGraph // graph of transitions between packages in our conversion graph +} + +/* + * TODO: Future extension (suggested by @matthchr): + * Instead of hard coding specific knowledge in the state type, implement a generic solution where stages can stash + * information in a map indexed by their unique identifier; later stages can then retrieve that information using + * that identifier. + */ + +// NewState returns a new empty state +func NewState() *State { + return &State{ + types: make(astmodel.Types), + conversionGraph: nil, + } +} + +// WithTypes returns a new independentState with the given types instead +func (s *State) WithTypes(types astmodel.Types) *State { + return &State{ + types: types, + conversionGraph: s.conversionGraph, + } +} + +// WithConversionGraph returns a new independent State with the given conversion graph instead +func (s *State) WithConversionGraph(graph *storage.ConversionGraph) *State { + if s.conversionGraph != nil { + panic("may only set the conversion graph once") + } + + return &State{ + types: s.types.Copy(), + conversionGraph: graph, + } +} + +// Types returns the set of types contained by the state +func (s *State) Types() astmodel.Types { + return s.types +} + +// ConversionGraph returns the conversion graph included in our state (may be null) +func (s *State) ConversionGraph() *storage.ConversionGraph { + return s.conversionGraph +} diff --git a/hack/generator/pkg/codegen/pipeline/status_augment.go b/hack/generator/pkg/codegen/pipeline/status_augment.go index 10ef982d7f2..dc5bd7e87cf 100644 --- a/hack/generator/pkg/codegen/pipeline/status_augment.go +++ b/hack/generator/pkg/codegen/pipeline/status_augment.go @@ -13,7 +13,7 @@ import ( ) func AugmentSpecWithStatus() Stage { - return MakeStage( + return MakeLegacyStage( "augmentSpecWithStatus", "Merges information from Status into Spec", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/status_from_swagger.go b/hack/generator/pkg/codegen/pipeline/status_from_swagger.go index aab3654a490..010daa532d7 100644 --- a/hack/generator/pkg/codegen/pipeline/status_from_swagger.go +++ b/hack/generator/pkg/codegen/pipeline/status_from_swagger.go @@ -41,7 +41,7 @@ avoid any conflicts with existing Spec types that have already been defined. */ func AddStatusFromSwagger(idFactory astmodel.IdentifierFactory, config *config.Configuration) Stage { - return MakeStage( + return MakeLegacyStage( "addStatusFromSwagger", "Add information from Swagger specs for 'status' fields", func(ctx context.Context, types astmodel.Types) (astmodel.Types, error) { diff --git a/hack/generator/pkg/codegen/pipeline/strip_unused_types.go b/hack/generator/pkg/codegen/pipeline/strip_unused_types.go index edbdbfbbd03..165d3cf3415 100644 --- a/hack/generator/pkg/codegen/pipeline/strip_unused_types.go +++ b/hack/generator/pkg/codegen/pipeline/strip_unused_types.go @@ -12,7 +12,7 @@ import ( ) func StripUnreferencedTypeDefinitions() Stage { - return MakeStage( + return MakeLegacyStage( "stripUnreferenced", "Strip unreferenced types", func(ctx context.Context, defs astmodel.Types) (astmodel.Types, error) {