Skip to content

Commit dc40f04

Browse files
committed
command/push: prefer Atlas over local, add -set flag
1 parent 8b0deba commit dc40f04

2 files changed

Lines changed: 165 additions & 3 deletions

File tree

‎command/push.go‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func (c *PushCommand) Run(args []string) int {
2424
var atlasAddress, atlasToken string
2525
var archiveVCS, moduleUpload bool
2626
var name string
27+
var set []string
2728
args = c.Meta.process(args, true)
2829
cmdFlags := c.Meta.flagSet("push")
2930
cmdFlags.StringVar(&atlasAddress, "atlas-address", "", "")
@@ -32,11 +33,18 @@ func (c *PushCommand) Run(args []string) int {
3233
cmdFlags.BoolVar(&moduleUpload, "upload-modules", true, "")
3334
cmdFlags.StringVar(&name, "name", "", "")
3435
cmdFlags.BoolVar(&archiveVCS, "vcs", true, "")
36+
cmdFlags.Var((*FlagStringSlice)(&set), "set", "")
3537
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
3638
if err := cmdFlags.Parse(args); err != nil {
3739
return 1
3840
}
3941

42+
// Make a map of the set values
43+
setMap := make(map[string]struct{}, len(set))
44+
for _, v := range set {
45+
setMap[v] = struct{}{}
46+
}
47+
4048
// The pwd is used for the configuration path if one is not given
4149
pwd, err := os.Getwd()
4250
if err != nil {
@@ -132,10 +140,10 @@ func (c *PushCommand) Run(args []string) int {
132140
return 1
133141
}
134142
for k, v := range vars {
135-
// Local variables override remote ones
136-
if _, exists := ctx.Variables()[k]; exists {
143+
if _, ok := setMap[k]; ok {
137144
continue
138145
}
146+
139147
ctx.SetVariable(k, v)
140148
}
141149

@@ -211,6 +219,10 @@ Options:
211219
-token=<token> Access token to use to upload. If blank or unspecified,
212220
the ATLAS_TOKEN environmental variable will be used.
213221
222+
-set=foo Variable keys that should overwrite values in Atlas.
223+
Otherwise, variables already set in Atlas will overwrite
224+
local values. This flag can be repeated.
225+
214226
-var 'foo=bar' Set a variable in the Terraform configuration. This
215227
flag can be set multiple times.
216228

‎command/push_test.go‎

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ func TestPush_inputPartial(t *testing.T) {
179179
}
180180
}
181181

182-
func TestPush_inputTfvars(t *testing.T) {
182+
// This tests that the push command will override Atlas variables
183+
// if requested.
184+
func TestPush_localOverride(t *testing.T) {
183185
// Disable test mode so input would be asked and setup the
184186
// input reader/writers.
185187
test = false
@@ -219,6 +221,154 @@ func TestPush_inputTfvars(t *testing.T) {
219221
client: client,
220222
}
221223

224+
path := testFixturePath("push-tfvars")
225+
args := []string{
226+
"-var-file", path + "/terraform.tfvars",
227+
"-vcs=false",
228+
"-set=foo",
229+
path,
230+
}
231+
if code := c.Run(args); code != 0 {
232+
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
233+
}
234+
235+
actual := testArchiveStr(t, archivePath)
236+
expected := []string{
237+
".terraform/",
238+
".terraform/terraform.tfstate",
239+
"main.tf",
240+
"terraform.tfvars",
241+
}
242+
if !reflect.DeepEqual(actual, expected) {
243+
t.Fatalf("bad: %#v", actual)
244+
}
245+
246+
if client.UpsertOptions.Name != "foo" {
247+
t.Fatalf("bad: %#v", client.UpsertOptions)
248+
}
249+
250+
variables := map[string]string{
251+
"foo": "bar",
252+
"bar": "foo",
253+
}
254+
if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
255+
t.Fatalf("bad: %#v", client.UpsertOptions)
256+
}
257+
}
258+
259+
// This tests that the push command prefers Atlas variables over
260+
// local ones.
261+
func TestPush_preferAtlas(t *testing.T) {
262+
// Disable test mode so input would be asked and setup the
263+
// input reader/writers.
264+
test = false
265+
defer func() { test = true }()
266+
defaultInputReader = bytes.NewBufferString("nope\n")
267+
defaultInputWriter = new(bytes.Buffer)
268+
269+
tmp, cwd := testCwd(t)
270+
defer testFixCwd(t, tmp, cwd)
271+
272+
// Create remote state file, this should be pulled
273+
conf, srv := testRemoteState(t, testState(), 200)
274+
defer srv.Close()
275+
276+
// Persist local remote state
277+
s := terraform.NewState()
278+
s.Serial = 5
279+
s.Remote = conf
280+
testStateFileRemote(t, s)
281+
282+
// Path where the archive will be "uploaded" to
283+
archivePath := testTempFile(t)
284+
defer os.Remove(archivePath)
285+
286+
client := &mockPushClient{File: archivePath}
287+
// Provided vars should override existing ones
288+
client.GetResult = map[string]string{
289+
"foo": "old",
290+
}
291+
ui := new(cli.MockUi)
292+
c := &PushCommand{
293+
Meta: Meta{
294+
ContextOpts: testCtxConfig(testProvider()),
295+
Ui: ui,
296+
},
297+
298+
client: client,
299+
}
300+
301+
path := testFixturePath("push-tfvars")
302+
args := []string{
303+
"-var-file", path + "/terraform.tfvars",
304+
"-vcs=false",
305+
path,
306+
}
307+
if code := c.Run(args); code != 0 {
308+
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
309+
}
310+
311+
actual := testArchiveStr(t, archivePath)
312+
expected := []string{
313+
".terraform/",
314+
".terraform/terraform.tfstate",
315+
"main.tf",
316+
"terraform.tfvars",
317+
}
318+
if !reflect.DeepEqual(actual, expected) {
319+
t.Fatalf("bad: %#v", actual)
320+
}
321+
322+
if client.UpsertOptions.Name != "foo" {
323+
t.Fatalf("bad: %#v", client.UpsertOptions)
324+
}
325+
326+
variables := map[string]string{
327+
"foo": "old",
328+
"bar": "foo",
329+
}
330+
if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
331+
t.Fatalf("bad: %#v", client.UpsertOptions)
332+
}
333+
}
334+
335+
// This tests that the push command will send the variables in tfvars
336+
func TestPush_tfvars(t *testing.T) {
337+
// Disable test mode so input would be asked and setup the
338+
// input reader/writers.
339+
test = false
340+
defer func() { test = true }()
341+
defaultInputReader = bytes.NewBufferString("nope\n")
342+
defaultInputWriter = new(bytes.Buffer)
343+
344+
tmp, cwd := testCwd(t)
345+
defer testFixCwd(t, tmp, cwd)
346+
347+
// Create remote state file, this should be pulled
348+
conf, srv := testRemoteState(t, testState(), 200)
349+
defer srv.Close()
350+
351+
// Persist local remote state
352+
s := terraform.NewState()
353+
s.Serial = 5
354+
s.Remote = conf
355+
testStateFileRemote(t, s)
356+
357+
// Path where the archive will be "uploaded" to
358+
archivePath := testTempFile(t)
359+
defer os.Remove(archivePath)
360+
361+
client := &mockPushClient{File: archivePath}
362+
ui := new(cli.MockUi)
363+
c := &PushCommand{
364+
Meta: Meta{
365+
ContextOpts: testCtxConfig(testProvider()),
366+
Ui: ui,
367+
},
368+
369+
client: client,
370+
}
371+
222372
path := testFixturePath("push-tfvars")
223373
args := []string{
224374
"-var-file", path + "/terraform.tfvars",

0 commit comments

Comments
 (0)