pulumi/sdk/go/common/testing/environment.go

283 lines
9.4 KiB
Go
Raw Permalink Normal View History

// Copyright 2016-2022, Pulumi Corporation.
2018-05-22 19:43:36 +00:00
//
// 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 testing
import (
"bytes"
"fmt"
"io"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"sync"
"testing"
"github.com/pulumi/pulumi/sdk/v3/go/common/tools"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/fsutil"
"github.com/stretchr/testify/assert"
)
Initial support for passing URLs to `new` and `up` (#1727) * Initial support for passing URLs to `new` and `up` This PR adds initial support for `pulumi new` using Git under the covers to manage Pulumi templates, providing the same experience as before. You can now also optionally pass a URL to a Git repository, e.g. `pulumi new [<url>]`, including subdirectories within the repository, and arbitrary branches, tags, or commits. The following commands result in the same behavior from the user's perspective: - `pulumi new javascript` - `pulumi new https://github.com/pulumi/templates/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/master/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates/javascript` To specify an arbitrary branch, tag, or commit: - `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates/javascript` Branches and tags can include '/' separators, and `pulumi` will still find the right subdirectory. URLs to Gists are also supported, e.g.: `pulumi new https://gist.github.com/justinvp/6673959ceb9d2ac5a14c6d536cb871a6` If the specified subdirectory in the repository does not contain a `Pulumi.yaml`, it will look for subdirectories within containing `Pulumi.yaml` files, and prompt the user to choose a template, along the lines of how `pulumi new` behaves when no template is specified. The following commands result in the CLI prompting to choose a template: - `pulumi new` - `pulumi new https://github.com/pulumi/templates/templates` - `pulumi new https://github.com/pulumi/templates/tree/master/templates` - `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates` Of course, arbitrary branches, tags, or commits can be specified as well: - `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates` - `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates` - `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates` This PR also includes initial support for passing URLs to `pulumi up`, providing a streamlined way to deploy installable cloud applications with Pulumi, without having to manage source code locally before doing a deployment. For example, `pulumi up https://github.com/justinvp/aws` can be used to deploy a sample AWS app. The stack can be updated with different versions, e.g. `pulumi up https://github.com/justinvp/aws/tree/v2 -s <stack-to-update>` Config values can optionally be passed via command line flags, e.g. `pulumi up https://github.com/justinvp/aws -c aws:region=us-west-2 -c foo:bar=blah` Gists can also be used, e.g. `pulumi up https://gist.github.com/justinvp/62fde0463f243fcb49f5a7222e51bc76` * Fix panic when hitting ^C from "choose template" prompt * Add description to templates When running `pulumi new` without specifying a template, include the template description along with the name in the "choose template" display. ``` $ pulumi new Please choose a template: aws-go A minimal AWS Go program aws-javascript A minimal AWS JavaScript program aws-python A minimal AWS Python program aws-typescript A minimal AWS TypeScript program > go A minimal Go program hello-aws-javascript A simple AWS serverless JavaScript program javascript A minimal JavaScript program python A minimal Python program typescript A minimal TypeScript program ``` * React to changes to the pulumi/templates repo. We restructured the `pulumi/templates` repo to have all the templates in the root instead of in a `templates` subdirectory, so make the change here to no longer look for templates in `templates`. This also fixes an issue around using `Depth: 1` that I found while testing this. When a named template is used, we attempt to clone or pull from the `pulumi/templates` repo to `~/.pulumi/templates`. Having it go in this well-known directory allows us to maintain previous behavior around allowing offline use of templates. If we use `Depth: 1` for the initial clone, it will fail when attempting to pull when there are updates to the remote repository. Unfortunately, there's no built-in `--unshallow` support in `go-git` and setting a larger `Depth` doesn't appear to help. There may be a workaround, but for now, if we're cloning the pulumi templates directory to `~/.pulumi/templates`, we won't use `Depth: 1`. For template URLs, we will continue to use `Depth: 1` as we clone those to a temp directory (which gets deleted) that we'll never try to update. * List available templates in help text * Address PR Feedback * Don't show "Installing dependencies" message for `up` * Fix secrets handling When prompting for config, if the existing stack value is a secret, keep it a secret and mask the prompt. If the template says it should be secret, make it a secret. * Fix ${PROJECT} and ${DESCRIPTION} handling for `up` Templates used with `up` should already have a filled-in project name and description, but if it's a `new`-style template, that has `${PROJECT}` and/or `${DESCRIPTION}`, be helpful and just replace these with better values. * Fix stack handling Add a bool `setCurrent` param to `requireStack` to control whether the current stack should be saved in workspace settings. For the `up <url>` case, we don't want to save. Also, split the `up` code into two separate functions: one for the `up <url>` case and another for the normal `up` case where you have workspace in your current directory. While we may be able to combine them back into a single function, right now it's a bit cleaner being separate, even with some small amount of duplication. * Fix panic due to nil crypter Lazily get the crypter only if needed inside `promptForConfig`. * Embellish comment * Harden isPreconfiguredEmptyStack check Fix the code to check to make sure the URL specified on the command line matches the URL stored in the `pulumi:template` config value, and that the rest of the config from the stack satisfies the config requirements of the template.
2018-08-11 01:08:16 +00:00
const (
sdk/go: Remove 'nolint' directives from package docs Go treats comments that match the following regex as directives. //[a-z0-9]+:[a-z0-9] Comments that are directives don't show in an entity's documentation. https://github.com/golang/go/commit/5a550b695117f07a4f2454039a4871250cd3ed09#diff-f56160fd9fcea272966a8a1d692ad9f49206fdd8dbcbfe384865a98cd9bc2749R165 Our code has `//nolint` directives that now show in the API Reference. This is because these directives are in one of the following forms, which don't get this special treatment. // nolint:foo //nolint: foo This change fixes all such directives found by the regex: `// nolint|//nolint: `. See bottom of commit for command used for the fix. Verification: Here's the output of `go doc` on some entities before and after this change. Before ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi | head -n8 package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" nolint: lll, interfacer nolint: lll, interfacer const EnvOrganization = "PULUMI_ORGANIZATION" ... var ErrPlugins = errors.New("pulumi: plugins requested") ``` After ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi | head -n8 package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" const EnvOrganization = "PULUMI_ORGANIZATION" ... var ErrPlugins = errors.New("pulumi: plugins requested") func BoolRef(v bool) *bool func Float64Ref(v float64) *float64 func IntRef(v int) *int func IsSecret(o Output) bool ``` Before ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi URN_ package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" func URN_(o string) ResourceOption URN_ is an optional URN of a previously-registered resource of this type to read from the engine. nolint: revive ``` After: ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi URN_ package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" func URN_(o string) ResourceOption URN_ is an optional URN of a previously-registered resource of this type to read from the engine. ``` Note that golangci-lint offers a 'nolintlint' linter that finds such miuses of nolint, but it also finds other issues so I've deferred that to a follow up PR. Resolves #11785 Related: https://github.com/golangci/golangci-lint/issues/892 [git-generate] FILES=$(mktemp) rg -l '// nolint|//nolint: ' | tee "$FILES" | xargs perl -p -i -e ' s|// nolint|//nolint|g; s|//nolint: |//nolint:|g; ' rg '.go$' < "$FILES" | xargs gofmt -w -s
2023-01-06 00:07:45 +00:00
//nolint:gosec
Initial support for passing URLs to `new` and `up` (#1727) * Initial support for passing URLs to `new` and `up` This PR adds initial support for `pulumi new` using Git under the covers to manage Pulumi templates, providing the same experience as before. You can now also optionally pass a URL to a Git repository, e.g. `pulumi new [<url>]`, including subdirectories within the repository, and arbitrary branches, tags, or commits. The following commands result in the same behavior from the user's perspective: - `pulumi new javascript` - `pulumi new https://github.com/pulumi/templates/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/master/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates/javascript` To specify an arbitrary branch, tag, or commit: - `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates/javascript` Branches and tags can include '/' separators, and `pulumi` will still find the right subdirectory. URLs to Gists are also supported, e.g.: `pulumi new https://gist.github.com/justinvp/6673959ceb9d2ac5a14c6d536cb871a6` If the specified subdirectory in the repository does not contain a `Pulumi.yaml`, it will look for subdirectories within containing `Pulumi.yaml` files, and prompt the user to choose a template, along the lines of how `pulumi new` behaves when no template is specified. The following commands result in the CLI prompting to choose a template: - `pulumi new` - `pulumi new https://github.com/pulumi/templates/templates` - `pulumi new https://github.com/pulumi/templates/tree/master/templates` - `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates` Of course, arbitrary branches, tags, or commits can be specified as well: - `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates` - `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates` - `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates` This PR also includes initial support for passing URLs to `pulumi up`, providing a streamlined way to deploy installable cloud applications with Pulumi, without having to manage source code locally before doing a deployment. For example, `pulumi up https://github.com/justinvp/aws` can be used to deploy a sample AWS app. The stack can be updated with different versions, e.g. `pulumi up https://github.com/justinvp/aws/tree/v2 -s <stack-to-update>` Config values can optionally be passed via command line flags, e.g. `pulumi up https://github.com/justinvp/aws -c aws:region=us-west-2 -c foo:bar=blah` Gists can also be used, e.g. `pulumi up https://gist.github.com/justinvp/62fde0463f243fcb49f5a7222e51bc76` * Fix panic when hitting ^C from "choose template" prompt * Add description to templates When running `pulumi new` without specifying a template, include the template description along with the name in the "choose template" display. ``` $ pulumi new Please choose a template: aws-go A minimal AWS Go program aws-javascript A minimal AWS JavaScript program aws-python A minimal AWS Python program aws-typescript A minimal AWS TypeScript program > go A minimal Go program hello-aws-javascript A simple AWS serverless JavaScript program javascript A minimal JavaScript program python A minimal Python program typescript A minimal TypeScript program ``` * React to changes to the pulumi/templates repo. We restructured the `pulumi/templates` repo to have all the templates in the root instead of in a `templates` subdirectory, so make the change here to no longer look for templates in `templates`. This also fixes an issue around using `Depth: 1` that I found while testing this. When a named template is used, we attempt to clone or pull from the `pulumi/templates` repo to `~/.pulumi/templates`. Having it go in this well-known directory allows us to maintain previous behavior around allowing offline use of templates. If we use `Depth: 1` for the initial clone, it will fail when attempting to pull when there are updates to the remote repository. Unfortunately, there's no built-in `--unshallow` support in `go-git` and setting a larger `Depth` doesn't appear to help. There may be a workaround, but for now, if we're cloning the pulumi templates directory to `~/.pulumi/templates`, we won't use `Depth: 1`. For template URLs, we will continue to use `Depth: 1` as we clone those to a temp directory (which gets deleted) that we'll never try to update. * List available templates in help text * Address PR Feedback * Don't show "Installing dependencies" message for `up` * Fix secrets handling When prompting for config, if the existing stack value is a secret, keep it a secret and mask the prompt. If the template says it should be secret, make it a secret. * Fix ${PROJECT} and ${DESCRIPTION} handling for `up` Templates used with `up` should already have a filled-in project name and description, but if it's a `new`-style template, that has `${PROJECT}` and/or `${DESCRIPTION}`, be helpful and just replace these with better values. * Fix stack handling Add a bool `setCurrent` param to `requireStack` to control whether the current stack should be saved in workspace settings. For the `up <url>` case, we don't want to save. Also, split the `up` code into two separate functions: one for the `up <url>` case and another for the normal `up` case where you have workspace in your current directory. While we may be able to combine them back into a single function, right now it's a bit cleaner being separate, even with some small amount of duplication. * Fix panic due to nil crypter Lazily get the crypter only if needed inside `promptForConfig`. * Embellish comment * Harden isPreconfiguredEmptyStack check Fix the code to check to make sure the URL specified on the command line matches the URL stored in the `pulumi:template` config value, and that the rest of the config from the stack satisfies the config requirements of the template.
2018-08-11 01:08:16 +00:00
pulumiCredentialsPathEnvVar = "PULUMI_CREDENTIALS_PATH"
)
// Environment is an extension of the testing.T type that provides support for a test environment
// on the local disk. The Environment has a root directory (e.g. a newly created temp folder) and
// a current working directory (to virtually change directories).
type Environment struct {
*testing.T
Use a new PULUMI_HOME for every test environment (#15559) <!--- 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. --> Should help with issues like https://github.com/pulumi/pulumi/issues/15240, and other cases of test case contamination. Run every new `testing.Environment` with a new PULUMI_HOME. ## 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 - [x] 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-03-01 21:32:49 +00:00
// HomePath is the PULUMI_HOME directory for the environment
HomePath string
// RootPath is a new temp directory where the environment starts.
RootPath string
// Current working directory, defaults to the root path.
CWD string
// Backend to use for commands
Backend string
// Environment variables to add to the environment for commands (`key=value`).
Env []string
// Passphrase for config secrets, if any
Passphrase string
// Set to true to turn off setting PULUMI_CONFIG_PASSPHRASE.
NoPassphrase bool
// Set to true to use the local Pulumi dev build from ~/.pulumi-dev/bin/pulumi which get from `make install`
UseLocalPulumiBuild bool
// Content to pass on stdin, if any
Stdin io.Reader
}
// WriteYarnRCForTest writes a .yarnrc file which sets global configuration for every yarn inovcation. We use this
// to work around some test issues we see in Travis.
func WriteYarnRCForTest(root string) error {
// Write a .yarnrc file to pass --mutex network to all yarn invocations, since tests
// may run concurrently and yarn may fail if invoked concurrently
// https://github.com/yarnpkg/yarn/issues/683
// Also add --network-concurrency 1 since we've been seeing
// https://github.com/yarnpkg/yarn/issues/4563 as well
return os.WriteFile(
filepath.Join(root, ".yarnrc"),
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
[]byte("--mutex network\n--network-concurrency 1\n"), 0o600)
}
// NewGoEnvironment returns a new Environment object, located in a GOPATH temp directory.
func NewGoEnvironment(t *testing.T) *Environment {
testRoot, err := tools.CreateTemporaryGoFolder("test-env")
if err != nil {
t.Errorf("error creating test directory %s", err)
}
t.Logf("Created new go test environment")
return &Environment{
T: t,
RootPath: testRoot,
CWD: testRoot,
}
}
// NewEnvironment returns a new Environment object, located in a temp directory.
func NewEnvironment(t *testing.T) *Environment {
root, err := os.MkdirTemp("", "test-env")
assert.NoError(t, err, "creating temp directory")
assert.NoError(t, WriteYarnRCForTest(root), "writing .yarnrc file")
Use a new PULUMI_HOME for every test environment (#15559) <!--- 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. --> Should help with issues like https://github.com/pulumi/pulumi/issues/15240, and other cases of test case contamination. Run every new `testing.Environment` with a new PULUMI_HOME. ## 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 - [x] 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-03-01 21:32:49 +00:00
// We always use a clean PULUMI_HOME for each environment to avoid any potential conflicts with plugins or config.
home, err := os.MkdirTemp("", "test-env-home")
assert.NoError(t, err, "creating temp PULUMI_HOME directory")
t.Logf("Created new test environment: %v", root)
return &Environment{
T: t,
Use a new PULUMI_HOME for every test environment (#15559) <!--- 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. --> Should help with issues like https://github.com/pulumi/pulumi/issues/15240, and other cases of test case contamination. Run every new `testing.Environment` with a new PULUMI_HOME. ## 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 - [x] 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-03-01 21:32:49 +00:00
HomePath: home,
RootPath: root,
CWD: root,
}
}
// SetBackend sets the backend to use for commands in this environment.
func (e *Environment) SetBackend(backend string) {
e.Backend = backend
}
// SetEnvVars appends to the list of environment variables.
// According to https://pkg.go.dev/os/exec#Cmd.Env:
2022-09-14 02:12:02 +00:00
//
// If Env contains duplicate environment keys, only the last
// value in the slice for each duplicate key is used.
//
// So later values take precedence.
func (e *Environment) SetEnvVars(env ...string) {
e.Env = append(e.Env, env...)
}
// ImportDirectory copies a folder into the test environment.
func (e *Environment) ImportDirectory(path string) {
err := fsutil.CopyFile(e.CWD, path, nil)
if err != nil {
e.T.Fatalf("error importing directory: %v", err)
}
}
// DeleteEnvironment deletes the environment's RootPath, and everything underneath it.
func (e *Environment) DeleteEnvironment() {
e.Helper()
err := os.RemoveAll(e.RootPath)
if err != nil {
// In CI, Windows sometimes lags behind in marking a resource
// as unused. This causes otherwise passing tests to fail.
// So ignore errors during cleanup.
e.Logf("error cleaning up test directory %q: %v", e.RootPath, err)
}
}
2021-08-31 07:25:50 +00:00
// DeleteEnvironment deletes the environment's RootPath, and everything
// underneath it. It tolerates failing to delete the environment.
2021-08-31 07:54:07 +00:00
func (e *Environment) DeleteEnvironmentFallible() error {
2021-08-31 07:25:50 +00:00
e.Helper()
return os.RemoveAll(e.RootPath)
}
// DeleteIfNotFailed deletes the environment's RootPath if the test hasn't failed. Otherwise
// keeps the files around for aiding debugging.
func (e *Environment) DeleteIfNotFailed() {
if !e.T.Failed() {
e.DeleteEnvironment()
}
}
// PathExists returns whether or not a file or directory exists relative to Environment's working directory.
func (e *Environment) PathExists(p string) bool {
fullPath := path.Join(e.CWD, p)
_, err := os.Stat(fullPath)
return err == nil
}
var YarnInstallMutex sync.Mutex
// RunCommand runs the command expecting a zero exit code, returning stdout and stderr.
func (e *Environment) RunCommand(cmd string, args ...string) (string, string) {
// We don't want to time out on yarn installs.
if cmd == "yarn" {
YarnInstallMutex.Lock()
defer YarnInstallMutex.Unlock()
}
if e.UseLocalPulumiBuild {
home, err := os.UserHomeDir()
if err != nil {
e.Logf("Run Error: %v", err)
e.Fatalf("Ran command %v args %v and expected success. Instead got failure.", cmd, args)
}
if home != "" {
cmd = filepath.Join(home, ".pulumi-dev", "bin", "pulumi")
}
}
e.Helper()
stdout, stderr, err := e.GetCommandResults(cmd, args...)
if err != nil {
e.Logf("Run Error: %v", err)
e.Logf("STDOUT: %v", stdout)
e.Logf("STDERR: %v", stderr)
e.Fatalf("Ran command %v args %v and expected success. Instead got failure.", cmd, args)
}
return stdout, stderr
}
// RunCommandExpectError runs the command expecting a non-zero exit code, returning stdout and stderr.
func (e *Environment) RunCommandExpectError(cmd string, args ...string) (string, string) {
e.Helper()
stdout, stderr, err := e.GetCommandResults(cmd, args...)
if err == nil {
e.Errorf("Ran command %v args %v and expected failure. Instead got success.", cmd, args)
e.Logf("STDOUT: %v", stdout)
e.Logf("STDERR: %v", stderr)
}
return stdout, stderr
}
Remove the need to `pulumi init` for the local backend This change removes the need to `pulumi init` when targeting the local backend. A fair amount of the change lays the foundation that the next set of changes to stop having `pulumi init` be used for cloud stacks as well. Previously, `pulumi init` logically did two things: 1. It created the bookkeeping directory for local stacks, this was stored in `<repository-root>/.pulumi`, where `<repository-root>` was the path to what we belived the "root" of your project was. In the case of git repositories, this was the directory that contained your `.git` folder. 2. It recorded repository information in `<repository-root>/.pulumi/repository.json`. This was used by the cloud backend when computing what project to interact with on Pulumi.com The new identity model will remove the need for (2), since we only need an owner and stack name to fully qualify a stack on pulumi.com, so it's easy enough to stop creating a folder just for that. However, for the local backend, we need to continue to retain some information about stacks (e.g. checkpoints, history, etc). In addition, we need to store our workspace settings (which today just contains the selected stack) somehere. For state stored by the local backend, we change the URL scheme from `local://` to `local://<optional-root-path>`. When `<optional-root-path>` is unset, it defaults to `$HOME`. We create our `.pulumi` folder in that directory. This is important because stack names now must be unique within the backend, but we have some tests using local stacks which use fixed stack names, so each integration test really wants its own "view" of the world. For the workspace settings, we introduce a new `workspaces` directory in `~/.pulumi`. In this folder we write the workspace settings file for each project. The file name is the name of the project, combined with the SHA1 of the path of the project file on disk, to ensure that multiple pulumi programs with the same project name have different workspace settings. This does mean that moving a project's location on disk will cause the CLI to "forget" what the selected stack was, which is unfortunate, but not the end of the world. If this ends up being a big pain point, we can certianly try to play games in the future (for example, if we saw a .git folder in a parent folder, we could store data in there). With respect to compatibility, we don't attempt to migrate older files to their newer locations. For long lived stacks managed using the local backend, we can provide information on where to move things to. For all stacks (regardless of backend) we'll require the user to `pulumi stack select` their stack again, but that seems like the correct trade-off vs writing complicated upgrade code.
2018-04-16 23:15:10 +00:00
// LocalURL returns a URL that uses the "fire and forget", storing its data inside the test folder (so multiple tests)
// may reuse stack names.
func (e *Environment) LocalURL() string {
return "file://" + filepath.ToSlash(e.RootPath)
Remove the need to `pulumi init` for the local backend This change removes the need to `pulumi init` when targeting the local backend. A fair amount of the change lays the foundation that the next set of changes to stop having `pulumi init` be used for cloud stacks as well. Previously, `pulumi init` logically did two things: 1. It created the bookkeeping directory for local stacks, this was stored in `<repository-root>/.pulumi`, where `<repository-root>` was the path to what we belived the "root" of your project was. In the case of git repositories, this was the directory that contained your `.git` folder. 2. It recorded repository information in `<repository-root>/.pulumi/repository.json`. This was used by the cloud backend when computing what project to interact with on Pulumi.com The new identity model will remove the need for (2), since we only need an owner and stack name to fully qualify a stack on pulumi.com, so it's easy enough to stop creating a folder just for that. However, for the local backend, we need to continue to retain some information about stacks (e.g. checkpoints, history, etc). In addition, we need to store our workspace settings (which today just contains the selected stack) somehere. For state stored by the local backend, we change the URL scheme from `local://` to `local://<optional-root-path>`. When `<optional-root-path>` is unset, it defaults to `$HOME`. We create our `.pulumi` folder in that directory. This is important because stack names now must be unique within the backend, but we have some tests using local stacks which use fixed stack names, so each integration test really wants its own "view" of the world. For the workspace settings, we introduce a new `workspaces` directory in `~/.pulumi`. In this folder we write the workspace settings file for each project. The file name is the name of the project, combined with the SHA1 of the path of the project file on disk, to ensure that multiple pulumi programs with the same project name have different workspace settings. This does mean that moving a project's location on disk will cause the CLI to "forget" what the selected stack was, which is unfortunate, but not the end of the world. If this ends up being a big pain point, we can certianly try to play games in the future (for example, if we saw a .git folder in a parent folder, we could store data in there). With respect to compatibility, we don't attempt to migrate older files to their newer locations. For long lived stacks managed using the local backend, we can provide information on where to move things to. For all stacks (regardless of backend) we'll require the user to `pulumi stack select` their stack again, but that seems like the correct trade-off vs writing complicated upgrade code.
2018-04-16 23:15:10 +00:00
}
// GetCommandResults runs the given command and args in the Environments CWD, returning
// STDOUT, STDERR, and the result of os/exec.Command{}.Run.
func (e *Environment) GetCommandResults(command string, args ...string) (string, string, error) {
return e.GetCommandResultsIn(e.CWD, command, args...)
}
// GetCommandResultsIn runs the given command and args in the given directory, returning
// STDOUT, STDERR, and the result of os/exec.Command{}.Run.
func (e *Environment) GetCommandResultsIn(dir string, command string, args ...string) (string, string, error) {
e.T.Helper()
e.T.Logf("Running command %v %v", command, strings.Join(args, " "))
// Buffer STDOUT and STDERR so we can return them later.
var outBuffer bytes.Buffer
var errBuffer bytes.Buffer
passphrase := "correct horse battery staple"
if e.Passphrase != "" {
passphrase = e.Passphrase
}
sdk/go: Remove 'nolint' directives from package docs Go treats comments that match the following regex as directives. //[a-z0-9]+:[a-z0-9] Comments that are directives don't show in an entity's documentation. https://github.com/golang/go/commit/5a550b695117f07a4f2454039a4871250cd3ed09#diff-f56160fd9fcea272966a8a1d692ad9f49206fdd8dbcbfe384865a98cd9bc2749R165 Our code has `//nolint` directives that now show in the API Reference. This is because these directives are in one of the following forms, which don't get this special treatment. // nolint:foo //nolint: foo This change fixes all such directives found by the regex: `// nolint|//nolint: `. See bottom of commit for command used for the fix. Verification: Here's the output of `go doc` on some entities before and after this change. Before ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi | head -n8 package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" nolint: lll, interfacer nolint: lll, interfacer const EnvOrganization = "PULUMI_ORGANIZATION" ... var ErrPlugins = errors.New("pulumi: plugins requested") ``` After ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi | head -n8 package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" const EnvOrganization = "PULUMI_ORGANIZATION" ... var ErrPlugins = errors.New("pulumi: plugins requested") func BoolRef(v bool) *bool func Float64Ref(v float64) *float64 func IntRef(v int) *int func IsSecret(o Output) bool ``` Before ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi URN_ package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" func URN_(o string) ResourceOption URN_ is an optional URN of a previously-registered resource of this type to read from the engine. nolint: revive ``` After: ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi URN_ package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" func URN_(o string) ResourceOption URN_ is an optional URN of a previously-registered resource of this type to read from the engine. ``` Note that golangci-lint offers a 'nolintlint' linter that finds such miuses of nolint, but it also finds other issues so I've deferred that to a follow up PR. Resolves #11785 Related: https://github.com/golangci/golangci-lint/issues/892 [git-generate] FILES=$(mktemp) rg -l '// nolint|//nolint: ' | tee "$FILES" | xargs perl -p -i -e ' s|// nolint|//nolint|g; s|//nolint: |//nolint:|g; ' rg '.go$' < "$FILES" | xargs gofmt -w -s
2023-01-06 00:07:45 +00:00
//nolint:gas
cmd := exec.Command(command, args...)
cmd.Dir = dir
if e.Stdin != nil {
cmd.Stdin = e.Stdin
}
cmd.Stdout = &outBuffer
cmd.Stderr = &errBuffer
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", pulumiCredentialsPathEnvVar, e.RootPath))
cmd.Env = append(cmd.Env, "PULUMI_DEBUG_COMMANDS=true")
Use a new PULUMI_HOME for every test environment (#15559) <!--- 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. --> Should help with issues like https://github.com/pulumi/pulumi/issues/15240, and other cases of test case contamination. Run every new `testing.Environment` with a new PULUMI_HOME. ## 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 - [x] 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-03-01 21:32:49 +00:00
cmd.Env = append(cmd.Env, "PULUMI_HOME="+e.HomePath)
if !e.NoPassphrase {
Enable perfsprint linter (#14813) <!--- 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. --> Prompted by a comment in another review: https://github.com/pulumi/pulumi/pull/14654#discussion_r1419995945 This lints that we don't use `fmt.Errorf` when `errors.New` will suffice, it also covers a load of other cases where `Sprintf` is sub-optimal. Most of these edits were made by running `perfsprint --fix`. ## 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 - [x] 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. -->
2023-12-12 12:19:42 +00:00
cmd.Env = append(cmd.Env, "PULUMI_CONFIG_PASSPHRASE="+passphrase)
}
if e.Backend != "" {
Enable perfsprint linter (#14813) <!--- 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. --> Prompted by a comment in another review: https://github.com/pulumi/pulumi/pull/14654#discussion_r1419995945 This lints that we don't use `fmt.Errorf` when `errors.New` will suffice, it also covers a load of other cases where `Sprintf` is sub-optimal. Most of these edits were made by running `perfsprint --fix`. ## 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 - [x] 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. -->
2023-12-12 12:19:42 +00:00
cmd.Env = append(cmd.Env, "PULUMI_BACKEND_URL="+e.Backend)
}
// According to https://pkg.go.dev/os/exec#Cmd.Env:
// If Env contains duplicate environment keys, only the last
// value in the slice for each duplicate key is used.
// By putting `append e.Env` last, we allow our users to override variables we include.
cmd.Env = append(cmd.Env, e.Env...)
runErr := cmd.Run()
return outBuffer.String(), errBuffer.String(), runErr
}
// WriteTestFile writes a new test file relative to the Environment's CWD with the given contents.
// Aborts the underlying test on any errors.
func (e *Environment) WriteTestFile(filename string, contents string) {
filename = filepath.Join(e.CWD, filename)
dir := filepath.Dir(filename)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
e.T.Fatalf("error making directories for test file (%v): %v", filename, err)
}
if err := os.WriteFile(filename, []byte(contents), os.ModePerm); err != nil {
e.T.Fatalf("writing test file (%v): %v", filename, err)
}
}