diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 05e6ced7..c064a2be 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -2,3 +2,5 @@ ### Bug Fixes +- Fix Stack Reference output properties to be usable as any type, not only strings inputs. + [#600](https://github.com/pulumi/pulumi-yaml/pull/600) diff --git a/go.mod b/go.mod index 3bad1d7f..e9cf84fe 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( github.com/hexops/autogold v1.3.0 github.com/iancoleman/strcase v0.2.0 github.com/pkg/errors v0.9.1 - github.com/pulumi/pulumi/pkg/v3 v3.121.0 - github.com/pulumi/pulumi/sdk/v3 v3.121.0 + github.com/pulumi/pulumi/pkg/v3 v3.123.1-0.20240711160144-b8226b705890 + github.com/pulumi/pulumi/sdk/v3 v3.123.1-0.20240711160144-b8226b705890 github.com/spf13/afero v1.9.5 github.com/stretchr/testify v1.9.0 github.com/zclconf/go-cty v1.13.2 diff --git a/go.sum b/go.sum index 7226e117..1eb41c17 100644 --- a/go.sum +++ b/go.sum @@ -430,10 +430,10 @@ github.com/pulumi/esc v0.9.1 h1:HH5eEv8sgyxSpY5a8yePyqFXzA8cvBvapfH8457+mIs= github.com/pulumi/esc v0.9.1/go.mod h1:oEJ6bOsjYlQUpjf70GiX+CXn3VBmpwFDxUTlmtUN84c= github.com/pulumi/inflector v0.1.1 h1:dvlxlWtXwOJTUUtcYDvwnl6Mpg33prhK+7mzeF+SobA= github.com/pulumi/inflector v0.1.1/go.mod h1:HUFCjcPTz96YtTuUlwG3i3EZG4WlniBvR9bd+iJxCUY= -github.com/pulumi/pulumi/pkg/v3 v3.121.0 h1:cLUQJYGJKfgCY0ubJo8dVwmsIm2WcgTprb9Orc/yiFg= -github.com/pulumi/pulumi/pkg/v3 v3.121.0/go.mod h1:aaRixfKOh4DhGtuDJcI56dTPkb7oJBgRgH1aMF1FzbU= -github.com/pulumi/pulumi/sdk/v3 v3.121.0 h1:UsnFKIVOtJN/hQKPkWHL9cZktewPVQRbNUXbXQY/qrk= -github.com/pulumi/pulumi/sdk/v3 v3.121.0/go.mod h1:p1U24en3zt51agx+WlNboSOV8eLlPWYAkxMzVEXKbnY= +github.com/pulumi/pulumi/pkg/v3 v3.123.1-0.20240711160144-b8226b705890 h1:fx6UbtFWpsm3Hls6bJ5gzO1EfAbAurmVnLBe94e89ho= +github.com/pulumi/pulumi/pkg/v3 v3.123.1-0.20240711160144-b8226b705890/go.mod h1:Tjrtb9HuGLvPHagkh/oIx7R+KFcnTzsfYIOEiYP54I4= +github.com/pulumi/pulumi/sdk/v3 v3.123.1-0.20240711160144-b8226b705890 h1:CBiyYJ+vERIeud6v8649a/VbU0sPGTmUAtJRovGW6Wc= +github.com/pulumi/pulumi/sdk/v3 v3.123.1-0.20240711160144-b8226b705890/go.mod h1:p1U24en3zt51agx+WlNboSOV8eLlPWYAkxMzVEXKbnY= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= diff --git a/pkg/pulumiyaml/analyser.go b/pkg/pulumiyaml/analyser.go index 17442b86..eae61ed1 100644 --- a/pkg/pulumiyaml/analyser.go +++ b/pkg/pulumiyaml/analyser.go @@ -229,6 +229,10 @@ func (tc *typeCache) isAssignable(fromExpr ast.Expr, to schema.Type) *notAssigna return nil } + if from == schema.AnyType || to == schema.AnyType { + return nil + } + dispType := func(t schema.Type) string { var maybeType string if schema.IsPrimitiveType(from) { @@ -270,9 +274,11 @@ func (tc *typeCache) isAssignable(fromExpr ast.Expr, to schema.Type) *notAssigna return okIf(len(reasons) == 0).Because(reasons...) case *schema.TokenType: - underlying := schema.AnyType + var underlying schema.Type if from.UnderlyingType != nil { underlying = from.UnderlyingType + } else { + return fail } check := isAssignable(underlying, to) return okIfAssignable(check).WithReason(". '%s' is a Token Type. Token types act like their underlying type", displayType(from)) diff --git a/pkg/pulumiyaml/analyser_test.go b/pkg/pulumiyaml/analyser_test.go index 8e39cdac..2a4f7c61 100644 --- a/pkg/pulumiyaml/analyser_test.go +++ b/pkg/pulumiyaml/analyser_test.go @@ -109,8 +109,7 @@ func TestTypeError(t *testing.T) { }, message: `Cannot assign '{prop1: asset, prop3: any}' to '{prop1: archive, prop2: boolean, prop3: string}': prop1: Cannot assign type 'asset' to type 'archive' - prop2: Missing required property 'prop2' - prop3: Cannot assign type 'any' to type 'string'`, + prop2: Missing required property 'prop2'`, }, // Token Types: @@ -126,10 +125,9 @@ func TestTypeError(t *testing.T) { }, { // Token types are assignable to the 'any' type, and no other type - from: &schema.TokenType{Token: "foo"}, - to: schema.StringType, - message: `Cannot assign 'foo' to 'string'. 'foo' is a Token Type. Token types act like their underlying type: - Cannot assign type 'any' to type 'string'`, + from: &schema.TokenType{Token: "foo"}, + to: schema.StringType, + message: `Cannot assign 'foo' to 'string'`, }, { // Token types are assignable to their underlying types @@ -213,8 +211,10 @@ func TestTypeError(t *testing.T) { t.Logf("err: %s", result.Error()) } } else { - require.Error(t, result) - assert.Equal(t, c.message, result.String()) + require.Error(t, result, fmt.Sprintf("Expected error %q, no error", c.message)) + if result != nil { + assert.Equal(t, c.message, result.String()) + } } }) } diff --git a/pkg/pulumiyaml/run_test.go b/pkg/pulumiyaml/run_test.go index 29aad0e4..81697115 100644 --- a/pkg/pulumiyaml/run_test.go +++ b/pkg/pulumiyaml/run_test.go @@ -38,6 +38,10 @@ type MockPackageLoader struct { } func (m MockPackageLoader) LoadPackage(name string, version *semver.Version) (Package, error) { + if name == "pulumi" { + return resourcePackage{schema.DefaultPulumiPackage.Reference()}, nil + } + if version != nil { // See if there is a version specific package if pkg, found := m.packages[name+"@"+version.String()]; found { @@ -196,7 +200,13 @@ func newMockPackageMap() PackageLoader { }, }, } - + case "test:resource:with-list-input": + return inputProperties("test:resource:not-run", schema.Property{ + Name: "listInput", + Type: &schema.ArrayType{ + ElementType: schema.StringType, + }, + }) default: return inputProperties(typeName) } @@ -2270,6 +2280,62 @@ func TestHandleUnknownPropertiesDuringPreview(t *testing.T) { assert.NoError(t, err) } +func TestStackReferenceOutputs(t *testing.T) { + t.Parallel() + + text := ` +name: test-alias +runtime: yaml +resources: + ref: + type: pulumi:pulumi:StackReference + properties: + name: any + sec: + type: test:resource:with-list-input + properties: + listInput: ${ref.outputs["listOutput"]} +` + tmpl := yamlTemplate(t, strings.TrimSpace(text)) + mocks := &testMonitor{ + NewResourceF: func(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error) { + t.Logf("args: %+v", args) + + if args.TypeToken == "pulumi:pulumi:StackReference" { + assert.Equal(t, "ref", args.Name) + return "ref", resource.PropertyMap{ + "outputs": resource.NewObjectProperty(resource.NewPropertyMapFromMap(map[string]any{ + "listOutput": []string{"foo", "bar"}, + })), + }, nil + } else if args.TypeToken == "test:resource:with-list-input" { + assert.Equal(t, "sec", args.Name) + assert.Equal(t, + resource.NewArrayProperty([]resource.PropertyValue{resource.NewStringProperty("foo"), resource.NewStringProperty("bar")}), + args.Inputs["listInput"]) + return "sec", args.Inputs, nil + } + + t.Fatalf("unexpected type token: %s", args.TypeToken) + + return args.Name, args.Inputs, nil + }, + } + err := pulumi.RunErr(func(ctx *pulumi.Context) error { + runner := newRunner(tmpl, newMockPackageMap()) + _, diags := TypeCheck(runner) + if diags.HasErrors() { + return diags + } + err := runner.Evaluate(ctx) + assert.Len(t, err, 0) + assert.Equal(t, err.Error(), "no diagnostics") + + return nil + }, pulumi.WithMocks("project", "stack", mocks)) + assert.NoError(t, err) +} + type mockLateboundResource struct { resourceSchema *schema.Resource }