13
13
# limitations under the License.
14
14
15
15
import click
16
- import contextlib
17
16
import functools
18
17
import glob
19
18
import itertools
20
19
import logging
21
20
import os
22
21
import shutil
23
22
23
+ from contextlib import contextmanager , nullcontext
24
24
25
25
_logger = logging .getLogger ('fireci' )
26
26
@@ -30,7 +30,7 @@ def _ensure_dir(directory):
30
30
os .makedirs (directory )
31
31
32
32
33
- @contextlib . contextmanager
33
+ @contextmanager
34
34
def _artifact_handler (target_directory , artifact_patterns ):
35
35
_logger .debug (
36
36
'Artifacts will be searched for in directories matching {} patterns and placed in {}'
@@ -45,7 +45,7 @@ def _artifact_handler(target_directory, artifact_patterns):
45
45
target_name = os .path .join (target_directory , "_" .join (path .split ('/' )))
46
46
_logger .debug ('Copying artifact {} to {}' .format (path , target_name ))
47
47
if os .path .isdir (path ):
48
- shutil .copytree (path , target_name )
48
+ shutil .copytree (path , target_name , dirs_exist_ok = True )
49
49
else :
50
50
shutil .copyfile (path , target_name )
51
51
@@ -68,8 +68,8 @@ class _CommonOptions:
68
68
'--artifact-patterns' ,
69
69
default = ('**/build/test-results' , '**/build/reports' ),
70
70
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.' ,
73
73
multiple = True ,
74
74
type = str ,
75
75
)
@@ -83,30 +83,34 @@ def main(options, **kwargs):
83
83
setattr (options , k , v )
84
84
85
85
86
- def ci_command (name = None ):
86
+ def ci_command (name = None , cls = click . Command , group = main ):
87
87
"""Decorator to use for CI commands.
88
88
89
89
The differences from the standard @click.command are:
90
90
91
91
* Allows configuration of artifacts that are uploaded for later viewing in CI.
92
- * Registers the command automatically
92
+ * Registers the command automatically.
93
93
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.
96
97
"""
97
98
98
99
def ci_command (f ):
99
100
actual_name = f .__name__ if name is None else name
100
101
101
- @main .command (name = actual_name , help = f .__doc__ )
102
+ @click .command (name = actual_name , cls = cls , help = f .__doc__ )
102
103
@_pass_options
103
104
@click .pass_context
104
105
def new_func (ctx , options , * args , ** kwargs ):
105
106
with _artifact_handler (
106
107
options .artifact_target_dir ,
107
- options .artifact_patterns ):
108
+ options .artifact_patterns ,
109
+ ) if cls is click .Command else nullcontext ():
108
110
return ctx .invoke (f , * args , ** kwargs )
109
111
112
+ group .add_command (new_func )
113
+
110
114
return functools .update_wrapper (new_func , f )
111
115
112
116
return ci_command
0 commit comments