From 5ea103779a76249e059023ec71803e48d6f3b8fb Mon Sep 17 00:00:00 2001 From: willdavsmith Date: Mon, 15 Jun 2026 09:51:59 -0700 Subject: [PATCH 1/7] Rename Recipe Packs recipeKind/recipeLocation to kind/source Implements #11879 for Radius.Core/recipePacks@2025-08-01-preview. Renames RecipeDefinition.recipeKind -> kind and recipeLocation -> source. parameters/outputs stay unprefixed. Updates the TypeSpec source of truth and regenerates OpenAPI/swagger, the Go SDK, and Bicep types. Also updates the datamodel, versioned conversion, internal recipes types, configloader, CLI display, tests, and fixtures. BREAKING CHANGE: recipeKind/recipeLocation are renamed to kind/source for the Radius.Core/recipePacks preview API. Existing preview recipe packs must be re-authored with the new field names. Signed-off-by: willdavsmith --- .../radius.core/2025-08-01-preview/types.json | 8 +-- pkg/cli/cmd/env/show/preview/show.go | 16 ++--- pkg/cli/cmd/env/show/preview/show_test.go | 40 ++++++------- pkg/cli/cmd/recipepack/show/display.go | 12 ++-- pkg/cli/cmd/recipepack/show/show_test.go | 4 +- pkg/cli/objectformats/objectformats.go | 16 ++--- pkg/cli/recipepack/recipepack.go | 28 ++++----- pkg/cli/recipepack/recipepack_test.go | 14 ++--- pkg/cli/test_client_factory/radius_core.go | 20 +++---- .../v20250801preview/recipepack_conversion.go | 16 ++--- .../recipepack_conversion_test.go | 25 ++++++++ .../testdata/recipepackresource.json | 8 +-- .../testdata/recipepackresourcedatamodel.json | 8 +-- .../v20250801preview/zz_generated_models.go | 11 ++-- .../zz_generated_models_serde.go | 14 ++--- .../converter/recipepack_converter_test.go | 60 +++++++++---------- pkg/corerp/datamodel/recipepack.go | 10 ++-- .../createorupdateenvironment_test.go | 20 +++---- .../createorupdaterecipepack_test.go | 40 ++++++------- .../testdata/recipepack_datamodel.json | 12 ++-- pkg/recipes/configloader/environment.go | 12 ++-- pkg/recipes/types.go | 10 ++-- pkg/ucp/initializer/service_test.go | 6 +- .../examples/RecipePacks_CreateOrUpdate.json | 16 ++--- .../examples/RecipePacks_Get.json | 8 +-- .../examples/RecipePacks_ListByScope.json | 8 +-- .../preview/2025-08-01-preview/openapi.json | 12 ++-- .../testdata/corerp-recipe-pack-test.bicep | 12 ++-- .../recipepacks-test-no-provider.bicep | 4 +- .../resources/testdata/recipepacks-test.bicep | 8 +-- .../testdata/terraformconfig-redis-test.bicep | 4 +- .../testdata/tfbicep-combined-test.bicep | 4 +- .../RecipePacks_CreateOrUpdate.json | 16 ++--- .../2025-08-01-preview/RecipePacks_Get.json | 8 +-- .../2025-08-01-preview/RecipePacks_List.json | 8 +-- .../RecipePacks_ListByScope.json | 8 +-- typespec/Radius.Core/recipePacks.tsp | 8 +-- 37 files changed, 282 insertions(+), 252 deletions(-) diff --git a/hack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.json b/hack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.json index b1e2ff48f64..8398c273260 100644 --- a/hack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.json +++ b/hack/bicep-types-radius/generated/radius/radius.core/2025-08-01-preview/types.json @@ -1581,7 +1581,7 @@ "$type": "ObjectType", "name": "RecipeDefinition", "properties": { - "recipeKind": { + "kind": { "type": { "$ref": "#/138" }, @@ -1593,14 +1593,14 @@ "$ref": "#/29" }, "flags": 0, - "description": "Connect to the location using HTTP (not HTTPS). This should be used when the location is known not to support HTTPS, for example in a locally hosted registry for Bicep recipes. Defaults to false (use HTTPS/TLS)" + "description": "Connect to the source using HTTP (not HTTPS). This should be used when the source is known not to support HTTPS, for example in a locally hosted registry for Bicep recipes. Defaults to false (use HTTPS/TLS)" }, - "recipeLocation": { + "source": { "type": { "$ref": "#/0" }, "flags": 1, - "description": "URL path to the recipe" + "description": "The source of the recipe. For Bicep recipes this is the OCI registry reference. For Terraform recipes this is the module source." }, "parameters": { "type": { diff --git a/pkg/cli/cmd/env/show/preview/show.go b/pkg/cli/cmd/env/show/preview/show.go index 160cd26a6a2..516b4c400ef 100644 --- a/pkg/cli/cmd/env/show/preview/show.go +++ b/pkg/cli/cmd/env/show/preview/show.go @@ -68,10 +68,10 @@ rad env show my-env --group my-env } type EnvRecipes struct { - RecipePack string - ResourceType string - RecipeKind string - RecipeLocation string + RecipePack string + ResourceType string + Kind string + Source string } // Runner is the runner implementation for the `rad env show` preview command. @@ -189,10 +189,10 @@ func (r *Runner) Run(ctx context.Context) error { for resourceType, recipe := range pack.RecipePackResource.Properties.Recipes { envRecipes = append(envRecipes, EnvRecipes{ - RecipePack: ID.Name(), - ResourceType: resourceType, - RecipeKind: string(*recipe.RecipeKind), - RecipeLocation: *recipe.RecipeLocation, + RecipePack: ID.Name(), + ResourceType: resourceType, + Kind: string(*recipe.Kind), + Source: *recipe.Source, }) } } diff --git a/pkg/cli/cmd/env/show/preview/show_test.go b/pkg/cli/cmd/env/show/preview/show_test.go index 66df4adb059..0192dfd1585 100644 --- a/pkg/cli/cmd/env/show/preview/show_test.go +++ b/pkg/cli/cmd/env/show/preview/show_test.go @@ -165,16 +165,16 @@ func Test_Run(t *testing.T) { Format: "table", Obj: []EnvRecipes{ { - RecipePack: "test-recipe-pack", - ResourceType: "test-recipe1", - RecipeKind: string(corerpv20250801.RecipeKindTerraform), - RecipeLocation: "https://example.com/recipe1?ref=v0.1", + RecipePack: "test-recipe-pack", + ResourceType: "test-recipe1", + Kind: string(corerpv20250801.RecipeKindTerraform), + Source: "https://example.com/recipe1?ref=v0.1", }, { - RecipePack: "test-recipe-pack", - ResourceType: "test-recipe2", - RecipeKind: string(corerpv20250801.RecipeKindTerraform), - RecipeLocation: "https://example.com/recipe2?ref=v0.1", + RecipePack: "test-recipe-pack", + ResourceType: "test-recipe2", + Kind: string(corerpv20250801.RecipeKindTerraform), + Source: "https://example.com/recipe2?ref=v0.1", }, }, Options: objectformats.GetRecipesForEnvironmentTableFormat(), @@ -243,23 +243,23 @@ func Test_Run_RecipeSortOrder(t *testing.T) { if recipePackName == "pack-a" { recipes = map[string]*corerpv20250801.RecipeDefinition{ "Applications.Datastores/sqlDatabases": { - RecipeLocation: new("ghcr.io/radius-project/recipes/sql"), - RecipeKind: to.Ptr(corerpv20250801.RecipeKindTerraform), + Source: new("ghcr.io/radius-project/recipes/sql"), + Kind: to.Ptr(corerpv20250801.RecipeKindTerraform), }, "Applications.Datastores/redisCaches": { - RecipeLocation: new("ghcr.io/radius-project/recipes/redis"), - RecipeKind: to.Ptr(corerpv20250801.RecipeKindTerraform), + Source: new("ghcr.io/radius-project/recipes/redis"), + Kind: to.Ptr(corerpv20250801.RecipeKindTerraform), }, } } else { recipes = map[string]*corerpv20250801.RecipeDefinition{ "Applications.Messaging/rabbitMQQueues": { - RecipeLocation: new("ghcr.io/radius-project/recipes/rabbitmq"), - RecipeKind: to.Ptr(corerpv20250801.RecipeKindBicep), + Source: new("ghcr.io/radius-project/recipes/rabbitmq"), + Kind: to.Ptr(corerpv20250801.RecipeKindBicep), }, "Applications.Dapr/stateStores": { - RecipeLocation: new("ghcr.io/radius-project/recipes/dapr-state"), - RecipeKind: to.Ptr(corerpv20250801.RecipeKindBicep), + Source: new("ghcr.io/radius-project/recipes/dapr-state"), + Kind: to.Ptr(corerpv20250801.RecipeKindBicep), }, } } @@ -294,10 +294,10 @@ func Test_Run_RecipeSortOrder(t *testing.T) { // Verify the recipes are sorted by RecipePack first, then by ResourceType expectedRecipes := []EnvRecipes{ - {RecipePack: "pack-a", ResourceType: "Applications.Datastores/redisCaches", RecipeKind: "terraform", RecipeLocation: "ghcr.io/radius-project/recipes/redis"}, - {RecipePack: "pack-a", ResourceType: "Applications.Datastores/sqlDatabases", RecipeKind: "terraform", RecipeLocation: "ghcr.io/radius-project/recipes/sql"}, - {RecipePack: "pack-b", ResourceType: "Applications.Dapr/stateStores", RecipeKind: "bicep", RecipeLocation: "ghcr.io/radius-project/recipes/dapr-state"}, - {RecipePack: "pack-b", ResourceType: "Applications.Messaging/rabbitMQQueues", RecipeKind: "bicep", RecipeLocation: "ghcr.io/radius-project/recipes/rabbitmq"}, + {RecipePack: "pack-a", ResourceType: "Applications.Datastores/redisCaches", Kind: "terraform", Source: "ghcr.io/radius-project/recipes/redis"}, + {RecipePack: "pack-a", ResourceType: "Applications.Datastores/sqlDatabases", Kind: "terraform", Source: "ghcr.io/radius-project/recipes/sql"}, + {RecipePack: "pack-b", ResourceType: "Applications.Dapr/stateStores", Kind: "bicep", Source: "ghcr.io/radius-project/recipes/dapr-state"}, + {RecipePack: "pack-b", ResourceType: "Applications.Messaging/rabbitMQQueues", Kind: "bicep", Source: "ghcr.io/radius-project/recipes/rabbitmq"}, } // The third output should be the recipes table diff --git a/pkg/cli/cmd/recipepack/show/display.go b/pkg/cli/cmd/recipepack/show/display.go index 5f6d949d64f..5ec80350dfe 100644 --- a/pkg/cli/cmd/recipepack/show/display.go +++ b/pkg/cli/cmd/recipepack/show/display.go @@ -47,18 +47,18 @@ func (r *Runner) display(recipePack v20250801preview.RecipePackResource) error { } kind := "unknown" - if definition.RecipeKind != nil { - kind = string(*definition.RecipeKind) + if definition.Kind != nil { + kind = string(*definition.Kind) } - location := "" - if definition.RecipeLocation != nil { - location = *definition.RecipeLocation + source := "" + if definition.Source != nil { + source = *definition.Source } r.Output.LogInfo("%s", resourceType) r.Output.LogInfo(" Kind: %s", kind) - r.Output.LogInfo(" Location: %s", location) + r.Output.LogInfo(" Source: %s", source) if len(definition.Parameters) > 0 { formatted, err := formatRecipeParameters(definition.Parameters) diff --git a/pkg/cli/cmd/recipepack/show/show_test.go b/pkg/cli/cmd/recipepack/show/show_test.go index 224b4ebfc45..2f3bbc87e1d 100644 --- a/pkg/cli/cmd/recipepack/show/show_test.go +++ b/pkg/cli/cmd/recipepack/show/show_test.go @@ -88,8 +88,8 @@ func Test_Run(t *testing.T) { Properties: &corerpv20250801preview.RecipePackProperties{ Recipes: map[string]*corerpv20250801preview.RecipeDefinition{ "Radius.Core/example": { - RecipeKind: to.Ptr(corerpv20250801preview.RecipeKindTerraform), - RecipeLocation: new("https://github.com/radius-project/example"), + Kind: to.Ptr(corerpv20250801preview.RecipeKindTerraform), + Source: new("https://github.com/radius-project/example"), Parameters: map[string]any{ "foo": "bar", }, diff --git a/pkg/cli/objectformats/objectformats.go b/pkg/cli/objectformats/objectformats.go index 16ae8233a13..71f6fe6b18a 100644 --- a/pkg/cli/objectformats/objectformats.go +++ b/pkg/cli/objectformats/objectformats.go @@ -71,11 +71,11 @@ func GetRecipeFormat() output.FormatterOptions { }, { Heading: "RECIPE KIND", - JSONPath: "{ .RecipeKind }", + JSONPath: "{ .Kind }", }, { - Heading: "RECIPE LOCATION", - JSONPath: "{ .RecipeLocation }", + Heading: "RECIPE SOURCE", + JSONPath: "{ .Source }", }, }, } @@ -90,11 +90,11 @@ func GetRecipeFormatWithoutHeadings() output.FormatterOptions { }, { Heading: "", - JSONPath: "{ .RecipeKind }", + JSONPath: "{ .Kind }", }, { Heading: "", - JSONPath: "{ .RecipeLocation }", + JSONPath: "{ .Source }", }, }, } @@ -141,11 +141,11 @@ func GetRecipesForEnvironmentTableFormat() output.FormatterOptions { }, { Heading: "RECIPE KIND", - JSONPath: "{ .RecipeKind }", + JSONPath: "{ .Kind }", }, { - Heading: "RECIPE LOCATION", - JSONPath: "{ .RecipeLocation }", + Heading: "RECIPE SOURCE", + JSONPath: "{ .Source }", }, }, } diff --git a/pkg/cli/recipepack/recipepack.go b/pkg/cli/recipepack/recipepack.go index 555605b2421..7bf020c0b53 100644 --- a/pkg/cli/recipepack/recipepack.go +++ b/pkg/cli/recipepack/recipepack.go @@ -54,8 +54,8 @@ func NewDefaultRecipePackResource() corerpv20250801.RecipePackResource { recipes := make(map[string]*corerpv20250801.RecipeDefinition) for _, def := range GetCoreTypesRecipeInfo() { recipes[def.ResourceType] = &corerpv20250801.RecipeDefinition{ - RecipeKind: &bicepKind, - RecipeLocation: to.Ptr(def.RecipeLocation), + Kind: &bicepKind, + Source: to.Ptr(def.Source), } } return corerpv20250801.RecipePackResource{ @@ -110,8 +110,8 @@ func GetOrCreateDefaultRecipePack(ctx context.Context, client *corerpv20250801.R type CoreTypesRecipeInfo struct { // ResourceType is the full resource type (e.g., "Radius.Compute/containers"). ResourceType string - // RecipeLocation is the OCI registry location for the recipe. - RecipeLocation string + // Source is the OCI registry location for the recipe. + Source string } // GetCoreTypesRecipeInfo returns recipe information for all core types. @@ -125,24 +125,24 @@ func GetCoreTypesRecipeInfo() []CoreTypesRecipeInfo { } return []CoreTypesRecipeInfo{ { - ResourceType: "Radius.Compute/containers", - RecipeLocation: "ghcr.io/radius-project/kube-recipes/containers:" + tag, + ResourceType: "Radius.Compute/containers", + Source: "ghcr.io/radius-project/kube-recipes/containers:" + tag, }, { - ResourceType: "Radius.Compute/persistentVolumes", - RecipeLocation: "ghcr.io/radius-project/kube-recipes/persistentvolumes:" + tag, + ResourceType: "Radius.Compute/persistentVolumes", + Source: "ghcr.io/radius-project/kube-recipes/persistentvolumes:" + tag, }, { - ResourceType: "Radius.Compute/routes", - RecipeLocation: "ghcr.io/radius-project/kube-recipes/routes:" + tag, + ResourceType: "Radius.Compute/routes", + Source: "ghcr.io/radius-project/kube-recipes/routes:" + tag, }, { - ResourceType: "Radius.Security/secrets", - RecipeLocation: "ghcr.io/radius-project/kube-recipes/secrets:" + tag, + ResourceType: "Radius.Security/secrets", + Source: "ghcr.io/radius-project/kube-recipes/secrets:" + tag, }, { - ResourceType: "Radius.Data/mySqlDatabases", - RecipeLocation: "ghcr.io/radius-project/kube-recipes/mysqldatabases:" + tag, + ResourceType: "Radius.Data/mySqlDatabases", + Source: "ghcr.io/radius-project/kube-recipes/mysqldatabases:" + tag, }, } } diff --git a/pkg/cli/recipepack/recipepack_test.go b/pkg/cli/recipepack/recipepack_test.go index 403d5ccf328..e824c6056d9 100644 --- a/pkg/cli/recipepack/recipepack_test.go +++ b/pkg/cli/recipepack/recipepack_test.go @@ -42,7 +42,7 @@ func Test_GetDefaultRecipePackDefinition(t *testing.T) { actualResourceTypes := make([]string, len(definitions)) for i, def := range definitions { actualResourceTypes[i] = def.ResourceType - require.NotEmpty(t, def.RecipeLocation, "RecipeLocation should not be empty for %s", def.ResourceType) + require.NotEmpty(t, def.Source, "Source should not be empty for %s", def.ResourceType) } require.ElementsMatch(t, expectedResourceTypes, actualResourceTypes) } @@ -53,8 +53,8 @@ func Test_GetDefaultRecipePackDefinition_UsesLatestTagForEdgeChannel(t *testing. definitions := GetCoreTypesRecipeInfo() for _, def := range definitions { - require.True(t, strings.HasSuffix(def.RecipeLocation, ":latest"), - "Expected :latest tag for edge channel, got %s", def.RecipeLocation) + require.True(t, strings.HasSuffix(def.Source, ":latest"), + "Expected :latest tag for edge channel, got %s", def.Source) } } @@ -76,9 +76,9 @@ func Test_NewDefaultRecipePackResource(t *testing.T) { for _, def := range definitions { recipe, exists := resource.Properties.Recipes[def.ResourceType] require.True(t, exists, "Expected recipe for resource type %s to exist", def.ResourceType) - require.NotNil(t, recipe.RecipeKind) - require.Equal(t, corerpv20250801.RecipeKindBicep, *recipe.RecipeKind) - require.NotNil(t, recipe.RecipeLocation) - require.Equal(t, def.RecipeLocation, *recipe.RecipeLocation) + require.NotNil(t, recipe.Kind) + require.Equal(t, corerpv20250801.RecipeKindBicep, *recipe.Kind) + require.NotNil(t, recipe.Source) + require.Equal(t, def.Source, *recipe.Source) } } diff --git a/pkg/cli/test_client_factory/radius_core.go b/pkg/cli/test_client_factory/radius_core.go index 1e1fcbf13ff..039cb9b719b 100644 --- a/pkg/cli/test_client_factory/radius_core.go +++ b/pkg/cli/test_client_factory/radius_core.go @@ -76,12 +76,12 @@ func WithRecipePackServerNoError() corerpfake.RecipePacksServer { Properties: &v20250801preview.RecipePackProperties{ Recipes: map[string]*v20250801preview.RecipeDefinition{ "test-recipe1": { - RecipeLocation: new("https://example.com/recipe1?ref=v0.1"), - RecipeKind: to.Ptr(v20250801preview.RecipeKindTerraform), + Source: new("https://example.com/recipe1?ref=v0.1"), + Kind: to.Ptr(v20250801preview.RecipeKindTerraform), }, "test-recipe2": { - RecipeLocation: new("https://example.com/recipe2?ref=v0.1"), - RecipeKind: to.Ptr(v20250801preview.RecipeKindTerraform), + Source: new("https://example.com/recipe2?ref=v0.1"), + Kind: to.Ptr(v20250801preview.RecipeKindTerraform), }, }, }, @@ -398,8 +398,8 @@ func WithRecipePackServerCoreTypes() corerpfake.RecipePacksServer { Properties: &v20250801preview.RecipePackProperties{ Recipes: map[string]*v20250801preview.RecipeDefinition{ resourceType: { - RecipeLocation: to.Ptr("ghcr.io/test/" + recipePackName + ":latest"), - RecipeKind: &bicepKind, + Source: to.Ptr("ghcr.io/test/" + recipePackName + ":latest"), + Kind: &bicepKind, }, }, }, @@ -433,8 +433,8 @@ func WithRecipePackServerUniqueTypes() corerpfake.RecipePacksServer { Properties: &v20250801preview.RecipePackProperties{ Recipes: map[string]*v20250801preview.RecipeDefinition{ "Test.Resource/" + recipePackName: { - RecipeLocation: to.Ptr("ghcr.io/test/" + recipePackName + ":latest"), - RecipeKind: &bicepKind, + Source: to.Ptr("ghcr.io/test/" + recipePackName + ":latest"), + Kind: &bicepKind, }, }, }, @@ -491,8 +491,8 @@ func WithRecipePackServerConflictingTypes() corerpfake.RecipePacksServer { Properties: &v20250801preview.RecipePackProperties{ Recipes: map[string]*v20250801preview.RecipeDefinition{ "Radius.Compute/containers": { - RecipeLocation: to.Ptr("ghcr.io/test/" + recipePackName + ":latest"), - RecipeKind: &bicepKind, + Source: to.Ptr("ghcr.io/test/" + recipePackName + ":latest"), + Kind: &bicepKind, }, }, }, diff --git a/pkg/corerp/api/v20250801preview/recipepack_conversion.go b/pkg/corerp/api/v20250801preview/recipepack_conversion.go index a740e48111c..de4b295a844 100644 --- a/pkg/corerp/api/v20250801preview/recipepack_conversion.go +++ b/pkg/corerp/api/v20250801preview/recipepack_conversion.go @@ -95,10 +95,10 @@ func toRecipesDataModel(recipes map[string]*RecipeDefinition) map[string]*datamo for key, recipe := range recipes { if recipe != nil { result[key] = &datamodel.RecipeDefinition{ - RecipeKind: toRecipeKindDataModel(recipe.RecipeKind), - RecipeLocation: to.String(recipe.RecipeLocation), - Parameters: recipe.Parameters, - PlainHTTP: to.Bool(recipe.PlainHTTP), + Kind: toRecipeKindDataModel(recipe.Kind), + Source: to.String(recipe.Source), + Parameters: recipe.Parameters, + PlainHTTP: to.Bool(recipe.PlainHTTP), } } } @@ -114,10 +114,10 @@ func fromRecipesDataModel(recipes map[string]*datamodel.RecipeDefinition) map[st for key, recipe := range recipes { if recipe != nil { result[key] = &RecipeDefinition{ - RecipeKind: fromRecipeKindDataModel(recipe.RecipeKind), - RecipeLocation: new(recipe.RecipeLocation), - Parameters: recipe.Parameters, - PlainHTTP: new(recipe.PlainHTTP), + Kind: fromRecipeKindDataModel(recipe.Kind), + Source: new(recipe.Source), + Parameters: recipe.Parameters, + PlainHTTP: new(recipe.PlainHTTP), } } } diff --git a/pkg/corerp/api/v20250801preview/recipepack_conversion_test.go b/pkg/corerp/api/v20250801preview/recipepack_conversion_test.go index a619be20377..b256db1939c 100644 --- a/pkg/corerp/api/v20250801preview/recipepack_conversion_test.go +++ b/pkg/corerp/api/v20250801preview/recipepack_conversion_test.go @@ -53,6 +53,19 @@ func TestRecipePackConvertVersionedToDataModel(t *testing.T) { // Validate API version metadata require.Equal(t, Version, recipePack.InternalMetadata.CreatedAPIVersion) require.Equal(t, Version, recipePack.InternalMetadata.UpdatedAPIVersion) + + // Validate recipe definitions, including the renamed kind/source fields. + require.Len(t, recipePack.Properties.Recipes, 2) + + container := recipePack.Properties.Recipes["Applications.Core/containers"] + require.NotNil(t, container) + require.Equal(t, "Bicep", container.Kind) + require.Equal(t, "br:ghcr.io/radius-project/recipes/kubernetes-container:latest", container.Source) + + stateStore := recipePack.Properties.Recipes["Applications.Dapr/stateStores"] + require.NotNil(t, stateStore) + require.Equal(t, "Terraform", stateStore.Kind) + require.Equal(t, "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", stateStore.Source) } func TestRecipePackConvertDataModelToVersioned(t *testing.T) { @@ -75,6 +88,18 @@ func TestRecipePackConvertDataModelToVersioned(t *testing.T) { require.Equal(t, dataModel.Type, *versionedResource.Type) require.Equal(t, dataModel.Location, *versionedResource.Location) require.NotNil(t, versionedResource.Properties) + + // Validate recipe definitions round-trip, including the renamed kind/source fields. + require.Len(t, versionedResource.Properties.Recipes, 2) + + stateStore := versionedResource.Properties.Recipes["Applications.Dapr/stateStores"] + require.NotNil(t, stateStore) + require.NotNil(t, stateStore.Kind) + require.Equal(t, RecipeKind("Terraform"), *stateStore.Kind) + require.Equal(t, "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", *stateStore.Source) + + container := versionedResource.Properties.Recipes["Applications.Core/containers"] + require.NotNil(t, container) } func TestRecipePackConvertInvalidModel(t *testing.T) { diff --git a/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json b/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json index ec91d1f7b9b..62215982c6d 100644 --- a/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json +++ b/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json @@ -15,8 +15,8 @@ ], "recipes": { "Applications.Core/containers": { - "recipeKind": "Bicep", - "recipeLocation": "br:ghcr.io/radius-project/recipes/kubernetes-container:latest", + "kind": "Bicep", + "source": "br:ghcr.io/radius-project/recipes/kubernetes-container:latest", "parameters": { "port": 8080, "replicas": 3 @@ -24,8 +24,8 @@ "plainHTTP": false }, "Applications.Dapr/stateStores": { - "recipeKind": "Terraform", - "recipeLocation": "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", + "kind": "Terraform", + "source": "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", "parameters": { "size": "small" }, diff --git a/pkg/corerp/api/v20250801preview/testdata/recipepackresourcedatamodel.json b/pkg/corerp/api/v20250801preview/testdata/recipepackresourcedatamodel.json index 30526b1ad2d..98af33f1b5d 100644 --- a/pkg/corerp/api/v20250801preview/testdata/recipepackresourcedatamodel.json +++ b/pkg/corerp/api/v20250801preview/testdata/recipepackresourcedatamodel.json @@ -27,8 +27,8 @@ ], "recipes": { "Applications.Core/containers": { - "recipeKind": "Bicep", - "recipeLocation": "br:ghcr.io/radius-project/recipes/kubernetes-container:latest", + "kind": "Bicep", + "source": "br:ghcr.io/radius-project/recipes/kubernetes-container:latest", "parameters": { "port": 8080, "replicas": 3 @@ -36,8 +36,8 @@ "plainHTTP": false }, "Applications.Dapr/stateStores": { - "recipeKind": "Terraform", - "recipeLocation": "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", + "kind": "Terraform", + "source": "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", "parameters": { "size": "small" }, diff --git a/pkg/corerp/api/v20250801preview/zz_generated_models.go b/pkg/corerp/api/v20250801preview/zz_generated_models.go index 4831bc8139f..24f23a204f5 100644 --- a/pkg/corerp/api/v20250801preview/zz_generated_models.go +++ b/pkg/corerp/api/v20250801preview/zz_generated_models.go @@ -516,16 +516,17 @@ type ProvidersKubernetes struct { // RecipeDefinition - Recipe definition for a specific resource type type RecipeDefinition struct { // REQUIRED; The type of recipe (e.g., Terraform, Bicep) - RecipeKind *RecipeKind + Kind *RecipeKind - // REQUIRED; URL path to the recipe - RecipeLocation *string + // REQUIRED; The source of the recipe. For Bicep recipes this is the OCI registry reference. For Terraform recipes this is + // the module source. + Source *string // Parameters to pass to the recipe Parameters map[string]any - // Connect to the location using HTTP (not HTTPS). This should be used when the location is known not to support HTTPS, for - // example in a locally hosted registry for Bicep recipes. Defaults to false (use + // Connect to the source using HTTP (not HTTPS). This should be used when the source is known not to support HTTPS, for example + // in a locally hosted registry for Bicep recipes. Defaults to false (use // HTTPS/TLS) PlainHTTP *bool } diff --git a/pkg/corerp/api/v20250801preview/zz_generated_models_serde.go b/pkg/corerp/api/v20250801preview/zz_generated_models_serde.go index fdebaf0d64b..56e0c02081c 100644 --- a/pkg/corerp/api/v20250801preview/zz_generated_models_serde.go +++ b/pkg/corerp/api/v20250801preview/zz_generated_models_serde.go @@ -1269,10 +1269,10 @@ func (p *ProvidersKubernetes) UnmarshalJSON(data []byte) error { // MarshalJSON implements the json.Marshaller interface for type RecipeDefinition. func (r RecipeDefinition) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) + populate(objectMap, "kind", r.Kind) populate(objectMap, "parameters", r.Parameters) populate(objectMap, "plainHttp", r.PlainHTTP) - populate(objectMap, "recipeKind", r.RecipeKind) - populate(objectMap, "recipeLocation", r.RecipeLocation) + populate(objectMap, "source", r.Source) return json.Marshal(objectMap) } @@ -1285,17 +1285,17 @@ func (r *RecipeDefinition) UnmarshalJSON(data []byte) error { for key, val := range rawMsg { var err error switch key { + case "kind": + err = unpopulate(val, "Kind", &r.Kind) + delete(rawMsg, key) case "parameters": err = unpopulate(val, "Parameters", &r.Parameters) delete(rawMsg, key) case "plainHttp": err = unpopulate(val, "PlainHTTP", &r.PlainHTTP) delete(rawMsg, key) - case "recipeKind": - err = unpopulate(val, "RecipeKind", &r.RecipeKind) - delete(rawMsg, key) - case "recipeLocation": - err = unpopulate(val, "RecipeLocation", &r.RecipeLocation) + case "source": + err = unpopulate(val, "Source", &r.Source) delete(rawMsg, key) } if err != nil { diff --git a/pkg/corerp/datamodel/converter/recipepack_converter_test.go b/pkg/corerp/datamodel/converter/recipepack_converter_test.go index 3bf535cde41..1db51bdd35c 100644 --- a/pkg/corerp/datamodel/converter/recipepack_converter_test.go +++ b/pkg/corerp/datamodel/converter/recipepack_converter_test.go @@ -58,17 +58,17 @@ func TestRecipePackDataModelToVersioned(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Core/containers": { - RecipeKind: "bicep", - RecipeLocation: "br:myregistry.azurecr.io/recipes/container:1.0", + Kind: "bicep", + Source: "br:myregistry.azurecr.io/recipes/container:1.0", Parameters: map[string]any{ "param1": "value1", }, PlainHTTP: false, }, "Applications.Datastores/sqlDatabases": { - RecipeKind: "terraform", - RecipeLocation: "https://github.com/radius-project/recipes.git//terraform/modules/sql", - PlainHTTP: false, + Kind: "terraform", + Source: "https://github.com/radius-project/recipes.git//terraform/modules/sql", + PlainHTTP: false, }, }, ReferencedBy: []string{ @@ -162,16 +162,16 @@ func TestRecipePackDataModelFromVersioned(t *testing.T) { "properties": { "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "br:myregistry.azurecr.io/recipes/container:1.0", + "kind": "bicep", + "source": "br:myregistry.azurecr.io/recipes/container:1.0", "parameters": { "param1": "value1" }, "plainHTTP": false }, "Applications.Datastores/sqlDatabases": { - "recipeKind": "terraform", - "recipeLocation": "https://github.com/radius-project/recipes.git//terraform/modules/sql" + "kind": "terraform", + "source": "https://github.com/radius-project/recipes.git//terraform/modules/sql" } }, "referencedBy": [ @@ -203,17 +203,17 @@ func TestRecipePackDataModelFromVersioned(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Core/containers": { - RecipeKind: "bicep", - RecipeLocation: "br:myregistry.azurecr.io/recipes/container:1.0", + Kind: "bicep", + Source: "br:myregistry.azurecr.io/recipes/container:1.0", Parameters: map[string]any{ "param1": "value1", }, PlainHTTP: false, }, "Applications.Datastores/sqlDatabases": { - RecipeKind: "terraform", - RecipeLocation: "https://github.com/radius-project/recipes.git//terraform/modules/sql", - PlainHTTP: false, + Kind: "terraform", + Source: "https://github.com/radius-project/recipes.git//terraform/modules/sql", + PlainHTTP: false, }, }, ReferencedBy: []string{ @@ -260,8 +260,8 @@ func TestRecipePackDataModelFromVersioned(t *testing.T) { "properties": { "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "br:myregistry.azurecr.io/recipes/container:1.0" + "kind": "bicep", + "source": "br:myregistry.azurecr.io/recipes/container:1.0" } } } @@ -284,9 +284,9 @@ func TestRecipePackDataModelFromVersioned(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Core/containers": { - RecipeKind: "bicep", - RecipeLocation: "br:myregistry.azurecr.io/recipes/container:1.0", - PlainHTTP: false, // Should default to false when not specified + Kind: "bicep", + Source: "br:myregistry.azurecr.io/recipes/container:1.0", + PlainHTTP: false, // Should default to false when not specified }, }, }, @@ -302,8 +302,8 @@ func TestRecipePackDataModelFromVersioned(t *testing.T) { "properties": { "recipes": { "Applications.Datastores/sqlDatabases": { - "recipeKind": "terraform", - "recipeLocation": "http://insecure-registry.example.com/recipes/sql", + "kind": "terraform", + "source": "http://insecure-registry.example.com/recipes/sql", "plainHttp": true } } @@ -327,9 +327,9 @@ func TestRecipePackDataModelFromVersioned(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Datastores/sqlDatabases": { - RecipeKind: "terraform", - RecipeLocation: "http://insecure-registry.example.com/recipes/sql", - PlainHTTP: true, // Explicitly set to true + Kind: "terraform", + Source: "http://insecure-registry.example.com/recipes/sql", + PlainHTTP: true, // Explicitly set to true }, }, }, @@ -386,8 +386,8 @@ func TestRecipePackDataModelFromVersioned(t *testing.T) { for key, expectedRecipe := range tc.expected.Properties.Recipes { actualRecipe, exists := result.Properties.Recipes[key] require.True(t, exists, "Recipe %s should exist", key) - require.Equal(t, expectedRecipe.RecipeKind, actualRecipe.RecipeKind) - require.Equal(t, expectedRecipe.RecipeLocation, actualRecipe.RecipeLocation) + require.Equal(t, expectedRecipe.Kind, actualRecipe.Kind) + require.Equal(t, expectedRecipe.Source, actualRecipe.Source) // Debug output for plainHTTP t.Logf("Recipe %s - Expected PlainHTTP: %v, Actual PlainHTTP: %v", key, expectedRecipe.PlainHTTP, actualRecipe.PlainHTTP) @@ -426,8 +426,8 @@ func TestRecipePackRoundTripConversion(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Core/containers": { - RecipeKind: "bicep", - RecipeLocation: "br:test.azurecr.io/recipes/container:latest", + Kind: "bicep", + Source: "br:test.azurecr.io/recipes/container:latest", Parameters: map[string]any{ "cpu": "0.5", "memory": "1Gi", @@ -468,8 +468,8 @@ func TestRecipePackRoundTripConversion(t *testing.T) { for key, originalRecipe := range originalDataModel.Properties.Recipes { resultRecipe, exists := resultDataModel.Properties.Recipes[key] require.True(t, exists, "Recipe %s should exist after round-trip", key) - require.Equal(t, originalRecipe.RecipeKind, resultRecipe.RecipeKind) - require.Equal(t, originalRecipe.RecipeLocation, resultRecipe.RecipeLocation) + require.Equal(t, originalRecipe.Kind, resultRecipe.Kind) + require.Equal(t, originalRecipe.Source, resultRecipe.Source) require.Equal(t, originalRecipe.PlainHTTP, resultRecipe.PlainHTTP) require.Equal(t, originalRecipe.Parameters, resultRecipe.Parameters) } diff --git a/pkg/corerp/datamodel/recipepack.go b/pkg/corerp/datamodel/recipepack.go index 7ab6c4c89ad..6181565c561 100644 --- a/pkg/corerp/datamodel/recipepack.go +++ b/pkg/corerp/datamodel/recipepack.go @@ -49,15 +49,15 @@ type RecipePackProperties struct { // RecipeDefinition represents a recipe definition in the datamodel. type RecipeDefinition struct { - // RecipeKind is the type of recipe (e.g., terraform, bicep). - RecipeKind string `json:"recipeKind"` + // Kind is the type of recipe (e.g., terraform, bicep). + Kind string `json:"kind"` - // RecipeLocation is the URL or path to the recipe source. - RecipeLocation string `json:"recipeLocation"` + // Source is the URL or path to the recipe source. + Source string `json:"source"` // Parameters to pass to the recipe. Parameters map[string]any `json:"parameters,omitempty"` - // PlainHTTP connects to the location using HTTP (not-HTTPS). + // PlainHTTP connects to the source using HTTP (not-HTTPS). PlainHTTP bool `json:"plainHTTP,omitempty"` } diff --git a/pkg/corerp/frontend/controller/environments/v20250801preview/createorupdateenvironment_test.go b/pkg/corerp/frontend/controller/environments/v20250801preview/createorupdateenvironment_test.go index 47dd13f5431..21c5a77bf72 100644 --- a/pkg/corerp/frontend/controller/environments/v20250801preview/createorupdateenvironment_test.go +++ b/pkg/corerp/frontend/controller/environments/v20250801preview/createorupdateenvironment_test.go @@ -378,8 +378,8 @@ func TestCreateOrUpdateEnvironment_RecipePackValidation(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Core/containers": { - RecipeKind: "bicep", - RecipeLocation: "br:myregistry.azurecr.io/recipes/container:1.0", + Kind: "bicep", + Source: "br:myregistry.azurecr.io/recipes/container:1.0", }, }, }, @@ -388,8 +388,8 @@ func TestCreateOrUpdateEnvironment_RecipePackValidation(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Dapr/stateStores": { - RecipeKind: "terraform", - RecipeLocation: "git::https://github.com/recipes/dapr-state", + Kind: "terraform", + Source: "git::https://github.com/recipes/dapr-state", }, }, }, @@ -413,8 +413,8 @@ func TestCreateOrUpdateEnvironment_RecipePackValidation(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Core/containers": { - RecipeKind: "bicep", - RecipeLocation: "br:myregistry.azurecr.io/recipes/container:1.0", + Kind: "bicep", + Source: "br:myregistry.azurecr.io/recipes/container:1.0", }, }, }, @@ -423,8 +423,8 @@ func TestCreateOrUpdateEnvironment_RecipePackValidation(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Core/containers": { - RecipeKind: "terraform", - RecipeLocation: "git::https://github.com/recipes/container", + Kind: "terraform", + Source: "git::https://github.com/recipes/container", }, }, }, @@ -456,8 +456,8 @@ func TestCreateOrUpdateEnvironment_RecipePackValidation(t *testing.T) { Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Core/containers": { - RecipeKind: "bicep", - RecipeLocation: "br:myregistry.azurecr.io/recipes/container:1.0", + Kind: "bicep", + Source: "br:myregistry.azurecr.io/recipes/container:1.0", }, }, }, diff --git a/pkg/corerp/frontend/controller/recipepacks/createorupdaterecipepack_test.go b/pkg/corerp/frontend/controller/recipepacks/createorupdaterecipepack_test.go index f34b1073e4c..0a96f5fe2b7 100644 --- a/pkg/corerp/frontend/controller/recipepacks/createorupdaterecipepack_test.go +++ b/pkg/corerp/frontend/controller/recipepacks/createorupdaterecipepack_test.go @@ -158,16 +158,16 @@ func getTestModels() (*v20250801preview.RecipePackResource, *datamodel.RecipePac Properties: &v20250801preview.RecipePackProperties{ Recipes: map[string]*v20250801preview.RecipeDefinition{ "Applications.Core/extenders": { - RecipeKind: to.Ptr(v20250801preview.RecipeKindBicep), - RecipeLocation: new("ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0"), + Kind: to.Ptr(v20250801preview.RecipeKindBicep), + Source: new("ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0"), }, "Radius.Resources/postgreSQL": { - RecipeKind: to.Ptr(v20250801preview.RecipeKindBicep), - RecipeLocation: new("ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0"), + Kind: to.Ptr(v20250801preview.RecipeKindBicep), + Source: new("ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0"), }, "Applications.Datastores/redisCaches": { - RecipeKind: to.Ptr(v20250801preview.RecipeKindBicep), - RecipeLocation: new("https://github.com/example/recipes/redis-cache.bicep"), + Kind: to.Ptr(v20250801preview.RecipeKindBicep), + Source: new("https://github.com/example/recipes/redis-cache.bicep"), Parameters: map[string]any{ "tier": "basic", }, @@ -188,16 +188,16 @@ func getTestModels() (*v20250801preview.RecipePackResource, *datamodel.RecipePac Properties: datamodel.RecipePackProperties{ Recipes: map[string]*datamodel.RecipeDefinition{ "Applications.Core/extenders": { - RecipeKind: "bicep", - RecipeLocation: "ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0", + Kind: "bicep", + Source: "ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0", }, "Radius.Resources/postgreSQL": { - RecipeKind: "bicep", - RecipeLocation: "ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0", + Kind: "bicep", + Source: "ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0", }, "Applications.Datastores/redisCaches": { - RecipeKind: "bicep", - RecipeLocation: "https://github.com/example/recipes/redis-cache.bicep", + Kind: "bicep", + Source: "https://github.com/example/recipes/redis-cache.bicep", Parameters: map[string]any{ "tier": "basic", }, @@ -215,18 +215,18 @@ func getTestModels() (*v20250801preview.RecipePackResource, *datamodel.RecipePac ProvisioningState: to.Ptr(v20250801preview.ProvisioningStateSucceeded), Recipes: map[string]*v20250801preview.RecipeDefinition{ "Applications.Core/extenders": { - RecipeKind: to.Ptr(v20250801preview.RecipeKindBicep), - RecipeLocation: new("ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0"), - PlainHTTP: new(false), + Kind: to.Ptr(v20250801preview.RecipeKindBicep), + Source: new("ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0"), + PlainHTTP: new(false), }, "Radius.Resources/postgreSQL": { - RecipeKind: to.Ptr(v20250801preview.RecipeKindBicep), - RecipeLocation: new("ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0"), - PlainHTTP: new(false), + Kind: to.Ptr(v20250801preview.RecipeKindBicep), + Source: new("ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0"), + PlainHTTP: new(false), }, "Applications.Datastores/redisCaches": { - RecipeKind: to.Ptr(v20250801preview.RecipeKindBicep), - RecipeLocation: new("https://github.com/example/recipes/redis-cache.bicep"), + Kind: to.Ptr(v20250801preview.RecipeKindBicep), + Source: new("https://github.com/example/recipes/redis-cache.bicep"), Parameters: map[string]any{ "tier": "basic", }, diff --git a/pkg/corerp/frontend/controller/recipepacks/testdata/recipepack_datamodel.json b/pkg/corerp/frontend/controller/recipepacks/testdata/recipepack_datamodel.json index 05a1a4d708d..4c6c9ec897e 100644 --- a/pkg/corerp/frontend/controller/recipepacks/testdata/recipepack_datamodel.json +++ b/pkg/corerp/frontend/controller/recipepacks/testdata/recipepack_datamodel.json @@ -14,16 +14,16 @@ "properties": { "recipes": { "Applications.Core/extenders": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0" + "kind": "bicep", + "source": "ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0" }, "Radius.Resources/postgreSQL": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0" + "kind": "bicep", + "source": "ghcr.io/radius-project/recipes/local-dev/extender-postgresql:0.50.0" }, "Applications.Datastores/redisCaches": { - "recipeKind": "bicep", - "recipeLocation": "https://github.com/example/recipes/redis-cache.bicep", + "kind": "bicep", + "source": "https://github.com/example/recipes/redis-cache.bicep", "parameters": { "tier": "basic" } diff --git a/pkg/recipes/configloader/environment.go b/pkg/recipes/configloader/environment.go index 0085383bfb8..0d681a7f098 100644 --- a/pkg/recipes/configloader/environment.go +++ b/pkg/recipes/configloader/environment.go @@ -365,10 +365,10 @@ func getRecipeDefinitionFromEnvironmentV20250801(ctx context.Context, environmen // We will remove this field from EnvironmentDefinition once we deprecate Applications.Core. definition := &recipes.EnvironmentDefinition{ Name: "default", - Driver: recipeDefinition.RecipeKind, + Driver: recipeDefinition.Kind, ResourceType: resource.Type(), Parameters: parameters, - TemplatePath: recipeDefinition.RecipeLocation, + TemplatePath: recipeDefinition.Source, PlainHTTP: recipeDefinition.PlainHTTP, } return definition, nil @@ -403,10 +403,10 @@ func fetchRecipeDefinition(ctx context.Context, recipePackIDs []string, armOptio plainHTTP = *definition.PlainHTTP } return &recipes.RecipeDefinition{ - RecipeKind: string(*definition.RecipeKind), - RecipeLocation: string(*definition.RecipeLocation), - Parameters: definition.Parameters, - PlainHTTP: plainHTTP, + Kind: string(*definition.Kind), + Source: string(*definition.Source), + Parameters: definition.Parameters, + PlainHTTP: plainHTTP, }, nil } } diff --git a/pkg/recipes/types.go b/pkg/recipes/types.go index 61d512487bc..a7f6bc786a9 100644 --- a/pkg/recipes/types.go +++ b/pkg/recipes/types.go @@ -152,13 +152,13 @@ type RecipePackResource struct { // RecipeDefinition represents a recipe definition for a specific resource type in a recipe pack. type RecipeDefinition struct { - // RecipeKind represents the type of recipe (e.g., terraform, bicep) - RecipeKind string - // RecipeLocation represents URL or path to the recipe source - RecipeLocation string + // Kind represents the type of recipe (e.g., terraform, bicep) + Kind string + // Source represents URL or path to the recipe source + Source string // Parameters represents parameters to pass to the recipe Parameters map[string]any - // PlainHTTP connects to the location using HTTP (not-HTTPS) + // PlainHTTP connects to the source using HTTP (not-HTTPS) PlainHTTP bool } diff --git a/pkg/ucp/initializer/service_test.go b/pkg/ucp/initializer/service_test.go index 6c1ef98414e..1f5560d302b 100644 --- a/pkg/ucp/initializer/service_test.go +++ b/pkg/ucp/initializer/service_test.go @@ -365,10 +365,14 @@ types: additionalProperties, ok := recipesProperty["additionalProperties"].(map[string]any) require.True(t, ok) recipeDefinitionProperties := requireSchemaProperties(t, additionalProperties) - recipeKindProperty := requireSchemaProperty(t, recipeDefinitionProperties, "recipeKind") + recipeKindProperty := requireSchemaProperty(t, recipeDefinitionProperties, "kind") assert.NotContains(t, recipeKindProperty, "$ref") assert.Equal(t, "string", recipeKindProperty["type"]) + recipeSourceProperty := requireSchemaProperty(t, recipeDefinitionProperties, "source") + assert.NotContains(t, recipeSourceProperty, "$ref") + assert.Equal(t, "string", recipeSourceProperty["type"]) + terraformConfigs := summaryModel.Properties.ResourceTypes["terraformConfigs"] terraformConfigSchema := terraformConfigs.APIVersions["2025-08-01-preview"].Schema terraformConfigProperties := requireSchemaProperties(t, terraformConfigSchema) diff --git a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_CreateOrUpdate.json b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_CreateOrUpdate.json index c803d5088b3..3943f2496e7 100644 --- a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_CreateOrUpdate.json +++ b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_CreateOrUpdate.json @@ -10,16 +10,16 @@ "properties": { "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/radius-project/recipes/azure-container-apps:latest", + "kind": "bicep", + "source": "ghcr.io/radius-project/recipes/azure-container-apps:latest", "parameters": { "cpu": "1.0", "memory": "2Gi" } }, "Applications.Dapr/stateStores": { - "recipeKind": "bicep", - "recipeLocation": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", + "kind": "bicep", + "source": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", "parameters": { "databaseName": "radius-db", "throughput": 400 @@ -43,16 +43,16 @@ ], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/radius-project/recipes/azure-container-apps:latest", + "kind": "bicep", + "source": "ghcr.io/radius-project/recipes/azure-container-apps:latest", "parameters": { "cpu": "1.0", "memory": "2Gi" } }, "Applications.Dapr/stateStores": { - "recipeKind": "bicep", - "recipeLocation": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", + "kind": "bicep", + "source": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", "parameters": { "databaseName": "radius-db", "throughput": 400 diff --git a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_Get.json b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_Get.json index e5c6b50be1e..a9e1c926125 100644 --- a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_Get.json +++ b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_Get.json @@ -20,16 +20,16 @@ ], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/radius-project/recipes/azure-container-apps:latest", + "kind": "bicep", + "source": "ghcr.io/radius-project/recipes/azure-container-apps:latest", "parameters": { "cpu": "1.0", "memory": "2Gi" } }, "Applications.Dapr/stateStores": { - "recipeKind": "bicep", - "recipeLocation": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", + "kind": "bicep", + "source": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", "parameters": { "databaseName": "radius-db", "throughput": 400 diff --git a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_ListByScope.json b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_ListByScope.json index 5f0e6e532cf..46d06767612 100644 --- a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_ListByScope.json +++ b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/examples/RecipePacks_ListByScope.json @@ -21,8 +21,8 @@ ], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" + "kind": "bicep", + "source": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" } } } @@ -37,8 +37,8 @@ "referencedBy": [], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" + "kind": "bicep", + "source": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" } } } diff --git a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/openapi.json b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/openapi.json index c786c3c5e8e..188b8ec193f 100644 --- a/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/openapi.json +++ b/swagger/specification/radius/resource-manager/Radius.Core/preview/2025-08-01-preview/openapi.json @@ -1993,17 +1993,17 @@ "type": "object", "description": "Recipe definition for a specific resource type", "properties": { - "recipeKind": { + "kind": { "$ref": "#/definitions/RecipeKind", "description": "The type of recipe (e.g., Terraform, Bicep)" }, "plainHttp": { "type": "boolean", - "description": "Connect to the location using HTTP (not HTTPS). This should be used when the location is known not to support HTTPS, for example in a locally hosted registry for Bicep recipes. Defaults to false (use HTTPS/TLS)" + "description": "Connect to the source using HTTP (not HTTPS). This should be used when the source is known not to support HTTPS, for example in a locally hosted registry for Bicep recipes. Defaults to false (use HTTPS/TLS)" }, - "recipeLocation": { + "source": { "type": "string", - "description": "URL path to the recipe" + "description": "The source of the recipe. For Bicep recipes this is the OCI registry reference. For Terraform recipes this is the module source." }, "parameters": { "type": "object", @@ -2012,8 +2012,8 @@ } }, "required": [ - "recipeKind", - "recipeLocation" + "kind", + "source" ] }, "RecipeKind": { diff --git a/test/functional-portable/cli/noncloud/testdata/corerp-recipe-pack-test.bicep b/test/functional-portable/cli/noncloud/testdata/corerp-recipe-pack-test.bicep index e76bb33075a..ef730083eb5 100644 --- a/test/functional-portable/cli/noncloud/testdata/corerp-recipe-pack-test.bicep +++ b/test/functional-portable/cli/noncloud/testdata/corerp-recipe-pack-test.bicep @@ -4,19 +4,19 @@ resource computeRecipePack 'Radius.Core/recipePacks@2025-08-01-preview' = { properties: { recipes: { 'Radius.Compute/containers': { - recipeKind: 'terraform' - recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' + kind: 'terraform' + source: 'https://github.com/project-radius/resource-types-contrib.git//recipes/compute/containers/kubernetes?ref=v0.48' parameters: { allowPlatformOptions: true } } 'Radius.Security/secrets': { - recipeKind: 'terraform' - recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets/kubernetes?ref=v0.48' + kind: 'terraform' + source: 'https://github.com/project-radius/resource-types-contrib.git//recipes/security/secrets/kubernetes?ref=v0.48' } 'Radius.Storage/volumes': { - recipeKind: 'terraform' - recipeLocation: 'https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes/kubernetes?ref=v0.48' + kind: 'terraform' + source: 'https://github.com/project-radius/resource-types-contrib.git//recipes/storage/volumes/kubernetes?ref=v0.48' } } } diff --git a/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test-no-provider.bicep b/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test-no-provider.bicep index 9dcd18ad766..f2f2534c5d8 100644 --- a/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test-no-provider.bicep +++ b/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test-no-provider.bicep @@ -14,8 +14,8 @@ resource recipepack 'Radius.Core/recipePacks@2025-08-01-preview' = { properties: { recipes: { 'Test.Resources/userTypeAlpha': { - recipeKind: 'bicep' - recipeLocation: '${registry}/test/testrecipes/test-bicep-recipes/dynamicrp_recipe:${version}' + kind: 'bicep' + source: '${registry}/test/testrecipes/test-bicep-recipes/dynamicrp_recipe:${version}' parameters: { port: port } diff --git a/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test.bicep b/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test.bicep index 891d8e9001a..a76dcdca213 100644 --- a/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test.bicep +++ b/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test.bicep @@ -18,16 +18,16 @@ resource recipepack 'Radius.Core/recipePacks@2025-08-01-preview' = { properties: { recipes: { 'Test.Resources/userTypeAlpha': { - recipeKind: 'bicep' - recipeLocation: '${registry}/test/testrecipes/test-bicep-recipes/dynamicrp_recipe:${version}' + kind: 'bicep' + source: '${registry}/test/testrecipes/test-bicep-recipes/dynamicrp_recipe:${version}' parameters: { port: port } } 'Test.Resources/postgres': { - recipeKind: 'bicep' + kind: 'bicep' // update the sha sum after making changes to the recipe - recipeLocation: '${registry}/test/testrecipes/test-bicep-recipes/dynamicrp_postgress_recipe@sha256:40d079856c2b7cf4df146c0726b31b8bea6a82ef1eb7fa9bc9e00498367f2a4d' + source: '${registry}/test/testrecipes/test-bicep-recipes/dynamicrp_postgress_recipe@sha256:40d079856c2b7cf4df146c0726b31b8bea6a82ef1eb7fa9bc9e00498367f2a4d' } } } diff --git a/test/functional-portable/dynamicrp/noncloud/resources/testdata/terraformconfig-redis-test.bicep b/test/functional-portable/dynamicrp/noncloud/resources/testdata/terraformconfig-redis-test.bicep index 22c47958073..af4242bcc34 100644 --- a/test/functional-portable/dynamicrp/noncloud/resources/testdata/terraformconfig-redis-test.bicep +++ b/test/functional-portable/dynamicrp/noncloud/resources/testdata/terraformconfig-redis-test.bicep @@ -30,8 +30,8 @@ resource recipepack 'Radius.Core/recipePacks@2025-08-01-preview' = { properties: { recipes: { 'Applications.Core/extenders': { - recipeKind: 'terraform' - recipeLocation: '${moduleServer}/kubernetes-redis.zip//modules' + kind: 'terraform' + source: '${moduleServer}/kubernetes-redis.zip//modules' } } } diff --git a/test/functional-portable/dynamicrp/noncloud/resources/testdata/tfbicep-combined-test.bicep b/test/functional-portable/dynamicrp/noncloud/resources/testdata/tfbicep-combined-test.bicep index 58e6408f970..15968d816c1 100644 --- a/test/functional-portable/dynamicrp/noncloud/resources/testdata/tfbicep-combined-test.bicep +++ b/test/functional-portable/dynamicrp/noncloud/resources/testdata/tfbicep-combined-test.bicep @@ -73,8 +73,8 @@ resource recipepack 'Radius.Core/recipePacks@2025-08-01-preview' = { properties: { recipes: { 'Applications.Core/extenders': { - recipeKind: 'terraform' - recipeLocation: '${moduleServer}/kubernetes-redis.zip//modules' + kind: 'terraform' + source: '${moduleServer}/kubernetes-redis.zip//modules' } } } diff --git a/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_CreateOrUpdate.json b/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_CreateOrUpdate.json index c803d5088b3..3943f2496e7 100644 --- a/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_CreateOrUpdate.json +++ b/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_CreateOrUpdate.json @@ -10,16 +10,16 @@ "properties": { "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/radius-project/recipes/azure-container-apps:latest", + "kind": "bicep", + "source": "ghcr.io/radius-project/recipes/azure-container-apps:latest", "parameters": { "cpu": "1.0", "memory": "2Gi" } }, "Applications.Dapr/stateStores": { - "recipeKind": "bicep", - "recipeLocation": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", + "kind": "bicep", + "source": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", "parameters": { "databaseName": "radius-db", "throughput": 400 @@ -43,16 +43,16 @@ ], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/radius-project/recipes/azure-container-apps:latest", + "kind": "bicep", + "source": "ghcr.io/radius-project/recipes/azure-container-apps:latest", "parameters": { "cpu": "1.0", "memory": "2Gi" } }, "Applications.Dapr/stateStores": { - "recipeKind": "bicep", - "recipeLocation": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", + "kind": "bicep", + "source": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", "parameters": { "databaseName": "radius-db", "throughput": 400 diff --git a/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_Get.json b/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_Get.json index e5c6b50be1e..a9e1c926125 100644 --- a/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_Get.json +++ b/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_Get.json @@ -20,16 +20,16 @@ ], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/radius-project/recipes/azure-container-apps:latest", + "kind": "bicep", + "source": "ghcr.io/radius-project/recipes/azure-container-apps:latest", "parameters": { "cpu": "1.0", "memory": "2Gi" } }, "Applications.Dapr/stateStores": { - "recipeKind": "bicep", - "recipeLocation": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", + "kind": "bicep", + "source": "br:myregistry.azurecr.io/bicep/recipes/cosmosdb:v1.0", "parameters": { "databaseName": "radius-db", "throughput": 400 diff --git a/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_List.json b/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_List.json index e38bbd79b16..62841b6c869 100644 --- a/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_List.json +++ b/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_List.json @@ -20,8 +20,8 @@ ], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/radius-project/recipes/azure-container-apps:latest" + "kind": "bicep", + "source": "ghcr.io/radius-project/recipes/azure-container-apps:latest" } } } @@ -36,8 +36,8 @@ "referencedBy": [], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" + "kind": "bicep", + "source": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" } } } diff --git a/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_ListByScope.json b/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_ListByScope.json index 5f0e6e532cf..46d06767612 100644 --- a/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_ListByScope.json +++ b/typespec/Radius.Core/examples/2025-08-01-preview/RecipePacks_ListByScope.json @@ -21,8 +21,8 @@ ], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" + "kind": "bicep", + "source": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" } } } @@ -37,8 +37,8 @@ "referencedBy": [], "recipes": { "Applications.Core/containers": { - "recipeKind": "bicep", - "recipeLocation": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" + "kind": "bicep", + "source": "ghcr.io/myregistry/bicep/recipes/myrecipe:v1.0" } } } diff --git a/typespec/Radius.Core/recipePacks.tsp b/typespec/Radius.Core/recipePacks.tsp index 2b9b494024f..7d7be16de9e 100644 --- a/typespec/Radius.Core/recipePacks.tsp +++ b/typespec/Radius.Core/recipePacks.tsp @@ -58,13 +58,13 @@ model RecipePackProperties { @doc("Recipe definition for a specific resource type") model RecipeDefinition { @doc("The type of recipe (e.g., Terraform, Bicep)") - recipeKind: RecipeKind; + kind: RecipeKind; - @doc("Connect to the location using HTTP (not HTTPS). This should be used when the location is known not to support HTTPS, for example in a locally hosted registry for Bicep recipes. Defaults to false (use HTTPS/TLS)") + @doc("Connect to the source using HTTP (not HTTPS). This should be used when the source is known not to support HTTPS, for example in a locally hosted registry for Bicep recipes. Defaults to false (use HTTPS/TLS)") plainHttp?: boolean; - @doc("URL path to the recipe") - recipeLocation: string; + @doc("The source of the recipe. For Bicep recipes this is the OCI registry reference. For Terraform recipes this is the module source.") + source: string; @doc("Parameters to pass to the recipe") parameters?: Record; From 097258a5ab506e1f4f037921d538c6017053fcb4 Mon Sep 17 00:00:00 2001 From: willdavsmith Date: Mon, 22 Jun 2026 10:15:04 -0700 Subject: [PATCH 2/7] Use lowercase RecipeKind enum values and clarify test variable names Address PR review feedback: - Lowercase recipe kind fixture/assertion values ("Bicep"/"Terraform" -> "bicep"/"terraform") to match the schema-valid RecipeKind enum. - Rename stale recipeKindProperty/recipeSourceProperty test variables to kindProperty/sourceProperty to match the renamed schema properties. Signed-off-by: willdavsmith --- .../v20250801preview/recipepack_conversion_test.go | 6 +++--- .../testdata/recipepackresource.json | 4 ++-- .../testdata/recipepackresourcedatamodel.json | 4 ++-- pkg/ucp/initializer/service_test.go | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/corerp/api/v20250801preview/recipepack_conversion_test.go b/pkg/corerp/api/v20250801preview/recipepack_conversion_test.go index b256db1939c..1e3a0fc845f 100644 --- a/pkg/corerp/api/v20250801preview/recipepack_conversion_test.go +++ b/pkg/corerp/api/v20250801preview/recipepack_conversion_test.go @@ -59,12 +59,12 @@ func TestRecipePackConvertVersionedToDataModel(t *testing.T) { container := recipePack.Properties.Recipes["Applications.Core/containers"] require.NotNil(t, container) - require.Equal(t, "Bicep", container.Kind) + require.Equal(t, "bicep", container.Kind) require.Equal(t, "br:ghcr.io/radius-project/recipes/kubernetes-container:latest", container.Source) stateStore := recipePack.Properties.Recipes["Applications.Dapr/stateStores"] require.NotNil(t, stateStore) - require.Equal(t, "Terraform", stateStore.Kind) + require.Equal(t, "terraform", stateStore.Kind) require.Equal(t, "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", stateStore.Source) } @@ -95,7 +95,7 @@ func TestRecipePackConvertDataModelToVersioned(t *testing.T) { stateStore := versionedResource.Properties.Recipes["Applications.Dapr/stateStores"] require.NotNil(t, stateStore) require.NotNil(t, stateStore.Kind) - require.Equal(t, RecipeKind("Terraform"), *stateStore.Kind) + require.Equal(t, RecipeKind("terraform"), *stateStore.Kind) require.Equal(t, "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", *stateStore.Source) container := versionedResource.Properties.Recipes["Applications.Core/containers"] diff --git a/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json b/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json index 62215982c6d..d972d5fe788 100644 --- a/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json +++ b/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json @@ -15,7 +15,7 @@ ], "recipes": { "Applications.Core/containers": { - "kind": "Bicep", + "kind": "bicep", "source": "br:ghcr.io/radius-project/recipes/kubernetes-container:latest", "parameters": { "port": 8080, @@ -24,7 +24,7 @@ "plainHTTP": false }, "Applications.Dapr/stateStores": { - "kind": "Terraform", + "kind": "terraform", "source": "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", "parameters": { "size": "small" diff --git a/pkg/corerp/api/v20250801preview/testdata/recipepackresourcedatamodel.json b/pkg/corerp/api/v20250801preview/testdata/recipepackresourcedatamodel.json index 98af33f1b5d..8b313fcf6ff 100644 --- a/pkg/corerp/api/v20250801preview/testdata/recipepackresourcedatamodel.json +++ b/pkg/corerp/api/v20250801preview/testdata/recipepackresourcedatamodel.json @@ -27,7 +27,7 @@ ], "recipes": { "Applications.Core/containers": { - "kind": "Bicep", + "kind": "bicep", "source": "br:ghcr.io/radius-project/recipes/kubernetes-container:latest", "parameters": { "port": 8080, @@ -36,7 +36,7 @@ "plainHTTP": false }, "Applications.Dapr/stateStores": { - "kind": "Terraform", + "kind": "terraform", "source": "oci://ghcr.io/radius-project/recipes/terraform/redis:latest", "parameters": { "size": "small" diff --git a/pkg/ucp/initializer/service_test.go b/pkg/ucp/initializer/service_test.go index 1f5560d302b..d803f57ddd8 100644 --- a/pkg/ucp/initializer/service_test.go +++ b/pkg/ucp/initializer/service_test.go @@ -365,13 +365,13 @@ types: additionalProperties, ok := recipesProperty["additionalProperties"].(map[string]any) require.True(t, ok) recipeDefinitionProperties := requireSchemaProperties(t, additionalProperties) - recipeKindProperty := requireSchemaProperty(t, recipeDefinitionProperties, "kind") - assert.NotContains(t, recipeKindProperty, "$ref") - assert.Equal(t, "string", recipeKindProperty["type"]) + kindProperty := requireSchemaProperty(t, recipeDefinitionProperties, "kind") + assert.NotContains(t, kindProperty, "$ref") + assert.Equal(t, "string", kindProperty["type"]) - recipeSourceProperty := requireSchemaProperty(t, recipeDefinitionProperties, "source") - assert.NotContains(t, recipeSourceProperty, "$ref") - assert.Equal(t, "string", recipeSourceProperty["type"]) + sourceProperty := requireSchemaProperty(t, recipeDefinitionProperties, "source") + assert.NotContains(t, sourceProperty, "$ref") + assert.Equal(t, "string", sourceProperty["type"]) terraformConfigs := summaryModel.Properties.ResourceTypes["terraformConfigs"] terraformConfigSchema := terraformConfigs.APIVersions["2025-08-01-preview"].Schema From d3bf2069febad95438f54ca3b7dce0144789868b Mon Sep 17 00:00:00 2001 From: willdavsmith Date: Mon, 22 Jun 2026 10:29:05 -0700 Subject: [PATCH 3/7] Harden env show recipe rendering and fix versioned fixture casing Address PR review feedback: - Guard against nil recipe Kind/Source pointers in 'rad env show' preview so a partial RecipePack payload can't panic the CLI, matching the recipe-pack show nil-check pattern. - Use plainHttp casing in the versioned RecipePackResource fixture so the generated serde recognizes the field. Signed-off-by: willdavsmith --- pkg/cli/cmd/env/show/preview/show.go | 18 ++++++++++++++++-- .../testdata/recipepackresource.json | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/pkg/cli/cmd/env/show/preview/show.go b/pkg/cli/cmd/env/show/preview/show.go index 59dae2a7f48..763f6a21f38 100644 --- a/pkg/cli/cmd/env/show/preview/show.go +++ b/pkg/cli/cmd/env/show/preview/show.go @@ -188,11 +188,25 @@ func (r *Runner) Run(ctx context.Context) error { } for resourceType, recipe := range pack.RecipePackResource.Properties.Recipes { + if recipe == nil { + continue + } + + kind := "unknown" + if recipe.Kind != nil { + kind = string(*recipe.Kind) + } + + source := "" + if recipe.Source != nil { + source = *recipe.Source + } + envRecipes = append(envRecipes, EnvRecipes{ RecipePack: ID.Name(), ResourceType: resourceType, - Kind: string(*recipe.Kind), - Source: *recipe.Source, + Kind: kind, + Source: source, }) } } diff --git a/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json b/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json index d972d5fe788..8b924c81d1b 100644 --- a/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json +++ b/pkg/corerp/api/v20250801preview/testdata/recipepackresource.json @@ -21,7 +21,7 @@ "port": 8080, "replicas": 3 }, - "plainHTTP": false + "plainHttp": false }, "Applications.Dapr/stateStores": { "kind": "terraform", @@ -29,7 +29,7 @@ "parameters": { "size": "small" }, - "plainHTTP": true + "plainHttp": true } } } From 1fa4939200e46083f2e182a42c3ddf6601e87aef Mon Sep 17 00:00:00 2001 From: willdavsmith Date: Mon, 22 Jun 2026 10:57:19 -0700 Subject: [PATCH 4/7] Return clear errors for missing recipe fields in fetchRecipeDefinition Address PR review feedback: guard against nil recipe definition and nil required Kind/Source pointers when resolving a recipe from a recipe pack, so a malformed or partial payload returns a descriptive error instead of panicking. Signed-off-by: willdavsmith --- pkg/recipes/configloader/environment.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/recipes/configloader/environment.go b/pkg/recipes/configloader/environment.go index 1204a6ab6d5..146ddfa01a9 100644 --- a/pkg/recipes/configloader/environment.go +++ b/pkg/recipes/configloader/environment.go @@ -398,6 +398,16 @@ func fetchRecipeDefinition(ctx context.Context, recipePackIDs []string, armOptio // Convert recipes map for recipePackResourceType, definition := range recipePackResource.Properties.Recipes { if strings.EqualFold(recipePackResourceType, resourceType) { + if definition == nil { + return nil, fmt.Errorf("recipe for resource type %q in recipe pack %q is missing its definition", resourceType, recipePackID) + } + if definition.Kind == nil { + return nil, fmt.Errorf("recipe for resource type %q in recipe pack %q is missing the required \"kind\" field", resourceType, recipePackID) + } + if definition.Source == nil { + return nil, fmt.Errorf("recipe for resource type %q in recipe pack %q is missing the required \"source\" field", resourceType, recipePackID) + } + var plainHTTP bool if definition.PlainHTTP != nil { plainHTTP = *definition.PlainHTTP From 6de0c016cabfb88452ab153c1c1346df807d5c59 Mon Sep 17 00:00:00 2001 From: willdavsmith Date: Mon, 22 Jun 2026 11:07:29 -0700 Subject: [PATCH 5/7] Rename recipe pack fields in by-name functional test fixture Address PR review feedback: recipepacks-test-by-name.bicep (used by Test_RecipePacks_ByName_Deployment) still used the legacy recipeKind/recipeLocation properties, which would fail against the renamed kind/source schema. Update it to match the renamed fields. Signed-off-by: willdavsmith --- .../resources/testdata/recipepacks-test-by-name.bicep | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test-by-name.bicep b/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test-by-name.bicep index a629f9476de..e37d43fd3b1 100644 --- a/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test-by-name.bicep +++ b/test/functional-portable/dynamicrp/noncloud/resources/testdata/recipepacks-test-by-name.bicep @@ -18,8 +18,8 @@ resource recipepack 'Radius.Core/recipePacks@2025-08-01-preview' = { properties: { recipes: { 'Test.Resources/userTypeAlpha': { - recipeKind: 'bicep' - recipeLocation: '${registry}/test/testrecipes/test-bicep-recipes/dynamicrp_recipe:${version}' + kind: 'bicep' + source: '${registry}/test/testrecipes/test-bicep-recipes/dynamicrp_recipe:${version}' parameters: { port: port } From 972e3c454d5e6bbcda4c373786323b54c5600be8 Mon Sep 17 00:00:00 2001 From: willdavsmith Date: Mon, 22 Jun 2026 11:17:56 -0700 Subject: [PATCH 6/7] Update extensibility architecture doc for kind/source rename Address PR review feedback: docs/architecture/extensibility.md is living architecture documentation, so update its recipe pack YAML example and prose references from recipeKind/recipeLocation to the renamed kind/source fields. Dated design notes under eng/design-notes are left unchanged as point-in-time records. Signed-off-by: willdavsmith --- docs/architecture/extensibility.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/architecture/extensibility.md b/docs/architecture/extensibility.md index c015b605454..45ae53d0f3a 100644 --- a/docs/architecture/extensibility.md +++ b/docs/architecture/extensibility.md @@ -240,8 +240,8 @@ properties: properties: recipes: Radius.Data/redisCaches: - recipeKind: bicep - recipeLocation: ghcr.io/.../redis:1.0.0 + kind: bicep + source: ghcr.io/.../redis:1.0.0 plainHttp: false parameters: { ... } ``` @@ -400,8 +400,8 @@ The engine `EnvironmentDefinition` whose `Driver` field is the `TemplateKind` string. For `Radius.Core` environments, this fetches the referenced recipe packs, finds the definition keyed by the resource type, applies matching - environment-level recipe parameter overrides, and maps `RecipeKind` / - `RecipeLocation` into the same `EnvironmentDefinition` shape. + environment-level recipe parameter overrides, and maps `Kind` / + `Source` into the same `EnvironmentDefinition` shape. 4. Selects the driver from the engine's `Drivers` map keyed by `EnvironmentDefinition.Driver` (see @@ -480,7 +480,7 @@ up before the Radius resource record is removed. - Dynamic resources default to recipe name `default` when `properties.recipe` is omitted. - The driver lookup key is the recipe's `templateKind` for - `Applications.Core` recipes and the mapped `recipeKind` for + `Applications.Core` recipes and the mapped `kind` for `Radius.Core` recipe packs. Adding a new driver means registering it in the engine's `Drivers` map. - Dynamic recipe output only becomes user-visible resource properties when @@ -500,7 +500,7 @@ up before the Radius resource record is removed. recipe through the environment recipe map or a recipe pack used by tests. - Adding a new recipe driver: implement `recipes/driver.Driver`, register it in [controllerconfig/config.go](../../pkg/recipes/controllerconfig/config.go), - and pick a stable driver key used by `templateKind` or `recipeKind`. + and pick a stable driver key used by `templateKind` or `kind`. - Adding a new capability that changes the deployment path: extend `DynamicResourceController.selectController` and add the corresponding controller under From 4d84465590a50ce5c4015e31fdf702df55ecec36 Mon Sep 17 00:00:00 2001 From: willdavsmith Date: Mon, 22 Jun 2026 11:44:37 -0700 Subject: [PATCH 7/7] Regenerate corerp 2025-08-01-preview models after merge Signed-off-by: willdavsmith --- pkg/corerp/api/v20250801preview/zz_generated_models.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/corerp/api/v20250801preview/zz_generated_models.go b/pkg/corerp/api/v20250801preview/zz_generated_models.go index 863b98788a8..326810e274b 100644 --- a/pkg/corerp/api/v20250801preview/zz_generated_models.go +++ b/pkg/corerp/api/v20250801preview/zz_generated_models.go @@ -421,8 +421,7 @@ type RecipeDefinition struct { Parameters map[string]any // Connect to the source using HTTP (not HTTPS). This should be used when the source is known not to support HTTPS, for example - // in a locally hosted registry for Bicep recipes. Defaults to false (use - // HTTPS/TLS) + // in a locally hosted registry for Bicep recipes. Defaults to false (use HTTPS/TLS) PlainHTTP *bool }