@@ -316,6 +316,144 @@ func TestCheckTerraformFlags_AllEdgeCases(t *testing.T) {
316316 }
317317}
318318
319+ // TestHasMultiComponentFlags tests the hasMultiComponentFlags function.
320+ func TestHasMultiComponentFlags (t * testing.T ) {
321+ tests := []struct {
322+ name string
323+ info * schema.ConfigAndStacksInfo
324+ expected bool
325+ }{
326+ {
327+ name : "no flags set" ,
328+ info : & schema.ConfigAndStacksInfo {},
329+ expected : false ,
330+ },
331+ {
332+ name : "all flag set" ,
333+ info : & schema.ConfigAndStacksInfo {
334+ All : true ,
335+ },
336+ expected : true ,
337+ },
338+ {
339+ name : "affected flag set" ,
340+ info : & schema.ConfigAndStacksInfo {
341+ Affected : true ,
342+ },
343+ expected : true ,
344+ },
345+ {
346+ name : "query flag set" ,
347+ info : & schema.ConfigAndStacksInfo {
348+ Query : ".components.test" ,
349+ },
350+ expected : true ,
351+ },
352+ {
353+ name : "components flag set" ,
354+ info : & schema.ConfigAndStacksInfo {
355+ Components : []string {"comp1" , "comp2" },
356+ },
357+ expected : true ,
358+ },
359+ {
360+ name : "empty components slice" ,
361+ info : & schema.ConfigAndStacksInfo {
362+ Components : []string {},
363+ },
364+ expected : false ,
365+ },
366+ {
367+ name : "multiple multi-component flags set" ,
368+ info : & schema.ConfigAndStacksInfo {
369+ All : true ,
370+ Query : ".components.test" ,
371+ },
372+ expected : true ,
373+ },
374+ }
375+
376+ for _ , tt := range tests {
377+ t .Run (tt .name , func (t * testing.T ) {
378+ result := hasMultiComponentFlags (tt .info )
379+ assert .Equal (t , tt .expected , result )
380+ })
381+ }
382+ }
383+
384+ // TestHandleInteractiveComponentStackSelection_SkipsPromptForMultiComponentFlags tests that
385+ // interactive prompting is skipped when multi-component flags are set.
386+ // Regression test for: https://github.com/cloudposse/atmos/issues/1945
387+ // Before the fix, `--all` flag was not applied to info before this check, causing
388+ // the prompt to appear even when `--all` was specified.
389+ func TestHandleInteractiveComponentStackSelection_SkipsPromptForMultiComponentFlags (t * testing.T ) {
390+ tests := []struct {
391+ name string
392+ info * schema.ConfigAndStacksInfo
393+ }{
394+ {
395+ name : "skips prompt when --all flag is set" ,
396+ info : & schema.ConfigAndStacksInfo {
397+ All : true ,
398+ },
399+ },
400+ {
401+ name : "skips prompt when --affected flag is set" ,
402+ info : & schema.ConfigAndStacksInfo {
403+ Affected : true ,
404+ },
405+ },
406+ {
407+ name : "skips prompt when --query flag is set" ,
408+ info : & schema.ConfigAndStacksInfo {
409+ Query : ".components.test" ,
410+ },
411+ },
412+ {
413+ name : "skips prompt when --components flag is set" ,
414+ info : & schema.ConfigAndStacksInfo {
415+ Components : []string {"comp1" , "comp2" },
416+ },
417+ },
418+ }
419+
420+ for _ , tt := range tests {
421+ t .Run (tt .name , func (t * testing.T ) {
422+ cmd := & cobra.Command {Use : "plan" }
423+
424+ // Capture the initial state - ComponentFromArg should remain empty
425+ // because the function should skip prompting and return early.
426+ initialComponent := tt .info .ComponentFromArg
427+ initialStack := tt .info .Stack
428+
429+ err := handleInteractiveComponentStackSelection (tt .info , cmd )
430+
431+ // Should return nil (no error) and NOT modify the info struct.
432+ assert .NoError (t , err )
433+ assert .Equal (t , initialComponent , tt .info .ComponentFromArg ,
434+ "ComponentFromArg should not be modified when multi-component flags are set" )
435+ assert .Equal (t , initialStack , tt .info .Stack ,
436+ "Stack should not be modified when multi-component flags are set" )
437+ })
438+ }
439+ }
440+
441+ // TestHandleInteractiveComponentStackSelection_SkipsWhenBothProvided tests that
442+ // interactive prompting is skipped when both component and stack are already provided.
443+ func TestHandleInteractiveComponentStackSelection_SkipsWhenBothProvided (t * testing.T ) {
444+ cmd := & cobra.Command {Use : "plan" }
445+ info := & schema.ConfigAndStacksInfo {
446+ ComponentFromArg : "my-component" ,
447+ Stack : "my-stack" ,
448+ }
449+
450+ err := handleInteractiveComponentStackSelection (info , cmd )
451+
452+ assert .NoError (t , err )
453+ assert .Equal (t , "my-component" , info .ComponentFromArg )
454+ assert .Equal (t , "my-stack" , info .Stack )
455+ }
456+
319457// TestStackFlagCompletion_NoArgs tests the stackFlagCompletion function without args.
320458func TestStackFlagCompletion_NoArgs (t * testing.T ) {
321459 t .Chdir ("../../examples/demo-stacks" )
@@ -394,53 +532,6 @@ func TestIsMultiComponentExecution(t *testing.T) {
394532 }
395533}
396534
397- // TestHasMultiComponentFlags tests the hasMultiComponentFlags function.
398- func TestHasMultiComponentFlags (t * testing.T ) {
399- tests := []struct {
400- name string
401- info * schema.ConfigAndStacksInfo
402- expected bool
403- }{
404- {
405- name : "all flag" ,
406- info : & schema.ConfigAndStacksInfo {All : true },
407- expected : true ,
408- },
409- {
410- name : "affected flag" ,
411- info : & schema.ConfigAndStacksInfo {Affected : true },
412- expected : true ,
413- },
414- {
415- name : "components set" ,
416- info : & schema.ConfigAndStacksInfo {Components : []string {"comp1" }},
417- expected : true ,
418- },
419- {
420- name : "query set" ,
421- info : & schema.ConfigAndStacksInfo {Query : ".test" },
422- expected : true ,
423- },
424- {
425- name : "no flags" ,
426- info : & schema.ConfigAndStacksInfo {},
427- expected : false ,
428- },
429- {
430- name : "empty components slice" ,
431- info : & schema.ConfigAndStacksInfo {Components : []string {}},
432- expected : false ,
433- },
434- }
435-
436- for _ , tt := range tests {
437- t .Run (tt .name , func (t * testing.T ) {
438- result := hasMultiComponentFlags (tt .info )
439- assert .Equal (t , tt .expected , result )
440- })
441- }
442- }
443-
444535// TestHasNonAffectedMultiFlags tests the hasNonAffectedMultiFlags function.
445536func TestHasNonAffectedMultiFlags (t * testing.T ) {
446537 tests := []struct {
0 commit comments