1313# limitations under the License.
1414
1515import click
16- import contextlib
1716import functools
1817import glob
1918import itertools
2019import logging
2120import os
2221import shutil
2322
23+ from contextlib import contextmanager , nullcontext
2424
2525_logger = logging .getLogger ('fireci' )
2626
@@ -30,7 +30,7 @@ def _ensure_dir(directory):
3030 os .makedirs (directory )
3131
3232
33- @contextlib . contextmanager
33+ @contextmanager
3434def _artifact_handler (target_directory , artifact_patterns ):
3535 _logger .debug (
3636 'Artifacts will be searched for in directories matching {} patterns and placed in {}'
@@ -45,7 +45,7 @@ def _artifact_handler(target_directory, artifact_patterns):
4545 target_name = os .path .join (target_directory , "_" .join (path .split ('/' )))
4646 _logger .debug ('Copying artifact {} to {}' .format (path , target_name ))
4747 if os .path .isdir (path ):
48- shutil .copytree (path , target_name )
48+ shutil .copytree (path , target_name , dirs_exist_ok = True )
4949 else :
5050 shutil .copyfile (path , target_name )
5151
@@ -68,8 +68,8 @@ class _CommonOptions:
6868 '--artifact-patterns' ,
6969 default = ('**/build/test-results' , '**/build/reports' ),
7070 help =
71- 'Shell-style artifact patterns that are copied into `artifact-target-dir`.' \
72- 'Can be specified multiple times.' ,
71+ 'Shell-style artifact patterns that are copied into `artifact-target-dir`. '
72+ 'Can be specified multiple times.' ,
7373 multiple = True ,
7474 type = str ,
7575)
@@ -83,30 +83,34 @@ def main(options, **kwargs):
8383 setattr (options , k , v )
8484
8585
86- def ci_command (name = None ):
86+ def ci_command (name = None , cls = click . Command , group = main ):
8787 """Decorator to use for CI commands.
8888
8989 The differences from the standard @click.command are:
9090
9191 * Allows configuration of artifacts that are uploaded for later viewing in CI.
92- * Registers the command automatically
92+ * Registers the command automatically.
9393
94- :param name: Optional name of the task. Defaults to the function name that is decorated with
95- this decorator.
94+ :param name: Optional name of the task. Defaults to the function name that is decorated with this decorator.
95+ :param cls: Specifies whether the func is a command or a command group. Defaults to `click.Command`.
96+ :param group: Specifies the group the command belongs to. Defaults to the `main` command group.
9697 """
9798
9899 def ci_command (f ):
99100 actual_name = f .__name__ if name is None else name
100101
101- @main .command (name = actual_name , help = f .__doc__ )
102+ @click .command (name = actual_name , cls = cls , help = f .__doc__ )
102103 @_pass_options
103104 @click .pass_context
104105 def new_func (ctx , options , * args , ** kwargs ):
105106 with _artifact_handler (
106107 options .artifact_target_dir ,
107- options .artifact_patterns ):
108+ options .artifact_patterns ,
109+ ) if cls is click .Command else nullcontext ():
108110 return ctx .invoke (f , * args , ** kwargs )
109111
112+ group .add_command (new_func )
113+
110114 return functools .update_wrapper (new_func , f )
111115
112116 return ci_command
0 commit comments