diff --git a/command/meta.go b/command/meta.go index 8a4578b5f..28a01c542 100644 --- a/command/meta.go +++ b/command/meta.go @@ -170,6 +170,7 @@ func (m *Meta) InputMode() terraform.InputMode { mode |= terraform.InputModeProvider if len(m.variables) == 0 && m.autoKey == "" { mode |= terraform.InputModeVar + mode |= terraform.InputModeVarUnset } return mode diff --git a/command/push.go b/command/push.go index b88446040..324e8a258 100644 --- a/command/push.go +++ b/command/push.go @@ -84,6 +84,17 @@ func (c *PushCommand) Run(args []string) int { return 1 } + // Get the variables we might already have + vars, err := c.client.Get("") + if err != nil { + c.Ui.Error(fmt.Sprintf( + "Error looking up prior pushed configuration: %s", err)) + return 1 + } + for k, v := range vars { + ctx.SetVariable(k, v) + } + // Ask for input if err := ctx.Input(c.InputMode()); err != nil { c.Ui.Error(fmt.Sprintf( @@ -155,6 +166,7 @@ func (c *PushCommand) Synopsis() string { // pushClient is implementd internally to control where pushes go. This is // either to Atlas or a mock for testing. type pushClient interface { + Get(string) (map[string]string, error) Upsert(*pushUpsertOptions) error } @@ -166,11 +178,22 @@ type pushUpsertOptions struct { type mockPushClient struct { File string + GetCalled bool + GetName string + GetResult map[string]string + GetError error + UpsertCalled bool UpsertOptions *pushUpsertOptions UpsertError error } +func (c *mockPushClient) Get(name string) (map[string]string, error) { + c.GetCalled = true + c.GetName = name + return c.GetResult, c.GetError +} + func (c *mockPushClient) Upsert(opts *pushUpsertOptions) error { f, err := os.Create(c.File) if err != nil { diff --git a/command/push_test.go b/command/push_test.go index 3c6415b62..68c5a8a42 100644 --- a/command/push_test.go +++ b/command/push_test.go @@ -117,6 +117,61 @@ func TestPush_input(t *testing.T) { } } +func TestPush_inputPartial(t *testing.T) { + tmp, cwd := testCwd(t) + defer testFixCwd(t, tmp, cwd) + + // Create remote state file, this should be pulled + conf, srv := testRemoteState(t, testState(), 200) + defer srv.Close() + + // Persist local remote state + s := terraform.NewState() + s.Serial = 5 + s.Remote = conf + testStateFileRemote(t, s) + + // Path where the archive will be "uploaded" to + archivePath := testTempFile(t) + defer os.Remove(archivePath) + + client := &mockPushClient{ + File: archivePath, + GetResult: map[string]string{"foo": "bar"}, + } + ui := new(cli.MockUi) + c := &PushCommand{ + Meta: Meta{ + ContextOpts: testCtxConfig(testProvider()), + Ui: ui, + }, + + client: client, + } + + // Disable test mode so input would be asked and setup the + // input reader/writers. + test = false + defer func() { test = true }() + defaultInputReader = bytes.NewBufferString("foo\n") + defaultInputWriter = new(bytes.Buffer) + + args := []string{ + testFixturePath("push-input-partial"), + } + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + variables := map[string]string{ + "foo": "bar", + "bar": "foo", + } + if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) { + t.Fatalf("bad: %#v", client.UpsertOptions) + } +} + func TestPush_noState(t *testing.T) { tmp, cwd := testCwd(t) defer testFixCwd(t, tmp, cwd) diff --git a/command/test-fixtures/push-input-partial/main.tf b/command/test-fixtures/push-input-partial/main.tf new file mode 100644 index 000000000..8862603b0 --- /dev/null +++ b/command/test-fixtures/push-input-partial/main.tf @@ -0,0 +1,4 @@ +variable "foo" {} +variable "bar" {} + +resource "test_instance" "foo" {}