Add --stack argument to a few missing commands (#2278)

As of this change, all of the stack specific commands for `pulumi` now
allow passing `--stack` to operate on a different stack from the
default one.

Fixes #1648
This commit is contained in:
Matt Ellis 2018-12-10 10:10:43 -08:00 committed by GitHub
parent ad78f3ef59
commit 59a54f1802
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 56 additions and 37 deletions

View file

@ -4,6 +4,8 @@
- Update the error message when When `pulumi` commands fail to detect your project to mention that `pulumi new` can be used to create a new project (fixes [pulumi/pulumi#2234](https://github.com/pulumi/pulumi/issues/2234))
- Added a `--stack` argument (short form `-s`) to `pulumi stack`, `pulumi stack init`, `pulumi state delete` and `pulumi state unprotect` to allow operating on a different stack than the currently selected stack. This brings these commands in line with the other commands that operate on stacks and already provided a `--stack` option (fixes [pulumi/pulumi#1648](https://github.com/pulumi/pulumi/issues/1648))
## 0.16.7 (Release December 5th, 2018)
### Improvements

View file

@ -31,6 +31,7 @@ import (
func newStackCmd() *cobra.Command {
var showIDs bool
var showURNs bool
var stackName string
cmd := &cobra.Command{
Use: "stack",
@ -46,7 +47,7 @@ func newStackCmd() *cobra.Command {
Color: cmdutil.GetGlobalColorization(),
}
s, err := requireCurrentStack(true, opts, true /*setCurrent*/)
s, err := requireStack(stackName, true, opts, true /*setCurrent*/)
if err != nil {
return err
}
@ -156,7 +157,9 @@ func newStackCmd() *cobra.Command {
return nil
}),
}
cmd.PersistentFlags().StringVarP(
&stackName, "stack", "s", "",
"The name of the stack to operate on. Defaults to the current stack")
cmd.PersistentFlags().BoolVarP(
&showIDs, "show-ids", "i", false, "Display each resource's provider-assigned unique ID")
cmd.PersistentFlags().BoolVarP(

View file

@ -23,6 +23,8 @@ import (
)
func newStackInitCmd() *cobra.Command {
var stackName string
cmd := &cobra.Command{
Use: "init [<organization-name>/]<stack-name>",
Args: cmdutil.MaximumNArgs(1),
@ -44,10 +46,15 @@ func newStackInitCmd() *cobra.Command {
return err
}
var stackName string
if len(args) > 0 {
if stackName != "" {
return errors.New("only one of --stack or argument stack name may be specified, not both")
}
stackName = args[0]
} else if cmdutil.Interactive() {
}
if stackName == "" && cmdutil.Interactive() {
name, nameErr := cmdutil.ReadConsole("Enter a stack name")
if nameErr != nil {
return nameErr
@ -69,5 +76,7 @@ func newStackInitCmd() *cobra.Command {
return err
}),
}
cmd.PersistentFlags().StringVarP(
&stackName, "stack", "s", "", "The name of the stack to create")
return cmd
}

View file

@ -39,7 +39,7 @@ func newStateCmd() *cobra.Command {
Use: "state",
Short: "Edit the current stack's state",
Long: `Edit the current stack's state
Subcommands of this command can be used to surgically edit parts of a stack's state. These can be useful when
troubleshooting a stack or when performing specific edits that otherwise would require editing the state file by hand.`,
Args: cmdutil.NoArgs,
@ -108,9 +108,9 @@ func locateStackResource(opts display.Options, snap *deploy.Snapshot, urn resour
return optionMap[option], nil
}
// runStateEdit runs the given state edit function on a resource with the given URN in the current stack.
func runStateEdit(urn resource.URN, operation edit.OperationFunc) error {
return runTotalStateEdit(func(opts display.Options, snap *deploy.Snapshot) error {
// runStateEdit runs the given state edit function on a resource with the given URN in a given stack.
func runStateEdit(stackName string, urn resource.URN, operation edit.OperationFunc) error {
return runTotalStateEdit(stackName, func(opts display.Options, snap *deploy.Snapshot) error {
res, err := locateStackResource(opts, snap, urn)
if err != nil {
return err
@ -120,13 +120,13 @@ func runStateEdit(urn resource.URN, operation edit.OperationFunc) error {
})
}
// runTotalStateEdit runs a snapshot-mutating function on the entirity of the current stack's snapshot. Before mutating
// runTotalStateEdit runs a snapshot-mutating function on the entirity of the given stack's snapshot. Before mutating
// the snapshot, the user is prompted for confirmation if the current session is interactive.
func runTotalStateEdit(operation func(opts display.Options, snap *deploy.Snapshot) error) error {
func runTotalStateEdit(stackName string, operation func(opts display.Options, snap *deploy.Snapshot) error) error {
opts := display.Options{
Color: cmdutil.GetGlobalColorization(),
}
s, err := requireCurrentStack(true, opts, true /*setCurrent*/)
s, err := requireStack(stackName, true, opts, true /*setCurrent*/)
if err != nil {
return err
}

View file

@ -27,21 +27,33 @@ import (
"github.com/spf13/cobra"
)
var force bool // Force deletion of protected resources
func newStateDeleteCommand() *cobra.Command {
var force bool // Force deletion of protected resources
var stack string
cmd := &cobra.Command{
Use: "delete",
Short: "Deletes a resource from a stack's state",
Long: `Deletes a resource from a stack's state
This command deletes a resource from a stack's state, as long as it is safe to do so. Resources can't be deleted if
there exist other resources that depend on it or are parented to it. Protected resources will not be deleted unless
it is specifically requested using the --force flag.`,
Args: cmdutil.ExactArgs(1),
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
urn := resource.URN(args[0])
err := runStateEdit(urn, doDeletion)
err := runStateEdit(stack, urn, func(snap *deploy.Snapshot, res *resource.State) error {
if !force {
return edit.DeleteResource(snap, res)
}
if res.Protect {
cmdutil.Diag().Warningf(diag.RawMessage("" /*urn*/, "deleting protected resource due to presence of --force"))
res.Protect = false
}
return edit.DeleteResource(snap, res)
})
if err != nil {
switch e := err.(type) {
case edit.ResourceHasDependenciesError:
@ -66,21 +78,9 @@ it is specifically requested using the --force flag.`,
}),
}
cmd.PersistentFlags().StringVarP(
&stack, "stack", "s", "",
"The name of the stack to operate on. Defaults to the current stack")
cmd.Flags().BoolVar(&force, "force", false, "Force deletion of protected resources")
return cmd
}
// doDeletion implements edit.OperationFunc and deletes a resource from the snapshot. If the `force` flag is present,
// doDeletion will unprotect the resource before deleting it.
func doDeletion(snap *deploy.Snapshot, res *resource.State) error {
if !force {
return edit.DeleteResource(snap, res)
}
if res.Protect {
cmdutil.Diag().Warningf(diag.RawMessage("" /*urn*/, "deleting protected resource due to presence of --force"))
res.Protect = false
}
return edit.DeleteResource(snap, res)
}

View file

@ -32,16 +32,18 @@ import (
func newStateUnprotectCommand() *cobra.Command {
var unprotectAll bool
var stack string
cmd := &cobra.Command{
Use: "unprotect",
Short: "Unprotect resources in a stack's state",
Long: `Unprotect resource in a stack's state
This command clears the 'protect' bit on one or more resources, allowing those resources to be deleted.`,
Args: cmdutil.MaximumNArgs(1),
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
if unprotectAll {
return unprotectAllResources()
return unprotectAllResources(stack)
}
if len(args) != 1 {
@ -49,16 +51,19 @@ This command clears the 'protect' bit on one or more resources, allowing those r
}
urn := resource.URN(args[0])
return unprotectResource(urn)
return unprotectResource(stack, urn)
}),
}
cmd.PersistentFlags().StringVarP(
&stack, "stack", "s", "",
"The name of the stack to operate on. Defaults to the current stack")
cmd.Flags().BoolVar(&unprotectAll, "all", false, "Unprotect all resources in the checkpoint")
return cmd
}
func unprotectAllResources() error {
err := runTotalStateEdit(func(_ display.Options, snap *deploy.Snapshot) error {
func unprotectAllResources(stackName string) error {
err := runTotalStateEdit(stackName, func(_ display.Options, snap *deploy.Snapshot) error {
for _, res := range snap.Resources {
err := edit.UnprotectResource(snap, res)
contract.AssertNoError(err)
@ -74,8 +79,8 @@ func unprotectAllResources() error {
return nil
}
func unprotectResource(urn resource.URN) error {
err := runStateEdit(urn, edit.UnprotectResource)
func unprotectResource(stackName string, urn resource.URN) error {
err := runStateEdit(stackName, urn, edit.UnprotectResource)
if err != nil {
return err
}