14
14
import json
15
15
import sys
16
16
import shutil
17
+ import os
17
18
18
19
THIS_DIRECTORY = Path (__file__ ).parent .absolute ()
19
20
EXAMPLE_DIRECTORIES = [d for d in (THIS_DIRECTORY / 'examples' ).iterdir () if d .is_dir ()]
@@ -35,60 +36,85 @@ def run_verbose(cmd_args, *args, **kwargs):
35
36
36
37
# Commands
37
38
def cmd_all_npm_install (args ):
38
- """" Install all node dependencies for all examples"""
39
+ """Install all node dependencies for all examples"""
39
40
for project_dir in EXAMPLE_DIRECTORIES + TEMPLATE_DIRECTORIES :
40
41
frontend_dir = next (project_dir .glob ("*/frontend/" ))
41
42
run_verbose (["npm" , "install" ], cwd = str (frontend_dir ))
42
43
43
44
44
45
def cmd_all_npm_build (args ):
45
- """" Build javascript code for all examples and templates"""
46
+ """Build javascript code for all examples and templates"""
46
47
for project_dir in EXAMPLE_DIRECTORIES + TEMPLATE_DIRECTORIES :
47
48
frontend_dir = next (project_dir .glob ("*/frontend/" ))
48
49
run_verbose (["npm" , "run" , "build" ], cwd = str (frontend_dir ))
49
50
50
51
51
- def cmd_all_install_python_deps (args ):
52
- """"Install all dependencies needed to run e2e tests for all examples and templates """
52
+ def cmd_e2e_build_images (args ):
53
+ """Build docker images for each component e2e tests"""
53
54
for project_dir in EXAMPLE_DIRECTORIES + TEMPLATE_DIRECTORIES :
54
- run_verbose (["pip" , "install" , "-e" , ".[devel]" ], cwd = str (project_dir ))
55
+ e2e_dir = next (project_dir .glob ("**/e2e/" ), None )
56
+ if e2e_dir and os .listdir (e2e_dir ):
57
+ # Define the image tag for the docker image
58
+ image_tag = (
59
+ f"component-template:py-{ args .python_version } -st-{ args .streamlit_version } -component-{ project_dir .parts [- 1 ]} "
60
+ )
61
+ # Build the docker image with specified build arguments
62
+ run_verbose (
63
+ [
64
+ "docker" ,
65
+ "build" ,
66
+ "." ,
67
+ f"--build-arg=STREAMLIT_VERSION={ args .streamlit_version } " ,
68
+ f"--build-arg=PYTHON_VERSION={ args .python_version } " ,
69
+ f"--tag={ image_tag } " ,
70
+ "--progress=plain" ,
71
+ ],
72
+ env = {** os .environ , "DOCKER_BUILDKIT" : "1" },
73
+ )
55
74
56
75
57
- def cmd_all_install_wheel_packages (args ):
58
- """"Install wheel packages of all examples and templates for e2e tests """
76
+ def cmd_e2e_run (args ):
77
+ """Run e2e tests for all examples and templates in separate docker images """
59
78
for project_dir in EXAMPLE_DIRECTORIES + TEMPLATE_DIRECTORIES :
60
- wheel_files = list (project_dir .glob ("dist/*.whl" ))
61
- if wheel_files :
62
- wheel_file = wheel_files [0 ]
63
- run_verbose (["pip" , "install" , str (wheel_file )], cwd = str (project_dir ))
64
- else :
65
- print (f"No wheel files found in { project_dir } " )
66
-
67
-
68
- def cmd_install_browsers (args ):
69
- """"Install multiple browsers to run e2e for all examples and templates"""
70
- run_verbose (["playwright" , "install" , "webkit" , "chromium" , "firefox" , "--with-deps" ])
71
-
72
-
73
- def cmd_all_run_e2e (args ):
74
- """"Run e2e tests for all examples and templates"""
75
- for project_dir in TEMPLATE_DIRECTORIES :
79
+ container_name = project_dir .parts [- 1 ]
80
+ image_tag = (
81
+ f"component-template:py-{ args .python_version } -st-{ args .streamlit_version } -component-{ container_name } "
82
+ )
76
83
e2e_dir = next (project_dir .glob ("**/e2e/" ), None )
77
- if e2e_dir :
78
- with tempfile .TemporaryDirectory () as tmp_dir :
79
- run_verbose (['python' , '-m' , 'venv' , f"{ tmp_dir } /venv" ])
80
- wheel_files = list (project_dir .glob ("dist/*.whl" ))
81
- if wheel_files :
82
- wheel_file = wheel_files [0 ]
83
- run_verbose ([f"{ tmp_dir } /venv/bin/pip" , "install" , f"{ str (wheel_file )} [devel]" ], cwd = str (project_dir ))
84
- else :
85
- print (f"No wheel files found in { project_dir } " )
86
- run_verbose ([f"{ tmp_dir } /venv/bin/pytest" , "-s" , "--browser" , "webkit" , "--browser" , "chromium" , "--browser" , "firefox" , "--reruns" , "5" , str (e2e_dir )])
87
-
88
- for project_dir in EXAMPLE_DIRECTORIES :
84
+ if e2e_dir and os .listdir (e2e_dir ):
85
+ run_verbose ([
86
+ "docker" ,
87
+ "run" ,
88
+ "--tty" ,
89
+ "--rm" ,
90
+ "--name" , container_name ,
91
+ "--volume" , f"{ e2e_dir .parent } /:/component/" ,
92
+ image_tag ,
93
+ "/bin/sh" , "-c" , # Run a shell command inside the container
94
+ "find /component/dist/ -name '*.whl' | xargs -I {} echo '{}[devel]' | xargs pip install && " # Install whl package and dev dependencies
95
+ f"playwright install webkit chromium firefox --with-deps && " # Install browsers
96
+ f"pytest" , # Run pytest
97
+ "-s" ,
98
+ "--browser" , "webkit" ,
99
+ "--browser" , "chromium" ,
100
+ "--browser" , "firefox" ,
101
+ "--reruns" , "5" ,
102
+ "--capture=no" ,
103
+ "--setup-show"
104
+ ])
105
+
106
+
107
+ def cmd_docker_images_cleanup (args ):
108
+ """Cleanup docker images and containers"""
109
+ for project_dir in EXAMPLE_DIRECTORIES + TEMPLATE_DIRECTORIES :
110
+ container_name = project_dir .parts [- 1 ]
111
+ image_name = (
112
+ f"component-template:py-{ args .python_version } -st-{ args .streamlit_version } -component-{ container_name } "
113
+ )
89
114
e2e_dir = next (project_dir .glob ("**/e2e/" ), None )
90
- if e2e_dir :
91
- run_verbose (["pytest" , "-s" , "--browser" , "webkit" , "--browser" , "chromium" , "--browser" , "firefox" , "--reruns" , "5" , str (e2e_dir )])
115
+ if e2e_dir and os .listdir (e2e_dir ):
116
+ # Remove the associated Docker image
117
+ run_verbose (["docker" , "rmi" , image_name ])
92
118
93
119
94
120
def cmd_all_python_build_package (args ):
@@ -104,8 +130,8 @@ def cmd_all_python_build_package(args):
104
130
105
131
def check_deps (template_package_json , current_package_json ):
106
132
return (
107
- check_deps_section (template_package_json , current_package_json , 'dependencies' ) +
108
- check_deps_section (template_package_json , current_package_json , 'devDependencies' )
133
+ check_deps_section (template_package_json , current_package_json , 'dependencies' ) +
134
+ check_deps_section (template_package_json , current_package_json , 'devDependencies' )
109
135
)
110
136
111
137
@@ -169,7 +195,8 @@ def cmd_check_templates_using_cookiecutter(args):
169
195
replay_file_content = json .loads (cookiecutter_variant .replay_file .read_text ())
170
196
171
197
with tempfile .TemporaryDirectory () as output_dir :
172
- print (f"Generating template with replay file: { cookiecutter_variant .replay_file .relative_to (THIS_DIRECTORY )} " )
198
+ print (
199
+ f"Generating template with replay file: { cookiecutter_variant .replay_file .relative_to (THIS_DIRECTORY )} " )
173
200
run_verbose (
174
201
[
175
202
"cookiecutter" ,
@@ -243,10 +270,27 @@ def cmd_update_templates(args):
243
270
"examples-check-deps" : cmd_example_check_deps ,
244
271
"templates-check-not-modified" : cmd_check_templates_using_cookiecutter ,
245
272
"templates-update" : cmd_update_templates ,
246
- "install-python-deps" : cmd_all_install_python_deps ,
247
- "install-wheel-packages" : cmd_all_install_wheel_packages ,
248
- "install-browsers" : cmd_install_browsers ,
249
- "run-e2e" : cmd_all_run_e2e ,
273
+ "e2e-build-images" : cmd_e2e_build_images ,
274
+ "e2e-run-tests" : cmd_e2e_run ,
275
+ "docker-images-cleanup" : cmd_docker_images_cleanup
276
+ }
277
+
278
+ ARG_STREAMLIT_VERSION = ("--streamlit-version" , "latest" , "Streamlit version for which tests will be run." )
279
+ ARG_PYTHON_VERSION = ("--python-version" , os .environ .get ("PYTHON_VERSION" , "3.11.4" ), "Python version for which tests will be run." )
280
+
281
+ ARGUMENTS = {
282
+ "e2e-build-images" : [
283
+ ARG_STREAMLIT_VERSION ,
284
+ ARG_PYTHON_VERSION
285
+ ],
286
+ "e2e-run-tests" : [
287
+ ARG_STREAMLIT_VERSION ,
288
+ ARG_PYTHON_VERSION
289
+ ],
290
+ "docker-images-cleanup" : [
291
+ (* ARG_STREAMLIT_VERSION [:2 ], f"Streamlit version used to create the Docker resources" ),
292
+ (* ARG_PYTHON_VERSION [:2 ], f"Python version used to create the Docker resources" )
293
+ ]
250
294
}
251
295
252
296
@@ -256,7 +300,14 @@ def get_parser():
256
300
subparsers = parser .add_subparsers (dest = "subcommand" , metavar = "COMMAND" )
257
301
subparsers .required = True
258
302
for command_name , command_fn in COMMANDS .items ():
259
- subparsers .add_parser (command_name , help = command_fn .__doc__ ).set_defaults (func = command_fn )
303
+ subparser = subparsers .add_parser (command_name , help = command_fn .__doc__ )
304
+
305
+ if command_name in ARGUMENTS :
306
+ for arg_name , arg_default , arg_help in ARGUMENTS [command_name ]:
307
+ subparser .add_argument (arg_name , default = arg_default , help = arg_help )
308
+
309
+ subparser .set_defaults (func = command_fn )
310
+
260
311
return parser
261
312
262
313
0 commit comments