pulumi/sdk/go/common/workspace/project_test.go

1790 lines
49 KiB
Go
Raw Normal View History

package workspace
import (
"context"
"encoding/json"
"fmt"
"os"
"testing"
"github.com/pulumi/esc"
"github.com/pulumi/pulumi/sdk/v3/go/common/encoding"
2022-09-22 15:32:18 +00:00
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/config"
2022-09-02 17:25:45 +00:00
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
"github.com/stretchr/testify/assert"
2023-02-10 17:05:21 +00:00
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
)
func TestProjectRuntimeInfoRoundtripYAML(t *testing.T) {
t.Parallel()
doTest := func(marshal func(interface{}) ([]byte, error), unmarshal func([]byte, interface{}) error) {
ri := NewProjectRuntimeInfo("nodejs", nil)
byts, err := marshal(ri)
assert.NoError(t, err)
var riRountrip ProjectRuntimeInfo
err = unmarshal(byts, &riRountrip)
assert.NoError(t, err)
assert.Equal(t, "nodejs", riRountrip.Name())
assert.Nil(t, riRountrip.Options())
ri = NewProjectRuntimeInfo("nodejs", map[string]interface{}{
"typescript": true,
"stringOption": "hello",
})
byts, err = marshal(ri)
assert.NoError(t, err)
err = unmarshal(byts, &riRountrip)
assert.NoError(t, err)
assert.Equal(t, "nodejs", riRountrip.Name())
assert.Equal(t, true, riRountrip.Options()["typescript"])
assert.Equal(t, "hello", riRountrip.Options()["stringOption"])
}
doTest(yaml.Marshal, yaml.Unmarshal)
doTest(json.Marshal, json.Unmarshal)
}
func TestProjectValidationForNameAndRuntime(t *testing.T) {
t.Parallel()
var err error
// Test lack of name
proj := Project{}
err = proj.Validate()
assert.EqualError(t, err, "project is missing a 'name' attribute")
// Test lack of runtime
proj.Name = "a project"
err = proj.Validate()
assert.EqualError(t, err, "project is missing a 'runtime' attribute")
2022-09-02 09:35:14 +00:00
// Test success
proj.Runtime = NewProjectRuntimeInfo("test", nil)
err = proj.Validate()
assert.NoError(t, err)
}
func TestProjectValidationFailsForIncorrectDefaultValueType(t *testing.T) {
t.Parallel()
project := Project{Name: "test", Runtime: NewProjectRuntimeInfo("dotnet", nil)}
invalidConfig := make(map[string]ProjectConfigType)
integerType := "integer"
invalidConfig["instanceSize"] = ProjectConfigType{
Type: &integerType,
Items: nil,
Default: "hello",
}
project.Config = invalidConfig
err := project.Validate()
assert.ErrorContains(t, err,
"The default value specified for configuration key 'instanceSize' is not of the expected type 'integer'")
invalidValues := make([]interface{}, 0)
invalidValues = append(invalidValues, "hello")
// default value here has type array<string>
// config type specified is array<array<string>>
// should fail!
arrayType := "array"
invalidConfigWithArray := make(map[string]ProjectConfigType)
invalidConfigWithArray["values"] = ProjectConfigType{
Type: &arrayType,
Items: &ProjectConfigItemsType{
Type: "array",
Items: &ProjectConfigItemsType{
Type: "string",
},
},
Default: invalidValues,
}
project.Config = invalidConfigWithArray
err = project.Validate()
assert.ErrorContains(t, err,
"The default value specified for configuration key 'values' is not of the expected type 'array<array<string>>'")
}
func TestProjectValidationSucceedsForCorrectDefaultValueType(t *testing.T) {
t.Parallel()
project := Project{Name: "test", Runtime: NewProjectRuntimeInfo("dotnet", nil)}
integerType := "integer"
validConfig := make(map[string]ProjectConfigType)
validConfig["instanceSize"] = ProjectConfigType{
Type: &integerType,
Items: nil,
Default: 1,
}
project.Config = validConfig
err := project.Validate()
assert.NoError(t, err, "There should be no validation error")
// validValues = ["hello"]
validValues := make([]interface{}, 0)
validValues = append(validValues, "hello")
// validValuesArray = [["hello"]]
validValuesArray := make([]interface{}, 0)
validValuesArray = append(validValuesArray, validValues)
// default value here has type array<array<string>>
// config type specified is also array<array<string>>
// should succeed
arrayType := "array"
validConfigWithArray := make(map[string]ProjectConfigType)
validConfigWithArray["values"] = ProjectConfigType{
Type: &arrayType,
Items: &ProjectConfigItemsType{
Type: "array",
Items: &ProjectConfigItemsType{
Type: "string",
},
},
Default: validValuesArray,
}
project.Config = validConfigWithArray
err = project.Validate()
assert.NoError(t, err, "There should be no validation error")
}
func writeAndLoad(t *testing.T, str string) (*Project, error) {
tmp, err := os.CreateTemp("", "*.json")
assert.NoError(t, err)
path := tmp.Name()
err = os.WriteFile(path, []byte(str), 0o600)
assert.NoError(t, err)
return LoadProject(path)
}
2022-09-02 17:25:45 +00:00
func TestProjectLoadJSON(t *testing.T) {
2022-09-02 09:35:14 +00:00
t.Parallel()
2022-09-02 17:25:45 +00:00
// Test wrong type
t.Run("wrong type", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, "\"hello \"")
// Assert.
assert.ErrorContains(t, err, "expected project to be an object, was 'string'")
})
t.Run("missing name attribute", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, "{}")
// Assert.
assert.ErrorContains(t, err, "project is missing a 'name' attribute")
})
t.Run("bad name", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, "{\"name\": \"\"}")
// Assert.
assert.ErrorContains(t, err, "project is missing a non-empty string 'name' attribute")
})
t.Run("missing runtime", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, "{\"name\": \"project\"}")
// Assert.
assert.ErrorContains(t, err, "project is missing a 'runtime' attribute")
})
t.Run("multiple errors 1", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, "{\"name\": \"project\", \"runtime\": 4}")
// Assert.
// The order can vary here, so we use Contains and not Equals.
expected := []string{
"3 errors occurred:",
"* #/runtime: oneOf failed",
"* #/runtime: expected string, but got number",
"* #/runtime: expected object, but got number",
}
for _, e := range expected {
assert.ErrorContains(t, err, e)
}
})
t.Run("multiple errors, 2", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, "{\"name\": \"project\", \"runtime\": \"test\", \"backend\": 4, \"main\": {}}")
// Assert.
// The order can vary here, so we use Contains and not Equals.
expected := []string{
"2 errors occurred:",
"* #/main: expected string or null, but got object",
"* #/backend: expected object or null, but got number",
}
for _, e := range expected {
assert.ErrorContains(t, err, e)
}
})
t.Run("success", func(t *testing.T) {
t.Parallel()
// Act.
proj, err := writeAndLoad(t, "{\"name\": \"project\", \"runtime\": \"test\"}")
// Assert.
2022-09-02 17:25:45 +00:00
assert.NoError(t, err)
assert.Equal(t, tokens.PackageName("project"), proj.Name)
assert.Equal(t, "test", proj.Runtime.Name())
})
t.Run("null optionals should work", func(t *testing.T) {
t.Parallel()
// Act.
proj, err := writeAndLoad(t, "{\"name\": \"project\", \"runtime\": \"test\", "+
"\"description\": null, \"main\": null, \"backend\": null}")
// Assert.
2022-09-02 17:25:45 +00:00
assert.NoError(t, err)
assert.Nil(t, proj.Description)
assert.Equal(t, "", proj.Main)
})
}
func TestProjectLoadJSONInformativeErrors(t *testing.T) {
t.Parallel()
t.Run("a missing name attribute", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, `{"Name": "project", "runtime": "test"}`)
// Assert.
assert.ErrorContains(t, err, "project is missing a 'name' attribute")
assert.ErrorContains(t, err, "found 'Name' instead")
})
2022-09-16 16:05:40 +00:00
t.Run("a missing runtime attribute", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, `{"name": "project", "rutnime": "test"}`)
// Assert.
assert.ErrorContains(t, err, "project is missing a 'runtime' attribute")
assert.ErrorContains(t, err, "found 'rutnime' instead")
})
t.Run("a minor spelling mistake in a schema field", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, `{
"name": "project",
"runtime": "test",
"template": {
"displatName": "foo"
}
}`)
// Assert.
assert.ErrorContains(t, err, "'displatName' not allowed; did you mean 'displayName'?")
})
t.Run("a major spelling mistake in a schema field", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, `{
"name": "project",
"runtime": "test",
"template": {
"displayNameDisplayName": "foo"
}
}`)
// Assert.
assert.ErrorContains(t, err, "'displayNameDisplayName' not allowed")
assert.ErrorContains(t, err, "'displayNameDisplayName' not allowed; the allowed attributes are "+
"'config', 'description', 'displayName', 'important', 'metadata' and 'quickstart'")
})
t.Run("specific errors when only a single attribute is expected", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, `{
"name": "project",
"runtime": "test",
"backend": {
"url": "https://pulumi.com",
"name": "test"
}
}`)
// Assert.
assert.ErrorContains(t, err, "'name' not allowed")
assert.ErrorContains(t, err, "'name' not allowed; the only allowed attribute is 'url'")
})
t.Run("a minor spelling mistake even deeper in the schema", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, `{
"name": "project",
"runtime": "test",
"plugins": {
"providers": [
{
"nome": "test"
}
]
}
}`)
// Assert.
assert.ErrorContains(t, err, "'nome' not allowed; did you mean 'name'")
})
t.Run("a major spelling mistake even deeper in the schema", func(t *testing.T) {
t.Parallel()
// Act.
_, err := writeAndLoad(t, `{
"name": "project",
"runtime": "test",
"plugins": {
"providers": [
{
"displayName": "test"
}
]
}
}`)
// Assert.
assert.ErrorContains(t, err, "'displayName' not allowed")
assert.ErrorContains(t, err, "'displayName' not allowed; the allowed attributes are "+
"'name', 'path' and 'version'")
})
}
2022-09-02 12:13:41 +00:00
func deleteFile(t *testing.T, file *os.File) {
if file != nil {
err := os.Remove(file.Name())
assert.NoError(t, err, "Error while deleting file")
}
}
func loadProjectFromText(t *testing.T, content string) (*Project, error) {
tmp, err := os.CreateTemp("", "*.yaml")
assert.NoError(t, err)
path := tmp.Name()
all: Reformat with gofumpt Per team discussion, switching to gofumpt. [gofumpt][1] is an alternative, stricter alternative to gofmt. It addresses other stylistic concerns that gofmt doesn't yet cover. [1]: https://github.com/mvdan/gofumpt See the full list of [Added rules][2], but it includes: - Dropping empty lines around function bodies - Dropping unnecessary variable grouping when there's only one variable - Ensuring an empty line between multi-line functions - simplification (`-s` in gofmt) is always enabled - Ensuring multi-line function signatures end with `) {` on a separate line. [2]: https://github.com/mvdan/gofumpt#Added-rules gofumpt is stricter, but there's no lock-in. All gofumpt output is valid gofmt output, so if we decide we don't like it, it's easy to switch back without any code changes. gofumpt support is built into the tooling we use for development so this won't change development workflows. - golangci-lint includes a gofumpt check (enabled in this PR) - gopls, the LSP for Go, includes a gofumpt option (see [installation instrutions][3]) [3]: https://github.com/mvdan/gofumpt#installation This change was generated by running: ```bash gofumpt -w $(rg --files -g '*.go' | rg -v testdata | rg -v compilation_error) ``` The following files were manually tweaked afterwards: - pkg/cmd/pulumi/stack_change_secrets_provider.go: one of the lines overflowed and had comments in an inconvenient place - pkg/cmd/pulumi/destroy.go: `var x T = y` where `T` wasn't necessary - pkg/cmd/pulumi/policy_new.go: long line because of error message - pkg/backend/snapshot_test.go: long line trying to assign three variables in the same assignment I have included mention of gofumpt in the CONTRIBUTING.md.
2023-03-03 16:36:39 +00:00
err = os.WriteFile(path, []byte(content), 0o600)
assert.NoError(t, err)
defer deleteFile(t, tmp)
return LoadProject(path)
}
2022-09-22 15:32:18 +00:00
func loadProjectStackFromText(t *testing.T, project *Project, content string) (*ProjectStack, error) {
tmp, err := os.CreateTemp("", "*.yaml")
2022-09-22 15:32:18 +00:00
assert.NoError(t, err)
path := tmp.Name()
all: Reformat with gofumpt Per team discussion, switching to gofumpt. [gofumpt][1] is an alternative, stricter alternative to gofmt. It addresses other stylistic concerns that gofmt doesn't yet cover. [1]: https://github.com/mvdan/gofumpt See the full list of [Added rules][2], but it includes: - Dropping empty lines around function bodies - Dropping unnecessary variable grouping when there's only one variable - Ensuring an empty line between multi-line functions - simplification (`-s` in gofmt) is always enabled - Ensuring multi-line function signatures end with `) {` on a separate line. [2]: https://github.com/mvdan/gofumpt#Added-rules gofumpt is stricter, but there's no lock-in. All gofumpt output is valid gofmt output, so if we decide we don't like it, it's easy to switch back without any code changes. gofumpt support is built into the tooling we use for development so this won't change development workflows. - golangci-lint includes a gofumpt check (enabled in this PR) - gopls, the LSP for Go, includes a gofumpt option (see [installation instrutions][3]) [3]: https://github.com/mvdan/gofumpt#installation This change was generated by running: ```bash gofumpt -w $(rg --files -g '*.go' | rg -v testdata | rg -v compilation_error) ``` The following files were manually tweaked afterwards: - pkg/cmd/pulumi/stack_change_secrets_provider.go: one of the lines overflowed and had comments in an inconvenient place - pkg/cmd/pulumi/destroy.go: `var x T = y` where `T` wasn't necessary - pkg/cmd/pulumi/policy_new.go: long line because of error message - pkg/backend/snapshot_test.go: long line trying to assign three variables in the same assignment I have included mention of gofumpt in the CONTRIBUTING.md.
2023-03-03 16:36:39 +00:00
err = os.WriteFile(path, []byte(content), 0o600)
2022-09-22 15:32:18 +00:00
assert.NoError(t, err)
defer deleteFile(t, tmp)
return LoadProjectStack(project, path)
}
func loadProjectStackFromJSONText(t *testing.T, project *Project, content string) (*ProjectStack, error) {
tmp, err := os.CreateTemp("", "*.json")
assert.NoError(t, err)
path := tmp.Name()
err = os.WriteFile(path, []byte(content), 0o600)
assert.NoError(t, err)
defer deleteFile(t, tmp)
return LoadProjectStack(project, path)
}
func TestProjectLoadsConfigSchemas(t *testing.T) {
2022-09-02 12:13:41 +00:00
t.Parallel()
projectContent := `
name: test
runtime: dotnet
config:
integerSchemaFull:
type: integer
description: a very important value
default: 1
integerSchemaSimple: 20
textSchemaFull:
type: string
default: t3.micro
textSchemaSimple: t4.large
booleanSchemaFull:
type: boolean
default: true
booleanSchemaSimple: false
simpleArrayOfStrings:
type: array
items:
type: string
default: [hello]
arrayOfArrays:
type: array
items:
type: array
items:
type: string
secretString:
type: string
secret: true
`
project, err := loadProjectFromText(t, projectContent)
assert.NoError(t, err, "Should be able to load the project")
assert.Equal(t, 9, len(project.Config), "There are 9 config type definition")
// full integer config schema
integerSchemFull, ok := project.Config["integerSchemaFull"]
assert.True(t, ok, "should be able to read integerSchemaFull")
assert.Equal(t, "integer", integerSchemFull.TypeName())
assert.Equal(t, "a very important value", integerSchemFull.Description)
assert.Equal(t, 1, integerSchemFull.Default)
assert.False(t, integerSchemFull.Secret)
assert.Nil(t, integerSchemFull.Items, "Primtive config type doesn't have an items type")
integerSchemaSimple, ok := project.Config["integerSchemaSimple"]
assert.True(t, ok, "should be able to read integerSchemaSimple")
assert.Equal(t, "", integerSchemaSimple.TypeName(), "not explicitly typed")
assert.False(t, integerSchemaSimple.IsExplicitlyTyped())
assert.False(t, integerSchemaSimple.Secret)
assert.Equal(t, 20, integerSchemaSimple.Default, "Default integer value is parsed correctly")
textSchemaFull, ok := project.Config["textSchemaFull"]
assert.True(t, ok, "should be able to read textSchemaFull")
assert.Equal(t, "string", textSchemaFull.TypeName())
assert.False(t, textSchemaFull.Secret)
assert.Equal(t, "t3.micro", textSchemaFull.Default)
assert.Equal(t, "", textSchemaFull.Description)
textSchemaSimple, ok := project.Config["textSchemaSimple"]
assert.True(t, ok, "should be able to read textSchemaSimple")
assert.Equal(t, "", textSchemaSimple.TypeName(), "not explicitly typed")
assert.False(t, textSchemaSimple.IsExplicitlyTyped())
assert.False(t, textSchemaSimple.Secret)
assert.Equal(t, "t4.large", textSchemaSimple.Default)
booleanSchemaFull, ok := project.Config["booleanSchemaFull"]
assert.True(t, ok, "should be able to read booleanSchemaFull")
assert.Equal(t, "boolean", booleanSchemaFull.TypeName())
assert.False(t, booleanSchemaFull.Secret)
assert.Equal(t, true, booleanSchemaFull.Default)
booleanSchemaSimple, ok := project.Config["booleanSchemaSimple"]
assert.True(t, ok, "should be able to read booleanSchemaSimple")
assert.Equal(t, "", booleanSchemaSimple.TypeName(), "not explicitly typed")
assert.False(t, booleanSchemaSimple.IsExplicitlyTyped())
assert.False(t, booleanSchemaSimple.Secret)
assert.Equal(t, false, booleanSchemaSimple.Default)
simpleArrayOfStrings, ok := project.Config["simpleArrayOfStrings"]
assert.True(t, ok, "should be able to read simpleArrayOfStrings")
assert.Equal(t, "array", simpleArrayOfStrings.TypeName())
assert.False(t, simpleArrayOfStrings.Secret)
assert.NotNil(t, simpleArrayOfStrings.Items)
assert.Equal(t, "string", simpleArrayOfStrings.Items.Type)
arrayValues := simpleArrayOfStrings.Default.([]interface{})
assert.Equal(t, "hello", arrayValues[0])
arrayOfArrays, ok := project.Config["arrayOfArrays"]
assert.True(t, ok, "should be able to read arrayOfArrays")
assert.Equal(t, "array", arrayOfArrays.TypeName())
assert.False(t, arrayOfArrays.Secret)
assert.NotNil(t, arrayOfArrays.Items)
assert.Equal(t, "array", arrayOfArrays.Items.Type)
assert.NotNil(t, arrayOfArrays.Items.Items)
assert.Equal(t, "string", arrayOfArrays.Items.Items.Type)
secretString, ok := project.Config["secretString"]
assert.True(t, ok, "should be able to read secretString")
assert.Equal(t, "string", secretString.TypeName())
assert.Equal(t, "", secretString.Description)
assert.Equal(t, nil, secretString.Default)
assert.True(t, secretString.Secret)
assert.Nil(t, secretString.Items)
}
2022-09-02 17:25:45 +00:00
2022-09-22 15:32:18 +00:00
func getConfigValue(t *testing.T, stackConfig config.Map, key string) string {
parsedKey, err := config.ParseKey(key)
assert.NoErrorf(t, err, "There should be no error parsing the config key '%v'", key)
configValue, foundValue := stackConfig[parsedKey]
assert.Truef(t, foundValue, "Couldn't find a value for config key %v", key)
value, valueError := configValue.Value(config.NopDecrypter)
assert.NoErrorf(t, valueError, "Error while getting the value for key %v", key)
return value
}
func getConfigValueUnmarshalled(t *testing.T, stackConfig config.Map, key string) interface{} {
parsedKey, err := config.ParseKey(key)
assert.NoErrorf(t, err, "There should be no error parsing the config key '%v'", key)
configValue, foundValue := stackConfig[parsedKey]
assert.Truef(t, foundValue, "Couldn't find a value for config key %v", key)
valueJSON, valueError := configValue.Value(config.NopDecrypter)
assert.NoErrorf(t, valueError, "Error while getting the value for key %v", key)
var value interface{}
err = json.Unmarshal([]byte(valueJSON), &value)
assert.NoErrorf(t, err, "Error while unmarshalling value for key %v", key)
return value
}
2022-09-22 15:32:18 +00:00
func TestStackConfigIsInheritedFromProjectConfig(t *testing.T) {
2022-09-22 16:27:08 +00:00
t.Parallel()
2022-09-22 15:32:18 +00:00
projectYaml := `
name: test
runtime: dotnet
config:
instanceSize: t3.micro
instanceCount: 20
protect: true`
projectStackYaml := `
config:
test:instanceSize: t4.large`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
2022-09-22 15:32:18 +00:00
assert.NoError(t, configError, "Config override should be valid")
assert.Equal(t, 3, len(stack.Config), "Stack config now has three values")
// value of instanceSize is overwritten from the stack
assert.Equal(t, "t4.large", getConfigValue(t, stack.Config, "test:instanceSize"))
// instanceCount and protect are inherited from the project
assert.Equal(t, "20", getConfigValue(t, stack.Config, "test:instanceCount"))
assert.Equal(t, "true", getConfigValue(t, stack.Config, "test:protect"))
}
func TestNamespacedConfigValuesAreInheritedCorrectly(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
aws:region: us-west-1
pulumi:disable-default-providers: ["*"]
instanceSize: t3.micro`
projectStackYaml := `
config:
test:instanceSize: t4.large`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.NoError(t, configError, "Config override should be valid")
assert.Equal(t, 3, len(stack.Config), "Stack config now has three values")
// value of instanceSize is overwritten from the stack
assert.Equal(t, "t4.large", getConfigValue(t, stack.Config, "test:instanceSize"))
// aws:region is namespaced and is inherited from the project
assert.Equal(t, "us-west-1", getConfigValue(t, stack.Config, "aws:region"))
assert.Equal(t, "[\"*\"]", getConfigValue(t, stack.Config, "pulumi:disable-default-providers"))
assert.Equal(t, []interface{}{"*"}, getConfigValueUnmarshalled(t, stack.Config, "pulumi:disable-default-providers"))
}
func TestLoadingStackConfigWithoutNamespacingTheProject(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
aws:region: us-west-1
instanceSize: t3.micro`
projectStackYaml := `
config:
instanceSize: t4.large`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.NoError(t, configError, "Config override should be valid")
assert.Equal(t, 2, len(stack.Config), "Stack config now has three values")
// value of instanceSize is overwritten from the stack
assert.Equal(t, "t4.large", getConfigValue(t, stack.Config, "test:instanceSize"))
// aws:region is namespaced and is inherited from the project
assert.Equal(t, "us-west-1", getConfigValue(t, stack.Config, "aws:region"))
}
func TestUntypedProjectConfigValuesAreNotValidated(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
instanceSize: t3.micro
aws:region: us-west-1`
projectStackYaml := `
config:
instanceSize: 9999
aws:region: 42`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.NoError(t, configError, "Config override should be valid")
assert.Equal(t, 2, len(stack.Config), "Stack config now has three values")
// value of instanceSize is overwritten from the stack
assert.Equal(t, "9999", getConfigValue(t, stack.Config, "test:instanceSize"))
assert.Equal(t, "42", getConfigValue(t, stack.Config, "aws:region"))
}
func TestUntypedProjectConfigValuesWithOnlyDefaultOrOnlyValue(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
instanceSize:
default: t3.micro
2023-02-10 17:05:21 +00:00
region:
value: us-west-1`
projectStackYaml := `
config:
aws:answer: 42`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.NoError(t, configError, "Config override should be valid")
assert.Equal(t, 3, len(stack.Config), "Stack config now has three values")
// value of instanceSize is overwritten from the stack
assert.Equal(t, "t3.micro", getConfigValue(t, stack.Config, "test:instanceSize"))
assert.Equal(t, "us-west-1", getConfigValue(t, stack.Config, "test:region"))
assert.Equal(t, "42", getConfigValue(t, stack.Config, "aws:answer"))
}
func TestUntypedStackConfigValuesDoNeedProjectDeclaration(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
createVpc: true`
projectStackYaml := `
config:
instanceSize: 42`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.NoError(t, configError, "Config override should be valid")
assert.Equal(t, 2, len(stack.Config), "Stack config now has three values")
// value of instanceSize is overwritten from the stack
assert.Equal(t, "42", getConfigValue(t, stack.Config, "test:instanceSize"))
assert.Equal(t, "true", getConfigValue(t, stack.Config, "test:createVpc"))
}
func TestNamespacedProjectConfigShouldNotBeExplicitlyTyped(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
aws:region:
type: string
value:
region: us-west-1`
_, projectError := loadProjectFromText(t, projectYaml)
assert.ErrorContains(t, projectError,
"Configuration key 'aws:region' is not namespaced by the project and should not define a type")
}
func TestProjectConfigCannotHaveBothValueAndDefault(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
instanceSize:
type: string
default: t3.micro
value: t4.large`
_, projectError := loadProjectFromText(t, projectYaml)
assert.ErrorContains(t, projectError,
"project config 'instanceSize' cannot have both a 'default' and 'value' attribute")
}
func TestProjectConfigCannotBeTypedArrayWithoutItems(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
instanceSize:
type: array
default: [t3.micro, t4.large]`
_, projectError := loadProjectFromText(t, projectYaml)
assert.ErrorContains(t, projectError,
"The configuration key 'instanceSize' declares an array "+
"but does not specify the underlying type via the 'items' attribute")
}
func TestNamespacedProjectConfigShouldNotBeProvideDefault(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
aws:region:
default: us-west-1`
_, projectError := loadProjectFromText(t, projectYaml)
assert.ErrorContains(t, projectError,
"Configuration key 'aws:region' is not namespaced by the project and should not define a default value")
assert.ErrorContains(t, projectError,
"Did you mean to use the 'value' attribute instead of 'default'?")
}
func TestUntypedProjectConfigObjectValuesPassedDownToStack(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
instanceSize:
value:
hello: world
aws:config:
value:
region: us-west-1`
projectStackYaml := `
config:
aws:whatever: 42`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.NoError(t, configError, "Config override should be valid")
assert.Equal(t, 3, len(stack.Config), "Stack config now has three values")
// value of instanceSize is overwritten from the stack
assert.Equal(t, "{\"hello\":\"world\"}", getConfigValue(t, stack.Config, "test:instanceSize"))
assert.Equal(t, "{\"region\":\"us-west-1\"}", getConfigValue(t, stack.Config, "aws:config"))
assert.Equal(t, "42", getConfigValue(t, stack.Config, "aws:whatever"))
}
2022-09-22 15:32:18 +00:00
func TestStackConfigErrorsWhenStackValueIsNotCorrectlyTyped(t *testing.T) {
2022-09-22 16:27:08 +00:00
t.Parallel()
2022-09-22 15:32:18 +00:00
projectYaml := `
name: test
runtime: dotnet
config:
values:
type: array
items:
2022-09-22 15:32:18 +00:00
type: string
default: [value]`
projectStackYaml := `
config:
test:values: someValue
`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.ErrorContains(t, configError, "Stack 'dev' with configuration key 'values' must be of type 'array<string>'")
2022-09-22 15:32:18 +00:00
}
func TestLoadingConfigIsRewrittenToStackConfigDir(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config: ./some/path`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
assert.Equal(t, "./some/path", project.StackConfigDir, "Stack config dir is read from the config property")
assert.Equal(t, 0, len(project.Config), "Config should be empty")
}
func TestDefningBothConfigAndStackConfigDirErrorsOut(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config: ./some/path
stackConfigDir: ./some/other/path`
project, projectError := loadProjectFromText(t, projectYaml)
assert.Nil(t, project, "Should NOT be able to load the project")
assert.ErrorContains(t, projectError, "Should not use both config and stackConfigDir")
}
func TestConfigObjectAndStackConfigDirSuccessfullyLoadProject(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
stackConfigDir: ./some/other/path
config:
value: hello
`
project, projectError := loadProjectFromText(t, projectYaml)
assert.Nil(t, projectError, "There is no error")
assert.NotNil(t, project, "The project can be loaded correctly")
assert.Equal(t, "./some/other/path", project.StackConfigDir)
assert.Equal(t, 1, len(project.Config), "there is one config value")
}
2022-09-22 15:32:18 +00:00
func TestStackConfigIntegerTypeIsCorrectlyValidated(t *testing.T) {
2022-09-22 16:27:08 +00:00
t.Parallel()
2022-09-22 15:32:18 +00:00
projectYaml := `
name: test
runtime: dotnet
config:
importantNumber:
type: integer
`
projectStackYamlValid := `
config:
test:importantNumber: 20
`
projectStackYamlInvalid := `
config:
test:importantNumber: hello
`
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
ctx := context.Background()
2022-09-22 15:32:18 +00:00
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYamlValid)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
ctx,
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
2022-09-22 15:32:18 +00:00
assert.NoError(t, configError, "there should no config type error")
invalidStackConfig, stackError := loadProjectStackFromText(t, project, projectStackYamlInvalid)
assert.NoError(t, stackError, "Should be able to read the stack")
configError = ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
ctx,
"dev",
project,
esc.Value{},
invalidStackConfig.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.ErrorContains(t, configError,
2022-09-22 15:32:18 +00:00
"Stack 'dev' with configuration key 'importantNumber' must be of type 'integer'")
}
func TestStackConfigErrorsWhenMissingStackValueForConfigTypeWithNoDefault(t *testing.T) {
2022-09-22 16:27:08 +00:00
t.Parallel()
2022-09-22 15:32:18 +00:00
projectYaml := `
name: test
runtime: dotnet
config:
values:
type: array
items:
2022-09-22 15:32:18 +00:00
type: string`
projectStackYaml := ``
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.ErrorContains(t, configError, "Stack 'dev' is missing configuration value 'values'")
}
func TestStackConfigErrorsWhenMissingTwoStackValueForConfigTypeWithNoDefault(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
another:
type: string
values:
type: array
items:
type: string`
projectStackYaml := ``
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.ErrorContains(t, configError, "Stack 'dev' is missing configuration values 'another' and 'values'")
}
func TestStackConfigErrorsWhenMissingMultipleStackValueForConfigTypeWithNoDefault(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
hello:
type: integer
values:
type: array
items:
type: string
world:
type: string`
projectStackYaml := ``
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.ErrorContains(t, configError, "Stack 'dev' is missing configuration values 'hello', 'values' and 'world'")
}
func TestStackConfigDoesNotErrorWhenProjectHasNotDefinedConfig(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet`
projectStackYaml := `
config:
hello: 21
world: 42
another: 42`
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYaml)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
esc.Value{},
stack.Config,
config.NewPanicCrypter(),
config.NewPanicCrypter())
assert.Nil(t, configError, "there should not be a config type error")
2022-09-22 15:32:18 +00:00
}
func TestStackConfigSecretIsCorrectlyValidated(t *testing.T) {
t.Parallel()
projectYaml := `
name: test
runtime: dotnet
config:
importantNumber:
type: integer
secret: true
`
crypter := config.Base64Crypter
encryptedValue, err := crypter.EncryptValue(context.Background(), "20")
assert.NoError(t, err)
projectStackYamlValid := fmt.Sprintf(`
config:
test:importantNumber:
secure: %s
`, encryptedValue)
projectStackYamlInvalid := `
config:
test:importantNumber: 20
`
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
ctx := context.Background()
project, projectError := loadProjectFromText(t, projectYaml)
assert.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, projectStackYamlValid)
assert.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
ctx,
"dev",
project,
esc.Value{},
stack.Config,
crypter,
crypter)
assert.NoError(t, configError, "there should no config type error")
invalidStackConfig, stackError := loadProjectStackFromText(t, project, projectStackYamlInvalid)
assert.NoError(t, stackError, "Should be able to read the stack")
configError = ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
ctx,
"dev",
project,
esc.Value{},
invalidStackConfig.Config,
crypter,
crypter)
assert.ErrorContains(t, configError,
"Stack 'dev' with configuration key 'importantNumber' must be encrypted as it's secret")
}
//nolint:lll
func TestEnvironmentMerge(t *testing.T) {
t.Parallel()
projectYAML := `
name: test
runtime: nodejs`
stackYAML := `
config:
test:boolean: true
test:number: 42
test:string: foo
test:array:
- first
- second
test:object:
foo: bar
object:
baz: 42`
env := esc.NewValue(map[string]esc.Value{
"test:boolean": esc.NewValue(false),
"test:number": esc.NewValue(json.Number("42")),
"test:string": esc.NewValue("esc"),
"test:array": esc.NewValue([]esc.Value{esc.NewValue("second"), esc.NewValue("first")}),
"test:secret": esc.NewSecret("hunter2"),
"test:object": esc.NewValue(map[string]esc.Value{
"boolean": esc.NewValue(true),
"number": esc.NewValue(json.Number("42")),
"string": esc.NewValue("esc"),
"array": esc.NewValue([]esc.Value{esc.NewValue("first"), esc.NewValue("second")}),
"object": esc.NewValue(map[string]esc.Value{"foo": esc.NewValue("bar")}),
"foo": esc.NewValue("qux"),
}),
})
project, projectError := loadProjectFromText(t, projectYAML)
require.NoError(t, projectError, "Shold be able to load the project")
stack, stackError := loadProjectStackFromText(t, project, stackYAML)
require.NoError(t, stackError, "Should be able to read the stack")
configError := ValidateStackConfigAndApplyProjectConfig(
Lift context parameter for ApplyProjectConfig (#16012) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> `mergeConfig` uses `Crypter.Encrypt` that needs a context and was using `context.TODO()`. This lifts that to a context parameter and fixes up all call sites. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2024-04-22 06:37:34 +00:00
context.Background(),
"dev",
project,
env,
stack.Config,
config.Base64Crypter,
config.Base64Crypter)
require.NoError(t, configError, "there should not be a config type error")
secureKeys := stack.Config.SecureKeys()
assert.Equal(t, []config.Key{config.MustMakeKey("test", "secret")}, secureKeys)
m, err := stack.Config.Decrypt(config.Base64Crypter)
require.NoError(t, err)
expected := map[config.Key]string{
config.MustMakeKey("test", "array"): "[\"first\",\"second\"]",
config.MustMakeKey("test", "boolean"): "true",
config.MustMakeKey("test", "number"): "42",
config.MustMakeKey("test", "object"): "{\"array\":[\"first\",\"second\"],\"boolean\":true,\"foo\":\"bar\",\"number\":42,\"object\":{\"baz\":42,\"foo\":\"bar\"},\"string\":\"esc\"}",
config.MustMakeKey("test", "string"): "foo",
config.MustMakeKey("test", "secret"): "hunter2",
}
assert.Equal(t, expected, m)
}
func TestProjectLoadYAML(t *testing.T) {
t.Parallel()
2022-09-02 12:13:41 +00:00
// Test wrong type
_, err := loadProjectFromText(t, "\"hello\"")
assert.ErrorContains(t, err, "expected project to be an object")
2022-09-02 12:13:41 +00:00
// Test bad key
_, err = loadProjectFromText(t, "4: hello")
assert.ErrorContains(t, err, "expected only string keys, got '%!s(int=4)'")
2022-09-02 12:13:41 +00:00
// Test nested bad key
_, err = loadProjectFromText(t, "hello:\n 6: bad")
assert.ErrorContains(t, err, "project is missing a 'name' attribute")
2022-09-02 12:13:41 +00:00
// Test lack of name
_, err = loadProjectFromText(t, "{}")
assert.ErrorContains(t, err, "project is missing a 'name' attribute")
2022-09-02 12:13:41 +00:00
// Test bad name
_, err = loadProjectFromText(t, "name:")
assert.ErrorContains(t, err, "project is missing a non-empty string 'name' attribute")
2022-09-02 12:13:41 +00:00
// Test missing runtime
_, err = loadProjectFromText(t, "name: project")
assert.ErrorContains(t, err, "project is missing a 'runtime' attribute")
2022-09-02 12:13:41 +00:00
// Test other schema errors
_, err = loadProjectFromText(t, "name: project\nruntime: 4")
2022-09-02 17:25:45 +00:00
// These can vary in order, so contains not equals check
expected := []string{
"3 errors occurred:",
"* #/runtime: oneOf failed",
"* #/runtime: expected string, but got number",
all: Reformat with gofumpt Per team discussion, switching to gofumpt. [gofumpt][1] is an alternative, stricter alternative to gofmt. It addresses other stylistic concerns that gofmt doesn't yet cover. [1]: https://github.com/mvdan/gofumpt See the full list of [Added rules][2], but it includes: - Dropping empty lines around function bodies - Dropping unnecessary variable grouping when there's only one variable - Ensuring an empty line between multi-line functions - simplification (`-s` in gofmt) is always enabled - Ensuring multi-line function signatures end with `) {` on a separate line. [2]: https://github.com/mvdan/gofumpt#Added-rules gofumpt is stricter, but there's no lock-in. All gofumpt output is valid gofmt output, so if we decide we don't like it, it's easy to switch back without any code changes. gofumpt support is built into the tooling we use for development so this won't change development workflows. - golangci-lint includes a gofumpt check (enabled in this PR) - gopls, the LSP for Go, includes a gofumpt option (see [installation instrutions][3]) [3]: https://github.com/mvdan/gofumpt#installation This change was generated by running: ```bash gofumpt -w $(rg --files -g '*.go' | rg -v testdata | rg -v compilation_error) ``` The following files were manually tweaked afterwards: - pkg/cmd/pulumi/stack_change_secrets_provider.go: one of the lines overflowed and had comments in an inconvenient place - pkg/cmd/pulumi/destroy.go: `var x T = y` where `T` wasn't necessary - pkg/cmd/pulumi/policy_new.go: long line because of error message - pkg/backend/snapshot_test.go: long line trying to assign three variables in the same assignment I have included mention of gofumpt in the CONTRIBUTING.md.
2023-03-03 16:36:39 +00:00
"* #/runtime: expected object, but got number",
}
2022-09-02 17:25:45 +00:00
for _, e := range expected {
assert.ErrorContains(t, err, e)
2022-09-02 17:25:45 +00:00
}
2022-09-02 12:13:41 +00:00
_, err = loadProjectFromText(t, "name: project\nruntime: test\nbackend: 4\nmain: {}")
2022-09-02 17:25:45 +00:00
expected = []string{
"2 errors occurred:",
2022-09-16 15:38:14 +00:00
"* #/main: expected string or null, but got object",
all: Reformat with gofumpt Per team discussion, switching to gofumpt. [gofumpt][1] is an alternative, stricter alternative to gofmt. It addresses other stylistic concerns that gofmt doesn't yet cover. [1]: https://github.com/mvdan/gofumpt See the full list of [Added rules][2], but it includes: - Dropping empty lines around function bodies - Dropping unnecessary variable grouping when there's only one variable - Ensuring an empty line between multi-line functions - simplification (`-s` in gofmt) is always enabled - Ensuring multi-line function signatures end with `) {` on a separate line. [2]: https://github.com/mvdan/gofumpt#Added-rules gofumpt is stricter, but there's no lock-in. All gofumpt output is valid gofmt output, so if we decide we don't like it, it's easy to switch back without any code changes. gofumpt support is built into the tooling we use for development so this won't change development workflows. - golangci-lint includes a gofumpt check (enabled in this PR) - gopls, the LSP for Go, includes a gofumpt option (see [installation instrutions][3]) [3]: https://github.com/mvdan/gofumpt#installation This change was generated by running: ```bash gofumpt -w $(rg --files -g '*.go' | rg -v testdata | rg -v compilation_error) ``` The following files were manually tweaked afterwards: - pkg/cmd/pulumi/stack_change_secrets_provider.go: one of the lines overflowed and had comments in an inconvenient place - pkg/cmd/pulumi/destroy.go: `var x T = y` where `T` wasn't necessary - pkg/cmd/pulumi/policy_new.go: long line because of error message - pkg/backend/snapshot_test.go: long line trying to assign three variables in the same assignment I have included mention of gofumpt in the CONTRIBUTING.md.
2023-03-03 16:36:39 +00:00
"* #/backend: expected object or null, but got number",
}
2022-09-02 17:25:45 +00:00
for _, e := range expected {
assert.ErrorContains(t, err, e)
2022-09-02 17:25:45 +00:00
}
2022-09-02 12:13:41 +00:00
2022-09-02 12:23:32 +00:00
// Test success
proj, err := loadProjectFromText(t, "name: project\nruntime: test")
2022-09-02 12:23:32 +00:00
assert.NoError(t, err)
2022-09-02 17:25:45 +00:00
assert.Equal(t, tokens.PackageName("project"), proj.Name)
2022-09-02 12:23:32 +00:00
assert.Equal(t, "test", proj.Runtime.Name())
2022-09-16 15:38:14 +00:00
// Test null optionals should work
proj, err = loadProjectFromText(t, "name: project\nruntime: test\ndescription:\nmain: null\nbackend:\n")
2022-09-16 15:38:14 +00:00
assert.NoError(t, err)
assert.Nil(t, proj.Description)
assert.Equal(t, "", proj.Main)
2022-09-02 12:13:41 +00:00
}
2023-02-10 17:05:21 +00:00
func TestProjectSaveLoadRoundtrip(t *testing.T) {
t.Parallel()
tests := []struct {
name string
project Project
}{
{
name: "Numeric name",
project: Project{
Name: "1234",
Runtime: NewProjectRuntimeInfo("python", nil),
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
tmp, err := os.CreateTemp("", "*.yaml")
require.NoError(t, err)
defer deleteFile(t, tmp)
path := tmp.Name()
err = tt.project.Save(path)
require.NoError(t, err)
loadedProject, err := LoadProject(path)
require.NoError(t, err)
require.NotNil(t, loadedProject)
// Clear the raw data before we compare
loadedProject.raw = nil
assert.Equal(t, tt.project, *loadedProject)
})
}
}
func TestProjectEditRoundtrip(t *testing.T) {
t.Parallel()
tests := []struct {
name string
yaml string
edit func(*Project)
expected string
}{
{
name: "Change name",
yaml: "name: test\nruntime: python\n",
edit: func(proj *Project) { proj.Name = "new" },
expected: "name: new\nruntime: python\n",
},
{
name: "Add runtime option",
yaml: "name: test\nruntime: python\n",
edit: func(proj *Project) {
proj.Runtime = NewProjectRuntimeInfo(
proj.Runtime.Name(),
map[string]interface{}{
"setting": "test",
})
},
expected: "name: test\nruntime:\n name: python\n options:\n setting: test\n",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
tmp, err := os.CreateTemp("", "*.yaml")
require.NoError(t, err)
defer deleteFile(t, tmp)
path := tmp.Name()
err = os.WriteFile(path, []byte(tt.yaml), 0o600)
require.NoError(t, err)
loadedProject, err := LoadProject(path)
require.NoError(t, err)
require.NotNil(t, loadedProject)
tt.edit(loadedProject)
err = loadedProject.Save(path)
require.NoError(t, err)
actualYaml, err := os.ReadFile(path)
require.NoError(t, err)
assert.Equal(t, tt.expected, string(actualYaml))
})
}
}
func TestEnvironmentAppend(t *testing.T) {
t.Parallel()
t.Run("JSON list", func(t *testing.T) {
t.Parallel()
projectYaml := `name: test
runtime: yaml`
projectStackJSON := "{}"
project, err := loadProjectFromText(t, projectYaml)
require.NoError(t, err)
stack, err := loadProjectStackFromJSONText(t, project, projectStackJSON)
require.NoError(t, err)
stack.Environment = stack.Environment.Append("env")
marshaled, err := encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, "{\n \"environment\": [\n \"env\"\n ]\n}\n", string(marshaled))
stack.Environment = stack.Environment.Append("env2")
marshaled, err = encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, "{\n \"environment\": [\n \"env\",\n \"env2\"\n ]\n}\n", string(marshaled))
})
t.Run("JSON literal", func(t *testing.T) {
t.Parallel()
projectYaml := `name: test
runtime: yaml`
projectStackJSON := `{
"environment": {
"values": {
"pulumiConfig": {
"aws:region": "us-west-2"
}
}
}
}
`
project, err := loadProjectFromText(t, projectYaml)
require.NoError(t, err)
stack, err := loadProjectStackFromJSONText(t, project, projectStackJSON)
require.NoError(t, err)
expected := `{
"environment": {
"imports": [
"env"
],
"values": {
"pulumiConfig": {
"aws:region": "us-west-2"
}
}
}
}
`
stack.Environment = stack.Environment.Append("env")
marshaled, err := encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
expected = `{
"environment": {
"imports": [
"env",
"env2"
],
"values": {
"pulumiConfig": {
"aws:region": "us-west-2"
}
}
}
}
`
stack.Environment = stack.Environment.Append("env2")
marshaled, err = encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
})
t.Run("YAML list", func(t *testing.T) {
t.Parallel()
projectYaml := `name: test
runtime: yaml`
projectStackYaml := ""
project, err := loadProjectFromText(t, projectYaml)
require.NoError(t, err)
stack, err := loadProjectStackFromText(t, project, projectStackYaml)
require.NoError(t, err)
stack.Environment = stack.Environment.Append("env")
marshaled, err := encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, "environment:\n - env\n", string(marshaled))
stack.Environment = stack.Environment.Append("env2")
marshaled, err = encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, "environment:\n - env\n - env2\n", string(marshaled))
})
t.Run("YAML literal", func(t *testing.T) {
t.Parallel()
projectYaml := `name: test
runtime: yaml`
projectStackYaml := `environment:
values:
pulumiConfig:
aws:region: us-west-2`
project, err := loadProjectFromText(t, projectYaml)
require.NoError(t, err)
stack, err := loadProjectStackFromText(t, project, projectStackYaml)
require.NoError(t, err)
expected := `environment:
imports:
- env
values:
pulumiConfig:
aws:region: us-west-2
`
stack.Environment = stack.Environment.Append("env")
marshaled, err := encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
expected = `environment:
imports:
- env
- env2
values:
pulumiConfig:
aws:region: us-west-2
`
stack.Environment = stack.Environment.Append("env2")
marshaled, err = encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
})
}
func TestEnvironmentRemove(t *testing.T) {
t.Parallel()
t.Run("JSON list", func(t *testing.T) {
t.Parallel()
projectYaml := `name: test
runtime: yaml`
projectStackJSON := `{
"environment": [
"env2",
"env",
"env2"
]
}
`
project, err := loadProjectFromText(t, projectYaml)
require.NoError(t, err)
stack, err := loadProjectStackFromJSONText(t, project, projectStackJSON)
require.NoError(t, err)
expected := `{
"environment": [
"env2",
"env"
]
}
`
stack.Environment = stack.Environment.Remove("env2")
marshaled, err := encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
expected = `{
"environment": [
"env2"
]
}
`
stack.Environment = stack.Environment.Remove("env")
marshaled, err = encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
stack.Environment = stack.Environment.Remove("env2")
marshaled, err = encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, "{}\n", string(marshaled))
})
t.Run("JSON literal", func(t *testing.T) {
t.Parallel()
projectYaml := `name: test
runtime: yaml`
projectStackJSON := `{
"environment": {
"imports": [
{
"env2": {
"merge": false
}
},
"env",
"env2"
],
"values": {
"pulumiConfig": {
"aws:region": "us-west-2"
}
}
}
}
`
project, err := loadProjectFromText(t, projectYaml)
require.NoError(t, err)
stack, err := loadProjectStackFromJSONText(t, project, projectStackJSON)
require.NoError(t, err)
expected := `{
"environment": {
"imports": [
{
"env2": {
"merge": false
}
},
"env"
],
"values": {
"pulumiConfig": {
"aws:region": "us-west-2"
}
}
}
}
`
stack.Environment = stack.Environment.Remove("env2")
marshaled, err := encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
expected = `{
"environment": {
"imports": [
"env"
],
"values": {
"pulumiConfig": {
"aws:region": "us-west-2"
}
}
}
}
`
stack.Environment = stack.Environment.Remove("env2")
marshaled, err = encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
expected = `{
"environment": {
"imports": [],
"values": {
"pulumiConfig": {
"aws:region": "us-west-2"
}
}
}
}
`
stack.Environment = stack.Environment.Remove("env")
marshaled, err = encoding.JSON.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
})
t.Run("YAML list", func(t *testing.T) {
t.Parallel()
projectYaml := `name: test
runtime: yaml`
projectStackYaml := `environment:
- env2
- env
- env2
`
project, err := loadProjectFromText(t, projectYaml)
require.NoError(t, err)
stack, err := loadProjectStackFromText(t, project, projectStackYaml)
require.NoError(t, err)
expected := `environment:
- env2
- env
`
stack.Environment = stack.Environment.Remove("env2")
marshaled, err := encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
stack.Environment = stack.Environment.Remove("env")
marshaled, err = encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, "environment:\n - env2\n", string(marshaled))
stack.Environment = stack.Environment.Remove("env2")
marshaled, err = encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, "{}\n", string(marshaled))
})
t.Run("YAML literal", func(t *testing.T) {
t.Parallel()
projectYaml := `name: test
runtime: yaml`
projectStackYaml := `environment:
imports:
- {env2: {merge: false}}
- env
- env2
values:
pulumiConfig:
aws:region: us-west-2`
project, err := loadProjectFromText(t, projectYaml)
require.NoError(t, err)
stack, err := loadProjectStackFromText(t, project, projectStackYaml)
require.NoError(t, err)
expected := `environment:
imports:
- {env2: {merge: false}}
- env
values:
pulumiConfig:
aws:region: us-west-2
`
stack.Environment = stack.Environment.Remove("env2")
marshaled, err := encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
expected = `environment:
imports:
- env
values:
pulumiConfig:
aws:region: us-west-2
`
stack.Environment = stack.Environment.Remove("env2")
marshaled, err = encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
expected = `environment:
values:
pulumiConfig:
aws:region: us-west-2
`
stack.Environment = stack.Environment.Remove("env")
marshaled, err = encoding.YAML.Marshal(stack)
require.NoError(t, err)
assert.Equal(t, expected, string(marshaled))
})
}