Fix Linting Issues (redux) (#2629)
* Update comments for new go fmt rules * Update DevContainer to Go 1.19 * Tweak comment
This commit is contained in:
Родитель
898ab11d9d
Коммит
4be29066fa
|
@ -1,7 +1,7 @@
|
|||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.137.0/containers/go/.devcontainer/base.Dockerfile
|
||||
|
||||
# This is pinned to a particular version of go:
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/go:0-1.18
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/go:0-1.19
|
||||
|
||||
# APT dependencies
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
|
|
@ -88,7 +88,7 @@ fi
|
|||
GOVER=$(go version)
|
||||
write-info "Go version: ${GOVER[*]}"
|
||||
|
||||
GOVERREQUIRED="go1.18.*"
|
||||
GOVERREQUIRED="go1.19.*"
|
||||
GOVERACTUAL=$(go version | { read _ _ ver _; echo $ver; })
|
||||
if ! [[ "$GOVERACTUAL" =~ $GOVERREQUIRED ]]; then
|
||||
write-error "Go must be version $GOVERREQUIRED, not $GOVERACTUAL; see : https://golang.org/doc/install"
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
// However, some services put the code & message at the top level instead.
|
||||
// This is common enough that the Azure Python SDK has specific handling to promote a nested error to the top level.
|
||||
// See https://github.com/Azure/azure-sdk-for-python/blob/9791fb5bc4cb6001768e6e1fb986b8d8f8326c43/sdk/core/azure-core/azure/core/exceptions.py#L153
|
||||
//
|
||||
type CloudError struct {
|
||||
error error
|
||||
|
||||
|
|
|
@ -175,12 +175,12 @@ func (h ResourceHierarchy) fullyQualifiedARMIDImpl(subscriptionID string, origin
|
|||
|
||||
// rootKind returns the ResourceHierarchyRoot type of the hierarchy.
|
||||
// There are 5 cases here:
|
||||
// 1. The hierarchy is comprised solely of a resource group. This is subscription rooted.
|
||||
// 2. The hierarchy has multiple entries and roots up to a resource group. This is Resource Group rooted.
|
||||
// 3. The hierarchy has multiple entries and doesn't root up to a resource group. This is subscription rooted.
|
||||
// 4. The hierarchy roots up to a tenant scope resource. This is tenant rooted.
|
||||
// 5. The hierarchy contains a resource that sets genruntime.ChildResourceIDOverrideAnnotation. This is
|
||||
// "Override" rooted.
|
||||
// 1. The hierarchy is comprised solely of a resource group. This is subscription rooted.
|
||||
// 2. The hierarchy has multiple entries and roots up to a resource group. This is Resource Group rooted.
|
||||
// 3. The hierarchy has multiple entries and doesn't root up to a resource group. This is subscription rooted.
|
||||
// 4. The hierarchy roots up to a tenant scope resource. This is tenant rooted.
|
||||
// 5. The hierarchy contains a resource that sets genruntime.ChildResourceIDOverrideAnnotation. This is
|
||||
// "Override" rooted.
|
||||
func (h ResourceHierarchy) rootKind(originalHierarchy ResourceHierarchy) ResourceHierarchyRoot {
|
||||
if len(h) == 0 {
|
||||
panic("resource hierarchy cannot be len 0")
|
||||
|
|
|
@ -29,9 +29,9 @@ import (
|
|||
//
|
||||
// Ideally we would panic on this error but we don't have a good way to deal with the following
|
||||
// problem at the moment:
|
||||
// - during record the controller does GET (404), PUT, … GET (OK)
|
||||
// - during playback the controller does GET (which now returns OK), DELETE, PUT, …
|
||||
// and fails due to a missing DELETE recording
|
||||
// - during record the controller does GET (404), PUT, … GET (OK)
|
||||
// - during playback the controller does GET (which now returns OK), DELETE, PUT, …
|
||||
// and fails due to a missing DELETE recording
|
||||
func translateErrors(r *recorder.Recorder, cassetteName string, t *testing.T) http.RoundTripper {
|
||||
return errorTranslation{r, cassetteName, nil, t}
|
||||
}
|
||||
|
|
|
@ -241,11 +241,11 @@ func (tc *KubePerTestContext) CreateResourceGroup(rg *resources.ResourceGroup) (
|
|||
|
||||
// registerCleanup registers the resource for cleanup at the end of the test. We must do this for every resource
|
||||
// for two reasons:
|
||||
// 1. Because OwnerReferences based deletion doesn't even run in EnvTest, see:
|
||||
// https://book.kubebuilder.io/reference/envtest.html#testing-considerations
|
||||
// 2. Even if it did run, it happens in the background which means that there's no guarantee that all the resources
|
||||
// are deleted before the test ends. When the resources aren't deleted, they attempt to log to a closed logger
|
||||
// which panics.
|
||||
// 1. Because OwnerReferences based deletion doesn't even run in EnvTest, see:
|
||||
// https://book.kubebuilder.io/reference/envtest.html#testing-considerations
|
||||
// 2. Even if it did run, it happens in the background which means that there's no guarantee that all the resources
|
||||
// are deleted before the test ends. When the resources aren't deleted, they attempt to log to a closed logger
|
||||
// which panics.
|
||||
func (tc *KubePerTestContext) registerCleanup(obj client.Object) {
|
||||
tc.tracker.Track(obj)
|
||||
}
|
||||
|
@ -279,10 +279,10 @@ var OperationTimeoutReplaying = 2 * time.Minute
|
|||
|
||||
// OperationTimeoutRecording is the default timeout for a single operation when recording.
|
||||
// This is so high because the following operations are slow:
|
||||
// * Deleting an AKS cluster.
|
||||
// * Creating a Redis Enterprise Database.
|
||||
// * Deleting a CosmosDB MongoDB.
|
||||
// * Creating a Virtual Network Gateway Controller.
|
||||
// - Deleting an AKS cluster.
|
||||
// - Creating a Redis Enterprise Database.
|
||||
// - Deleting a CosmosDB MongoDB.
|
||||
// - Creating a Virtual Network Gateway Controller.
|
||||
var OperationTimeoutRecording = 30 * time.Minute
|
||||
|
||||
func (tc *KubePerTestContext) DefaultOperationTimeout() time.Duration {
|
||||
|
@ -521,13 +521,14 @@ func (tc *KubePerTestContext) deleteResourcesAndWait(objs ...client.Object) {
|
|||
// Note that this protects against deleting resources that have a parent-child relationship in the same request. This is perfectly
|
||||
// fine in the real world, but in many of our recording envtests we can get into a situation where there's a race
|
||||
// during deletion that causes HTTP replay issues. The sequence of events is:
|
||||
// 1. Delete parent resource and child resource at the same time.
|
||||
// 2. During recording, child deletion never sees a successful (finished) DELETE request because parent is deleted so soon
|
||||
// after the child that we just record a successful DELETE for the parent and don't bother sending the final child
|
||||
// DELETE that would return success.
|
||||
// 3. During replay, the race is how quickly the parent deletes and how many requests the child has a chance to send
|
||||
// in that time. If the parent deletes slowly the child might try to send more requests than we actually have recorded
|
||||
// (because none of them represent a terminal "actually deleted" state), which will cause a test failure.
|
||||
// 1. Delete parent resource and child resource at the same time.
|
||||
// 2. During recording, child deletion never sees a successful (finished) DELETE request because parent is deleted so soon
|
||||
// after the child that we just record a successful DELETE for the parent and don't bother sending the final child
|
||||
// DELETE that would return success.
|
||||
// 3. During replay, the race is how quickly the parent deletes and how many requests the child has a chance to send
|
||||
// in that time. If the parent deletes slowly the child might try to send more requests than we actually have recorded
|
||||
// (because none of them represent a terminal "actually deleted" state), which will cause a test failure.
|
||||
//
|
||||
// In envtest it's still critical to delete everything, because ownership based deletion isn't enabled in envtest and we can't
|
||||
// leave resources around or they will continue to attempt to log to a closed test logger. To avoid this we
|
||||
// carefully delete resources starting with the root and working our way down one rank at a time. This shouldn't be much
|
||||
|
|
|
@ -71,9 +71,9 @@ var _ Calculator = &calculator{}
|
|||
// 2. If syncPeriod is set, success results that would normally be terminal are instead configured to try again in syncPeriod.
|
||||
// 3. If requeueDelayOverride is set, all happy-path requests have requeueDelayOverride set.
|
||||
// The scenarios that this handler doesn't target:
|
||||
// 1. Any error other than ReadyConditionImpacting error.
|
||||
// 2. Happy-path requests when requeueDelayOverride is not set. These are scenarios where the operator is working
|
||||
// as expected and we're just doing something like polling an async operation.
|
||||
// 1. Any error other than ReadyConditionImpacting error.
|
||||
// 2. Happy-path requests when requeueDelayOverride is not set. These are scenarios where the operator is working
|
||||
// as expected and we're just doing something like polling an async operation.
|
||||
func (i *calculator) NextInterval(req ctrl.Request, result ctrl.Result, err error) (ctrl.Result, error) {
|
||||
i.failuresLock.Lock()
|
||||
defer i.failuresLock.Unlock()
|
||||
|
|
|
@ -56,7 +56,7 @@ func Test_Success_WithSyncPeriod_ReturnsSyncPeriod(t *testing.T) {
|
|||
t.Parallel()
|
||||
g := NewGomegaWithT(t)
|
||||
|
||||
syncPeriod := 10 * time.Second
|
||||
syncPeriod := 12 * time.Second
|
||||
calc := newCalculator(
|
||||
CalculatorParameters{
|
||||
ErrorBaseDelay: 1 * time.Second,
|
||||
|
@ -69,7 +69,10 @@ func Test_Success_WithSyncPeriod_ReturnsSyncPeriod(t *testing.T) {
|
|||
|
||||
result, err := calc.NextInterval(req, ctrl.Result{}, nil)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
g.Expect(result.RequeueAfter > 8*time.Second).To(BeTrue())
|
||||
|
||||
// Threshold here needs to be at or below the lower-bound of the RequeuePeriod, taking Jitter into account
|
||||
// Currently jitter is 0.25, so the 12s above becomes 9s to 15s
|
||||
g.Expect(result.RequeueAfter >= 9*time.Second).To(BeTrue())
|
||||
|
||||
g.Expect(calc.(*calculator).failures).To(HaveLen(0))
|
||||
}
|
||||
|
|
|
@ -154,10 +154,11 @@ func (c Condition) ShouldOverwrite(other Condition) bool {
|
|||
|
||||
// priority of the condition for overwrite purposes if Condition ObservedGeneration's are the same. Higher is more important.
|
||||
// The result of this is the following:
|
||||
// 1. Status == True conditions, and Status == False conditions with Severity == Warning or Error are all the highest priority.
|
||||
// This means that the most recent update with any of those states will overwrite anything.
|
||||
// 2. Status == False conditions with Severity == Info will only overwrite other Status == False conditions with Severity == Info.
|
||||
// 3. Status == Unknown conditions will not overwrite anything.
|
||||
// 1. Status == True conditions, and Status == False conditions with Severity == Warning or Error are all the highest priority.
|
||||
// This means that the most recent update with any of those states will overwrite anything.
|
||||
// 2. Status == False conditions with Severity == Info will only overwrite other Status == False conditions with Severity == Info.
|
||||
// 3. Status == Unknown conditions will not overwrite anything.
|
||||
//
|
||||
// Keep in mind that this priority is specifically for comparing Conditions with the same ObservedGeneration. If the ObservedGeneration
|
||||
// is different, the newer one always wins.
|
||||
func (c Condition) priority() int {
|
||||
|
|
|
@ -19,24 +19,23 @@ import (
|
|||
// referencing types from other packages. If we tried to use an interface with a single method, we'd inevitably end up
|
||||
// with circular package references:
|
||||
//
|
||||
// +----------------+ +----------------+
|
||||
// | v1 | | v2 |
|
||||
// | PersonSpec | --- import v2 ---> | PersonSpec |
|
||||
// | | | |
|
||||
// | ConvertTo() | <--- import v1 --- | ConvertTo() |
|
||||
// +----------------+ +----------------+
|
||||
// +----------------+ +----------------+
|
||||
// | v1 | | v2 |
|
||||
// | PersonSpec | --- import v2 ---> | PersonSpec |
|
||||
// | | | |
|
||||
// | ConvertTo() | <--- import v1 --- | ConvertTo() |
|
||||
// +----------------+ +----------------+
|
||||
//
|
||||
// Instead, we have to have support for both directions, so that we can always operate from one side of the package
|
||||
// reference chain:
|
||||
//
|
||||
// +----------------+ +----------------+
|
||||
// | v1 | | v2 |
|
||||
// | PersonSpec | | PersonSpec |
|
||||
// | | | |
|
||||
// | ConvertTo() | --- import v2 ---> | |
|
||||
// | ConvertFrom() | | |
|
||||
// +----------------+ +----------------+
|
||||
//
|
||||
// +----------------+ +----------------+
|
||||
// | v1 | | v2 |
|
||||
// | PersonSpec | | PersonSpec |
|
||||
// | | | |
|
||||
// | ConvertTo() | --- import v2 ---> | |
|
||||
// | ConvertFrom() | | |
|
||||
// +----------------+ +----------------+
|
||||
type ConvertibleSpec interface {
|
||||
// ConvertSpecTo will populate the passed Spec by copying over all available information from this one
|
||||
ConvertSpecTo(destination ConvertibleSpec) error
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
// ConvertibleStatus is implemented by status types to allow conversion among the different versions of a given status
|
||||
//
|
||||
// Why do we need both directions of conversion? See ConvertibleSpec for details.
|
||||
//
|
||||
type ConvertibleStatus interface {
|
||||
// ConvertStatusTo will populate the passed Status by copying over all available information from this one
|
||||
ConvertStatusTo(destination ConvertibleStatus) error
|
||||
|
|
|
@ -309,8 +309,8 @@ func (builder *convertFromARMBuilder) operatorSpecPropertyHandler(
|
|||
//
|
||||
// If 'X' is a property that was flattened:
|
||||
//
|
||||
// k8sObj.Y1 = armObj.X.Y1;
|
||||
// k8sObj.Y2 = armObj.X.Y2;
|
||||
// k8sObj.Y1 = armObj.X.Y1;
|
||||
// k8sObj.Y2 = armObj.X.Y2;
|
||||
//
|
||||
// in reality each assignment is likely to be another conversion that is specific
|
||||
// to the type being converted.
|
||||
|
@ -464,6 +464,7 @@ func (builder *convertFromARMBuilder) propertiesWithSameNameHandler(
|
|||
|
||||
// convertComplexTypeNameProperty handles conversion of complex TypeName properties.
|
||||
// This function generates code that looks like this:
|
||||
//
|
||||
// <nameHint>Converted := <destinationType>{}
|
||||
// err = <nameHint>Converted.FromARM(owner, <source>)
|
||||
// if err != nil {
|
||||
|
|
|
@ -294,8 +294,8 @@ func (builder *convertToARMBuilder) referencePropertyHandler(
|
|||
//
|
||||
// If 'X' is a property that was flattened:
|
||||
//
|
||||
// armObj.X.Y1 = k8sObj.Y1;
|
||||
// armObj.X.Y2 = k8sObj.Y2;
|
||||
// armObj.X.Y1 = k8sObj.Y1;
|
||||
// armObj.X.Y2 = k8sObj.Y2;
|
||||
//
|
||||
// in reality each assignment is likely to be another conversion that is specific
|
||||
// to the type being converted.
|
||||
|
@ -399,9 +399,10 @@ func (builder *convertToARMBuilder) flattenedPropertyHandler(
|
|||
// that assigns it a value if any of the “from” properties are not nil.
|
||||
//
|
||||
// Resultant code looks like:
|
||||
// if (from1 != nil) || (from2 != nil) || … {
|
||||
// <resultIdent>.<toProp> = &<toPropTypeName>{}
|
||||
// }
|
||||
//
|
||||
// if (from1 != nil) || (from2 != nil) || … {
|
||||
// <resultIdent>.<toProp> = &<toPropTypeName>{}
|
||||
// }
|
||||
func (builder *convertToARMBuilder) buildToPropInitializer(
|
||||
fromProps []*astmodel.PropertyDefinition,
|
||||
toPropTypeName astmodel.TypeName,
|
||||
|
@ -458,6 +459,7 @@ func (builder *convertToARMBuilder) propertiesWithSameNameHandler(
|
|||
|
||||
// convertReferenceProperty handles conversion of reference properties.
|
||||
// This function generates code that looks like this:
|
||||
//
|
||||
// <namehint>ARMID, err := resolved.ResolvedReferences.Lookup(<source>)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
|
@ -493,6 +495,7 @@ func (builder *convertToARMBuilder) convertReferenceProperty(_ *astmodel.Convers
|
|||
|
||||
// convertSecretProperty handles conversion of secret properties.
|
||||
// This function generates code that looks like this:
|
||||
//
|
||||
// <namehint>Secret, err := resolved.ResolvedSecrets.Lookup(<source>)
|
||||
// if err != nil {
|
||||
// return nil, errors.Wrap(err, "looking up secret for <source>")
|
||||
|
@ -533,12 +536,12 @@ func (builder *convertToARMBuilder) convertSecretProperty(_ *astmodel.Conversion
|
|||
|
||||
// convertConfigMapProperty handles conversion of configMap properties.
|
||||
// This function generates code that looks like this:
|
||||
//
|
||||
// <namehint>Value, err := resolved.ResolvedConfigMaps.Lookup(<source>)
|
||||
// if err != nil {
|
||||
// return nil, errors.Wrap(err, "looking up config map value for <source>")
|
||||
// }
|
||||
// <destination> = <namehint>Value
|
||||
//
|
||||
func (builder *convertToARMBuilder) convertConfigMapProperty(_ *astmodel.ConversionFunctionBuilder, params astmodel.ConversionParameters) []dst.Stmt {
|
||||
isString := astmodel.TypeEquals(params.DestinationType, astmodel.StringType)
|
||||
if !isString {
|
||||
|
@ -574,7 +577,8 @@ func (builder *convertToARMBuilder) convertConfigMapProperty(_ *astmodel.Convers
|
|||
|
||||
// convertComplexTypeNameProperty handles conversion of complex TypeName properties.
|
||||
// This function generates code that looks like this:
|
||||
// <nameHint>, err := <source>.ToARM(name)
|
||||
//
|
||||
// <nameHint>, err := <source>.ToARM(name)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
// SimpleAssignment performs a simple assignment like:
|
||||
//
|
||||
// <lhs> = <rhs>
|
||||
// <lhs> = <rhs>
|
||||
//
|
||||
// See also ShortDeclaration
|
||||
func SimpleAssignment(lhs dst.Expr, rhs dst.Expr) *dst.AssignStmt {
|
||||
|
@ -31,7 +31,7 @@ func SimpleAssignment(lhs dst.Expr, rhs dst.Expr) *dst.AssignStmt {
|
|||
|
||||
// ShortDeclaration performs a simple assignment like:
|
||||
//
|
||||
// <id> := <rhs>
|
||||
// <id> := <rhs>
|
||||
//
|
||||
// Method naming inspired by https://tour.golang.org/basics/10
|
||||
func ShortDeclaration(id string, rhs dst.Expr) *dst.AssignStmt {
|
||||
|
@ -62,7 +62,9 @@ func AssignmentStatement(lhs dst.Expr, tok token.Token, rhs dst.Expr) *dst.Assig
|
|||
}
|
||||
|
||||
// QualifiedAssignment performs a simple assignment like:
|
||||
// <lhs>.<lhsSel> := <rhs> // tok = token.DEFINE
|
||||
//
|
||||
// <lhs>.<lhsSel> := <rhs> // tok = token.DEFINE
|
||||
//
|
||||
// or <lhs>.<lhsSel> = <rhs> // tok = token.ASSIGN
|
||||
func QualifiedAssignment(lhs dst.Expr, lhsSel string, tok token.Token, rhs dst.Expr) *dst.AssignStmt {
|
||||
return &dst.AssignStmt{
|
||||
|
@ -73,8 +75,9 @@ func QualifiedAssignment(lhs dst.Expr, lhsSel string, tok token.Token, rhs dst.E
|
|||
}
|
||||
|
||||
// SimpleAssignmentWithErr performs a simple assignment like:
|
||||
// <lhs>, err := <rhs> // tok = token.DEFINE
|
||||
// or <lhs>, err = <rhs> // tok = token.ASSIGN
|
||||
//
|
||||
// <lhs>, err := <rhs> // tok = token.DEFINE
|
||||
// or <lhs>, err = <rhs> // tok = token.ASSIGN
|
||||
func SimpleAssignmentWithErr(lhs dst.Expr, tok token.Token, rhs dst.Expr) *dst.AssignStmt {
|
||||
errId := dst.NewIdent("err")
|
||||
return &dst.AssignStmt{
|
||||
|
@ -92,6 +95,7 @@ func SimpleAssignmentWithErr(lhs dst.Expr, tok token.Token, rhs dst.Expr) *dst.A
|
|||
// AssignToInterface performs an assignment of a well-typed variable to an interface{}. This is usually used to
|
||||
// perform a type assertion on a concrete type in a subsequent statement (which Go doesn't allow, it only allows type
|
||||
// assertions on interface types).
|
||||
//
|
||||
// var <lhsVar> interface{} = <rhs>
|
||||
func AssignToInterface(lhsVar string, rhs dst.Expr) *dst.DeclStmt {
|
||||
return &dst.DeclStmt{
|
||||
|
|
|
@ -14,8 +14,8 @@ import (
|
|||
|
||||
// CheckErrorAndReturn checks if the err is non-nil, and if it is returns.
|
||||
//
|
||||
// if err != nil {
|
||||
// return <otherReturns...>, err
|
||||
// if err != nil {
|
||||
// return <otherReturns...>, err
|
||||
// }
|
||||
func CheckErrorAndReturn(otherReturns ...dst.Expr) dst.Stmt {
|
||||
retStmt := &dst.ReturnStmt{
|
||||
|
@ -28,16 +28,15 @@ func CheckErrorAndReturn(otherReturns ...dst.Expr) dst.Stmt {
|
|||
// CheckErrorAndWrap checks if the err is non-nil, and if it is returns it, wrapped with additional information
|
||||
// If no arguments are provided, will generate
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, <message>)
|
||||
// }
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, <message>)
|
||||
// }
|
||||
//
|
||||
// otherwise will generate
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrapf(err, <message>, <args>)
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrapf(err, <message>, <args>)
|
||||
// }
|
||||
func CheckErrorAndWrap(errorsPackage string, message string, args ...dst.Expr) dst.Stmt {
|
||||
wrap := WrapError(errorsPackage, "err", message, args...)
|
||||
return CheckErrorAndSingleStatement(Returns(wrap))
|
||||
|
@ -45,8 +44,8 @@ func CheckErrorAndWrap(errorsPackage string, message string, args ...dst.Expr) d
|
|||
|
||||
// CheckErrorAndSingleStatement checks if the err is non-nil, and if it is executes the provided statement.
|
||||
//
|
||||
// if err != nil {
|
||||
// <stmt>
|
||||
// if err != nil {
|
||||
// <stmt>
|
||||
// }
|
||||
func CheckErrorAndSingleStatement(stmt dst.Stmt) dst.Stmt {
|
||||
return &dst.IfStmt{
|
||||
|
@ -82,10 +81,12 @@ func WrapError(errorsPackage string, err string, message string, args ...dst.Exp
|
|||
// with its default value.
|
||||
//
|
||||
// For example:
|
||||
// var <varName> <packageRef>.<structName>
|
||||
//
|
||||
// var <varName> <packageRef>.<structName>
|
||||
//
|
||||
// Note that it does *not* do:
|
||||
// <varName> := <packageRef>.<structName>{}
|
||||
//
|
||||
// <varName> := <packageRef>.<structName>{}
|
||||
//
|
||||
// …as that does not work for enum types.
|
||||
func NewVariableQualified(varName string, qualifier string, structName string) dst.Stmt {
|
||||
|
@ -109,10 +110,12 @@ func NewVariableQualified(varName string, qualifier string, structName string) d
|
|||
// with its default value.
|
||||
//
|
||||
// For example:
|
||||
// var <varName> <structName>
|
||||
//
|
||||
// var <varName> <structName>
|
||||
//
|
||||
// Note that it does *not* do:
|
||||
// <varName> := <structName>{}
|
||||
//
|
||||
// <varName> := <structName>{}
|
||||
//
|
||||
// …as that does not work for enum types.
|
||||
func NewVariable(varName string, structName string) dst.Stmt {
|
||||
|
@ -135,8 +138,7 @@ func NewVariableWithType(varName string, varType dst.Expr) dst.Stmt {
|
|||
|
||||
// LocalVariableDeclaration performs a local variable declaration for use within a method
|
||||
//
|
||||
// var <ident> <typ>
|
||||
//
|
||||
// var <ident> <typ>
|
||||
func LocalVariableDeclaration(ident string, typ dst.Expr, comment string) *dst.DeclStmt {
|
||||
return &dst.DeclStmt{
|
||||
Decl: VariableDeclaration(ident, typ, comment),
|
||||
|
@ -145,8 +147,8 @@ func LocalVariableDeclaration(ident string, typ dst.Expr, comment string) *dst.D
|
|||
|
||||
// VariableDeclaration performs a global variable declaration
|
||||
//
|
||||
// // <comment>
|
||||
// var <ident> <typ>
|
||||
// // <comment>
|
||||
// var <ident> <typ>
|
||||
//
|
||||
// For a LocalVariable within a method, use LocalVariableDeclaration() to create an ast.Stmt instead
|
||||
func VariableDeclaration(ident string, typ dst.Expr, comment string) *dst.GenDecl {
|
||||
|
@ -169,8 +171,7 @@ func VariableDeclaration(ident string, typ dst.Expr, comment string) *dst.GenDec
|
|||
|
||||
// TypeAssert returns an assignment statement with a type assertion
|
||||
//
|
||||
// <lhs>, ok := <rhs>.(<type>)
|
||||
//
|
||||
// <lhs>, ok := <rhs>.(<type>)
|
||||
func TypeAssert(lhs dst.Expr, rhs dst.Expr, typ dst.Expr) *dst.AssignStmt {
|
||||
return &dst.AssignStmt{
|
||||
Lhs: []dst.Expr{
|
||||
|
@ -192,7 +193,6 @@ func TypeAssert(lhs dst.Expr, rhs dst.Expr, typ dst.Expr) *dst.AssignStmt {
|
|||
// if ok {
|
||||
// return <returns>
|
||||
// }
|
||||
//
|
||||
func ReturnIfOk(returns ...dst.Expr) *dst.IfStmt {
|
||||
return ReturnIfExpr(dst.NewIdent("ok"), returns...)
|
||||
}
|
||||
|
@ -202,7 +202,6 @@ func ReturnIfOk(returns ...dst.Expr) *dst.IfStmt {
|
|||
// if !ok {
|
||||
// return <returns>
|
||||
// }
|
||||
//
|
||||
func ReturnIfNotOk(returns ...dst.Expr) *dst.IfStmt {
|
||||
return ReturnIfExpr(
|
||||
&dst.UnaryExpr{
|
||||
|
@ -214,10 +213,9 @@ func ReturnIfNotOk(returns ...dst.Expr) *dst.IfStmt {
|
|||
|
||||
// ReturnIfNil checks if a variable is nil and if it is returns
|
||||
//
|
||||
// if <toCheck> == nil {
|
||||
// return <returns...>
|
||||
// if <toCheck> == nil {
|
||||
// return <returns...>
|
||||
// }
|
||||
//
|
||||
func ReturnIfNil(toCheck dst.Expr, returns ...dst.Expr) dst.Stmt {
|
||||
return ReturnIfExpr(
|
||||
AreEqual(toCheck, Nil()),
|
||||
|
@ -226,10 +224,9 @@ func ReturnIfNil(toCheck dst.Expr, returns ...dst.Expr) dst.Stmt {
|
|||
|
||||
// ReturnIfNotNil checks if a variable is not nil and if it is returns
|
||||
//
|
||||
// if <toCheck> != nil {
|
||||
// return <returns...>
|
||||
// if <toCheck> != nil {
|
||||
// return <returns...>
|
||||
// }
|
||||
//
|
||||
func ReturnIfNotNil(toCheck dst.Expr, returns ...dst.Expr) dst.Stmt {
|
||||
return ReturnIfExpr(
|
||||
AreNotEqual(toCheck, Nil()),
|
||||
|
@ -239,9 +236,8 @@ func ReturnIfNotNil(toCheck dst.Expr, returns ...dst.Expr) dst.Stmt {
|
|||
// ReturnIfExpr returns if the expression evaluates as true
|
||||
//
|
||||
// if <cond> {
|
||||
// return <returns...>
|
||||
// return <returns...>
|
||||
// }
|
||||
//
|
||||
func ReturnIfExpr(cond dst.Expr, returns ...dst.Expr) *dst.IfStmt {
|
||||
if len(returns) == 0 {
|
||||
panic("Expected at least 1 return for ReturnIfOk")
|
||||
|
@ -262,7 +258,6 @@ func ReturnIfExpr(cond dst.Expr, returns ...dst.Expr) *dst.IfStmt {
|
|||
// FormatError produces a call to fmt.Errorf with the given format string and args
|
||||
//
|
||||
// fmt.Errorf(<formatString>, <args>)
|
||||
//
|
||||
func FormatError(fmtPackage string, formatString string, args ...dst.Expr) dst.Expr {
|
||||
var callArgs []dst.Expr
|
||||
callArgs = append(
|
||||
|
@ -275,7 +270,6 @@ func FormatError(fmtPackage string, formatString string, args ...dst.Expr) dst.E
|
|||
// AddrOf returns a statement that gets the address of the provided expression.
|
||||
//
|
||||
// &<expr>
|
||||
//
|
||||
func AddrOf(expr dst.Expr) *dst.UnaryExpr {
|
||||
return &dst.UnaryExpr{
|
||||
Op: token.AND,
|
||||
|
@ -299,7 +293,6 @@ func AsReference(expr dst.Expr) dst.Expr {
|
|||
// Dereference returns a statement that dereferences the pointer returned by the provided expression
|
||||
//
|
||||
// *<expr>
|
||||
//
|
||||
func Dereference(expr dst.Expr) dst.Expr {
|
||||
return &dst.StarExpr{
|
||||
X: dst.Clone(expr).(dst.Expr),
|
||||
|
@ -308,9 +301,9 @@ func Dereference(expr dst.Expr) dst.Expr {
|
|||
|
||||
// Returns creates a return statement with one or more expressions, of the form
|
||||
//
|
||||
// return <expr>
|
||||
// or return <expr>, <expr>, ...
|
||||
// return <expr>
|
||||
//
|
||||
// or return <expr>, <expr>, ...
|
||||
func Returns(returns ...dst.Expr) dst.Stmt {
|
||||
return &dst.ReturnStmt{
|
||||
Decs: dst.ReturnStmtDecorations{
|
||||
|
@ -324,9 +317,8 @@ func Returns(returns ...dst.Expr) dst.Stmt {
|
|||
|
||||
// ReturnNoError creates a return nil statement for when no error occurs
|
||||
//
|
||||
// // No error
|
||||
// return nil
|
||||
//
|
||||
// // No error
|
||||
// return nil
|
||||
func ReturnNoError() dst.Stmt {
|
||||
result := Returns(Nil())
|
||||
result.Decorations().Before = dst.EmptyLine
|
||||
|
@ -350,7 +342,6 @@ func WrappedErrorf(errorsPackage string, template string, args ...interface{}) d
|
|||
// QualifiedTypeName generates a reference to a type within an imported package
|
||||
//
|
||||
// <pkg>.<name>
|
||||
//
|
||||
func QualifiedTypeName(pkg string, name string) *dst.SelectorExpr {
|
||||
return &dst.SelectorExpr{
|
||||
X: dst.NewIdent(pkg),
|
||||
|
@ -361,7 +352,6 @@ func QualifiedTypeName(pkg string, name string) *dst.SelectorExpr {
|
|||
// Selector generates a field reference into an existing expression
|
||||
//
|
||||
// <expr>.<name0>.(<name1>.<name2>…)
|
||||
//
|
||||
func Selector(expr dst.Expr, names ...string) *dst.SelectorExpr {
|
||||
exprs := []dst.Expr{dst.Clone(expr).(dst.Expr)}
|
||||
for _, name := range names {
|
||||
|
@ -379,7 +369,6 @@ func Selector(expr dst.Expr, names ...string) *dst.SelectorExpr {
|
|||
// AreEqual generates a == comparison between the two expressions
|
||||
//
|
||||
// <lhs> == <rhs>
|
||||
//
|
||||
func AreEqual(lhs dst.Expr, rhs dst.Expr) *dst.BinaryExpr {
|
||||
return BinaryExpr(lhs, token.EQL, rhs)
|
||||
}
|
||||
|
@ -387,7 +376,6 @@ func AreEqual(lhs dst.Expr, rhs dst.Expr) *dst.BinaryExpr {
|
|||
// AreNotEqual generates a != comparison between the two expressions
|
||||
//
|
||||
// <lhs> != <rhs>
|
||||
//
|
||||
func AreNotEqual(lhs dst.Expr, rhs dst.Expr) *dst.BinaryExpr {
|
||||
return BinaryExpr(lhs, token.NEQ, rhs)
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
// CallFunc creates an expression to call a function with specified arguments
|
||||
//
|
||||
// <funcName>(<arguments>...)
|
||||
//
|
||||
func CallFunc(funcName string, arguments ...dst.Expr) *dst.CallExpr {
|
||||
return createCallExpr(dst.NewIdent(funcName), arguments...)
|
||||
}
|
||||
|
@ -21,7 +20,6 @@ func CallFunc(funcName string, arguments ...dst.Expr) *dst.CallExpr {
|
|||
// arguments
|
||||
//
|
||||
// <qualifier>.<funcName>(arguments...)
|
||||
//
|
||||
func CallQualifiedFunc(qualifier string, funcName string, arguments ...dst.Expr) *dst.CallExpr {
|
||||
return createCallExpr(
|
||||
&dst.SelectorExpr{
|
||||
|
@ -34,7 +32,6 @@ func CallQualifiedFunc(qualifier string, funcName string, arguments ...dst.Expr)
|
|||
// CallExpr creates an expression to call the named function with the specified arguments
|
||||
//
|
||||
// <expr>.<funcName>(arguments...)
|
||||
//
|
||||
func CallExpr(expr dst.Expr, funcName string, arguments ...dst.Expr) *dst.CallExpr {
|
||||
var receiver dst.Expr = expr
|
||||
if star, ok := expr.(*dst.StarExpr); ok {
|
||||
|
|
|
@ -13,10 +13,9 @@ import (
|
|||
|
||||
// SimpleIf creates a simple if statement with multiple statements
|
||||
//
|
||||
// if <condition> {
|
||||
// <trueBranch>
|
||||
// }
|
||||
//
|
||||
// if <condition> {
|
||||
// <trueBranch>
|
||||
// }
|
||||
func SimpleIf(condition dst.Expr, statements ...dst.Stmt) *dst.IfStmt {
|
||||
return &dst.IfStmt{
|
||||
Cond: condition,
|
||||
|
@ -26,12 +25,12 @@ func SimpleIf(condition dst.Expr, statements ...dst.Stmt) *dst.IfStmt {
|
|||
|
||||
// SimpleIfElse creates a simple if else statement. Each branch may contain multiple statements.
|
||||
//
|
||||
// if <condition> {
|
||||
// <trueBranch>
|
||||
// } else {
|
||||
// <falseBranch>
|
||||
// }
|
||||
// if <condition> {
|
||||
// <trueBranch>
|
||||
// } else {
|
||||
//
|
||||
// <falseBranch>
|
||||
// }
|
||||
func SimpleIfElse(condition dst.Expr, trueBranch []dst.Stmt, falseBranch []dst.Stmt) *dst.IfStmt {
|
||||
result := &dst.IfStmt{
|
||||
Cond: condition,
|
||||
|
@ -44,10 +43,9 @@ func SimpleIfElse(condition dst.Expr, trueBranch []dst.Stmt, falseBranch []dst.S
|
|||
|
||||
// IfEqual executes a series of statements if the supplied expressions are
|
||||
//
|
||||
// if <left> == <right> {
|
||||
// <statements>
|
||||
// }
|
||||
//
|
||||
// if <left> == <right> {
|
||||
// <statements>
|
||||
// }
|
||||
func IfEqual(left dst.Expr, right dst.Expr, statements ...dst.Stmt) *dst.IfStmt {
|
||||
return &dst.IfStmt{
|
||||
Cond: AreEqual(left, right),
|
||||
|
@ -57,10 +55,9 @@ func IfEqual(left dst.Expr, right dst.Expr, statements ...dst.Stmt) *dst.IfStmt
|
|||
|
||||
// IfNotNil executes a series of statements if the supplied expression is not nil
|
||||
//
|
||||
// if <source> != nil {
|
||||
// <statements>
|
||||
// }
|
||||
//
|
||||
// if <source> != nil {
|
||||
// <statements>
|
||||
// }
|
||||
func IfNotNil(toCheck dst.Expr, statements ...dst.Stmt) *dst.IfStmt {
|
||||
return &dst.IfStmt{
|
||||
Cond: NotNil(toCheck),
|
||||
|
@ -70,10 +67,9 @@ func IfNotNil(toCheck dst.Expr, statements ...dst.Stmt) *dst.IfStmt {
|
|||
|
||||
// IfNil executes a series of statements if the supplied expression is nil
|
||||
//
|
||||
// if <source> != nil {
|
||||
// <statements>
|
||||
// }
|
||||
//
|
||||
// if <source> != nil {
|
||||
// <statements>
|
||||
// }
|
||||
func IfNil(toCheck dst.Expr, statements ...dst.Stmt) *dst.IfStmt {
|
||||
return &dst.IfStmt{
|
||||
Cond: AreEqual(toCheck, Nil()),
|
||||
|
@ -86,7 +82,6 @@ func IfNil(toCheck dst.Expr, statements ...dst.Stmt) *dst.IfStmt {
|
|||
// if ok {
|
||||
// <statements>
|
||||
// }
|
||||
//
|
||||
func IfOk(statements ...dst.Stmt) *dst.IfStmt {
|
||||
return &dst.IfStmt{
|
||||
Cond: dst.NewIdent("ok"),
|
||||
|
@ -99,7 +94,6 @@ func IfOk(statements ...dst.Stmt) *dst.IfStmt {
|
|||
// if !ok {
|
||||
// <statements>
|
||||
// }
|
||||
//
|
||||
func IfNotOk(statements ...dst.Stmt) *dst.IfStmt {
|
||||
return &dst.IfStmt{
|
||||
Cond: &dst.UnaryExpr{
|
||||
|
@ -116,10 +110,9 @@ func IfNotOk(statements ...dst.Stmt) *dst.IfStmt {
|
|||
// local is the name of the local variable to initialize
|
||||
// statements form the body of the if statement
|
||||
//
|
||||
// if <local>, ok := <expr>.(<typeExpr>); ok {
|
||||
// <statements>
|
||||
// }
|
||||
//
|
||||
// if <local>, ok := <expr>.(<typeExpr>); ok {
|
||||
// <statements>
|
||||
// }
|
||||
func IfType(expr dst.Expr, typeExpr dst.Expr, local string, statements ...dst.Stmt) *dst.IfStmt {
|
||||
return &dst.IfStmt{
|
||||
Init: TypeAssert(dst.NewIdent(local), expr, typeExpr),
|
||||
|
|
|
@ -51,9 +51,10 @@ func NewTestFuncDetails(testingPackage string, testName string, body ...dst.Stmt
|
|||
}
|
||||
|
||||
// DefineFunc defines a function (header, body, etc), like:
|
||||
// <comment>
|
||||
//
|
||||
// <comment>
|
||||
// func (<receiverIdent> <receiverType>) <name>(<params...>) (<returns...>) {
|
||||
// <body...>
|
||||
// <body...>
|
||||
// }
|
||||
func (fn *FuncDetails) DefineFunc() *dst.FuncDecl {
|
||||
|
||||
|
|
|
@ -13,8 +13,7 @@ import (
|
|||
|
||||
// MakeMap returns the call expression for making a map
|
||||
//
|
||||
// make(map[<key>]<value>)
|
||||
//
|
||||
// make(map[<key>]<value>)
|
||||
func MakeMap(key dst.Expr, value dst.Expr) *dst.CallExpr {
|
||||
return &dst.CallExpr{
|
||||
Fun: dst.NewIdent("make"),
|
||||
|
@ -29,8 +28,7 @@ func MakeMap(key dst.Expr, value dst.Expr) *dst.CallExpr {
|
|||
|
||||
// MakeMapWithCapacity returns the call expression for making a map with a predefined capacity
|
||||
//
|
||||
// make(map[<key>]<value>, <capacity>)
|
||||
//
|
||||
// make(map[<key>]<value>, <capacity>)
|
||||
func MakeMapWithCapacity(key dst.Expr, value dst.Expr, capacity dst.Expr) *dst.CallExpr {
|
||||
return &dst.CallExpr{
|
||||
Fun: dst.NewIdent("make"),
|
||||
|
@ -46,8 +44,7 @@ func MakeMapWithCapacity(key dst.Expr, value dst.Expr, capacity dst.Expr) *dst.C
|
|||
|
||||
// InsertMap returns an assignment statement for inserting an item into a map
|
||||
//
|
||||
// <mapExpr>[<key>] = <rhs>
|
||||
//
|
||||
// <mapExpr>[<key>] = <rhs>
|
||||
func InsertMap(mapExpr dst.Expr, key dst.Expr, rhs dst.Expr) *dst.AssignStmt {
|
||||
return SimpleAssignment(
|
||||
&dst.IndexExpr{
|
||||
|
@ -60,10 +57,9 @@ func InsertMap(mapExpr dst.Expr, key dst.Expr, rhs dst.Expr) *dst.AssignStmt {
|
|||
// IterateOverMapWithValue creates a statement to iterate over the content of a map using the
|
||||
// specified identifiers for each key and value found.
|
||||
//
|
||||
// for <key>, <item> := range <mapExpr> {
|
||||
// <statements>
|
||||
// }
|
||||
//
|
||||
// for <key>, <item> := range <mapExpr> {
|
||||
// <statements>
|
||||
// }
|
||||
func IterateOverMapWithValue(key string, item string, mapExpr dst.Expr, statements ...dst.Stmt) *dst.RangeStmt {
|
||||
return &dst.RangeStmt{
|
||||
Key: dst.NewIdent(key),
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
// MakeSlice returns the call expression for making a slice
|
||||
//
|
||||
// make([]<value>)
|
||||
//
|
||||
func MakeSlice(listType dst.Expr, len dst.Expr) *dst.CallExpr {
|
||||
return &dst.CallExpr{
|
||||
Fun: dst.NewIdent("make"),
|
||||
|
@ -28,7 +27,6 @@ func MakeSlice(listType dst.Expr, len dst.Expr) *dst.CallExpr {
|
|||
// AppendItemToSlice returns a statement to append a single item to a slice
|
||||
//
|
||||
// <lhs> = append(<lhs>, <rhs>)
|
||||
//
|
||||
func AppendItemToSlice(lhs dst.Expr, rhs dst.Expr) dst.Stmt {
|
||||
return SimpleAssignment(
|
||||
dst.Clone(lhs).(dst.Expr),
|
||||
|
@ -38,7 +36,6 @@ func AppendItemToSlice(lhs dst.Expr, rhs dst.Expr) dst.Stmt {
|
|||
// AppendItemsToSlice returns a statement to append many individual items to a slice
|
||||
//
|
||||
// <lhs> = append(<lhs>, <rhs>, <rhs>, <rhs>, ...)
|
||||
//
|
||||
func AppendItemsToSlice(lhs dst.Expr, rhs ...dst.Expr) dst.Stmt {
|
||||
args := make([]dst.Expr, 0, len(rhs)+1)
|
||||
args = append(args, lhs)
|
||||
|
@ -54,7 +51,6 @@ func AppendItemsToSlice(lhs dst.Expr, rhs ...dst.Expr) dst.Stmt {
|
|||
// AppendSliceToSlice returns a statement to append a slice to another slice
|
||||
//
|
||||
// <lhs> = append(<lhs>, <rhs>...)
|
||||
//
|
||||
func AppendSliceToSlice(lhs dst.Expr, rhs dst.Expr) dst.Stmt {
|
||||
f := CallFunc("append", dst.Clone(lhs).(dst.Expr), dst.Clone(rhs).(dst.Expr))
|
||||
f.Ellipsis = true
|
||||
|
@ -66,10 +62,9 @@ func AppendSliceToSlice(lhs dst.Expr, rhs dst.Expr) dst.Stmt {
|
|||
// IterateOverSlice creates a statement to iterate over the content of a list using the specified
|
||||
// identifier for each element in the list
|
||||
//
|
||||
// for _, <item> := range <list> {
|
||||
// <statements>
|
||||
// }
|
||||
//
|
||||
// for _, <item> := range <list> {
|
||||
// <statements>
|
||||
// }
|
||||
func IterateOverSlice(item string, list dst.Expr, statements ...dst.Stmt) *dst.RangeStmt {
|
||||
return &dst.RangeStmt{
|
||||
Key: dst.NewIdent("_"),
|
||||
|
@ -83,10 +78,9 @@ func IterateOverSlice(item string, list dst.Expr, statements ...dst.Stmt) *dst.R
|
|||
// IterateOverSliceWithIndex creates a statement to iterate over the content of a list using the specified
|
||||
// identifiers for each index and element in the list
|
||||
//
|
||||
// for <index>, <item> := range <list> {
|
||||
// <statements>
|
||||
// }
|
||||
//
|
||||
// for <index>, <item> := range <list> {
|
||||
// <statements>
|
||||
// }
|
||||
func IterateOverSliceWithIndex(index string, item string, list dst.Expr, statements ...dst.Stmt) *dst.RangeStmt {
|
||||
return &dst.RangeStmt{
|
||||
Key: dst.NewIdent(index),
|
||||
|
|
|
@ -176,7 +176,8 @@ func (builder *ConversionFunctionBuilder) BuildConversion(params ConversionParam
|
|||
|
||||
// IdentityConvertComplexOptionalProperty handles conversion for optional properties with complex elements
|
||||
// This function generates code that looks like this:
|
||||
// if <source> != nil {
|
||||
//
|
||||
// if <source> != nil {
|
||||
// <code for producing result from destinationType.Element()>
|
||||
// <destination> = &<result>
|
||||
// }
|
||||
|
@ -222,7 +223,8 @@ func IdentityConvertComplexOptionalProperty(builder *ConversionFunctionBuilder,
|
|||
|
||||
// IdentityConvertComplexArrayProperty handles conversion for array properties with complex elements
|
||||
// This function generates code that looks like this:
|
||||
// for _, item := range <source> {
|
||||
//
|
||||
// for _, item := range <source> {
|
||||
// <code for producing result from destinationType.Element()>
|
||||
// <destination> = append(<destination>, <result>)
|
||||
// }
|
||||
|
@ -293,10 +295,11 @@ func IdentityConvertComplexArrayProperty(builder *ConversionFunctionBuilder, par
|
|||
// IdentityConvertComplexMapProperty handles conversion for map properties with complex values.
|
||||
// This function panics if the map keys are not primitive types.
|
||||
// This function generates code that looks like this:
|
||||
// if <source> != nil {
|
||||
//
|
||||
// if <source> != nil {
|
||||
// <destination> = make(map[<destinationType.KeyType()]<destinationType.ValueType()>, len(<source>))
|
||||
// for key, value := range <source> {
|
||||
// <code for producing result from destinationType.ValueType()>
|
||||
// <code for producing result from destinationType.ValueType()>
|
||||
// <destination>[key] = <result>
|
||||
// }
|
||||
// }
|
||||
|
@ -388,6 +391,7 @@ func IdentityConvertComplexMapProperty(builder *ConversionFunctionBuilder, param
|
|||
// Note that because this handler is dealing with TypeName's and not Optional<TypeName>, it is safe to
|
||||
// perform a simple assignment rather than a copy.
|
||||
// This function generates code that looks like this:
|
||||
//
|
||||
// <destination> <assignmentHandler> <source>
|
||||
func IdentityAssignTypeName(_ *ConversionFunctionBuilder, params ConversionParameters) []dst.Stmt {
|
||||
destinationType, ok := params.DestinationType.(TypeName)
|
||||
|
@ -474,15 +478,17 @@ func AssignToOptional(builder *ConversionFunctionBuilder, params ConversionParam
|
|||
|
||||
// AssignFromOptional assigns address of source to destination.
|
||||
// This function generates code that looks like this, for simple conversions:
|
||||
// if (<source> != nil) {
|
||||
// <destination> <assignmentHandler> *<source>
|
||||
// }
|
||||
//
|
||||
// if (<source> != nil) {
|
||||
// <destination> <assignmentHandler> *<source>
|
||||
// }
|
||||
//
|
||||
// or:
|
||||
// if (<source> != nil) {
|
||||
// <destination>Temp := convert(*<source>)
|
||||
// <destination> <assignmentHandler> <destination>Temp
|
||||
// }
|
||||
//
|
||||
// if (<source> != nil) {
|
||||
// <destination>Temp := convert(*<source>)
|
||||
// <destination> <assignmentHandler> <destination>Temp
|
||||
// }
|
||||
func AssignFromOptional(builder *ConversionFunctionBuilder, params ConversionParameters) []dst.Stmt {
|
||||
optSrc, ok := params.SourceType.(*OptionalType)
|
||||
if !ok {
|
||||
|
@ -556,7 +562,8 @@ func IdentityAssignValidatedTypeSource(builder *ConversionFunctionBuilder, param
|
|||
|
||||
// IdentityDeepCopyJSON special cases copying JSON-type fields to call the DeepCopy method.
|
||||
// It generates code that looks like:
|
||||
// <destination> = *<source>.DeepCopy()
|
||||
//
|
||||
// <destination> = *<source>.DeepCopy()
|
||||
func IdentityDeepCopyJSON(_ *ConversionFunctionBuilder, params ConversionParameters) []dst.Stmt {
|
||||
if !TypeEquals(params.DestinationType, JSONType) {
|
||||
return nil
|
||||
|
@ -585,8 +592,9 @@ func AssignmentHandlerAssign(lhs dst.Expr, rhs dst.Expr) dst.Stmt {
|
|||
|
||||
// CreateLocal creates an unused local variable name.
|
||||
// Names are chosen according to the following rules:
|
||||
// 1. If there is no local variable with the <suffix> name, use that.
|
||||
// 2. If there is a local variable with the <suffix> name, create a variable name <nameHint><suffix>.
|
||||
// 1. If there is no local variable with the <suffix> name, use that.
|
||||
// 2. If there is a local variable with the <suffix> name, create a variable name <nameHint><suffix>.
|
||||
//
|
||||
// In the case that <nameHint><suffix> is also taken append numbers to the end in standard KnownLocalsSet fashion.
|
||||
// Note that this function trims numbers on the right hand side of nameHint, so a nameHint of "item1" will get a local
|
||||
// variable named item<suffix>.
|
||||
|
|
|
@ -329,11 +329,11 @@ func simplifyName(context string, name string) string {
|
|||
|
||||
// sliceIntoWords splits the provided identifier into a slice of individual words.
|
||||
// A word is defined by one of the following:
|
||||
// 1. A space ("a test" becomes "a" and "test")
|
||||
// 2. A transition between lowercase and uppercase ("aWord" becomes "a" and "Word")
|
||||
// 3. A transition between multiple uppercase letters and a lowercase letter ("XMLDocument" becomes "XML" and "Document")
|
||||
// 4. A transition between a letter and a digit ("book12" becomes "book" and "12")
|
||||
// 5. A transition between a digit and a letter ("12monkeys" becomes "12" and "monkeys")
|
||||
// 1. A space ("a test" becomes "a" and "test")
|
||||
// 2. A transition between lowercase and uppercase ("aWord" becomes "a" and "Word")
|
||||
// 3. A transition between multiple uppercase letters and a lowercase letter ("XMLDocument" becomes "XML" and "Document")
|
||||
// 4. A transition between a letter and a digit ("book12" becomes "book" and "12")
|
||||
// 5. A transition between a digit and a letter ("12monkeys" becomes "12" and "monkeys")
|
||||
func sliceIntoWords(identifier string) []string {
|
||||
// Trim any leading and trailing spaces to make our life easier later
|
||||
identifier = strings.Trim(identifier, " ")
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
//
|
||||
// Conceptually it takes (via Add) a list of functions of the form:
|
||||
//
|
||||
// func ([ctx interface{},] left {some Type}, right {some Type}) (Type, error)
|
||||
// func ([ctx interface{},] left {some Type}, right {some Type}) (Type, error)
|
||||
//
|
||||
// where `left` and `right` can be concrete types that implement the `Type` interface.
|
||||
//
|
||||
|
|
|
@ -76,7 +76,7 @@ func TestWriteDebugDescription(t *testing.T) {
|
|||
}
|
||||
|
||||
// TestWriteDebugDescriptionNils ensures that WriteDebugDescription() doesn't panic even if called on a nil reference,
|
||||
//(this is a diagnostic method that should pretty much always do something useful)
|
||||
// (this is a diagnostic method that should pretty much always do something useful)
|
||||
func TestWriteDebugDescriptionNils(t *testing.T) {
|
||||
t.Parallel()
|
||||
g := NewGomegaWithT(t)
|
||||
|
|
|
@ -28,7 +28,6 @@ import "fmt"
|
|||
// VisitObjectType = func(this TypeVisitor, it *ObjectType, ctx interface{}) (Type, error) // Works
|
||||
// VisitObjectType = func(it TypeName) Type // Fails - parameter is not an *ObjectType
|
||||
// VisitObjectType = func(this TypeVisitor, it TypeName, ctx interface{}) (ObjectType, error) // Fails -return is not Type
|
||||
//
|
||||
type TypeVisitorBuilder struct {
|
||||
VisitTypeName interface{}
|
||||
VisitOneOfType interface{}
|
||||
|
|
|
@ -32,26 +32,27 @@ func (e resourceRemovalVisitorContext) WithMoreDepth() resourceRemovalVisitorCon
|
|||
|
||||
// EmbeddedResourceRemover uses a variety of heuristics to remove resources that are embedded inside other resources.
|
||||
// There are a number of different kinds of embeddings:
|
||||
// 1. A "Properties" embedding. When we process the Azure JSON schema/Swagger we manufacture a "Spec"
|
||||
// type that doesn't exist in the JSON schema/Swagger. In the JSON schema the resource itself must comply with ARM
|
||||
// resource requirements, meaning that all of the RP specific properties are stored in the "Properties"
|
||||
// property which for the sake of example we will say has type "R1Properties".
|
||||
// Other resources which have a property somewhere in their type hierarchy with that same "R1Properties"
|
||||
// type are actually embedding the R1 resource entirely inside themselves. Since the R1 resource is its own
|
||||
// resource it doesn't make sense to have it embedded inside another resource in Kubernetes. These embeddings
|
||||
// should really just be cross resource references. This pipeline finds such embeddings and removes them. A concrete
|
||||
// example of one such embedding is
|
||||
// v20181001 Microsoft.Networking Connection.Spec.Properties.LocalNetworkGateway2.Properties.
|
||||
// The LocalNetworkGateway2 property is of type "LocalNetworkGateway" which is itself a resource.
|
||||
// The ideal shape of Connection.Spec.Properties.LocalNetworkGate2 would just be a reference to a
|
||||
// LocalNetworkGateway resource.
|
||||
// 2. A subresource embedding. For the same reasons above, embedded subresources don't make sense in Kubernetes.
|
||||
// In the case of embedded subresources, the ideal shape would be a complete removal of the reference. We forbid
|
||||
// parent resources directly referencing child resources as it complicates the Watches scenario for each resource
|
||||
// reconciler. It's also not a common pattern in Kubernetes - usually you can identify children for a
|
||||
// given parent via a label. An example of this type of embedding is
|
||||
// v20180601 Microsoft.Networking RouteTable.Spec.Properties.Routes. The Routes property is of type RouteTableRoutes
|
||||
// which is a child resource of RouteTable.
|
||||
// 1. A "Properties" embedding. When we process the Azure JSON schema/Swagger we manufacture a "Spec"
|
||||
// type that doesn't exist in the JSON schema/Swagger. In the JSON schema the resource itself must comply with ARM
|
||||
// resource requirements, meaning that all of the RP specific properties are stored in the "Properties"
|
||||
// property which for the sake of example we will say has type "R1Properties".
|
||||
// Other resources which have a property somewhere in their type hierarchy with that same "R1Properties"
|
||||
// type are actually embedding the R1 resource entirely inside themselves. Since the R1 resource is its own
|
||||
// resource it doesn't make sense to have it embedded inside another resource in Kubernetes. These embeddings
|
||||
// should really just be cross resource references. This pipeline finds such embeddings and removes them. A concrete
|
||||
// example of one such embedding is
|
||||
// v20181001 Microsoft.Networking Connection.Spec.Properties.LocalNetworkGateway2.Properties.
|
||||
// The LocalNetworkGateway2 property is of type "LocalNetworkGateway" which is itself a resource.
|
||||
// The ideal shape of Connection.Spec.Properties.LocalNetworkGate2 would just be a reference to a
|
||||
// LocalNetworkGateway resource.
|
||||
// 2. A subresource embedding. For the same reasons above, embedded subresources don't make sense in Kubernetes.
|
||||
// In the case of embedded subresources, the ideal shape would be a complete removal of the reference. We forbid
|
||||
// parent resources directly referencing child resources as it complicates the Watches scenario for each resource
|
||||
// reconciler. It's also not a common pattern in Kubernetes - usually you can identify children for a
|
||||
// given parent via a label. An example of this type of embedding is
|
||||
// v20180601 Microsoft.Networking RouteTable.Spec.Properties.Routes. The Routes property is of type RouteTableRoutes
|
||||
// which is a child resource of RouteTable.
|
||||
//
|
||||
// Note that even though the above examples do not include Status definitions, the same rules apply to Status definitions, with
|
||||
// the only difference being that for Status definitions the resource reference in Swagger (the source of the Status definitions)
|
||||
// is to the Status type (as opposed to the "Properties" type for Spec).
|
||||
|
|
|
@ -196,20 +196,21 @@ func validateConfigMapDestinations(k *functions.ResourceFunction, codeGeneration
|
|||
}
|
||||
|
||||
// validateOperatorSpecSliceBody helps generate the body of the validateResourceReferences function:
|
||||
// func (account *DatabaseAccount) validateConfigMapDestinations() error {
|
||||
// if <receiver>.Spec.OperatorSpec == nil {
|
||||
// return nil
|
||||
// }
|
||||
// if <receiver>.Spec.OperatorSpec.<operatorSpecProperty> == nil {
|
||||
// return nil
|
||||
// }
|
||||
// toValidate := []*<validateType>{
|
||||
// account.Spec.OperatorSpec.ConfigMaps.ClientId,
|
||||
// account.Spec.OperatorSpec.ConfigMaps.PrincipalId,
|
||||
// ...
|
||||
// }
|
||||
// return genruntime.<validateFunctionName>(toValidate)
|
||||
// }
|
||||
//
|
||||
// func (account *DatabaseAccount) validateConfigMapDestinations() error {
|
||||
// if <receiver>.Spec.OperatorSpec == nil {
|
||||
// return nil
|
||||
// }
|
||||
// if <receiver>.Spec.OperatorSpec.<operatorSpecProperty> == nil {
|
||||
// return nil
|
||||
// }
|
||||
// toValidate := []*<validateType>{
|
||||
// account.Spec.OperatorSpec.ConfigMaps.ClientId,
|
||||
// account.Spec.OperatorSpec.ConfigMaps.PrincipalId,
|
||||
// ...
|
||||
// }
|
||||
// return genruntime.<validateFunctionName>(toValidate)
|
||||
// }
|
||||
func validateOperatorSpecSliceBody(
|
||||
codeGenerationContext *astmodel.CodeGenerationContext,
|
||||
resource *astmodel.ResourceType,
|
||||
|
|
|
@ -70,9 +70,9 @@ func nestSpecIntoForProvider(
|
|||
// nestType nests the contents of the provided outerType into a property with the given nestedPropertyName whose
|
||||
// type is the given nestedTypeName. The result is a type that looks something like the following:
|
||||
//
|
||||
// type <outerTypeName> struct {
|
||||
// <nestedPropertyName> <nestedTypeName> `yaml:"<nestedPropertyName>"`
|
||||
// }
|
||||
// type <outerTypeName> struct {
|
||||
// <nestedPropertyName> <nestedTypeName> `yaml:"<nestedPropertyName>"`
|
||||
// }
|
||||
func nestType(
|
||||
idFactory astmodel.IdentifierFactory,
|
||||
definitions astmodel.TypeDefinitionSet,
|
||||
|
|
|
@ -46,7 +46,6 @@ const DetectSkippingPropertiesStageID = "detectSkippingProperties"
|
|||
// Additional complexities:
|
||||
// - We need to handle type renaming between versions.
|
||||
// - When introduced, we will also need to handle property renaming between versions
|
||||
//
|
||||
func DetectSkippingProperties() *Stage {
|
||||
return NewStage(
|
||||
DetectSkippingPropertiesStageID,
|
||||
|
|
|
@ -101,7 +101,6 @@ func removeFlatten(t astmodel.Type) astmodel.Type {
|
|||
// We will flatten it and rename the second property, resulting in:
|
||||
// - `Type`
|
||||
// - `PropertiesType`
|
||||
//
|
||||
func fixCollisions(props []*astmodel.PropertyDefinition) []*astmodel.PropertyDefinition {
|
||||
names := make(map[astmodel.PropertyName]int)
|
||||
|
||||
|
|
|
@ -22,13 +22,14 @@ const RemoveStatusPropertyValidationsStageID = "removeStatusPropertyValidation"
|
|||
// This is required because Status is retrieved directly from the ARM API, and there are
|
||||
// cases where ARM might return something that isn't actually "valid" according to the validation,
|
||||
// but makes sense in context. Some examples:
|
||||
// 1. Status has a modelAsString enum with 2 values, but in a future API version, a 3rd value is added.
|
||||
// The fact that the enum is modelAsString allows the service to return the new 3rd value even in old API
|
||||
// versions.
|
||||
// 2. Status has an int that must be between 10 and 20. In a future API version, that restriction is relaxed and
|
||||
// the same int can now be between 0 and 50.
|
||||
// 3. A bug in the services Swagger specification causes the service to accept enums with any case, but always
|
||||
// return the enum all uppercase
|
||||
// 1. Status has a modelAsString enum with 2 values, but in a future API version, a 3rd value is added.
|
||||
// The fact that the enum is modelAsString allows the service to return the new 3rd value even in old API
|
||||
// versions.
|
||||
// 2. Status has an int that must be between 10 and 20. In a future API version, that restriction is relaxed and
|
||||
// the same int can now be between 0 and 50.
|
||||
// 3. A bug in the services Swagger specification causes the service to accept enums with any case, but always
|
||||
// return the enum all uppercase
|
||||
//
|
||||
// In the above cases, if we left validation on the Status types, we would be unable to persist the content
|
||||
// returned by the service (apiserver will reject it as not matching the OpenAPI schema). This could be a problem
|
||||
// in cases where the resource was created via some other means and then imported into
|
||||
|
|
|
@ -175,14 +175,15 @@ func orderByFunctionName(functions []*functions.IndexRegistrationFunction) func(
|
|||
}
|
||||
|
||||
// createGetKnownTypesFunc creates a getKnownTypes function that returns all known types:
|
||||
// func getKnownTypes() []client.Object {
|
||||
// var result []client.Object
|
||||
// result = append(result, new(<package>.<resource>))
|
||||
// result = append(result, new(<package>.<resource>))
|
||||
// result = append(result, new(<package>.<resource>))
|
||||
// ...
|
||||
// return result
|
||||
// }
|
||||
//
|
||||
// func getKnownTypes() []client.Object {
|
||||
// var result []client.Object
|
||||
// result = append(result, new(<package>.<resource>))
|
||||
// result = append(result, new(<package>.<resource>))
|
||||
// result = append(result, new(<package>.<resource>))
|
||||
// ...
|
||||
// return result
|
||||
// }
|
||||
func createGetKnownTypesFunc(codeGenerationContext *astmodel.CodeGenerationContext, resources []astmodel.TypeName) (dst.Decl, error) {
|
||||
funcName := "getKnownTypes"
|
||||
funcComment := "returns the list of all types."
|
||||
|
@ -236,27 +237,28 @@ func createGetKnownTypesFunc(codeGenerationContext *astmodel.CodeGenerationConte
|
|||
}
|
||||
|
||||
// createGetKnownStorageTypesFunc creates a getKnownStorageTypes function that returns all storage types:
|
||||
// func getKnownStorageTypes() []registration.StorageType {
|
||||
// var result []*registration.StorageType
|
||||
// result = append(result, ®istration.StorageType{
|
||||
// Obj: new(<package>.<resource>),
|
||||
// Indexes: []registration.Index{
|
||||
// {
|
||||
// Key: <key>,
|
||||
// Func: <func>,
|
||||
// },
|
||||
//
|
||||
// func getKnownStorageTypes() []registration.StorageType {
|
||||
// var result []*registration.StorageType
|
||||
// result = append(result, ®istration.StorageType{
|
||||
// Obj: new(<package>.<resource>),
|
||||
// Indexes: []registration.Index{
|
||||
// {
|
||||
// Key: <key>,
|
||||
// Func: <func>,
|
||||
// },
|
||||
// Watches: []registration.Watch{
|
||||
// {
|
||||
// Src: <source> (usually corev1.Secret{}),
|
||||
// },
|
||||
// },
|
||||
// Watches: []registration.Watch{
|
||||
// {
|
||||
// Src: <source> (usually corev1.Secret{}),
|
||||
// },
|
||||
// })
|
||||
// result = append(result, registration.StorageType{Obj: new(<package>.<resource>)})
|
||||
// result = append(result, registration.StorageType{Obj: new(<package>.<resource>)})
|
||||
// ...
|
||||
// return result
|
||||
// }
|
||||
// },
|
||||
// })
|
||||
// result = append(result, registration.StorageType{Obj: new(<package>.<resource>)})
|
||||
// result = append(result, registration.StorageType{Obj: new(<package>.<resource>)})
|
||||
// ...
|
||||
// return result
|
||||
// }
|
||||
func (r *ResourceRegistrationFile) createGetKnownStorageTypesFunc(
|
||||
codeGenerationContext *astmodel.CodeGenerationContext,
|
||||
) dst.Decl {
|
||||
|
@ -375,14 +377,15 @@ func (r *ResourceRegistrationFile) createGetResourceExtensions(context *astmodel
|
|||
}
|
||||
|
||||
// createCreateSchemeFunc creates a createScheme() function like:
|
||||
// func createScheme() *runtime.Scheme {
|
||||
// scheme := runtime.NewScheme()
|
||||
// _ = clientgoscheme.AddToScheme(scheme)
|
||||
// _ = batchv20170901.AddToScheme(scheme)
|
||||
// _ = documentdbv20150408.AddToScheme(scheme)
|
||||
// _ = storagev20190401.AddToScheme(scheme)
|
||||
// return scheme
|
||||
// }
|
||||
//
|
||||
// func createScheme() *runtime.Scheme {
|
||||
// scheme := runtime.NewScheme()
|
||||
// _ = clientgoscheme.AddToScheme(scheme)
|
||||
// _ = batchv20170901.AddToScheme(scheme)
|
||||
// _ = documentdbv20150408.AddToScheme(scheme)
|
||||
// _ = storagev20190401.AddToScheme(scheme)
|
||||
// return scheme
|
||||
// }
|
||||
func (r *ResourceRegistrationFile) createCreateSchemeFunc(codeGenerationContext *astmodel.CodeGenerationContext) (dst.Decl, error) {
|
||||
runtime, err := codeGenerationContext.GetImportedPackageName(astmodel.APIMachineryRuntimeReference)
|
||||
if err != nil {
|
||||
|
@ -500,6 +503,7 @@ func (r *ResourceRegistrationFile) makeWatchesExpr(typeName astmodel.TypeName, c
|
|||
}
|
||||
|
||||
// makeSimpleWatchesExpr generates code for a Watches expression:
|
||||
//
|
||||
// {
|
||||
// Src: &source.Kind{Type: &<fieldType>{}},
|
||||
// MakeEventHandler: <watchHelperFuncName>([]string{<typeNameKeys[typeName]>}, &<typeName>{}),
|
||||
|
|
|
@ -146,7 +146,6 @@ func (stage *Stage) RequiresPrerequisiteStages(prerequisites ...string) {
|
|||
// Post-requisites are thus not completely isomorphic with RequiresPrerequisiteStages as there may be supporting stages that are
|
||||
// sometimes omitted from execution when targeting different outcomes. Having both pre- and post-requisites allows the
|
||||
// dependencies to drop out cleanly when different stages are present.
|
||||
//
|
||||
func (stage *Stage) RequiresPostrequisiteStages(postrequisites ...string) {
|
||||
if len(stage.postrequisites) > 0 {
|
||||
panic(fmt.Sprintf(
|
||||
|
|
|
@ -28,7 +28,8 @@ import (
|
|||
"github.com/Azure/azure-service-operator/v2/tools/generator/internal/jsonast"
|
||||
)
|
||||
|
||||
/* addStatusFromSwagger creates a PipelineStage to add status information into the generated resources.
|
||||
/*
|
||||
addStatusFromSwagger creates a PipelineStage to add status information into the generated resources.
|
||||
|
||||
This information is derived from the Azure Swagger specifications. We parse the Swagger specs and look for
|
||||
any actions that appear to be ARM resources (have PUT methods with types we can use and appropriate names in the
|
||||
|
@ -39,7 +40,6 @@ Next, we walk over all the resources we are currently generating CRDs for and at
|
|||
a match for the resource in the status information we have parsed. If we locate a match, it is
|
||||
added to the Status field of the Resource type, after we have renamed all the status types to
|
||||
avoid any conflicts with existing Spec types that have already been defined.
|
||||
|
||||
*/
|
||||
func AddStatusFromSwagger(idFactory astmodel.IdentifierFactory, config *config.Configuration) *Stage {
|
||||
return NewLegacyStage(
|
||||
|
|
|
@ -18,22 +18,28 @@ import (
|
|||
const UnrollRecursiveTypesStageID = "unrollRecursiveTypes"
|
||||
|
||||
// UnrollRecursiveTypes finds types that reference themselves and "unrolls" the reference. So a type that looks like:
|
||||
// type Error struct {
|
||||
// code string
|
||||
// message string
|
||||
// errors []Error
|
||||
// }
|
||||
//
|
||||
// type Error struct {
|
||||
// code string
|
||||
// message string
|
||||
// errors []Error
|
||||
// }
|
||||
//
|
||||
// gets unrolled to look like:
|
||||
// type Error struct {
|
||||
// code string
|
||||
// message string
|
||||
// errors []Error_Unrolled
|
||||
// }
|
||||
//
|
||||
// type Error struct {
|
||||
// code string
|
||||
// message string
|
||||
// errors []Error_Unrolled
|
||||
// }
|
||||
//
|
||||
// where Error_Unrolled looks like:
|
||||
// type Error_Unrolled struct {
|
||||
// code string
|
||||
// message string
|
||||
// }
|
||||
//
|
||||
// type Error_Unrolled struct {
|
||||
// code string
|
||||
// message string
|
||||
// }
|
||||
//
|
||||
// The recursive references must be removed because
|
||||
// controller-tools doesn't support generating "references" (JSON $ref) so it can't support recursive types today.
|
||||
// See https://github.com/kubernetes-sigs/controller-tools/issues/489 for more information.
|
||||
|
|
|
@ -116,7 +116,6 @@ func (graph *ConversionGraph) TransitionCount() int {
|
|||
// declaringType is the type containing the property.
|
||||
// property is the name of the property.
|
||||
// definitions is a set of known definitions.
|
||||
//
|
||||
func (graph *ConversionGraph) FindNextProperty(
|
||||
ref astmodel.PropertyReference,
|
||||
definitions astmodel.TypeDefinitionSet) (astmodel.PropertyReference, error) {
|
||||
|
|
|
@ -80,11 +80,12 @@ func (p *PropertyConverter) useBaseTypeForEnumerations(
|
|||
}
|
||||
|
||||
// shortCircuitNamesOfSimpleTypes redirects or replaces TypeNames
|
||||
// o If a TypeName points into an API package, it is redirected into the appropriate storage package
|
||||
// o If a TypeName references an enumeration, it is replaced with the underlying type of the enumeration as our
|
||||
// storage definitions don't use enumerations, they use primitive definitions
|
||||
// o If a TypeName references an alias for a primitive type (these are used to specify validations), it is replace
|
||||
// with the primitive type
|
||||
//
|
||||
// o If a TypeName points into an API package, it is redirected into the appropriate storage package
|
||||
// o If a TypeName references an enumeration, it is replaced with the underlying type of the enumeration as our
|
||||
// storage definitions don't use enumerations, they use primitive definitions
|
||||
// o If a TypeName references an alias for a primitive type (these are used to specify validations), it is replace
|
||||
// with the primitive type
|
||||
func (p *PropertyConverter) shortCircuitNamesOfSimpleTypes(
|
||||
tv *astmodel.TypeVisitor, tn astmodel.TypeName, ctx interface{}) (astmodel.Type, error) {
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ import (
|
|||
// │ ObjectModelConfiguration │───────║ GroupConfiguration ║───────│ VersionConfiguration │───────│ TypeConfiguration │───────│ PropertyConfiguration │
|
||||
// │ │1 1..n║ ║1 1..n│ │1 1..n│ │1 1..n│ │
|
||||
// └──────────────────────────┘ ╚════════════════════╝ └──────────────────────┘ └───────────────────┘ └───────────────────────┘
|
||||
//
|
||||
type GroupConfiguration struct {
|
||||
name string
|
||||
versions map[string]*VersionConfiguration
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
// ║ ObjectModelConfiguration ║───────│ GroupConfiguration │───────│ VersionConfiguration │───────│ TypeConfiguration │───────│ PropertyConfiguration │
|
||||
// ║ ║1 1..n│ │1 1..n│ │1 1..n│ │1 1..n│ │
|
||||
// ╚══════════════════════════╝ └────────────────────┘ └──────────────────────┘ └───────────────────┘ └───────────────────────┘
|
||||
//
|
||||
type ObjectModelConfiguration struct {
|
||||
groups map[string]*GroupConfiguration // nested configuration for individual groups
|
||||
typoAdvisor *TypoAdvisor
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
// │ ObjectModelConfiguration │───────│ GroupConfiguration │───────│ VersionConfiguration │───────│ TypeConfiguration │───────║ PropertyConfiguration ║
|
||||
// │ │1 1..n│ │1 1..n│ │1 1..n│ │1 1..n║ ║
|
||||
// └──────────────────────────┘ └────────────────────┘ └──────────────────────┘ └───────────────────┘ ╚═══════════════════════╝
|
||||
//
|
||||
type PropertyConfiguration struct {
|
||||
name string
|
||||
nameInNextVersion configurable[string] // Name this property has in the next version
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
// │ ObjectModelConfiguration │───────│ GroupConfiguration │───────│ VersionConfiguration │───────║ TypeConfiguration ║───────│ PropertyConfiguration │
|
||||
// │ │1 1..n│ │1 1..n│ │1 1..n║ ║1 1..n│ │
|
||||
// └──────────────────────────┘ └────────────────────┘ └──────────────────────┘ ╚═══════════════════╝ └───────────────────────┘
|
||||
//
|
||||
type TypeConfiguration struct {
|
||||
name string
|
||||
properties map[string]*PropertyConfiguration
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
// │ ObjectModelConfiguration │───────│ GroupConfiguration │───────║ VersionConfiguration ║───────│ TypeConfiguration │───────│ PropertyConfiguration │
|
||||
// │ │1 1..n│ │1 1..n║ ║1 1..n│ │1 1..n│ │
|
||||
// └──────────────────────────┘ └────────────────────┘ ╚══════════════════════╝ └───────────────────┘ └───────────────────────┘
|
||||
//
|
||||
type VersionConfiguration struct {
|
||||
name string
|
||||
types map[string]*TypeConfiguration
|
||||
|
|
|
@ -35,10 +35,10 @@ type PropertyConversion func(
|
|||
// ctx contains additional information that may be needed when creating the property conversion
|
||||
//
|
||||
// The factory should return one of three result sets:
|
||||
// * For a fatal error, one that guarantees no conversion can be generated, return (nil, error)
|
||||
// This will abort the conversion process and return an error for logging.
|
||||
// * For a valid conversion, return (conversion, nil)
|
||||
// * When no conversion could be generated by this factory, return (nil, nil) to delegate to another factory
|
||||
// - For a fatal error, one that guarantees no conversion can be generated, return (nil, error)
|
||||
// This will abort the conversion process and return an error for logging.
|
||||
// - For a valid conversion, return (conversion, nil)
|
||||
// - When no conversion could be generated by this factory, return (nil, nil) to delegate to another factory
|
||||
//
|
||||
// Each conversion should be written with lead predicates to make sure that it only fires in the correct circumstances.
|
||||
// This requires, in particular, that most conversions check for optionality and bag items and exit early when those are
|
||||
|
@ -47,7 +47,6 @@ type PropertyConversion func(
|
|||
// generate the correct code; any conversion that relies on being "protected" from particular situations by having other
|
||||
// conversions earlier in the list held by propertyConversionFactories is brittle and likely to generate the incorrect
|
||||
// code if the order of items in the list is modified.
|
||||
//
|
||||
type PropertyConversionFactory func(
|
||||
source *TypedConversionEndpoint,
|
||||
destination *TypedConversionEndpoint,
|
||||
|
@ -110,47 +109,48 @@ func init() {
|
|||
// source *string => destination *Sku
|
||||
//
|
||||
// assuming
|
||||
// type Sku string
|
||||
//
|
||||
// type Sku string
|
||||
//
|
||||
// assignFromOptional can handle the optionality of sourceEndpoint and makes a recursive call
|
||||
// to CreateTypeConversion() with the simpler target:
|
||||
//
|
||||
// source string => destination *Sku
|
||||
//
|
||||
// assignToOptional can handle the optionality of destinationEndpoint and makes a recursive
|
||||
// call to CreateTypeConversion() with a simpler target:
|
||||
// assignToOptional can handle the optionality of destinationEndpoint and makes a recursive
|
||||
// call to CreateTypeConversion() with a simpler target:
|
||||
//
|
||||
// source string => destination Sku
|
||||
// source string => destination Sku
|
||||
//
|
||||
// assignToAliasedPrimitive can handle the type conversion of string to Sku, and makes
|
||||
// a recursive call to CreateTypeConversion() with a simpler target:
|
||||
// assignToAliasedPrimitive can handle the type conversion of string to Sku, and makes
|
||||
// a recursive call to CreateTypeConversion() with a simpler target:
|
||||
//
|
||||
// source string => destination string
|
||||
// source string => destination string
|
||||
//
|
||||
// assignPrimitiveFromPrimitive can handle primitive values, and generates a
|
||||
// conversion that does a simple assignment:
|
||||
// assignPrimitiveFromPrimitive can handle primitive values, and generates a
|
||||
// conversion that does a simple assignment:
|
||||
//
|
||||
// destination = source
|
||||
// destination = source
|
||||
//
|
||||
// assignToAliasedPrimitive injects the necessary type conversion:
|
||||
// assignToAliasedPrimitive injects the necessary type conversion:
|
||||
//
|
||||
// destination = Sku(source)
|
||||
// destination = Sku(source)
|
||||
//
|
||||
// assignToOptional injects a local variable and takes it's address
|
||||
// assignToOptional injects a local variable and takes it's address
|
||||
//
|
||||
// sku := Sku(source)
|
||||
// destination = &sku
|
||||
// sku := Sku(source)
|
||||
// destination = &sku
|
||||
//
|
||||
// finally, assignFromOptional injects the check to see if we have a value to assign in the
|
||||
// first place, assigning a suitable zero value if we don't:
|
||||
//
|
||||
// if source != nil {
|
||||
// sku := Sku(source)
|
||||
// destination := &sku
|
||||
// } else {
|
||||
// destination := ""
|
||||
// }
|
||||
// if source != nil {
|
||||
// sku := Sku(source)
|
||||
// destination := &sku
|
||||
// } else {
|
||||
//
|
||||
// destination := ""
|
||||
// }
|
||||
func CreateTypeConversion(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -193,26 +193,27 @@ func NameOfPropertyAssignmentFunction(
|
|||
|
||||
// writeToBagItem will generate a conversion where the destination is in our property bag
|
||||
//
|
||||
// For non-optional sources, the value is directly added
|
||||
// # For non-optional sources, the value is directly added
|
||||
//
|
||||
// <propertyBag>.Add(<propertyName>, <source>)
|
||||
//
|
||||
// For optional sources, the value is only added if non-nil; if nil, we remove any existing item
|
||||
//
|
||||
// if <source> != nil {
|
||||
// <propertyBag>.Add(<propertyName>, *<source>)
|
||||
// } else {
|
||||
// <propertyBag>.Remove(<propertyName>)
|
||||
// }
|
||||
// if <source> != nil {
|
||||
// <propertyBag>.Add(<propertyName>, *<source>)
|
||||
// } else {
|
||||
//
|
||||
// <propertyBag>.Remove(<propertyName>)
|
||||
// }
|
||||
//
|
||||
// For slice and slice sources, the value is only added if it is non-empty; if empty we remove any existing item
|
||||
//
|
||||
// if len(<source>) > 0 {
|
||||
// <propertyBag>.Add(<propertyName>, <source>)
|
||||
// } else {
|
||||
// <propertyBag>.Remove(<propertyName>)
|
||||
// }
|
||||
// if len(<source>) > 0 {
|
||||
// <propertyBag>.Add(<propertyName>, <source>)
|
||||
// } else {
|
||||
//
|
||||
// <propertyBag>.Remove(<propertyName>)
|
||||
// }
|
||||
func writeToBagItem(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -288,7 +289,6 @@ func writeToBagItem(
|
|||
// underlying type of the destination is compatible with the source.
|
||||
//
|
||||
// <destination> = &<source>
|
||||
//
|
||||
func assignToOptional(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -348,18 +348,18 @@ func assignToOptional(
|
|||
|
||||
// pullFromBagItem will populate a property from a property bag
|
||||
//
|
||||
// if <propertyBag>.Contains(<sourceName>) {
|
||||
// var <value> <destinationType>
|
||||
// err := <propertyBag>.Pull(<sourceName>, &<value>)
|
||||
// if err != nil {
|
||||
// return errors.Wrapf(err, ...)
|
||||
// }
|
||||
// if <propertyBag>.Contains(<sourceName>) {
|
||||
// var <value> <destinationType>
|
||||
// err := <propertyBag>.Pull(<sourceName>, &<value>)
|
||||
// if err != nil {
|
||||
// return errors.Wrapf(err, ...)
|
||||
// }
|
||||
//
|
||||
// <destination> = <value>
|
||||
// } else {
|
||||
// <destination> = <zero>
|
||||
// }
|
||||
// <destination> = <value>
|
||||
// } else {
|
||||
//
|
||||
// <destination> = <zero>
|
||||
// }
|
||||
func pullFromBagItem(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -444,15 +444,16 @@ func pullFromBagItem(
|
|||
// assignFromOptional will handle the case where the source type may be missing (nil)
|
||||
//
|
||||
// <original> := <source>
|
||||
// if <original> != nil {
|
||||
// <destination> = *<original>
|
||||
// } else {
|
||||
// <destination> = <zero>
|
||||
// }
|
||||
//
|
||||
// if <original> != nil {
|
||||
// <destination> = *<original>
|
||||
// } else {
|
||||
//
|
||||
// <destination> = <zero>
|
||||
// }
|
||||
//
|
||||
// Must trigger before assignToOptional so we generate the right zero values; to enforce this, assignToOptional includes
|
||||
// a predicate check that the source is NOT optional, allowing this conversion to trigger first.
|
||||
//
|
||||
func assignFromOptional(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -528,7 +529,6 @@ func assignFromOptional(
|
|||
// the source is type compatible with the base type of the enumeration
|
||||
//
|
||||
// <destination> = <enumeration-cast>(<source>)
|
||||
//
|
||||
func assignToEnumeration(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -585,7 +585,6 @@ func assignToEnumeration(
|
|||
// same primitive type and are not optional
|
||||
//
|
||||
// <destination> = <source>
|
||||
//
|
||||
func assignPrimitiveFromPrimitive(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -627,7 +626,6 @@ func assignPrimitiveFromPrimitive(
|
|||
// definitions have the same underlying primitive type and are not optional
|
||||
//
|
||||
// <destination> = <cast>(<source>)
|
||||
//
|
||||
func assignAliasedPrimitiveFromAliasedPrimitive(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -727,7 +725,6 @@ func assignFromAliasedPrimitive(
|
|||
// is not optional and we can find a conversion to give us the primitive type.
|
||||
//
|
||||
// <destination> = <cast>(<source>)
|
||||
//
|
||||
func assignToAliasedPrimitive(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -859,13 +856,14 @@ func assignHandcraftedImplementations(
|
|||
// underlying definitions of the two arrays are compatible
|
||||
//
|
||||
// <arr> := make([]<type>, len(<reader>))
|
||||
// for <index>, <value> := range <reader> {
|
||||
// // Shadow the loop variable to avoid aliasing
|
||||
// <value> := <value>
|
||||
// <arr>[<index>] := <value> // Or other conversion as required
|
||||
// }
|
||||
// <writer> = <arr>
|
||||
//
|
||||
// for <index>, <value> := range <reader> {
|
||||
// // Shadow the loop variable to avoid aliasing
|
||||
// <value> := <value>
|
||||
// <arr>[<index>] := <value> // Or other conversion as required
|
||||
// }
|
||||
//
|
||||
// <writer> = <arr>
|
||||
func assignArrayFromArray(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -978,16 +976,16 @@ func assignArrayFromArray(
|
|||
// assignMapFromMap will generate a code fragment to populate an array, assuming the
|
||||
// underlying definitions of the two arrays are compatible
|
||||
//
|
||||
// if <reader> != nil {
|
||||
// <map> := make(map[<key>]<type>)
|
||||
// for key, <item> := range <reader> {
|
||||
// <map>[<key>] := <item>
|
||||
// }
|
||||
// <writer> = <map>
|
||||
// } else {
|
||||
// <writer> = <zero>
|
||||
// }
|
||||
// if <reader> != nil {
|
||||
// <map> := make(map[<key>]<type>)
|
||||
// for key, <item> := range <reader> {
|
||||
// <map>[<key>] := <item>
|
||||
// }
|
||||
// <writer> = <map>
|
||||
// } else {
|
||||
//
|
||||
// <writer> = <zero>
|
||||
// }
|
||||
func assignMapFromMap(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -1176,7 +1174,6 @@ func assignEnumFromEnum(
|
|||
//
|
||||
// <local> = <baseType>(<source>)
|
||||
// <destination> = <enum>(<local>)
|
||||
//
|
||||
func assignPrimitiveFromEnum(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -1223,11 +1220,12 @@ func assignPrimitiveFromEnum(
|
|||
//
|
||||
// var <local> <destinationType>
|
||||
// err := <local>.AssignPropertiesFrom(<source>)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "while calling <local>.AssignPropertiesFrom(<source>)")
|
||||
// }
|
||||
// <destination> = <local>
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "while calling <local>.AssignPropertiesFrom(<source>)")
|
||||
// }
|
||||
//
|
||||
// <destination> = <local>
|
||||
func assignObjectDirectlyFromObject(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -1335,11 +1333,12 @@ func assignObjectDirectlyFromObject(
|
|||
//
|
||||
// var <local> <destinationType>
|
||||
// err := <source>.AssignPropertiesTo(&<local>)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "while calling <local>.AssignPropertiesTo(<source>)")
|
||||
// }
|
||||
// <destination> = <local>
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "while calling <local>.AssignPropertiesTo(<source>)")
|
||||
// }
|
||||
//
|
||||
// <destination> = <local>
|
||||
func assignObjectDirectlyToObject(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -1450,19 +1449,20 @@ func assignObjectDirectlyToObject(
|
|||
//
|
||||
// var <local> <intermediateType>
|
||||
// err := <local>.AssignPropertiesFrom(<source>)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "while calling <local>.AssignPropertiesFrom(<source>)")
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "while calling <local>.AssignPropertiesFrom(<source>)")
|
||||
// }
|
||||
//
|
||||
// var <otherlocal> <destinationType>
|
||||
// err := <otherlocal>.AssignPropertiesFrom(<local>)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "while calling <otherlocal>.AssignPropertiesFrom(<local>)")
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "while calling <otherlocal>.AssignPropertiesFrom(<local>)")
|
||||
// }
|
||||
//
|
||||
// Note the actual steps are generated by nested conversions; this handler works by finding the two conversions needed
|
||||
// given our intermediate type and chaining them together.
|
||||
//
|
||||
func assignObjectsViaIntermediateObject(
|
||||
sourceEndpoint *TypedConversionEndpoint,
|
||||
destinationEndpoint *TypedConversionEndpoint,
|
||||
|
@ -1619,7 +1619,6 @@ const (
|
|||
// copyKnownType will generate an assignment with the results of a call on the specified TypeName
|
||||
//
|
||||
// <destination> = <source>.<methodName>()
|
||||
//
|
||||
func copyKnownType(name astmodel.TypeName, methodName string, returnKind knownTypeMethodReturn) func(*TypedConversionEndpoint, *TypedConversionEndpoint, *PropertyConversionContext) (PropertyConversion, error) {
|
||||
return func(sourceEndpoint *TypedConversionEndpoint, destinationEndpoint *TypedConversionEndpoint, _ *PropertyConversionContext) (PropertyConversion, error) {
|
||||
// Require both source and destination to not be bag items
|
||||
|
|
|
@ -42,7 +42,6 @@ func (set ReadableConversionEndpointSet) CreateValueFunctionEndpoints(sourceType
|
|||
// Background: When our source instance has a property bag, that bag might contain values we can write into properties
|
||||
// on our destination instance. We therefore iterate through each property on the *destination* type and create a
|
||||
// ReadableConversionEndpoint for each one that looks in the property bag for a value.
|
||||
//
|
||||
func (set ReadableConversionEndpointSet) CreatePropertyBagMemberEndpoints(destinationType astmodel.Type) int {
|
||||
// Add a property bag item endpoint for each property we don't already support
|
||||
return set.addForEachProperty(destinationType, func(prop *astmodel.PropertyDefinition) *ReadableConversionEndpoint {
|
||||
|
|
|
@ -32,7 +32,6 @@ func (set WritableConversionEndpointSet) CreatePropertyEndpoints(destinationType
|
|||
// Background: When our destination instance has a property bag, that bag can be used to stash properties from the
|
||||
// source where there is no matching destination property. We therefore iterate through each property on the *source*
|
||||
// type and create a WritableConversionEndpoint for each one so the value is stashed in the property bag.
|
||||
//
|
||||
func (set WritableConversionEndpointSet) CreatePropertyBagMemberEndpoints(sourceType astmodel.Type) int {
|
||||
// Add a property bag member endpoint for each property we don't already support
|
||||
return set.addForEachProperty(sourceType, func(prop *astmodel.PropertyDefinition) *WritableConversionEndpoint {
|
||||
|
|
|
@ -26,17 +26,16 @@ import (
|
|||
// preexisting AssignProperties*() method. Otherwise, we chain to that type to do the conversion to an intermediate
|
||||
// instance and then convert using that.
|
||||
//
|
||||
// func (r <receiver>) ConvertFrom(instance <interfaceType>) error {
|
||||
// source, ok := instance.(*<otherType>)
|
||||
// if !ok {
|
||||
// // Need indirect conversion
|
||||
// source = &<otherType>{}
|
||||
// source.ConvertFrom(instance)
|
||||
// }
|
||||
//
|
||||
// return r.AssignPropertiesFrom(source)
|
||||
// }
|
||||
// func (r <receiver>) ConvertFrom(instance <interfaceType>) error {
|
||||
// source, ok := instance.(*<otherType>)
|
||||
// if !ok {
|
||||
// // Need indirect conversion
|
||||
// source = &<otherType>{}
|
||||
// source.ConvertFrom(instance)
|
||||
// }
|
||||
//
|
||||
// return r.AssignPropertiesFrom(source)
|
||||
// }
|
||||
type ChainedConversionFunction struct {
|
||||
// name is the unique name for this function
|
||||
name string
|
||||
|
@ -149,24 +148,23 @@ func (fn *ChainedConversionFunction) AsFunc(
|
|||
//
|
||||
// For ConvertFrom, we generate
|
||||
//
|
||||
// src, ok := source.(*<intermediateType>)
|
||||
// if ok {
|
||||
// // Populate our instance from source
|
||||
// return s.AssignPropertiesFrom(source)
|
||||
// }
|
||||
// src, ok := source.(*<intermediateType>)
|
||||
// if ok {
|
||||
// // Populate our instance from source
|
||||
// return s.AssignPropertiesFrom(source)
|
||||
// }
|
||||
//
|
||||
// // Convert to an intermediate form
|
||||
// src = &<intermediateType>{}
|
||||
// err := src.ConvertFrom(source)
|
||||
// if err != nil {
|
||||
// return errors.Wrapf(err, "...elided...")
|
||||
// }
|
||||
// // Convert to an intermediate form
|
||||
// src = &<intermediateType>{}
|
||||
// err := src.ConvertFrom(source)
|
||||
// if err != nil {
|
||||
// return errors.Wrapf(err, "...elided...")
|
||||
// }
|
||||
//
|
||||
// // Update our instance from src
|
||||
// return s.AssignPropertiesFrom(src)
|
||||
// // Update our instance from src
|
||||
// return s.AssignPropertiesFrom(src)
|
||||
//
|
||||
// For ConvertTo, we have essentially the same structure, but two-step conversion is done in the other order.
|
||||
//
|
||||
func (fn *ChainedConversionFunction) bodyForConvert(
|
||||
receiverName string, parameterName string, generationContext *astmodel.CodeGenerationContext) []dst.Stmt {
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@ import (
|
|||
|
||||
// GetConditionsFunction returns a function declaration containing the implementation of the GetConditions() function.
|
||||
//
|
||||
// func (r *<receiver>) GetConditions() genruntime.Conditions {
|
||||
// return r.Status.Conditions
|
||||
// }
|
||||
// func (r *<receiver>) GetConditions() genruntime.Conditions {
|
||||
// return r.Status.Conditions
|
||||
// }
|
||||
func GetConditionsFunction(k *ResourceFunction, codeGenerationContext *astmodel.CodeGenerationContext, receiver astmodel.TypeName, methodName string) *dst.FuncDecl {
|
||||
receiverIdent := k.IdFactory().CreateReceiver(receiver.Name())
|
||||
receiverType := receiver.AsType(codeGenerationContext)
|
||||
|
@ -44,9 +44,9 @@ func GetConditionsFunction(k *ResourceFunction, codeGenerationContext *astmodel.
|
|||
|
||||
// SetConditionsFunction returns a function declaration containing the implementation of the SetConditions() function.
|
||||
//
|
||||
// func (r *<receiver>) SetConditions(conditions genruntime.Conditions) {
|
||||
// r.Status.Conditions = conditions
|
||||
// }
|
||||
// func (r *<receiver>) SetConditions(conditions genruntime.Conditions) {
|
||||
// r.Status.Conditions = conditions
|
||||
// }
|
||||
func SetConditionsFunction(k *ResourceFunction, codeGenerationContext *astmodel.CodeGenerationContext, receiver astmodel.TypeName, methodName string) *dst.FuncDecl {
|
||||
conditionsParameterName := k.IdFactory().CreateIdentifier(astmodel.ConditionsProperty, astmodel.NotExported)
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ func validateResourceReferences(k *ResourceFunction, codeGenerationContext *astm
|
|||
}
|
||||
|
||||
// validateResourceReferencesBody helps generate the body of the validateResourceReferences function:
|
||||
// refs, err := reflecthelpers.FindResourceReferences(&<resource>.Spec)
|
||||
//
|
||||
// refs, err := reflecthelpers.FindResourceReferences(&<resource>.Spec)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
@ -123,10 +124,10 @@ func validateWriteOncePropertiesFunction(resourceFn *ResourceFunction, codeGener
|
|||
|
||||
// validateWriteOncePropertiesFunctionBody helps generate the body of the validateWriteOncePropertiesFunctionBody function:
|
||||
//
|
||||
// oldObj, ok := old.(*Receiver)
|
||||
// if !ok {
|
||||
// return nil
|
||||
// }
|
||||
// oldObj, ok := old.(*Receiver)
|
||||
// if !ok {
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// return genruntime.ValidateWriteOnceProperties(oldObj, <receiverIndent>)
|
||||
func validateWriteOncePropertiesFunctionBody(receiver astmodel.TypeName, codeGenerationContext *astmodel.CodeGenerationContext, receiverIdent string) []dst.Stmt {
|
||||
|
@ -175,7 +176,8 @@ func validateOptionalConfigMapReferences(k *ResourceFunction, codeGenerationCont
|
|||
}
|
||||
|
||||
// validateOptionalConfigMapReferencesBody helps generate the body of the validateResourceReferences function:
|
||||
// refs, err := reflecthelpers.FindOptionalConfigMapReferences(&<resource>.Spec)
|
||||
//
|
||||
// refs, err := reflecthelpers.FindOptionalConfigMapReferences(&<resource>.Spec)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
|
|
@ -214,6 +214,7 @@ func (v *ValidatorBuilder) validateDelete(k *ResourceFunction, codeGenerationCon
|
|||
// validateBody returns the body for the generic validation function which invokes all local (code generated) validations
|
||||
// as well as checking if there are any handcrafted validations and invoking them too:
|
||||
// For example:
|
||||
//
|
||||
// validations := <receiverIdent>.createValidations()
|
||||
// var temp interface{} = <receiverIdent>
|
||||
// if runtimeValidator, ok := temp.(genruntime.Validator); ok {
|
||||
|
@ -326,12 +327,15 @@ func (v *ValidatorBuilder) makeLocalValidationFuncDetails(kind ValidationKind, c
|
|||
}
|
||||
|
||||
// localValidationFuncBody returns the body of the local (code generated) validation functions:
|
||||
//
|
||||
// return []func() error{
|
||||
// <receiver>.<validationFunc1>,
|
||||
// <receiver>.<validationFunc2>,
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// or in the case of update functions (that may not need the old parameter):
|
||||
//
|
||||
// return []func(old runtime.Object) error{
|
||||
// func(old runtime.Object) error {
|
||||
// return <receiver>.<validationFunc1>
|
||||
|
@ -361,8 +365,11 @@ func (v *ValidatorBuilder) localValidationFuncBody(kind ValidationKind, codeGene
|
|||
// makeLocalValidationElement creates a validation expression, automatically removing the old parameter for update
|
||||
// validations if it's not needed. These elements are used to build the list of validation functions.
|
||||
// If validation != ValidationKindUpdate or validation == ValidationKindUpdate that DOES use the old parameter:
|
||||
//
|
||||
// <receiver>.<validationFunc>
|
||||
//
|
||||
// If validate == ValidationKindUpdate that doesn't use the old parameter:
|
||||
//
|
||||
// func(old runtime.Object) error {
|
||||
// return <receiver>.<validationFunc>
|
||||
// }
|
||||
|
|
|
@ -63,20 +63,21 @@ func (d *KubernetesExporterBuilder) ToInterfaceImplementation() *astmodel.Interf
|
|||
// exportKubernetesResource returns the body of the ExportKubernetesResources function, which implements
|
||||
// the genruntime.KubernetesExporter interface.
|
||||
// Generates code like:
|
||||
// func (<receiver> *<receiverType>) ExportKubernetesResources(_ context.Context, _ genruntime.MetaObject, _ *genericarmclient.GenericClient, _ logr.Logger) ([]client.Object, error) {
|
||||
// collector := configmaps.NewCollector(<receiver>.Namespace)
|
||||
// if <receiver>.Spec.OperatorSpec != nil && <receiver>.Spec.OperatorSpec.ConfigMaps != nil {
|
||||
// if <receiver>.<propertyPath> != nil {
|
||||
// collector.AddValue(<receiver>.Spec.OperatorSpec.ConfigMaps.<configMapProperty>, *<receiver>.<propertyPath>)
|
||||
//
|
||||
// func (<receiver> *<receiverType>) ExportKubernetesResources(_ context.Context, _ genruntime.MetaObject, _ *genericarmclient.GenericClient, _ logr.Logger) ([]client.Object, error) {
|
||||
// collector := configmaps.NewCollector(<receiver>.Namespace)
|
||||
// if <receiver>.Spec.OperatorSpec != nil && <receiver>.Spec.OperatorSpec.ConfigMaps != nil {
|
||||
// if <receiver>.<propertyPath> != nil {
|
||||
// collector.AddValue(<receiver>.Spec.OperatorSpec.ConfigMaps.<configMapProperty>, *<receiver>.<propertyPath>)
|
||||
// }
|
||||
// }
|
||||
// ...
|
||||
// result, err := collector.Values()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return configmaps.SliceToClientObjectSlice(result), nil
|
||||
// }
|
||||
// ...
|
||||
// result, err := collector.Values()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return configmaps.SliceToClientObjectSlice(result), nil
|
||||
//}
|
||||
func (d *KubernetesExporterBuilder) exportKubernetesResources(k *ResourceFunction, codeGenerationContext *astmodel.CodeGenerationContext, receiver astmodel.TypeName, methodName string) *dst.FuncDecl {
|
||||
receiverIdent := k.IdFactory().CreateReceiver(receiver.Name())
|
||||
receiverType := receiver.AsType(codeGenerationContext)
|
||||
|
|
|
@ -16,14 +16,13 @@ import (
|
|||
// We put these on our resource types, giving us a way to obtain the right type of instance when the reconciler is
|
||||
// working with ARM. The code differs slightly depending on whether we're injecting into an API or storage variant.
|
||||
//
|
||||
// func (resource *SomeResource) OriginalGVK() scheme.GroupVersionKind {
|
||||
// return scheme.GroupVersionKind{
|
||||
// Group: GroupVersion.Group,
|
||||
// Version: resource.Spec.OriginalVersion,
|
||||
// Kind: "SomeResource",
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func (resource *SomeResource) OriginalGVK() scheme.GroupVersionKind {
|
||||
// return scheme.GroupVersionKind{
|
||||
// Group: GroupVersion.Group,
|
||||
// Version: resource.Spec.OriginalVersion,
|
||||
// Kind: "SomeResource",
|
||||
// }
|
||||
// }
|
||||
type OriginalGVKFunction struct {
|
||||
idFactory astmodel.IdentifierFactory
|
||||
hasOriginalVersionFunction bool
|
||||
|
|
|
@ -16,10 +16,9 @@ import (
|
|||
// We put these on the *API* versions of our spec types, giving us a way to obtain the right type of instance when the
|
||||
// reconciler is working with ARM.
|
||||
//
|
||||
// func (spec *SomeSpec) OriginalVersion() string {
|
||||
// return GroupVersion.Version
|
||||
// }
|
||||
//
|
||||
// func (spec *SomeSpec) OriginalVersion() string {
|
||||
// return GroupVersion.Version
|
||||
// }
|
||||
type OriginalVersionFunction struct {
|
||||
idFactory astmodel.IdentifierFactory
|
||||
}
|
||||
|
|
|
@ -24,24 +24,24 @@ import (
|
|||
// If the two instances involved in conversion are not in the same "spoke" leading to this "hub" version, we'll pivot to
|
||||
// the reverse conversion, starting at the far end of that "spoke":
|
||||
//
|
||||
// func (s <hubtype>) ConvertFrom(instance <interfaceType>>) error {
|
||||
// return instance.ConvertTo(s)
|
||||
// }
|
||||
// func (s <hubtype>) ConvertFrom(instance <interfaceType>>) error {
|
||||
// return instance.ConvertTo(s)
|
||||
// }
|
||||
//
|
||||
// The pivot is needed when following the package references from resource version to resource version won't lead us to
|
||||
// encounter the other type that's involved in the conversion, as we can see if we're trying to convert between v1 and
|
||||
// v2:
|
||||
//
|
||||
// ################## ################# +---------------+
|
||||
// # v1 # # v2 # | v3 |
|
||||
// # Person # # Person # | Person |
|
||||
// ################## ################# +---------------+
|
||||
// | | |
|
||||
// v v v
|
||||
// +----------------+ +---------------+ +---------------+
|
||||
// | v1storage | | v2storage | | v3storage |
|
||||
// | Person |----------------->| Person |----------------->| Person |
|
||||
// +----------------+ +---------------+ +---------------+
|
||||
// ################## ################# +---------------+
|
||||
// # v1 # # v2 # | v3 |
|
||||
// # Person # # Person # | Person |
|
||||
// ################## ################# +---------------+
|
||||
// | | |
|
||||
// v v v
|
||||
// +----------------+ +---------------+ +---------------+
|
||||
// | v1storage | | v2storage | | v3storage |
|
||||
// | Person |----------------->| Person |----------------->| Person |
|
||||
// +----------------+ +---------------+ +---------------+
|
||||
//
|
||||
// Following package references from v1 leads us, in turn, to v1storage, v2storage, and finally v3storage (our hub
|
||||
// version), none of is the version we need to terminate the conversion path.
|
||||
|
@ -52,13 +52,13 @@ import (
|
|||
//
|
||||
// v1.Person.ConvertTo(v2.Person)
|
||||
// --> v1storage.Person.ConvertTo(v2.Person)
|
||||
// --> v2storage.Person.ConvertTo(v2.Person)
|
||||
// --> v3storage.Person.ConvertTo(v2.Person) // Pivot!
|
||||
// --> v2.Person.ConvertFrom(v3storage.Person) // Change of direction
|
||||
// --> v2storage.Person.ConvertFrom(v3storage.Person)
|
||||
//
|
||||
// --> v2storage.Person.ConvertTo(v2.Person)
|
||||
// --> v3storage.Person.ConvertTo(v2.Person) // Pivot!
|
||||
// --> v2.Person.ConvertFrom(v3storage.Person) // Change of direction
|
||||
// --> v2storage.Person.ConvertFrom(v3storage.Person)
|
||||
//
|
||||
// Note that conversions like this always pivot through the hub version.
|
||||
//
|
||||
type PivotConversionFunction struct {
|
||||
// nameFrom is the name for this function when converting FROM a provided instance
|
||||
nameFrom string
|
||||
|
@ -162,7 +162,6 @@ func (fn *PivotConversionFunction) AsFunc(
|
|||
//
|
||||
// Note that the method called is in the *other* *direction*; we restart the conversion at the extreme of the second
|
||||
// spoke, invoking conversions back towards the hub again.
|
||||
//
|
||||
func (fn *PivotConversionFunction) bodyForPivot(
|
||||
receiverName string,
|
||||
parameterName string,
|
||||
|
|
|
@ -233,9 +233,11 @@ func (fn *PropertyAssignmentFunction) generateBody(
|
|||
|
||||
// createPropertyBagPrologue creates any introductory statements needed to set up our property bag before we start doing
|
||||
// assignments. We need to handle three cases:
|
||||
// o If our source has a property bag, we clone it.
|
||||
// o If our destination has a property bag (and our source does not), we create a new one.
|
||||
// o If neither source nor destination has a property bag, we don't need to do anything.
|
||||
//
|
||||
// o If our source has a property bag, we clone it.
|
||||
// o If our destination has a property bag (and our source does not), we create a new one.
|
||||
// o If neither source nor destination has a property bag, we don't need to do anything.
|
||||
//
|
||||
// source is the name of the source to read the property bag from
|
||||
func (fn *PropertyAssignmentFunction) createPropertyBagPrologue(
|
||||
source string,
|
||||
|
@ -289,10 +291,11 @@ func (fn *PropertyAssignmentFunction) createPropertyBagPrologue(
|
|||
|
||||
// propertyBagEpilogue creates any concluding statements required to handle our property bag after assignments are
|
||||
// complete.
|
||||
// o If the destination has a property bag
|
||||
// > If our bag is empty, we set the destination to nil
|
||||
// > Otherwise we need to store our current property bag there
|
||||
// o Otherwise we do nothing
|
||||
//
|
||||
// o If the destination has a property bag
|
||||
// > If our bag is empty, we set the destination to nil
|
||||
// > Otherwise we need to store our current property bag there
|
||||
// o Otherwise we do nothing
|
||||
func (fn *PropertyAssignmentFunction) propertyBagEpilogue(
|
||||
destination string,
|
||||
) []dst.Stmt {
|
||||
|
|
|
@ -20,31 +20,30 @@ import (
|
|||
//
|
||||
// Direct conversion from the hub type:
|
||||
//
|
||||
// func (<receiver> <receiverType>) Convert<From|To>(hub conversion.Hub) error {
|
||||
// source, ok := hub.(*<hub.Type>)
|
||||
// if !ok {
|
||||
// return fmt.Errorf("expected <hub.Type> but received %T instead", hub)
|
||||
// }
|
||||
// return <receiver>.AssignProperties<From|To><Type>(source)
|
||||
// }
|
||||
// func (<receiver> <receiverType>) Convert<From|To>(hub conversion.Hub) error {
|
||||
// source, ok := hub.(*<hub.Type>)
|
||||
// if !ok {
|
||||
// return fmt.Errorf("expected <hub.Type> but received %T instead", hub)
|
||||
// }
|
||||
// return <receiver>.AssignProperties<From|To><Type>(source)
|
||||
// }
|
||||
//
|
||||
// Indirect conversion, multiple steps via an intermediate instance
|
||||
//
|
||||
// func (r <receiver>) Convert<From|To>(hub conversion.Hub) error {
|
||||
// var source <vNext>
|
||||
// err := source.Convert<From|To>(hub)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from hub to source")
|
||||
// }
|
||||
// func (r <receiver>) Convert<From|To>(hub conversion.Hub) error {
|
||||
// var source <vNext>
|
||||
// err := source.Convert<From|To>(hub)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from hub to source")
|
||||
// }
|
||||
//
|
||||
// err = <receiver>.AssignProperties<From|To><Type>(&source)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from source to <type>")
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
// }
|
||||
// err = <receiver>.AssignProperties<From|To><Type>(&source)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from source to <type>")
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
// }
|
||||
type ResourceConversionFunction struct {
|
||||
// hub is the TypeName of the canonical hub type, the final target or original source for conversion
|
||||
hub astmodel.TypeName
|
||||
|
@ -141,12 +140,12 @@ func (fn *ResourceConversionFunction) Hub() astmodel.TypeName {
|
|||
// directConversion creates a simple direct conversion between the two types
|
||||
//
|
||||
// <local>, ok := <hubAsInterface>.(<actualHubType>)
|
||||
// if !ok {
|
||||
// return errors.Errorf("expected <actualHubType> but received %T instead", <hubAsInterface>)
|
||||
// }
|
||||
//
|
||||
// if !ok {
|
||||
// return errors.Errorf("expected <actualHubType> but received %T instead", <hubAsInterface>)
|
||||
// }
|
||||
//
|
||||
// return <receiver>.AssignProperties(To|From)<type>(<local>)
|
||||
//
|
||||
func (fn *ResourceConversionFunction) directConversion(
|
||||
receiverName string, generationContext *astmodel.CodeGenerationContext) []dst.Stmt {
|
||||
fmtPackage := generationContext.MustGetImportedPackageName(astmodel.FmtReference)
|
||||
|
@ -182,17 +181,18 @@ func (fn *ResourceConversionFunction) directConversion(
|
|||
//
|
||||
// var source <intermediateType>
|
||||
// err := source.ConvertFrom(<hub>)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from hub to source")
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from hub to source")
|
||||
// }
|
||||
//
|
||||
// err = <receiver>.AssignPropertiesFrom<type>(&source)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from source to <type>")
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from source to <type>")
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
//
|
||||
func (fn *ResourceConversionFunction) indirectConversionFromHub(
|
||||
receiverName string, generationContext *astmodel.CodeGenerationContext) []dst.Stmt {
|
||||
errorsPackage := generationContext.MustGetImportedPackageName(astmodel.GitHubErrorsReference)
|
||||
|
@ -240,17 +240,18 @@ func (fn *ResourceConversionFunction) indirectConversionFromHub(
|
|||
//
|
||||
// var destination <intermediateType>
|
||||
// err = <receiver>.AssignPropertiesTo<type>(&destination)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting to destination from <type>")
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting to destination from <type>")
|
||||
// }
|
||||
//
|
||||
// err := destination.ConvertTo(<hub>)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from destination to hub")
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "converting from destination to hub")
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
//
|
||||
func (fn *ResourceConversionFunction) indirectConversionToHub(
|
||||
receiverName string, generationContext *astmodel.CodeGenerationContext) []dst.Stmt {
|
||||
errorsPackage := generationContext.MustGetImportedPackageName(astmodel.GitHubErrorsReference)
|
||||
|
|
|
@ -270,11 +270,14 @@ func fixedValueGetAzureNameFunction(fixedValue string) functions.ObjectFunctionH
|
|||
|
||||
// newOwnerFunction creates the Owner function declaration. This has two possible formats.
|
||||
// For normal resources:
|
||||
//
|
||||
// func (<receiver> *<receiver>) Owner() *genruntime.ResourceReference {
|
||||
// group, kind := genruntime.LookupOwnerGroupKind(<receiver>.Spec)
|
||||
// return &genruntime.ResourceReference{Group: group, Kind: kind, Namespace: <receiver>.Namespace, Name: <receiver>.Spec.Owner.Name}
|
||||
// }
|
||||
//
|
||||
// For extension resources:
|
||||
//
|
||||
// func (<receiver> *<receiver>) Owner() *genruntime.ResourceReference {
|
||||
// return &genruntime.ResourceReference{Group: <receiver>.Spec.Owner.Group, Kind: <receiver>.Spec.Owner.Kind, name: <receiver>.Spec.Owner.Name}
|
||||
// }
|
||||
|
@ -329,6 +332,7 @@ func newOwnerFunction(r *astmodel.ResourceType) func(k *functions.ObjectFunction
|
|||
}
|
||||
|
||||
// newGetResourceScopeFunction creates a function that returns the scope of the resource.
|
||||
//
|
||||
// func (<receiver> *<receiver>) GetResourceScope() genruntime.ResourceScope {
|
||||
// return genruntime.ResourceScopeResourceGroup
|
||||
// }
|
||||
|
|
|
@ -115,29 +115,30 @@ func (scanner *SchemaScanner) RunHandlerForSchema(ctx context.Context, schema Sc
|
|||
}
|
||||
|
||||
// GenerateDefinitionsFromDeploymentTemplate takes in the resources section of the Azure deployment template schema and returns golang AST Packages
|
||||
// containing the types described in the schema which match the {resource_type}/{version} filters provided.
|
||||
//
|
||||
// The schema we are working with is something like the following (in yaml for brevity):
|
||||
// containing the types described in the schema which match the {resource_type}/{version} filters provided.
|
||||
//
|
||||
// resources:
|
||||
// items:
|
||||
// oneOf:
|
||||
// allOf:
|
||||
// $ref: {{ base resource schema for ARM }}
|
||||
// oneOf:
|
||||
// - ARM resources
|
||||
// oneOf:
|
||||
// allOf:
|
||||
// $ref: {{ base resource for external resources, think SendGrid }}
|
||||
// oneOf:
|
||||
// - External ARM resources
|
||||
// oneOf:
|
||||
// allOf:
|
||||
// $ref: {{ base resource for ARM specific stuff like locks, deployments, etc }}
|
||||
// oneOf:
|
||||
// - ARM specific resources. I'm not 100% sure why...
|
||||
// The schema we are working with is something like the following (in yaml for brevity):
|
||||
//
|
||||
// allOf acts like composition which composites each schema from the child oneOf with the base reference from allOf.
|
||||
// resources:
|
||||
// items:
|
||||
// oneOf:
|
||||
// allOf:
|
||||
// $ref: {{ base resource schema for ARM }}
|
||||
// oneOf:
|
||||
// - ARM resources
|
||||
// oneOf:
|
||||
// allOf:
|
||||
// $ref: {{ base resource for external resources, think SendGrid }}
|
||||
// oneOf:
|
||||
// - External ARM resources
|
||||
// oneOf:
|
||||
// allOf:
|
||||
// $ref: {{ base resource for ARM specific stuff like locks, deployments, etc }}
|
||||
// oneOf:
|
||||
// - ARM specific resources. I'm not 100% sure why...
|
||||
//
|
||||
// allOf acts like composition which composites each schema from the child oneOf with the base reference from allOf.
|
||||
func (scanner *SchemaScanner) GenerateDefinitionsFromDeploymentTemplate(ctx context.Context, root Schema) (astmodel.TypeDefinitionSet, error) {
|
||||
ctx, span := tab.StartSpan(ctx, "GenerateDefinitionsFromDeploymentTemplate")
|
||||
defer span.End()
|
||||
|
|
|
@ -19,23 +19,24 @@ import (
|
|||
// apiVersion: apiextensions.k8s.io/v1
|
||||
// kind: CustomResourceDefinition
|
||||
// metadata:
|
||||
// name: roleassignments.microsoft.authorization.azure.com
|
||||
// annotations:
|
||||
// cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
|
||||
//
|
||||
// name: roleassignments.microsoft.authorization.azure.com
|
||||
// annotations:
|
||||
// cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
|
||||
//
|
||||
// spec:
|
||||
// preserveUnknownFields: false
|
||||
// conversion:
|
||||
// strategy: Webhook
|
||||
// webhook:
|
||||
// conversionReviewVersions:
|
||||
// - v1beta1
|
||||
// clientConfig:
|
||||
// service:
|
||||
// namespace: system
|
||||
// name: webhook-service
|
||||
// path: /convert
|
||||
//
|
||||
//
|
||||
// preserveUnknownFields: false
|
||||
// conversion:
|
||||
// strategy: Webhook
|
||||
// webhook:
|
||||
// conversionReviewVersions:
|
||||
// - v1beta1
|
||||
// clientConfig:
|
||||
// service:
|
||||
// namespace: system
|
||||
// name: webhook-service
|
||||
// path: /convert
|
||||
type ConversionPatchFile struct {
|
||||
ApiVersion string `yaml:"apiVersion"`
|
||||
Kind string `yaml:"kind"`
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
// - patches/webhook-conversion-microsoft.authorization.azure.com_roleassignments.yaml
|
||||
// - patches/webhook-conversion-microsoft.batch.azure.com_batchaccounts.yaml
|
||||
// ...
|
||||
//
|
||||
type CRDKustomizeFile struct {
|
||||
Resources []string `yaml:"resources"` // File paths to resource CRDs
|
||||
Patches []string `yaml:"patches"` // File paths to patch files used to enable conversions
|
||||
|
|
|
@ -147,7 +147,6 @@ func (tc *ResourceConversionTestCase) Equals(other astmodel.TestCase, override a
|
|||
// properties := gopter.NewProperties(parameters)
|
||||
// properties.Property("...", prop.ForAll(RunTestForX, XGenerator())
|
||||
// properties.TestingRun(t, gopter.NewFormatedReporter(true, 240, os.Stdout))
|
||||
//
|
||||
func (tc *ResourceConversionTestCase) createTestRunner(codegenContext *astmodel.CodeGenerationContext) dst.Decl {
|
||||
const (
|
||||
parametersLocal = "parameters"
|
||||
|
@ -237,24 +236,26 @@ func (tc *ResourceConversionTestCase) createTestRunner(codegenContext *astmodel.
|
|||
//
|
||||
// var hub OtherType
|
||||
// err := subject.ConvertTo(&hub)
|
||||
// if err != nil {
|
||||
// return err.Error()
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// return err.Error()
|
||||
// }
|
||||
//
|
||||
// var result OurType
|
||||
// err = result.ConvertFrom(&hub)
|
||||
// if err != nil {
|
||||
// return err.Error()
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// return err.Error()
|
||||
// }
|
||||
//
|
||||
// match := cmp.Equal(subject, actual, cmpopts.EquateEmpty())
|
||||
// if !match {
|
||||
// result := diff.Diff(subject, actual);
|
||||
// return result
|
||||
// }
|
||||
//
|
||||
// if !match {
|
||||
// result := diff.Diff(subject, actual);
|
||||
// return result
|
||||
// }
|
||||
//
|
||||
// return ""
|
||||
//
|
||||
func (tc *ResourceConversionTestCase) createTestMethod(
|
||||
subject astmodel.TypeName,
|
||||
codegenContext *astmodel.CodeGenerationContext) dst.Decl {
|
||||
|
|
Загрузка…
Ссылка в новой задаче