[Automation API] remove stack name validation and fqsn enforcement (#5337)

This commit is contained in:
Evan Boyle 2020-09-14 17:45:07 -07:00 committed by GitHub
parent 855f1fd1cd
commit c05ac500da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 292 additions and 312 deletions

View file

@ -3,6 +3,8 @@ CHANGELOG
## HEAD (Unreleased)
- Relax stack name validations for Automation API [#5337](https://github.com/pulumi/pulumi/pull/5337)
- Allow Pulumi to read a passphrase file, via `PULUMI_CONFIG_PASSPHRASE_FILE` to interact
with the passphrase secrets provider. Pulumi will first try and use the `PULUMI_CONFIG_PASSPHRASE`
to get the passphrase then will check `PULUMI_CONFIG_PASSPHRASE_FILE` and then all through to

View file

@ -38,7 +38,7 @@ In addition to fine-grained building blocks, Automation API provides three out o
```
3. Programs defined as a function alongside your Automation API code (NewStackInlineSource)
```go
stack, err := NewStackInlineSource(ctx, "myOrg/myProj/myStack", func(pCtx *pulumi.Context) error {
stack, err := NewStackInlineSource(ctx, "myOrg/myProj/myStack", "myProj", func(pCtx *pulumi.Context) error {
bucket, err := s3.NewBucket(pCtx, "bucket", nil)
if err != nil {
return err

View file

@ -31,11 +31,11 @@ func TestConcurrentUpdateError(t *testing.T) {
ctx := context.Background()
pName := "conflict_error"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "conflict_error")
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -82,10 +82,10 @@ func TestInlineConcurrentUpdateError(t *testing.T) {
ctx := context.Background()
pName := "inline_conflict_error"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
// initialize
s, err := NewStackInlineSource(ctx, fqsn, func(ctx *pulumi.Context) error {
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
time.Sleep(1 * time.Second)
ctx.Export("exp_static", pulumi.String("foo"))
return nil
@ -137,11 +137,11 @@ const compilationErrProj = "compilation_error"
func TestCompilationErrorGo(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, compilationErrProj, sName)
stackName := FullyQualifiedStackName(pulumiOrg, compilationErrProj, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "compilation_error", "go")
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -169,7 +169,7 @@ func TestCompilationErrorGo(t *testing.T) {
func TestSelectStack404Error(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, "testproj", sName)
stackName := FullyQualifiedStackName(pulumiOrg, "testproj", sName)
// initialize
pDir := filepath.Join(".", "test", "testproj")
@ -181,7 +181,7 @@ func TestSelectStack404Error(t *testing.T) {
}
// attempt to select stack that has not been created.
_, err = SelectStack(ctx, fqsn, w)
_, err = SelectStack(ctx, stackName, w)
assert.NotNil(t, err)
assert.True(t, IsSelectStack404Error(err))
}
@ -189,11 +189,11 @@ func TestSelectStack404Error(t *testing.T) {
func TestCreateStack409Error(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, "testproj", sName)
stackName := FullyQualifiedStackName(pulumiOrg, "testproj", sName)
// initialize first stack
pDir := filepath.Join(".", "test", "testproj")
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -214,7 +214,7 @@ func TestCreateStack409Error(t *testing.T) {
}
// attempt to create a dupe stack.
_, err = NewStack(ctx, fqsn, w)
_, err = NewStack(ctx, stackName, w)
assert.NotNil(t, err)
assert.True(t, IsCreateStack409Error(err))
}
@ -222,11 +222,11 @@ func TestCreateStack409Error(t *testing.T) {
func TestCompilationErrorDotnet(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, compilationErrProj, sName)
stackName := FullyQualifiedStackName(pulumiOrg, compilationErrProj, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "compilation_error", "dotnet")
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -254,7 +254,7 @@ func TestCompilationErrorDotnet(t *testing.T) {
func TestCompilationErrorTypescript(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, compilationErrProj, sName)
stackName := FullyQualifiedStackName(pulumiOrg, compilationErrProj, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "compilation_error", "typescript")
@ -267,7 +267,7 @@ func TestCompilationErrorTypescript(t *testing.T) {
t.FailNow()
}
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -297,11 +297,11 @@ const runtimeErrProj = "runtime_error"
func TestRuntimeErrorGo(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
stackName := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "runtime_error", "go")
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -329,10 +329,10 @@ func TestRuntimeErrorGo(t *testing.T) {
func TestRuntimeErrorInlineGo(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
stackName := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
// initialize
s, err := NewStackInlineSource(ctx, fqsn, func(ctx *pulumi.Context) error {
s, err := NewStackInlineSource(ctx, stackName, runtimeErrProj, func(ctx *pulumi.Context) error {
var x []string
ctx.Export("a", pulumi.String(x[0]))
return nil
@ -366,7 +366,7 @@ func TestRuntimeErrorInlineGo(t *testing.T) {
func TestRuntimeErrorPython(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
stackName := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "runtime_error", "python")
@ -379,7 +379,7 @@ func TestRuntimeErrorPython(t *testing.T) {
t.FailNow()
}
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -407,7 +407,7 @@ func TestRuntimeErrorPython(t *testing.T) {
func TestRuntimeErrorJavascript(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
stackName := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "runtime_error", "javascript")
@ -420,7 +420,7 @@ func TestRuntimeErrorJavascript(t *testing.T) {
t.FailNow()
}
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -448,7 +448,7 @@ func TestRuntimeErrorJavascript(t *testing.T) {
func TestRuntimeErrorTypescript(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
stackName := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "runtime_error", "typescript")
@ -461,7 +461,7 @@ func TestRuntimeErrorTypescript(t *testing.T) {
t.FailNow()
}
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -489,11 +489,11 @@ func TestRuntimeErrorTypescript(t *testing.T) {
func TestRuntimeErrorDotnet(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
stackName := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "runtime_error", "dotnet")
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()

View file

@ -36,8 +36,9 @@ func Example() error {
ctx := context.Background()
// This stack creates an output
fqsn := FullyQualifiedStackName("myOrg", "projA", "devStack")
stackA, err := NewStackInlineSource(ctx, fqsn, func(pCtx *pulumi.Context) error {
projA := "projA"
stackName := FullyQualifiedStackName("myOrg", projA, "devStack")
stackA, err := NewStackInlineSource(ctx, stackName, projA, func(pCtx *pulumi.Context) error {
pCtx.Export("outputA", pulumi.String("valueA"))
return nil
})
@ -51,8 +52,9 @@ func Example() error {
}
// this stack creates an uses stackA's output to create a new output
fqsn = FullyQualifiedStackName("myOrg", "projB", "devStack")
stackB, err := NewStackInlineSource(ctx, fqsn, func(pCtx *pulumi.Context) error {
projB := "projB"
stackName = FullyQualifiedStackName("myOrg", projB, "devStack")
stackB, err := NewStackInlineSource(ctx, stackName, projB, func(pCtx *pulumi.Context) error {
// output a new value "valueA/valueB"
pCtx.Export(
"outputB",
@ -78,10 +80,10 @@ func Example() error {
}
func ExampleFullyQualifiedStackName() {
fqsn := FullyQualifiedStackName("myOrgName", "myProjectName", "myStackName")
stackName := FullyQualifiedStackName("myOrgName", "myProjectName", "myStackName")
// "myOrgName/myProjectName/myStackName"
ctx := context.Background()
_, _ = NewStackLocalSource(ctx, fqsn, filepath.Join(".", "project"))
_, _ = NewStackLocalSource(ctx, stackName, filepath.Join(".", "project"))
}
func ExampleIsCompilationError() {
@ -142,12 +144,6 @@ func ExampleIsUnexpectedEngineError() {
}
}
func ExampleValidateFullyQualifiedStackName() {
badFqsn := "project/stack"
// false
fmt.Println(ValidateFullyQualifiedStackName(badFqsn))
}
func ExampleConfigMap() {
cfg := ConfigMap{
"plaintext": {Value: "unencrypted"},
@ -180,7 +176,7 @@ func ExampleDestroyResult() {
func ExampleGitRepo() {
ctx := context.Background()
pName := "go_remote_proj"
fqsn := FullyQualifiedStackName("myOrg", pName, "myStack")
stackName := FullyQualifiedStackName("myOrg", pName, "myStack")
// we'll compile a the program into an executable with the name "examplesBinary"
binName := "examplesBinary"
@ -203,7 +199,7 @@ func ExampleGitRepo() {
}
// initialize a stack from the git repo, specifying our project override
NewStackRemoteSource(ctx, fqsn, repo, Project(project))
NewStackRemoteSource(ctx, stackName, repo, Project(project))
}
func ExampleGitRepo_personalAccessToken() {
@ -452,40 +448,40 @@ func ExampleLocalWorkspace_RefreshConfig() {
ctx := context.Background()
// create a workspace from a local project
w, _ := NewLocalWorkspace(ctx, WorkDir(filepath.Join(".", "program")))
fqsnA := FullyQualifiedStackName("org", "proj", "stackA")
stackNameA := FullyQualifiedStackName("org", "proj", "stackA")
// get the last deployed config from stack A
// this overwrites config in pulumi.stackA.yaml
cfg, _ := w.RefreshConfig(ctx, fqsnA)
cfg, _ := w.RefreshConfig(ctx, stackNameA)
// add a key to the ConfigMap
cfg["addition_config_key"] = ConfigValue{Value: "additional_config_value"}
// create a new stack
fqsnB := FullyQualifiedStackName("org", "proj", "stackB")
w.CreateStack(ctx, fqsnB)
stackNameB := FullyQualifiedStackName("org", "proj", "stackB")
w.CreateStack(ctx, stackNameB)
// save the modified config to stackB
w.SetAllConfig(ctx, fqsnB, cfg)
w.SetAllConfig(ctx, stackNameB, cfg)
}
func ExampleLocalWorkspace_RemoveAllConfig() {
ctx := context.Background()
// create a workspace from a local project
w, _ := NewLocalWorkspace(ctx, WorkDir(filepath.Join(".", "program")))
fqsn := FullyQualifiedStackName("org", "proj", "stackA")
stackName := FullyQualifiedStackName("org", "proj", "stackA")
// get all config currently set in the workspace
cfg, _ := w.GetAllConfig(ctx, fqsn)
cfg, _ := w.GetAllConfig(ctx, stackName)
var keys []string
for k := range cfg {
keys = append(keys, k)
}
// remove those config values
_ = w.RemoveAllConfig(ctx, fqsn, keys)
_ = w.RemoveAllConfig(ctx, stackName, keys)
}
func ExampleLocalWorkspace_RemoveConfig() {
ctx := context.Background()
// create a workspace from a local project
w, _ := NewLocalWorkspace(ctx, WorkDir(filepath.Join(".", "program")))
fqsn := FullyQualifiedStackName("org", "proj", "stackA")
_ = w.RemoveConfig(ctx, fqsn, "key_to_remove")
stackName := FullyQualifiedStackName("org", "proj", "stackA")
_ = w.RemoveConfig(ctx, stackName, "key_to_remove")
}
func ExampleLocalWorkspace_RemovePlugin() {
@ -499,33 +495,33 @@ func ExampleLocalWorkspace_RemoveStack() {
ctx := context.Background()
// create a workspace from a local project
w, _ := NewLocalWorkspace(ctx, WorkDir(filepath.Join(".", "program")))
fqsn := FullyQualifiedStackName("org", "proj", "stack")
_ = w.RemoveStack(ctx, fqsn)
stackName := FullyQualifiedStackName("org", "proj", "stack")
_ = w.RemoveStack(ctx, stackName)
}
func ExampleLocalWorkspace_SelectStack() {
ctx := context.Background()
// create a workspace from a local project
w, _ := NewLocalWorkspace(ctx, WorkDir(filepath.Join(".", "program")))
fqsn := FullyQualifiedStackName("org", "proj", "existing_stack")
_ = w.SelectStack(ctx, fqsn)
stackName := FullyQualifiedStackName("org", "proj", "existing_stack")
_ = w.SelectStack(ctx, stackName)
}
func ExampleLocalWorkspace_SetAllConfig() {
ctx := context.Background()
// create a workspace from a local project
w, _ := NewLocalWorkspace(ctx, WorkDir(filepath.Join(".", "program")))
fqsnA := FullyQualifiedStackName("org", "proj", "stackA")
stackNameA := FullyQualifiedStackName("org", "proj", "stackA")
// get the last deployed config from stack A
// this overwrites config in pulumi.stackA.yaml
cfg, _ := w.RefreshConfig(ctx, fqsnA)
cfg, _ := w.RefreshConfig(ctx, stackNameA)
// add a key to the ConfigMap
cfg["addition_config_key"] = ConfigValue{Value: "additional_config_value"}
// create a new stack
fqsnB := FullyQualifiedStackName("org", "proj", "stackB")
w.CreateStack(ctx, fqsnB)
stackNameB := FullyQualifiedStackName("org", "proj", "stackB")
w.CreateStack(ctx, stackNameB)
// save the modified config to stackB
w.SetAllConfig(ctx, fqsnB, cfg)
w.SetAllConfig(ctx, stackNameB, cfg)
}
func ExampleLocalWorkspace_SetProgram() {
@ -552,32 +548,32 @@ func ExampleLocalWorkspace_StackSettings() {
ctx := context.Background()
// create a workspace from a local project
w, _ := NewLocalWorkspace(ctx, WorkDir(filepath.Join(".", "program")))
fqsnA := FullyQualifiedStackName("org", "proj", "stackA")
stackNameA := FullyQualifiedStackName("org", "proj", "stackA")
// read existing stack settings for stackA if any
ss, err := w.StackSettings(ctx, fqsnA)
ss, err := w.StackSettings(ctx, stackNameA)
if err != nil {
// no pulumi.stackA.yaml was found, so create a default
ss = &workspace.ProjectStack{}
}
fqsnB := FullyQualifiedStackName("org", "proj", "stackB")
stackNameB := FullyQualifiedStackName("org", "proj", "stackB")
// copy the settings to stackB
w.SaveStackSettings(ctx, fqsnB, ss)
w.SaveStackSettings(ctx, stackNameB, ss)
}
func ExampleLocalWorkspace_SaveStackSettings() {
ctx := context.Background()
// create a workspace from a local project
w, _ := NewLocalWorkspace(ctx, WorkDir(filepath.Join(".", "program")))
fqsnA := FullyQualifiedStackName("org", "proj", "stackA")
stackNameA := FullyQualifiedStackName("org", "proj", "stackA")
// read existing stack settings for stackA if any
ss, err := w.StackSettings(ctx, fqsnA)
ss, err := w.StackSettings(ctx, stackNameA)
if err != nil {
// no pulumi.stackA.yaml was found, so create a default
ss = &workspace.ProjectStack{}
}
fqsnB := FullyQualifiedStackName("org", "proj", "stackB")
stackNameB := FullyQualifiedStackName("org", "proj", "stackB")
// copy the settings to stackB
w.SaveStackSettings(ctx, fqsnB, ss)
w.SaveStackSettings(ctx, stackNameB, ss)
}
func ExampleLocalWorkspace_WhoAmI() {
@ -590,7 +586,7 @@ func ExampleLocalWorkspace_WhoAmI() {
func ExampleSetupFn() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("myOrg", "nodejs_project", "myStack")
stackName := FullyQualifiedStackName("myOrg", "nodejs_project", "myStack")
repo := GitRepo{
URL: "https://some.example.repo.git",
@ -605,12 +601,12 @@ func ExampleSetupFn() {
}
// initialize a stack from the git repo
NewStackRemoteSource(ctx, fqsn, repo)
NewStackRemoteSource(ctx, stackName, repo)
}
func ExampleStack() error {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "dev_stack")
stackName := FullyQualifiedStackName("org", "project", "dev_stack")
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
@ -623,7 +619,7 @@ func ExampleStack() error {
// initialize
pDir := filepath.Join(".", "project")
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
return err
}
@ -681,8 +677,8 @@ func ExampleNewStack() error {
return err
}
fqsn := FullyQualifiedStackName("org", "proj", "stack")
stack, err := NewStack(ctx, fqsn, w)
stackName := FullyQualifiedStackName("org", "proj", "stack")
stack, err := NewStack(ctx, stackName, w)
if err != nil {
return err
}
@ -697,8 +693,8 @@ func ExampleUpsertStack() error {
return err
}
fqsn := FullyQualifiedStackName("org", "proj", "stack")
stack, err := UpsertStack(ctx, fqsn, w)
stackName := FullyQualifiedStackName("org", "proj", "stack")
stack, err := UpsertStack(ctx, stackName, w)
if err != nil {
return err
}
@ -708,10 +704,11 @@ func ExampleUpsertStack() error {
func ExampleNewStackInlineSource() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("myOrg", "proj", "stack")
projName := "proj"
stackName := FullyQualifiedStackName("myOrg", projName, "stack")
// create a new Stack with a default ProjectSettings file, and a temporary WorkDir created in a new
// LocalWorkspace on behalf of the user.
stack, _ := NewStackInlineSource(ctx, fqsn, func(pCtx *pulumi.Context) error {
stack, _ := NewStackInlineSource(ctx, stackName, projName, func(pCtx *pulumi.Context) error {
pCtx.Export("outputA", pulumi.String("valueA"))
return nil
})
@ -727,10 +724,11 @@ func ExampleNewStackInlineSource() {
func ExampleUpsertStackInlineSource() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("myOrg", "proj", "stack")
projName := "proj"
stackName := FullyQualifiedStackName("myOrg", "proj", "stack")
// create or select a new Stack with a default ProjectSettings file, and a temporary WorkDir created in a new
// LocalWorkspace on behalf of the user.
stack, _ := UpsertStackInlineSource(ctx, fqsn, func(pCtx *pulumi.Context) error {
stack, _ := UpsertStackInlineSource(ctx, stackName, projName, func(pCtx *pulumi.Context) error {
pCtx.Export("outputA", pulumi.String("valueA"))
return nil
})
@ -746,10 +744,11 @@ func ExampleUpsertStackInlineSource() {
func ExampleSelectStackInlineSource() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("myOrg", "proj", "existing_stack")
projName := "proj"
stackName := FullyQualifiedStackName("myOrg", projName, "existing_stack")
// selects an existing stack with a default ProjectSettings file, and a temporary WorkDir in a new LocalWorkspace
// created on behalf of the user.
stack, _ := SelectStackInlineSource(ctx, fqsn, func(pCtx *pulumi.Context) error {
stack, _ := SelectStackInlineSource(ctx, stackName, projName, func(pCtx *pulumi.Context) error {
pCtx.Export("outputA", pulumi.String("valueA"))
return nil
})
@ -765,11 +764,11 @@ func ExampleSelectStackInlineSource() {
func ExampleNewStackLocalSource() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("myOrg", "proj", "stack")
stackName := FullyQualifiedStackName("myOrg", "proj", "stack")
workDir := filepath.Join(".", "program", "dir")
// creates a new stack with a new LocalWorkspace created from provided WorkDir. This Workspace will pick up
// any available Settings files (Pulumi.yaml, Pulumi.<stack>.yaml)
stack, _ := NewStackLocalSource(ctx, fqsn, workDir)
stack, _ := NewStackLocalSource(ctx, stackName, workDir)
// Stack.Up runs the program in workDir
stack.Up(ctx)
// we can update the Workspace program for subsequent updates if desired
@ -783,11 +782,11 @@ func ExampleNewStackLocalSource() {
func ExampleUpsertStackLocalSource() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("myOrg", "proj", "stack")
stackName := FullyQualifiedStackName("myOrg", "proj", "stack")
workDir := filepath.Join(".", "program", "dir")
// create or select a new stack with a new LocalWorkspace created from provided WorkDir. This Workspace will pick up
// any available Settings files (Pulumi.yaml, Pulumi.<stack>.yaml)
stack, _ := UpsertStackLocalSource(ctx, fqsn, workDir)
stack, _ := UpsertStackLocalSource(ctx, stackName, workDir)
// Stack.Up runs the program in workDir
stack.Up(ctx)
// we can update the Workspace program for subsequent updates if desired
@ -801,11 +800,11 @@ func ExampleUpsertStackLocalSource() {
func ExampleSelectStackLocalSource() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("myOrg", "proj", "stack")
stackName := FullyQualifiedStackName("myOrg", "proj", "stack")
workDir := filepath.Join(".", "program", "dir")
// selects an existing stack with a new LocalWorkspace created from provided WorkDir. This Workspace will pick up
// any available Settings files (Pulumi.yaml, Pulumi.<stack>.yaml)
stack, _ := SelectStackLocalSource(ctx, fqsn, workDir)
stack, _ := SelectStackLocalSource(ctx, stackName, workDir)
// Stack.Up runs the program in workDir
stack.Up(ctx)
// we can update the Workspace program for subsequent updates if desired
@ -820,7 +819,7 @@ func ExampleSelectStackLocalSource() {
func ExampleNewStackRemoteSource() {
ctx := context.Background()
pName := "go_remote_proj"
fqsn := FullyQualifiedStackName("myOrg", pName, "myStack")
stackName := FullyQualifiedStackName("myOrg", pName, "myStack")
// we'll compile a the program into an executable with the name "examplesBinary"
binName := "examplesBinary"
@ -845,13 +844,13 @@ func ExampleNewStackRemoteSource() {
}
// initialize a stack from the git repo, specifying our project override
NewStackRemoteSource(ctx, fqsn, repo, Project(project))
NewStackRemoteSource(ctx, stackName, repo, Project(project))
}
func ExampleUpsertStackRemoteSource() {
ctx := context.Background()
pName := "go_remote_proj"
fqsn := FullyQualifiedStackName("myOrg", pName, "myStack")
stackName := FullyQualifiedStackName("myOrg", pName, "myStack")
// we'll compile a the program into an executable with the name "examplesBinary"
binName := "examplesBinary"
@ -876,13 +875,13 @@ func ExampleUpsertStackRemoteSource() {
}
// initialize or select a stack from the git repo, specifying our project override
UpsertStackRemoteSource(ctx, fqsn, repo, Project(project))
UpsertStackRemoteSource(ctx, stackName, repo, Project(project))
}
func ExampleSelectStackRemoteSource() {
ctx := context.Background()
pName := "go_remote_proj"
fqsn := FullyQualifiedStackName("myOrg", pName, "myStack")
stackName := FullyQualifiedStackName("myOrg", pName, "myStack")
// we'll compile a the program into an executable with the name "examplesBinary"
binName := "examplesBinary"
@ -907,45 +906,45 @@ func ExampleSelectStackRemoteSource() {
}
// select an existing stack using a LocalWorkspace created from the git repo, specifying our project override
SelectStackRemoteSource(ctx, fqsn, repo, Project(project))
SelectStackRemoteSource(ctx, stackName, repo, Project(project))
}
func ExampleStack_Destroy() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stackName := FullyQualifiedStackName("org", "project", "stack")
// select an existing stack to destroy
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
stack.Destroy(ctx, optdestroy.Message("a message to save with the destroy operation"))
}
func ExampleStack_Up() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stackName := FullyQualifiedStackName("org", "project", "stack")
// create a new stack to update
stack, _ := NewStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stack, _ := NewStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
stack.Up(ctx, optup.Message("a message to save with the up operation"), optup.Parallel(10000))
}
func ExampleStack_Preview() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stackName := FullyQualifiedStackName("org", "project", "stack")
// create a new stack and preview changes
stack, _ := NewStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stack, _ := NewStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
stack.Preview(ctx, optpreview.Message("a message to save with the preive operation"))
}
func ExampleStack_Refresh() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stackName := FullyQualifiedStackName("org", "project", "stack")
// select an existing stack and refresh the resources under management
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
stack.Refresh(ctx, optrefresh.Message("a message to save with the refresh operation"))
}
func ExampleStack_GetAllConfig() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
cfg, _ := stack.GetAllConfig(ctx)
fmt.Println(cfg["config_key"].Value)
fmt.Println(cfg["config_key"].Secret)
@ -953,8 +952,8 @@ func ExampleStack_GetAllConfig() {
func ExampleStack_GetConfig() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
cfgVal, _ := stack.GetConfig(ctx, "config_key")
fmt.Println(cfgVal.Value)
fmt.Println(cfgVal.Secret)
@ -962,8 +961,8 @@ func ExampleStack_GetConfig() {
func ExampleStack_History() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
hist, _ := stack.History(ctx)
// last operation start time
fmt.Println(hist[0].StartTime)
@ -971,8 +970,8 @@ func ExampleStack_History() {
func ExampleStack_Info() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
info, _ := stack.Info(ctx)
// url to view the Stack in the Pulumi SaaS or other backend
fmt.Println(info.URL)
@ -980,8 +979,8 @@ func ExampleStack_Info() {
func ExampleStack_Outputs() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
outs, _ := stack.Outputs(ctx)
fmt.Println(outs["key"].Value.(string))
fmt.Println(outs["key"].Secret)
@ -989,40 +988,40 @@ func ExampleStack_Outputs() {
func ExampleStack_RefreshConfig() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
// get the last deployed config from stack and overwrite Pulumi.stack.yaml
_, _ = stack.RefreshConfig(ctx)
}
func ExampleStack_RemoveConfig() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
// remove config matching the specified key
_ = stack.RemoveConfig(ctx, "key_to_remove")
}
func ExampleStack_RemoveAllConfig() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
// remove config matching the specified keys
_ = stack.RemoveAllConfig(ctx, []string{"key0", "key1", "...", "keyN"})
}
func ExampleStack_SetConfig() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
// set config key-value pair
_ = stack.SetConfig(ctx, "key_to_set", ConfigValue{Value: "abc", Secret: true})
}
func ExampleStack_SetAllConfig() {
ctx := context.Background()
fqsn := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, fqsn, filepath.Join(".", "program"))
stackName := FullyQualifiedStackName("org", "project", "stack")
stack, _ := SelectStackLocalSource(ctx, stackName, filepath.Join(".", "program"))
cfg := ConfigMap{
"key0": ConfigValue{Value: "abc", Secret: true},
"key1": ConfigValue{Value: "def"},

View file

@ -73,13 +73,10 @@ func (l *LocalWorkspace) SaveProjectSettings(ctx context.Context, settings *work
return settings.Save(pulumiYamlPath)
}
// StackSettings returns the settings object for the stack matching the specified fullyQualifiedStackName if any.
// StackSettings returns the settings object for the stack matching the specified stack name if any.
// LocalWorkspace reads this from a Pulumi.<stack>.yaml file in Workspace.WorkDir().
func (l *LocalWorkspace) StackSettings(ctx context.Context, fqsn string) (*workspace.ProjectStack, error) {
name, err := getStackFromFQSN(fqsn)
if err != nil {
return nil, errors.Wrap(err, "failed to load stack settings, invalid stack name")
}
func (l *LocalWorkspace) StackSettings(ctx context.Context, stackName string) (*workspace.ProjectStack, error) {
name := getStackSettingsName(stackName)
for _, ext := range settingsExtensions {
stackPath := filepath.Join(l.WorkDir(), fmt.Sprintf("pulumi.%s%s", name, ext))
if _, err := os.Stat(stackPath); err != nil {
@ -90,52 +87,49 @@ func (l *LocalWorkspace) StackSettings(ctx context.Context, fqsn string) (*works
return proj, nil
}
}
return nil, errors.Errorf("unable to find stack settings in workspace for %s", fqsn)
return nil, errors.Errorf("unable to find stack settings in workspace for %s", stackName)
}
// SaveStackSettings overwrites the settings object for the stack matching the specified fullyQualifiedStackName.
// SaveStackSettings overwrites the settings object for the stack matching the specified stack name.
// LocalWorkspace writes this value to a Pulumi.<stack>.yaml file in Workspace.WorkDir()
func (l *LocalWorkspace) SaveStackSettings(
ctx context.Context,
fqsn string,
stackName string,
settings *workspace.ProjectStack,
) error {
name, err := getStackFromFQSN(fqsn)
if err != nil {
return errors.Wrap(err, "failed to save stack settings, invalid stack name")
}
name := getStackSettingsName(stackName)
stackYamlPath := filepath.Join(l.WorkDir(), fmt.Sprintf("pulumi.%s.yaml:", name))
err = settings.Save(stackYamlPath)
err := settings.Save(stackYamlPath)
if err != nil {
return errors.Wrapf(err, "failed to save stack setttings for %s", fqsn)
return errors.Wrapf(err, "failed to save stack setttings for %s", stackName)
}
return nil
}
// SerializeArgsForOp is hook to provide additional args to every CLI commands before they are executed.
// Provided with fullyQualifiedStackName,
// Provided with stack name,
// returns a list of args to append to an invoked command ["--config=...", ]
// LocalWorkspace does not utilize this extensibility point.
func (l *LocalWorkspace) SerializeArgsForOp(ctx context.Context, fqsn string) ([]string, error) {
func (l *LocalWorkspace) SerializeArgsForOp(ctx context.Context, stackName string) ([]string, error) {
// not utilized for LocalWorkspace
return nil, nil
}
// PostCommandCallback is a hook executed after every command. Called with the fullyQualifiedStackName.
// PostCommandCallback is a hook executed after every command. Called with the stack name.
// An extensibility point to perform workspace cleanup (CLI operations may create/modify a Pulumi.stack.yaml)
// LocalWorkspace does not utilize this extensibility point.
func (l *LocalWorkspace) PostCommandCallback(ctx context.Context, fqsn string) error {
func (l *LocalWorkspace) PostCommandCallback(ctx context.Context, stackName string) error {
// not utilized for LocalWorkspace
return nil
}
// GetConfig returns the value associated with the specified fullyQualifiedStackName and key,
// GetConfig returns the value associated with the specified stack name and key,
// scoped to the current workspace. LocalWorkspace reads this config from the matching Pulumi.stack.yaml file.
func (l *LocalWorkspace) GetConfig(ctx context.Context, fqsn string, key string) (ConfigValue, error) {
func (l *LocalWorkspace) GetConfig(ctx context.Context, stackName string, key string) (ConfigValue, error) {
var val ConfigValue
err := l.SelectStack(ctx, fqsn)
err := l.SelectStack(ctx, stackName)
if err != nil {
return val, errors.Wrapf(err, "could not get config, unable to select stack %s", fqsn)
return val, errors.Wrapf(err, "could not get config, unable to select stack %s", stackName)
}
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "config", "get", key, "--json")
if err != nil {
@ -148,13 +142,13 @@ func (l *LocalWorkspace) GetConfig(ctx context.Context, fqsn string, key string)
return val, nil
}
// GetAllConfig returns the config map for the specified fullyQualifiedStackName, scoped to the current workspace.
// GetAllConfig returns the config map for the specified stack name, scoped to the current workspace.
// LocalWorkspace reads this config from the matching Pulumi.stack.yaml file.
func (l *LocalWorkspace) GetAllConfig(ctx context.Context, fqsn string) (ConfigMap, error) {
func (l *LocalWorkspace) GetAllConfig(ctx context.Context, stackName string) (ConfigMap, error) {
var val ConfigMap
err := l.SelectStack(ctx, fqsn)
err := l.SelectStack(ctx, stackName)
if err != nil {
return val, errors.Wrapf(err, "could not get config, unable to select stack %s", fqsn)
return val, errors.Wrapf(err, "could not get config, unable to select stack %s", stackName)
}
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "config", "--show-secrets", "--json")
if err != nil {
@ -167,12 +161,12 @@ func (l *LocalWorkspace) GetAllConfig(ctx context.Context, fqsn string) (ConfigM
return val, nil
}
// SetConfig sets the specified key-value pair on the provided fullyQualifiedStackName.
// SetConfig sets the specified key-value pair on the provided stack name.
// LocalWorkspace writes this value to the matching Pulumi.<stack>.yaml file in Workspace.WorkDir().
func (l *LocalWorkspace) SetConfig(ctx context.Context, fqsn string, key string, val ConfigValue) error {
err := l.SelectStack(ctx, fqsn)
func (l *LocalWorkspace) SetConfig(ctx context.Context, stackName string, key string, val ConfigValue) error {
err := l.SelectStack(ctx, stackName)
if err != nil {
return errors.Wrapf(err, "could not set config, unable to select stack %s", fqsn)
return errors.Wrapf(err, "could not set config, unable to select stack %s", stackName)
}
secretArg := "--plaintext"
@ -187,11 +181,11 @@ func (l *LocalWorkspace) SetConfig(ctx context.Context, fqsn string, key string,
return nil
}
// SetAllConfig sets all values in the provided config map for the specified fullyQualifiedStackName.
// SetAllConfig sets all values in the provided config map for the specified stack name.
// LocalWorkspace writes the config to the matching Pulumi.<stack>.yaml file in Workspace.WorkDir().
func (l *LocalWorkspace) SetAllConfig(ctx context.Context, fqsn string, config ConfigMap) error {
func (l *LocalWorkspace) SetAllConfig(ctx context.Context, stackName string, config ConfigMap) error {
for k, v := range config {
err := l.SetConfig(ctx, fqsn, k, v)
err := l.SetConfig(ctx, stackName, k, v)
if err != nil {
return err
}
@ -199,12 +193,12 @@ func (l *LocalWorkspace) SetAllConfig(ctx context.Context, fqsn string, config C
return nil
}
// RemoveConfig removes the specified key-value pair on the provided fullyQualifiedStackName.
// RemoveConfig removes the specified key-value pair on the provided stack name.
// It will remove any matching values in the Pulumi.<stack>.yaml file in Workspace.WorkDir().
func (l *LocalWorkspace) RemoveConfig(ctx context.Context, fqsn string, key string) error {
err := l.SelectStack(ctx, fqsn)
func (l *LocalWorkspace) RemoveConfig(ctx context.Context, stackName string, key string) error {
err := l.SelectStack(ctx, stackName)
if err != nil {
return errors.Wrapf(err, "could not remove config, unable to select stack %s", fqsn)
return errors.Wrapf(err, "could not remove config, unable to select stack %s", stackName)
}
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "config", "rm", key)
@ -214,11 +208,11 @@ func (l *LocalWorkspace) RemoveConfig(ctx context.Context, fqsn string, key stri
return nil
}
// RemoveAllConfig removes all values in the provided key list for the specified fullyQualifiedStackName
// RemoveAllConfig removes all values in the provided key list for the specified stack name
// It will remove any matching values in the Pulumi.<stack>.yaml file in Workspace.WorkDir().
func (l *LocalWorkspace) RemoveAllConfig(ctx context.Context, fqsn string, keys []string) error {
func (l *LocalWorkspace) RemoveAllConfig(ctx context.Context, stackName string, keys []string) error {
for _, k := range keys {
err := l.RemoveConfig(ctx, fqsn, k)
err := l.RemoveConfig(ctx, stackName, k)
if err != nil {
return err
}
@ -226,12 +220,12 @@ func (l *LocalWorkspace) RemoveAllConfig(ctx context.Context, fqsn string, keys
return nil
}
// RefreshConfig gets and sets the config map used with the last Update for Stack matching fullyQualifiedStackName.
// RefreshConfig gets and sets the config map used with the last Update for Stack matching stack name.
// It will overwrite all configuration in the Pulumi.<stack>.yaml file in Workspace.WorkDir().
func (l *LocalWorkspace) RefreshConfig(ctx context.Context, fqsn string) (ConfigMap, error) {
err := l.SelectStack(ctx, fqsn)
func (l *LocalWorkspace) RefreshConfig(ctx context.Context, stackName string) (ConfigMap, error) {
err := l.SelectStack(ctx, stackName)
if err != nil {
return nil, errors.Wrapf(err, "could not refresh config, unable to select stack %s", fqsn)
return nil, errors.Wrapf(err, "could not refresh config, unable to select stack %s", stackName)
}
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "config", "refresh", "--force")
@ -239,7 +233,7 @@ func (l *LocalWorkspace) RefreshConfig(ctx context.Context, fqsn string) (Config
return nil, newAutoError(errors.Wrap(err, "could not refresh config"), stdout, stderr, errCode)
}
cfg, err := l.GetAllConfig(ctx, fqsn)
cfg, err := l.GetAllConfig(ctx, stackName)
if err != nil {
return nil, errors.Wrap(err, "could not fetch config after refresh")
}
@ -324,14 +318,9 @@ func (l *LocalWorkspace) Stack(ctx context.Context) (*StackSummary, error) {
return nil, nil
}
// CreateStack creates and sets a new stack with the fullyQualifiedStackName, failing if one already exists.
func (l *LocalWorkspace) CreateStack(ctx context.Context, fqsn string) error {
err := ValidateFullyQualifiedStackName(fqsn)
if err != nil {
return errors.Wrap(err, "failed to create stack")
}
args := []string{"stack", "init", fqsn}
// CreateStack creates and sets a new stack with the stack name, failing if one already exists.
func (l *LocalWorkspace) CreateStack(ctx context.Context, stackName string) error {
args := []string{"stack", "init", stackName}
if l.secretsProvider != "" {
args = append(args, fmt.Sprintf("--secrets-provider=%s", l.secretsProvider))
}
@ -343,14 +332,9 @@ func (l *LocalWorkspace) CreateStack(ctx context.Context, fqsn string) error {
return nil
}
// SelectStack selects and sets an existing stack matching the fullyQualifiedStackName, failing if none exists.
func (l *LocalWorkspace) SelectStack(ctx context.Context, fqsn string) error {
err := ValidateFullyQualifiedStackName(fqsn)
if err != nil {
return errors.Wrap(err, "failed to select stack")
}
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "stack", "select", fqsn)
// SelectStack selects and sets an existing stack matching the stack name, failing if none exists.
func (l *LocalWorkspace) SelectStack(ctx context.Context, stackName string) error {
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "stack", "select", stackName)
if err != nil {
return newAutoError(errors.Wrap(err, "failed to select stack"), stdout, stderr, errCode)
}
@ -359,13 +343,8 @@ func (l *LocalWorkspace) SelectStack(ctx context.Context, fqsn string) error {
}
// RemoveStack deletes the stack and all associated configuration and history.
func (l *LocalWorkspace) RemoveStack(ctx context.Context, fqsn string) error {
err := ValidateFullyQualifiedStackName(fqsn)
if err != nil {
return errors.Wrap(err, "failed to remove stack")
}
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "stack", "rm", "--yes", fqsn)
func (l *LocalWorkspace) RemoveStack(ctx context.Context, stackName string) error {
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "stack", "rm", "--yes", stackName)
if err != nil {
return newAutoError(errors.Wrap(err, "failed to remove stack"), stdout, stderr, errCode)
}
@ -375,16 +354,6 @@ func (l *LocalWorkspace) RemoveStack(ctx context.Context, fqsn string) error {
// ListStacks returns all Stacks created under the current Project.
// This queries underlying backend and may return stacks not present in the Workspace (as Pulumi.<stack>.yaml files).
func (l *LocalWorkspace) ListStacks(ctx context.Context) ([]StackSummary, error) {
user, err := l.WhoAmI(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not list stacks")
}
proj, err := l.ProjectSettings(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not list stacks")
}
var stacks []StackSummary
stdout, stderr, errCode, err := l.runPulumiCmdSync(ctx, "stack", "ls", "--json")
if err != nil {
@ -394,14 +363,6 @@ func (l *LocalWorkspace) ListStacks(ctx context.Context) ([]StackSummary, error)
if err != nil {
return nil, errors.Wrap(err, "unable to unmarshal config value")
}
for _, s := range stacks {
nameParts := strings.Split(s.Name, "/")
if len(nameParts) == 1 {
s.Name = fmt.Sprintf("%s/%s/%s", user, proj.Name.String(), s.Name)
} else {
s.Name = fmt.Sprintf("%s/%s/%s", nameParts[0], proj.Name.String(), nameParts[1])
}
}
return stacks, nil
}
@ -515,9 +476,9 @@ func NewLocalWorkspace(ctx context.Context, opts ...LocalWorkspaceOption) (Works
}
}
for fqsn := range lwOpts.Stacks {
s := lwOpts.Stacks[fqsn]
err := l.SaveStackSettings(ctx, fqsn, &s)
for stackName := range lwOpts.Stacks {
s := lwOpts.Stacks[stackName]
err := l.SaveStackSettings(ctx, stackName, &s)
if err != nil {
return nil, errors.Wrap(err, "failed to create workspace")
}
@ -551,7 +512,7 @@ type localWorkspaceOptions struct {
PulumiHome string
// Project is the project settings for the workspace.
Project *workspace.Project
// Stacks is a map of [fqsn -> stack settings objects] to seed the workspace.
// Stacks is a map of [stackName -> stack settings objects] to seed the workspace.
Stacks map[string]workspace.ProjectStack
// Repo is a git repo with a Pulumi Project to clone into the WorkDir.
Repo *GitRepo
@ -660,22 +621,10 @@ func SecretsProvider(secretsProvider string) LocalWorkspaceOption {
})
}
// ValidateFullyQualifiedStackName validates that the fqsn is in the form "org/project/name".
func ValidateFullyQualifiedStackName(fqsn string) error {
parts := strings.Split(fqsn, "/")
if len(parts) != 3 {
return errors.Errorf(
"invalid fully qualified stack name: %s, expected in the form 'org/project/stack'",
fqsn,
)
}
return nil
}
// NewStackLocalSource creates a Stack backed by a LocalWorkspace created on behalf of the user,
// from the specified WorkDir. This Workspace will pick up
// any available Settings files (Pulumi.yaml, Pulumi.<stack>.yaml).
func NewStackLocalSource(ctx context.Context, fqsn, workDir string, opts ...LocalWorkspaceOption) (Stack, error) {
func NewStackLocalSource(ctx context.Context, stackName, workDir string, opts ...LocalWorkspaceOption) (Stack, error) {
opts = append(opts, WorkDir(workDir))
w, err := NewLocalWorkspace(ctx, opts...)
var stack Stack
@ -683,14 +632,19 @@ func NewStackLocalSource(ctx context.Context, fqsn, workDir string, opts ...Loca
return stack, errors.Wrap(err, "failed to create stack")
}
return NewStack(ctx, fqsn, w)
return NewStack(ctx, stackName, w)
}
// UpsertStackLocalSource creates a Stack backed by a LocalWorkspace created on behalf of the user,
// from the specified WorkDir. If the Stack already exists, it will not error
// and proceed to selecting the Stack.This Workspace will pick up any available
// Settings files (Pulumi.yaml, Pulumi.<stack>.yaml).
func UpsertStackLocalSource(ctx context.Context, fqsn, workDir string, opts ...LocalWorkspaceOption) (Stack, error) {
func UpsertStackLocalSource(
ctx context.Context,
stackName,
workDir string,
opts ...LocalWorkspaceOption,
) (Stack, error) {
opts = append(opts, WorkDir(workDir))
w, err := NewLocalWorkspace(ctx, opts...)
var stack Stack
@ -698,13 +652,18 @@ func UpsertStackLocalSource(ctx context.Context, fqsn, workDir string, opts ...L
return stack, errors.Wrap(err, "failed to create stack")
}
return UpsertStack(ctx, fqsn, w)
return UpsertStack(ctx, stackName, w)
}
// SelectStackLocalSource selects an existing Stack backed by a LocalWorkspace created on behalf of the user,
// from the specified WorkDir. This Workspace will pick up
// any available Settings files (Pulumi.yaml, Pulumi.<stack>.yaml).
func SelectStackLocalSource(ctx context.Context, fqsn, workDir string, opts ...LocalWorkspaceOption) (Stack, error) {
func SelectStackLocalSource(
ctx context.Context,
stackName,
workDir string,
opts ...LocalWorkspaceOption,
) (Stack, error) {
opts = append(opts, WorkDir(workDir))
w, err := NewLocalWorkspace(ctx, opts...)
var stack Stack
@ -712,14 +671,19 @@ func SelectStackLocalSource(ctx context.Context, fqsn, workDir string, opts ...L
return stack, errors.Wrap(err, "failed to select stack")
}
return SelectStack(ctx, fqsn, w)
return SelectStack(ctx, stackName, w)
}
// NewStackRemoteSource creates a Stack backed by a LocalWorkspace created on behalf of the user,
// with source code cloned from the specified GitRepo. This Workspace will pick up
// any available Settings files (Pulumi.yaml, Pulumi.<stack>.yaml) that are cloned into the Workspace.
// Unless a WorkDir option is specified, the GitRepo will be clone into a new temporary directory provided by the OS.
func NewStackRemoteSource(ctx context.Context, fqsn string, repo GitRepo, opts ...LocalWorkspaceOption) (Stack, error) {
func NewStackRemoteSource(
ctx context.Context,
stackName string,
repo GitRepo,
opts ...LocalWorkspaceOption,
) (Stack, error) {
opts = append(opts, Repo(repo))
w, err := NewLocalWorkspace(ctx, opts...)
var stack Stack
@ -727,7 +691,7 @@ func NewStackRemoteSource(ctx context.Context, fqsn string, repo GitRepo, opts .
return stack, errors.Wrap(err, "failed to create stack")
}
return NewStack(ctx, fqsn, w)
return NewStack(ctx, stackName, w)
}
// UpsertStackRemoteSource creates a Stack backed by a LocalWorkspace created on behalf of the user,
@ -737,7 +701,7 @@ func NewStackRemoteSource(ctx context.Context, fqsn string, repo GitRepo, opts .
// into the Workspace. Unless a WorkDir option is specified, the GitRepo will be clone
// into a new temporary directory provided by the OS.
func UpsertStackRemoteSource(
ctx context.Context, fqsn string, repo GitRepo, opts ...LocalWorkspaceOption) (Stack, error) {
ctx context.Context, stackName string, repo GitRepo, opts ...LocalWorkspaceOption) (Stack, error) {
opts = append(opts, Repo(repo))
w, err := NewLocalWorkspace(ctx, opts...)
var stack Stack
@ -745,7 +709,7 @@ func UpsertStackRemoteSource(
return stack, errors.Wrap(err, "failed to create stack")
}
return UpsertStack(ctx, fqsn, w)
return UpsertStack(ctx, stackName, w)
}
// SelectStackRemoteSource selects an existing Stack backed by a LocalWorkspace created on behalf of the user,
@ -754,7 +718,7 @@ func UpsertStackRemoteSource(
// Unless a WorkDir option is specified, the GitRepo will be clone into a new temporary directory provided by the OS.
func SelectStackRemoteSource(
ctx context.Context,
fqsn string, repo GitRepo,
stackName string, repo GitRepo,
opts ...LocalWorkspaceOption,
) (Stack, error) {
opts = append(opts, Repo(repo))
@ -764,7 +728,7 @@ func SelectStackRemoteSource(
return stack, errors.Wrap(err, "failed to select stack")
}
return SelectStack(ctx, fqsn, w)
return SelectStack(ctx, stackName, w)
}
// NewStackInlineSource creates a Stack backed by a LocalWorkspace created on behalf of the user,
@ -773,13 +737,14 @@ func SelectStackRemoteSource(
// to a new temporary directory provided by the OS.
func NewStackInlineSource(
ctx context.Context,
fqsn string,
stackName string,
projectName string,
program pulumi.RunFunc,
opts ...LocalWorkspaceOption,
) (Stack, error) {
var stack Stack
opts = append(opts, Program(program))
proj, err := defaultInlineProject(fqsn)
proj, err := defaultInlineProject(projectName)
if err != nil {
return stack, errors.Wrap(err, "failed to create stack")
}
@ -790,7 +755,7 @@ func NewStackInlineSource(
return stack, errors.Wrap(err, "failed to create stack")
}
return NewStack(ctx, fqsn, w)
return NewStack(ctx, stackName, w)
}
// UpsertStackInlineSource creates a Stack backed by a LocalWorkspace created on behalf of the user,
@ -800,13 +765,14 @@ func NewStackInlineSource(
// is specified, the working directory will default to a new temporary directory provided by the OS.
func UpsertStackInlineSource(
ctx context.Context,
fqsn string,
stackName string,
projectName string,
program pulumi.RunFunc,
opts ...LocalWorkspaceOption,
) (Stack, error) {
var stack Stack
opts = append(opts, Program(program))
proj, err := defaultInlineProject(fqsn)
proj, err := defaultInlineProject(projectName)
if err != nil {
return stack, errors.Wrap(err, "failed to create stack")
}
@ -817,7 +783,7 @@ func UpsertStackInlineSource(
return stack, errors.Wrap(err, "failed to create stack")
}
return UpsertStack(ctx, fqsn, w)
return UpsertStack(ctx, stackName, w)
}
// SelectStackInlineSource selects an existing Stack backed by a new LocalWorkspace created on behalf of the user,
@ -826,13 +792,14 @@ func UpsertStackInlineSource(
// to a new temporary directory provided by the OS.
func SelectStackInlineSource(
ctx context.Context,
fqsn string,
stackName string,
projectName string,
program pulumi.RunFunc,
opts ...LocalWorkspaceOption,
) (Stack, error) {
var stack Stack
opts = append(opts, Program(program))
proj, err := defaultInlineProject(fqsn)
proj, err := defaultInlineProject(projectName)
if err != nil {
return stack, errors.Wrap(err, "failed to select stack")
}
@ -843,29 +810,28 @@ func SelectStackInlineSource(
return stack, errors.Wrap(err, "failed to select stack")
}
return SelectStack(ctx, fqsn, w)
return SelectStack(ctx, stackName, w)
}
func defaultInlineProject(fqsn string) (workspace.Project, error) {
func defaultInlineProject(projectName string) (workspace.Project, error) {
var proj workspace.Project
err := ValidateFullyQualifiedStackName(fqsn)
if err != nil {
return proj, err
}
pName := strings.Split(fqsn, "/")[1]
proj = workspace.Project{
Name: tokens.PackageName(pName),
Name: tokens.PackageName(projectName),
Runtime: workspace.NewProjectRuntimeInfo("go", nil),
}
return proj, nil
}
func getStackFromFQSN(fqsn string) (string, error) {
if err := ValidateFullyQualifiedStackName(fqsn); err != nil {
return "", err
// stack names come in many forms:
// s, o/p/s, u/p/s o/s
// so just return the last chunk which is what will be used in pulumi.<stack>.yaml
func getStackSettingsName(stackName string) string {
parts := strings.Split(stackName, "/")
if len(parts) < 1 {
return stackName
}
return strings.Split(fqsn, "/")[2], nil
return parts[len(parts)-1]
}
const pulumiHomeEnv = "PULUMI_HOME"

View file

@ -31,13 +31,14 @@ import (
"github.com/stretchr/testify/assert"
)
const pulumiOrg = "moolumi"
var pulumiOrg = getTestOrg()
const pName = "testproj"
func TestWorkspaceSecretsProvider(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
// We can't use Workspace EnvVars as the Workspace uses the secrets provider to
// create the Stack
@ -45,7 +46,7 @@ func TestWorkspaceSecretsProvider(t *testing.T) {
assert.Nil(t, err, "failed to set EnvVar.")
// initialize
s, err := NewStackInlineSource(ctx, fqsn, func(ctx *pulumi.Context) error {
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
@ -107,7 +108,7 @@ func TestWorkspaceSecretsProvider(t *testing.T) {
func TestNewStackLocalSource(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
@ -120,7 +121,7 @@ func TestNewStackLocalSource(t *testing.T) {
// initialize
pDir := filepath.Join(".", "test", "testproj")
s, err := NewStackLocalSource(ctx, fqsn, pDir)
s, err := NewStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -209,7 +210,7 @@ func TestNewStackLocalSource(t *testing.T) {
func TestUpsertStackLocalSource(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
@ -222,7 +223,7 @@ func TestUpsertStackLocalSource(t *testing.T) {
// initialize
pDir := filepath.Join(".", "test", "testproj")
s, err := UpsertStackLocalSource(ctx, fqsn, pDir)
s, err := UpsertStackLocalSource(ctx, stackName, pDir)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -317,7 +318,7 @@ func TestNewStackRemoteSource(t *testing.T) {
ctx := context.Background()
pName := "go_remote_proj"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
@ -333,7 +334,7 @@ func TestNewStackRemoteSource(t *testing.T) {
}
// initialize
s, err := NewStackRemoteSource(ctx, fqsn, repo)
s, err := NewStackRemoteSource(ctx, stackName, repo)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -405,7 +406,7 @@ func TestUpsertStackRemoteSource(t *testing.T) {
ctx := context.Background()
pName := "go_remote_proj"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
@ -421,7 +422,7 @@ func TestUpsertStackRemoteSource(t *testing.T) {
}
// initialize
s, err := UpsertStackRemoteSource(ctx, fqsn, repo)
s, err := UpsertStackRemoteSource(ctx, stackName, repo)
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -493,7 +494,7 @@ func TestNewStackRemoteSourceWithSetup(t *testing.T) {
ctx := context.Background()
pName := "go_remote_proj"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
@ -521,7 +522,7 @@ func TestNewStackRemoteSourceWithSetup(t *testing.T) {
}
// initialize
s, err := NewStackRemoteSource(ctx, fqsn, repo, Project(project))
s, err := NewStackRemoteSource(ctx, stackName, repo, Project(project))
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -593,7 +594,7 @@ func TestUpsertStackRemoteSourceWithSetup(t *testing.T) {
ctx := context.Background()
pName := "go_remote_proj"
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
@ -621,7 +622,7 @@ func TestUpsertStackRemoteSourceWithSetup(t *testing.T) {
}
// initialize or select
s, err := UpsertStackRemoteSource(ctx, fqsn, repo, Project(project))
s, err := UpsertStackRemoteSource(ctx, stackName, repo, Project(project))
if err != nil {
t.Errorf("failed to initialize stack, err: %v", err)
t.FailNow()
@ -692,7 +693,7 @@ func TestUpsertStackRemoteSourceWithSetup(t *testing.T) {
func TestNewStackInlineSource(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
@ -704,7 +705,7 @@ func TestNewStackInlineSource(t *testing.T) {
}
// initialize
s, err := NewStackInlineSource(ctx, fqsn, func(ctx *pulumi.Context) error {
s, err := NewStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
@ -781,7 +782,7 @@ func TestNewStackInlineSource(t *testing.T) {
func TestUpsertStackInlineSource(t *testing.T) {
ctx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
fqsn := FullyQualifiedStackName(pulumiOrg, pName, sName)
stackName := FullyQualifiedStackName(pulumiOrg, pName, sName)
cfg := ConfigMap{
"bar": ConfigValue{
Value: "abc",
@ -793,7 +794,7 @@ func TestUpsertStackInlineSource(t *testing.T) {
}
// initialize or select
s, err := UpsertStackInlineSource(ctx, fqsn, func(ctx *pulumi.Context) error {
s, err := UpsertStackInlineSource(ctx, stackName, pName, func(ctx *pulumi.Context) error {
c := config.New(ctx, "")
ctx.Export("exp_static", pulumi.String("foo"))
ctx.Export("exp_cfg", pulumi.String(c.Get("bar")))
@ -872,10 +873,10 @@ func TestNestedStackFails(t *testing.T) {
t.Skip("skipping test, see pulumi/pulumi#5301")
testCtx := context.Background()
sName := fmt.Sprintf("int_test%d", rangeIn(10000000, 99999999))
parentFQSN := FullyQualifiedStackName(pulumiOrg, "parent", sName)
nestedFQSN := FullyQualifiedStackName(pulumiOrg, "nested", sName)
parentstackName := FullyQualifiedStackName(pulumiOrg, "parent", sName)
nestedstackName := FullyQualifiedStackName(pulumiOrg, "nested", sName)
nestedStack, err := NewStackInlineSource(testCtx, nestedFQSN, func(ctx *pulumi.Context) error {
nestedStack, err := NewStackInlineSource(testCtx, nestedstackName, "nested", func(ctx *pulumi.Context) error {
ctx.Export("exp_static", pulumi.String("foo"))
return nil
})
@ -885,7 +886,7 @@ func TestNestedStackFails(t *testing.T) {
}
// initialize
s, err := NewStackInlineSource(testCtx, parentFQSN, func(ctx *pulumi.Context) error {
s, err := NewStackInlineSource(testCtx, parentstackName, "parent", func(ctx *pulumi.Context) error {
_, err := nestedStack.Up(testCtx)
return err
})
@ -928,3 +929,11 @@ func TestNestedStackFails(t *testing.T) {
assert.Equal(t, "destroy", dRes.Summary.Kind)
assert.Equal(t, "succeeded", dRes.Summary.Result)
}
func getTestOrg() string {
testOrg := "pulumi-test"
if _, set := os.LookupEnv("PULUMI_TEST_ORG"); set {
testOrg = os.Getenv("PULUMI_TEST_ORG")
}
return testOrg
}

View file

@ -114,29 +114,33 @@ import (
// Stack is an isolated, independently configurable instance of a Pulumi program.
// Stack exposes methods for the full pulumi lifecycle (up/preview/refresh/destroy), as well as managing configuration.
// Automation API stacks are addressed by a fully qualified stack name (fqsn) in the form "org/project/stack".
// Multiple Stacks are commonly used to denote different phases of development
// (such as development, staging and production) or feature branches (such as feature-x-dev, jane-feature-x-dev).
type Stack struct {
workspace Workspace
fqsn string
stackName string
}
// FullyQualifiedStackName returns an appropriately formatted name to be used for Stack creation/selection.
// FullyQualifiedStackName returns a stack name formatted with the greatest possible specificity:
// org/project/stack or user/project/stack
// Using this format avoids ambiguity in stack identity guards creating or selecting the wrong stack.
// Note that filestate backends (local file, S3, Azure Blob) do not support stack names in this
// format, and instead only use the stack name without an org/user or project to qualify it.
// See: https://github.com/pulumi/pulumi/issues/2522
func FullyQualifiedStackName(org, project, stack string) string {
return fmt.Sprintf("%s/%s/%s", org, project, stack)
}
// NewStack creates a new stack using the given workspace, and fully qualified stack name (org/project/name).
// NewStack creates a new stack using the given workspace, and stack name.
// It fails if a stack with that name already exists
func NewStack(ctx context.Context, fqsn string, ws Workspace) (Stack, error) {
func NewStack(ctx context.Context, stackName string, ws Workspace) (Stack, error) {
var s Stack
s = Stack{
workspace: ws,
fqsn: fqsn,
stackName: stackName,
}
err := ws.CreateStack(ctx, fqsn)
err := ws.CreateStack(ctx, stackName)
if err != nil {
return s, err
}
@ -144,17 +148,17 @@ func NewStack(ctx context.Context, fqsn string, ws Workspace) (Stack, error) {
return s, nil
}
// SelectStack selects stack using the given workspace, and fully qualified stack name (org/project/name).
// SelectStack selects stack using the given workspace, and stack name.
// It returns an error if the given Stack does not exist. All LocalWorkspace operations will call SelectStack()
// before running.
func SelectStack(ctx context.Context, fqsn string, ws Workspace) (Stack, error) {
func SelectStack(ctx context.Context, stackName string, ws Workspace) (Stack, error) {
var s Stack
s = Stack{
workspace: ws,
fqsn: fqsn,
stackName: stackName,
}
err := ws.SelectStack(ctx, fqsn)
err := ws.SelectStack(ctx, stackName)
if err != nil {
return s, err
}
@ -162,19 +166,19 @@ func SelectStack(ctx context.Context, fqsn string, ws Workspace) (Stack, error)
return s, nil
}
// UpsertStack tries to create a new stack using the given workspace and fully
// qualified stack name (org/project/name) if the stack does not already exist,
// UpsertStack tries to create a new stack using the given workspace and
// stack name if the stack does not already exist,
// or falls back to selecting the existing stack. If the stack does not exist,
// it will be created and selected.
func UpsertStack(ctx context.Context, fqsn string, ws Workspace) (Stack, error) {
s, err := NewStack(ctx, fqsn, ws)
func UpsertStack(ctx context.Context, stackName string, ws Workspace) (Stack, error) {
s, err := NewStack(ctx, stackName, ws)
// error for all failures except if the stack already exists, as we'll
// just select the stack if it exists.
if err != nil && !IsCreateStack409Error(err) {
return s, err
}
err = ws.SelectStack(ctx, fqsn)
err = ws.SelectStack(ctx, stackName)
if err != nil {
return s, err
}
@ -182,9 +186,9 @@ func UpsertStack(ctx context.Context, fqsn string, ws Workspace) (Stack, error)
return s, nil
}
// Name returns the fully qualified stack name in the form "org/project/stack"
// Name returns the stack name
func (s *Stack) Name() string {
return s.fqsn
return s.stackName
}
// Workspace returns the underlying Workspace backing the Stack.

View file

@ -30,31 +30,31 @@ type Workspace interface {
// SaveProjectSettings overwrites the settings object in the current project.
// There can only be a single project per workspace. Fails is new project name does not match old.
SaveProjectSettings(context.Context, *workspace.Project) error
// StackSettings returns the settings object for the stack matching the specified fullyQualifiedStackName if any.
// StackSettings returns the settings object for the stack matching the specified stack name if any.
StackSettings(context.Context, string) (*workspace.ProjectStack, error)
// SaveStackSettings overwrites the settings object for the stack matching the specified fullyQualifiedStackName.
// SaveStackSettings overwrites the settings object for the stack matching the specified stack name.
SaveStackSettings(context.Context, string, *workspace.ProjectStack) error
// SerializeArgsForOp is hook to provide additional args to every CLI commands before they are executed.
// Provided with fullyQualifiedStackName,
// Provided with stack name,
// returns a list of args to append to an invoked command ["--config=...", ].
SerializeArgsForOp(context.Context, string) ([]string, error)
// PostCommandCallback is a hook executed after every command. Called with the fullyQualifiedStackName.
// PostCommandCallback is a hook executed after every command. Called with the stack name.
// An extensibility point to perform workspace cleanup (CLI operations may create/modify a Pulumi.stack.yaml).
PostCommandCallback(context.Context, string) error
// GetConfig returns the value associated with the specified fullyQualifiedStackName and key,
// GetConfig returns the value associated with the specified stack name and key,
// scoped to the current workspace.
GetConfig(context.Context, string, string) (ConfigValue, error)
// GetAllConfig returns the config map for the specified fullyQualifiedStackName, scoped to the current workspace.
// GetAllConfig returns the config map for the specified stack name, scoped to the current workspace.
GetAllConfig(context.Context, string) (ConfigMap, error)
// SetConfig sets the specified key-value pair on the provided fullyQualifiedStackName.
// SetConfig sets the specified key-value pair on the provided stack name.
SetConfig(context.Context, string, string, ConfigValue) error
// SetAllConfig sets all values in the provided config map for the specified fullyQualifiedStackName.
// SetAllConfig sets all values in the provided config map for the specified stack name.
SetAllConfig(context.Context, string, ConfigMap) error
// RemoveConfig removes the specified key-value pair on the provided fullyQualifiedStackName.
// RemoveConfig removes the specified key-value pair on the provided stack name.
RemoveConfig(context.Context, string, string) error
// RemoveAllConfig removes all values in the provided key list for the specified fullyQualifiedStackName.
// RemoveAllConfig removes all values in the provided key list for the specified stack name.
RemoveAllConfig(context.Context, string, []string) error
// RefreshConfig gets and sets the config map used with the last Update for Stack matching fullyQualifiedStackName.
// RefreshConfig gets and sets the config map used with the last Update for Stack matching stack name.
RefreshConfig(context.Context, string) (ConfigMap, error)
// GetEnvVars returns the environment values scoped to the current workspace.
GetEnvVars() map[string]string
@ -76,9 +76,9 @@ type Workspace interface {
WhoAmI(context.Context) (string, error)
// Stack returns a summary of the currently selected stack, if any.
Stack(context.Context) (*StackSummary, error)
// CreateStack creates and sets a new stack with the fullyQualifiedStackName, failing if one already exists.
// CreateStack creates and sets a new stack with the stack name, failing if one already exists.
CreateStack(context.Context, string) error
// SelectStack selects and sets an existing stack matching the fullyQualifiedStackName, failing if none exists.
// SelectStack selects and sets an existing stack matching the stack name, failing if none exists.
SelectStack(context.Context, string) error
// RemoveStack deletes the stack and all associated configuration and history.
RemoveStack(context.Context, string) error