Skip to content

Commit

Permalink
Deprecate Config, replace with StackConfigDir (#9145)
Browse files Browse the repository at this point in the history
* Deprecate Config, replace with StacksDirectory

* Add to CHANGELOG

* lint

* Table test + error if both keys are given

* Apply Parallel suggestion from Friel

Co-authored-by: Aaron Friel <mayreply@aaronfriel.com>

* Add compat note to changelog

* Remove Parallel

* Update CHANGELOG_PENDING.md

Co-authored-by: Vlad Gorodetsky <v@gor.io>

* nolint

* Update to stackConfigDir

* Update CHANGELOG_PENDING.md

* Fix symlinks in tests

Co-authored-by: Aaron Friel <mayreply@aaronfriel.com>
Co-authored-by: Vlad Gorodetsky <v@gor.io>
  • Loading branch information
3 people committed Mar 13, 2022
1 parent 2acb9db commit 2b3fbdb
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 7 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG_PENDING.md
Expand Up @@ -3,7 +3,10 @@
- [language/dotnet] - Updated Pulumi dotnet packages to use grpc-dotnet instead of grpc.
[#9149](https://github.com/pulumi/pulumi/pull/9149)

- [cli/config] Rename the `config` property in `Pulumi.yaml` to `stackConfigDir`. The `config` key will continue to be supported.
[#9145](https://github.com/pulumi/pulumi/pull/9145)

### Bug Fixes

[sdk/nodejs] - Fix uncaught error "ENOENT: no such file or directory" when an error occurs during the stack up
[#9065](https://github.com/pulumi/pulumi/issues/9065)
[#9065](https://github.com/pulumi/pulumi/issues/9065)
26 changes: 23 additions & 3 deletions sdk/go/common/workspace/paths.go
@@ -1,4 +1,4 @@
// Copyright 2016-2018, Pulumi Corporation.
// Copyright 2016-2022, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -98,8 +98,28 @@ func DetectProjectStackPath(stackName tokens.QName) (string, error) {
return "", err
}

return filepath.Join(filepath.Dir(projPath), proj.Config, fmt.Sprintf("%s.%s%s", ProjectFile, qnameFileName(stackName),
filepath.Ext(projPath))), nil
fileName := fmt.Sprintf("%s.%s%s", ProjectFile, qnameFileName(stackName), filepath.Ext(projPath))

// Back compat: StackConfigDir used to be called Config.
configValue, hasConfigValue := proj.Config.(string)
hasConfigValue = hasConfigValue && configValue != ""

if proj.StackConfigDir != "" {
// If config and stackConfigDir are both set return an error
if hasConfigValue {
return "", fmt.Errorf("can not set `config` and `stackConfigDir`, remove the `config` entry")
}

return filepath.Join(filepath.Dir(projPath), proj.StackConfigDir, fileName), nil
}

// Back compat: If StackConfigDir is not present and Config is given and it's a non-empty string use it
// for the stacks directory.
if hasConfigValue {
return filepath.Join(filepath.Dir(projPath), configValue, fileName), nil
}

return filepath.Join(filepath.Dir(projPath), fileName), nil
}

// DetectProjectPathFrom locates the closest project from the given path, searching "upwards" in the directory
Expand Down
117 changes: 117 additions & 0 deletions sdk/go/common/workspace/paths_test.go
@@ -0,0 +1,117 @@
// Copyright 2016-2022, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package workspace

import (
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
"github.com/stretchr/testify/assert"
)

// In the tests below we use temporary directories and then expect DetectProjectAndPath to return a path to
// that directory. However DetectProjectAndPath will do symlink resolution, while ioutil.TempDir normally does
// not. This can lead to asserts especially on macos where TmpDir will have returned /var/folders/XX, but
// after sym link resolution that is /private/var/folders/XX.
func mkTempDir(t *testing.T, pattern string) string {
tmpDir, err := ioutil.TempDir("", pattern)
assert.NoError(t, err)
result, err := filepath.EvalSymlinks(tmpDir)
assert.NoError(t, err)
return result
}

//nolint:paralleltest // Theses test use and change the current working directory
func TestDetectProjectAndPath(t *testing.T) {
tmpDir := mkTempDir(t, "TestDetectProjectAndPath")
cwd, err := os.Getwd()
assert.NoError(t, err)
defer func() { err := os.Chdir(cwd); assert.NoError(t, err) }()
err = os.Chdir(tmpDir)
assert.NoError(t, err)

yamlPath := filepath.Join(tmpDir, "Pulumi.yaml")
yamlContents :=
"name: some_project\ndescription: Some project\nruntime: nodejs\n"

err = os.WriteFile(yamlPath, []byte(yamlContents), 0600)
assert.NoError(t, err)

project, path, err := DetectProjectAndPath()
assert.NoError(t, err)
assert.Equal(t, yamlPath, path)
assert.Equal(t, tokens.PackageName("some_project"), project.Name)
assert.Equal(t, "Some project", *project.Description)
assert.Equal(t, "nodejs", project.Runtime.name)
}

//nolint:paralleltest // Theses test use and change the current working directory
func TestProjectStackPath(t *testing.T) {
expectedPath := func(expectedPath string) func(t *testing.T, projectDir, path string, err error) {
return func(t *testing.T, projectDir, path string, err error) {
assert.NoError(t, err)
assert.Equal(t, filepath.Join(projectDir, expectedPath), path)
}
}

tests := []struct {
name string
yamlContents string
validate func(t *testing.T, projectDir, path string, err error)
}{{
"WithoutStackConfigDir",
"name: some_project\ndescription: Some project\nruntime: nodejs\n",
expectedPath("Pulumi.my_stack.yaml"),
}, {
"WithStackConfigDir",
"name: some_project\ndescription: Some project\nruntime: nodejs\nstackConfigDir: stacks\n",
expectedPath(filepath.Join("stacks", "Pulumi.my_stack.yaml")),
}, {
"WithConfig",
"name: some_project\ndescription: Some project\nruntime: nodejs\nconfig: stacks\n",
expectedPath(filepath.Join("stacks", "Pulumi.my_stack.yaml")),
}, {
"WithBoth",
"name: some_project\ndescription: Some project\nruntime: nodejs\nconfig: stacksA\nstackConfigDir: stacksB\n",
func(t *testing.T, projectDir, path string, err error) {
assert.Error(t, err)
assert.Equal(t, "can not set `config` and `stackConfigDir`, remove the `config` entry", err.Error())
},
}}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
tmpDir := mkTempDir(t, "TestProjectStackPath")
cwd, err := os.Getwd()
assert.NoError(t, err)
defer func() { err := os.Chdir(cwd); assert.NoError(t, err) }()
err = os.Chdir(tmpDir)
assert.NoError(t, err)

err = os.WriteFile(
filepath.Join(tmpDir, "Pulumi.yaml"),
[]byte(tt.yamlContents),
0600)
assert.NoError(t, err)

path, err := DetectProjectStackPath("my_stack")
tt.validate(t, tmpDir, path, err)
})
}
}
10 changes: 7 additions & 3 deletions sdk/go/common/workspace/project.go
@@ -1,4 +1,4 @@
// Copyright 2016-2018, Pulumi Corporation.
// Copyright 2016-2022, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -87,8 +87,12 @@ type Project struct {
// License is the optional license governing this project's usage.
License *string `json:"license,omitempty" yaml:"license,omitempty"`

// Config indicates where to store the Pulumi.<stack-name>.yaml files, combined with the folder Pulumi.yaml is in.
Config string `json:"config,omitempty" yaml:"config,omitempty"`
// Config has been renamed to StackConfigDir.
Config interface{} `json:"config,omitempty" yaml:"config,omitempty"`

// StackConfigDir indicates where to store the Pulumi.<stack-name>.yaml files, combined with the folder
// Pulumi.yaml is in.
StackConfigDir string `json:"stackConfigDir,omitempty" yaml:"stackConfigDir,omitempty"`

// Template is an optional template manifest, if this project is a template.
Template *ProjectTemplate `json:"template,omitempty" yaml:"template,omitempty"`
Expand Down

0 comments on commit 2b3fbdb

Please sign in to comment.