@@ -327,6 +327,64 @@ def __call__(self, parser, namespace, values, option_string=None):
327
327
parser .exit ()
328
328
329
329
330
+ class ExtendKeyValuePairs (argparse .Action ):
331
+ def __init__ (
332
+ self ,
333
+ option_strings ,
334
+ dest ,
335
+ nargs = None ,
336
+ const = None ,
337
+ default = None ,
338
+ type = None ,
339
+ choices = None ,
340
+ required = False ,
341
+ help = None ,
342
+ metavar = None ,
343
+ ): # pylint: disable=W0622
344
+ super ().__init__ (
345
+ option_strings = option_strings ,
346
+ dest = dest ,
347
+ nargs = nargs ,
348
+ const = const ,
349
+ default = default ,
350
+ type = type ,
351
+ choices = choices ,
352
+ required = required ,
353
+ help = help ,
354
+ metavar = metavar ,
355
+ )
356
+
357
+ def __call__ (self , parser , namespace , values , option_string = None ):
358
+ try :
359
+ items = {}
360
+ for value in values :
361
+ # split it into key and value
362
+ key , value = value .split ("=" , 1 )
363
+ items [key .strip ()] = value .strip ()
364
+
365
+ result = getattr (namespace , self .dest ) + [items ]
366
+ setattr (namespace , self .dest , result )
367
+ except Exception : # pylint: disable=W0703
368
+ parser .print_help ()
369
+ parser .exit ()
370
+
371
+
372
+ class ExtendAction (argparse .Action ):
373
+ """Support argument types that are lists and can
374
+ be specified multiple times.
375
+ """
376
+
377
+ def __call__ (self , parser , namespace , values , option_string = None ):
378
+ items = getattr (namespace , self .dest )
379
+ items = [] if items is None else items
380
+ for value in values :
381
+ if isinstance (value , list ):
382
+ items .extend (value )
383
+ else :
384
+ items .append (value )
385
+ setattr (namespace , self .dest , items )
386
+
387
+
330
388
class CliArgs :
331
389
"""Base Args class"""
332
390
@@ -344,21 +402,6 @@ def error(self, message):
344
402
self .print_help (sys .stderr )
345
403
self .exit (32 , f"{ self .prog } : error: { message } \n " )
346
404
347
- class ExtendAction (argparse .Action ):
348
- """Support argument types that are lists and can
349
- be specified multiple times.
350
- """
351
-
352
- def __call__ (self , parser , namespace , values , option_string = None ):
353
- items = getattr (namespace , self .dest )
354
- items = [] if items is None else items
355
- for value in values :
356
- if isinstance (value , list ):
357
- items .extend (value )
358
- else :
359
- items .append (value )
360
- setattr (namespace , self .dest , items )
361
-
362
405
usage = (
363
406
"\n Basic: cfn-lint test.yaml\n "
364
407
"Ignore a rule: cfn-lint -i E3012 -- test.yaml\n "
@@ -368,18 +411,23 @@ def __call__(self, parser, namespace, values, option_string=None):
368
411
369
412
parser = ArgumentParser (description = "CloudFormation Linter" , usage = usage )
370
413
parser .register ("action" , "extend" , ExtendAction )
414
+ parser .register ("action" , "rule_configuration" , RuleConfigurationAction )
415
+ parser .register ("action" , "extend_key_value" , ExtendKeyValuePairs )
371
416
372
417
standard = parser .add_argument_group ("Standard" )
373
418
advanced = parser .add_argument_group ("Advanced / Debugging" )
374
419
420
+ validation_group = standard .add_mutually_exclusive_group ()
421
+ parameter_group = standard .add_mutually_exclusive_group ()
422
+
375
423
# Allow the template to be passes as an optional or a positional argument
376
424
standard .add_argument (
377
425
"templates" ,
378
426
metavar = "TEMPLATE" ,
379
427
nargs = "*" ,
380
428
help = "The CloudFormation template to be linted" ,
381
429
)
382
- standard .add_argument (
430
+ validation_group .add_argument (
383
431
"-t" ,
384
432
"--template" ,
385
433
metavar = "TEMPLATE" ,
@@ -403,22 +451,21 @@ def __call__(self, parser, namespace, values, option_string=None):
403
451
default = [],
404
452
action = "extend" ,
405
453
)
406
- standard .add_argument (
454
+ validation_group .add_argument (
407
455
"--deployment-files" ,
408
456
dest = "deployment_files" ,
409
457
help = "Deployment files" ,
410
458
nargs = "+" ,
411
459
default = [],
412
460
action = "extend" ,
413
461
)
414
- standard .add_argument (
462
+ parameter_group .add_argument (
415
463
"-tp" ,
416
464
"--template-parameters" ,
417
465
dest = "template_parameters" ,
418
- metavar = "KEY=VALUE" ,
419
466
nargs = "+" ,
420
- default = {} ,
421
- action = key_value ,
467
+ default = [] ,
468
+ action = "extend_key_value" ,
422
469
help = "only check rules whose id do not match these values" ,
423
470
)
424
471
advanced .add_argument (
@@ -509,7 +556,7 @@ def __call__(self, parser, namespace, values, option_string=None):
509
556
dest = "configure_rules" ,
510
557
nargs = "+" ,
511
558
default = {},
512
- action = RuleConfigurationAction ,
559
+ action = "rule_configuration" ,
513
560
help = (
514
561
"Provide configuration for a rule. Format RuleId:key=value. Example:"
515
562
" E3012:strict=true"
@@ -614,15 +661,15 @@ def set_template_args(self, template):
614
661
615
662
if isinstance (configs , dict ):
616
663
for key , value in {
617
- "ignore_checks" : (list ),
618
- "regions" : (list ),
619
664
"append_rules" : (list ),
620
- "override_spec " : (str ),
665
+ "configure_rules " : (dict ),
621
666
"custom_rules" : (str ),
622
667
"ignore_bad_template" : (bool ),
668
+ "ignore_checks" : (list ),
623
669
"include_checks" : (list ),
624
- "configure_rules" : (dict ),
625
670
"include_experimental" : (bool ),
671
+ "override_spec" : (str ),
672
+ "regions" : (list ),
626
673
}.items ():
627
674
if key in configs :
628
675
if isinstance (configs [key ], value ):
@@ -635,17 +682,18 @@ def set_template_args(self, template):
635
682
636
683
class ManualArgs (TypedDict , total = False ):
637
684
configure_rules : dict [str , dict [str , Any ]]
638
- include_checks : list [str ]
639
- ignore_checks : list [str ]
640
- template_parameters : dict [str , Any ]
641
- mandatory_checks : list [str ]
642
- include_experimental : bool
685
+ deployment_files : list [str ]
643
686
ignore_bad_template : bool
687
+ ignore_checks : list [str ]
644
688
ignore_templates : list
689
+ include_checks : list [str ]
690
+ include_experimental : bool
691
+ mandatory_checks : list [str ]
645
692
merge_configs : bool
646
693
non_zero_exit_code : str
647
694
output_file : str
648
695
regions : list
696
+ template_parameters : list [dict [str , Any ]]
649
697
650
698
651
699
# pylint: disable=too-many-public-methods
@@ -665,24 +713,25 @@ def __init__(self, cli_args: list[str] | None = None, **kwargs: Unpack[ManualArg
665
713
def __repr__ (self ):
666
714
return format_json_string (
667
715
{
716
+ "append_rules" : self .append_rules ,
717
+ "config_file" : self .config_file ,
718
+ "configure_rules" : self .configure_rules ,
719
+ "custom_rules" : self .custom_rules ,
720
+ "debug" : self .debug ,
721
+ "deployment_files" : self .deployment_files ,
722
+ "format" : self .format ,
723
+ "ignore_bad_template" : self .ignore_bad_template ,
668
724
"ignore_checks" : self .ignore_checks ,
669
725
"include_checks" : self .include_checks ,
670
- "mandatory_checks" : self .mandatory_checks ,
671
- "template_parameters" : self .template_parameters ,
672
726
"include_experimental" : self .include_experimental ,
673
- "configure_rules" : self .configure_rules ,
674
- "regions" : self .regions ,
675
- "ignore_bad_template" : self .ignore_bad_template ,
676
- "debug" : self .debug ,
677
727
"info" : self .info ,
678
- "format" : self .format ,
679
- "templates" : self .templates ,
680
- "append_rules" : self .append_rules ,
681
- "override_spec" : self .override_spec ,
682
- "custom_rules" : self .custom_rules ,
683
- "config_file" : self .config_file ,
728
+ "mandatory_checks" : self .mandatory_checks ,
684
729
"merge_configs" : self .merge_configs ,
685
730
"non_zero_exit_code" : self .non_zero_exit_code ,
731
+ "override_spec" : self .override_spec ,
732
+ "regions" : self .regions ,
733
+ "template_parameters" : self .template_parameters ,
734
+ "templates" : self .templates ,
686
735
}
687
736
)
688
737
@@ -845,7 +894,7 @@ def template_parameters(self):
845
894
return self ._get_argument_value ("template_parameters" , True , True )
846
895
847
896
@template_parameters .setter
848
- def template_parameters (self , template_parameters : dict [str , Any ]):
897
+ def template_parameters (self , template_parameters : list [ dict [str , Any ] ]):
849
898
self ._manual_args ["template_parameters" ] = template_parameters
850
899
851
900
@property
0 commit comments