stoobly-agent 1.10.0__py3-none-any.whl → 1.10.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/__main__.py +10 -0
  3. stoobly_agent/app/api/application_http_request_handler.py +5 -2
  4. stoobly_agent/app/cli/ca_cert_cli.py +9 -5
  5. stoobly_agent/app/cli/helpers/replay_facade.py +2 -2
  6. stoobly_agent/app/cli/intercept_cli.py +5 -5
  7. stoobly_agent/app/cli/request_cli.py +2 -2
  8. stoobly_agent/app/cli/scaffold/app.py +14 -5
  9. stoobly_agent/app/cli/scaffold/app_command.py +0 -4
  10. stoobly_agent/app/cli/scaffold/app_config.py +49 -2
  11. stoobly_agent/app/cli/scaffold/app_create_command.py +145 -76
  12. stoobly_agent/app/cli/scaffold/constants.py +9 -4
  13. stoobly_agent/app/cli/scaffold/docker/constants.py +3 -1
  14. stoobly_agent/app/cli/scaffold/docker/service/build_decorator.py +4 -4
  15. stoobly_agent/app/cli/scaffold/docker/service/builder.py +31 -54
  16. stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py +3 -0
  17. stoobly_agent/app/cli/scaffold/docker/template_files.py +112 -0
  18. stoobly_agent/app/cli/scaffold/docker/workflow/build_decorator.py +1 -1
  19. stoobly_agent/app/cli/scaffold/docker/workflow/builder.py +30 -47
  20. stoobly_agent/app/cli/scaffold/docker/workflow/command_decorator.py +3 -2
  21. stoobly_agent/app/cli/scaffold/docker/workflow/detached_decorator.py +1 -1
  22. stoobly_agent/app/cli/scaffold/docker/workflow/dns_decorator.py +2 -3
  23. stoobly_agent/app/cli/scaffold/docker/workflow/local_decorator.py +1 -1
  24. stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py +1 -1
  25. stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py +1 -1
  26. stoobly_agent/app/cli/scaffold/docker/workflow/run_command.py +423 -0
  27. stoobly_agent/app/cli/scaffold/local/__init__.py +0 -0
  28. stoobly_agent/app/cli/scaffold/local/service/__init__.py +0 -0
  29. stoobly_agent/app/cli/scaffold/local/service/builder.py +72 -0
  30. stoobly_agent/app/cli/scaffold/local/workflow/__init__.py +0 -0
  31. stoobly_agent/app/cli/scaffold/local/workflow/builder.py +35 -0
  32. stoobly_agent/app/cli/scaffold/local/workflow/run_command.py +339 -0
  33. stoobly_agent/app/cli/scaffold/service_command.py +9 -1
  34. stoobly_agent/app/cli/scaffold/service_config.py +9 -25
  35. stoobly_agent/app/cli/scaffold/service_create_command.py +18 -6
  36. stoobly_agent/app/cli/scaffold/service_docker_compose.py +3 -3
  37. stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +10 -7
  38. stoobly_agent/app/cli/scaffold/templates/app/.Makefile +2 -2
  39. stoobly_agent/app/cli/scaffold/templates/app/build/.docker-compose.base.yml +4 -4
  40. stoobly_agent/app/cli/scaffold/templates/app/build/mock/configure +3 -0
  41. stoobly_agent/app/cli/scaffold/templates/app/build/record/configure +28 -0
  42. stoobly_agent/app/cli/scaffold/templates/app/build/test/configure +3 -0
  43. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/.docker-compose.base.yml +4 -4
  44. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/configure +3 -0
  45. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/run +3 -0
  46. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/configure +3 -0
  47. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/run +3 -0
  48. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/configure +3 -0
  49. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/run +3 -0
  50. stoobly_agent/app/cli/scaffold/templates/build/services/build/mock/.configure +5 -1
  51. stoobly_agent/app/cli/scaffold/templates/build/services/build/mock/.init +5 -1
  52. stoobly_agent/app/cli/scaffold/templates/build/services/build/mock/.run +14 -0
  53. stoobly_agent/app/cli/scaffold/templates/build/services/build/record/.configure +5 -1
  54. stoobly_agent/app/cli/scaffold/templates/build/services/build/record/.init +5 -1
  55. stoobly_agent/app/cli/scaffold/templates/build/services/build/record/.run +14 -0
  56. stoobly_agent/app/cli/scaffold/templates/build/services/build/test/.configure +5 -1
  57. stoobly_agent/app/cli/scaffold/templates/build/services/build/test/.init +5 -1
  58. stoobly_agent/app/cli/scaffold/templates/build/services/build/test/.run +14 -0
  59. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/mock/.configure +5 -1
  60. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/mock/.init +5 -1
  61. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/mock/.run +19 -0
  62. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/record/.configure +5 -1
  63. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/record/.init +5 -1
  64. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/record/.run +19 -0
  65. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/test/.configure +5 -1
  66. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/test/.init +5 -1
  67. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/test/.run +19 -0
  68. stoobly_agent/app/cli/scaffold/templates/build/workflows/exec/scaffold/.up +0 -1
  69. stoobly_agent/app/cli/scaffold/templates/build/workflows/mock/.configure +5 -1
  70. stoobly_agent/app/cli/scaffold/templates/build/workflows/mock/.init +5 -1
  71. stoobly_agent/app/cli/scaffold/templates/build/workflows/mock/.run +14 -0
  72. stoobly_agent/app/cli/scaffold/templates/build/workflows/record/.configure +25 -1
  73. stoobly_agent/app/cli/scaffold/templates/build/workflows/record/.init +5 -1
  74. stoobly_agent/app/cli/scaffold/templates/build/workflows/record/.run +14 -0
  75. stoobly_agent/app/cli/scaffold/templates/build/workflows/test/.configure +5 -1
  76. stoobly_agent/app/cli/scaffold/templates/build/workflows/test/.init +5 -1
  77. stoobly_agent/app/cli/scaffold/templates/build/workflows/test/.run +14 -0
  78. stoobly_agent/app/cli/scaffold/templates/constants.py +35 -19
  79. stoobly_agent/app/cli/scaffold/templates/factory.py +34 -18
  80. stoobly_agent/app/cli/scaffold/templates/plugins/cypress/test/.run +21 -0
  81. stoobly_agent/app/cli/scaffold/templates/plugins/playwright/test/.run +21 -0
  82. stoobly_agent/app/cli/scaffold/templates/workflow/mock/configure +5 -0
  83. stoobly_agent/app/cli/scaffold/templates/workflow/mock/run +3 -0
  84. stoobly_agent/app/cli/scaffold/templates/workflow/record/configure +21 -0
  85. stoobly_agent/app/cli/scaffold/templates/workflow/record/run +3 -0
  86. stoobly_agent/app/cli/scaffold/templates/workflow/test/configure +5 -0
  87. stoobly_agent/app/cli/scaffold/templates/workflow/test/run +3 -0
  88. stoobly_agent/app/cli/scaffold/workflow_command.py +18 -4
  89. stoobly_agent/app/cli/scaffold/workflow_copy_command.py +5 -4
  90. stoobly_agent/app/cli/scaffold/workflow_create_command.py +31 -29
  91. stoobly_agent/app/cli/scaffold/workflow_run_command.py +18 -151
  92. stoobly_agent/app/cli/scaffold_cli.py +134 -182
  93. stoobly_agent/app/cli/scenario_cli.py +2 -2
  94. stoobly_agent/app/cli/types/test.py +2 -2
  95. stoobly_agent/app/cli/types/workflow_run_command.py +52 -3
  96. stoobly_agent/app/proxy/handle_mock_service.py +1 -1
  97. stoobly_agent/app/proxy/intercept_settings.py +6 -26
  98. stoobly_agent/app/proxy/mock/eval_fixtures_service.py +177 -27
  99. stoobly_agent/app/proxy/mock/types/__init__.py +22 -1
  100. stoobly_agent/app/proxy/record/upload_request_service.py +3 -6
  101. stoobly_agent/app/proxy/replay/body_parser_service.py +8 -5
  102. stoobly_agent/app/proxy/replay/multipart.py +15 -13
  103. stoobly_agent/app/proxy/replay/replay_request_service.py +2 -2
  104. stoobly_agent/app/proxy/run.py +3 -0
  105. stoobly_agent/app/proxy/test/context.py +0 -4
  106. stoobly_agent/app/proxy/test/context_abc.py +0 -5
  107. stoobly_agent/app/proxy/utils/publish_change_service.py +20 -23
  108. stoobly_agent/app/settings/__init__.py +10 -7
  109. stoobly_agent/cli.py +61 -16
  110. stoobly_agent/config/data_dir.py +1 -8
  111. stoobly_agent/public/12-es2015.618ecfd5f735b801b50f.js +1 -0
  112. stoobly_agent/public/12-es5.618ecfd5f735b801b50f.js +1 -0
  113. stoobly_agent/public/index.html +1 -1
  114. stoobly_agent/public/main-es2015.5a9aa16433404c3f423a.js +1 -0
  115. stoobly_agent/public/main-es5.5a9aa16433404c3f423a.js +1 -0
  116. stoobly_agent/public/runtime-es2015.77bcd31efed9e5d5d431.js +1 -0
  117. stoobly_agent/public/runtime-es5.77bcd31efed9e5d5d431.js +1 -0
  118. stoobly_agent/test/app/cli/intercept/intercept_configure_test.py +17 -6
  119. stoobly_agent/test/app/cli/scaffold/docker/cli_invoker.py +177 -0
  120. stoobly_agent/test/app/cli/scaffold/{cli_test.py → docker/cli_test.py} +4 -11
  121. stoobly_agent/test/app/cli/scaffold/{e2e_test.py → docker/e2e_test.py} +42 -27
  122. stoobly_agent/test/app/cli/scaffold/local/__init__.py +0 -0
  123. stoobly_agent/test/app/cli/scaffold/{cli_invoker.py → local/cli_invoker.py} +38 -32
  124. stoobly_agent/test/app/cli/scaffold/local/e2e_test.py +342 -0
  125. stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
  126. stoobly_agent/test/app/proxy/mock/eval_fixtures_service_test.py +903 -2
  127. stoobly_agent/test/app/proxy/replay/body_parser_service_test.py +95 -3
  128. stoobly_agent/test/config/data_dir_test.py +2 -7
  129. stoobly_agent/test/test_helper.py +16 -5
  130. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.2.dist-info}/METADATA +4 -2
  131. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.2.dist-info}/RECORD +157 -129
  132. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.2.dist-info}/WHEEL +1 -1
  133. stoobly_agent/app/cli/helpers/shell.py +0 -26
  134. stoobly_agent/app/cli/scaffold/templates/app/build/mock/bin/configure +0 -3
  135. stoobly_agent/app/cli/scaffold/templates/app/build/record/bin/configure +0 -3
  136. stoobly_agent/app/cli/scaffold/templates/app/build/test/bin/configure +0 -3
  137. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/bin/configure +0 -3
  138. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/bin/configure +0 -3
  139. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/configure +0 -3
  140. stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/configure +0 -13
  141. stoobly_agent/app/cli/scaffold/templates/workflow/record/bin/configure +0 -47
  142. stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/configure +0 -13
  143. stoobly_agent/public/12-es2015.be58ed0ef449008b932e.js +0 -1
  144. stoobly_agent/public/12-es5.be58ed0ef449008b932e.js +0 -1
  145. stoobly_agent/public/main-es2015.089b46f303768fbe864f.js +0 -1
  146. stoobly_agent/public/main-es5.089b46f303768fbe864f.js +0 -1
  147. stoobly_agent/public/runtime-es2015.f8c814b38b27708e91c1.js +0 -1
  148. stoobly_agent/public/runtime-es5.f8c814b38b27708e91c1.js +0 -1
  149. /stoobly_agent/app/cli/scaffold/templates/app/build/mock/{.docker-compose.mock.yml → .docker-compose.yml} +0 -0
  150. /stoobly_agent/app/cli/scaffold/templates/app/build/mock/{bin/init → init} +0 -0
  151. /stoobly_agent/app/cli/scaffold/templates/app/build/record/{.docker-compose.record.yml → .docker-compose.yml} +0 -0
  152. /stoobly_agent/app/cli/scaffold/templates/app/build/record/{bin/init → init} +0 -0
  153. /stoobly_agent/app/cli/scaffold/templates/app/build/test/{.docker-compose.test.yml → .docker-compose.yml} +0 -0
  154. /stoobly_agent/app/cli/scaffold/templates/app/build/test/{bin/init → init} +0 -0
  155. /stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/{.docker-compose.mock.yml → .docker-compose.yml} +0 -0
  156. /stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/{bin/init → init} +0 -0
  157. /stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/{.docker-compose.record.yml → .docker-compose.yml} +0 -0
  158. /stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/{bin/init → init} +0 -0
  159. /stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/{.docker-compose.test.yml → .docker-compose.yml} +0 -0
  160. /stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/{bin/init → init} +0 -0
  161. /stoobly_agent/app/cli/scaffold/templates/app/gateway/mock/{.docker-compose.mock.yml → .docker-compose.yml} +0 -0
  162. /stoobly_agent/app/cli/scaffold/templates/app/gateway/record/{.docker-compose.record.yml → .docker-compose.yml} +0 -0
  163. /stoobly_agent/app/cli/scaffold/templates/app/gateway/test/{.docker-compose.test.yml → .docker-compose.yml} +0 -0
  164. /stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/{.docker-compose.exec.yml → .docker-compose.yml} +0 -0
  165. /stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/mock/{.docker-compose.mock.yml → .docker-compose.yml} +0 -0
  166. /stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/record/{.docker-compose.record.yml → .docker-compose.yml} +0 -0
  167. /stoobly_agent/app/cli/scaffold/templates/plugins/cypress/test/{.docker-compose.test.yml → .docker-compose.yml} +0 -0
  168. /stoobly_agent/app/cli/scaffold/templates/plugins/playwright/test/{.docker-compose.test.yml → .docker-compose.yml} +0 -0
  169. /stoobly_agent/app/cli/scaffold/templates/workflow/mock/{bin/init → init} +0 -0
  170. /stoobly_agent/app/cli/scaffold/templates/workflow/record/{bin/init → init} +0 -0
  171. /stoobly_agent/app/cli/scaffold/templates/workflow/test/{bin/init → init} +0 -0
  172. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.2.dist-info}/entry_points.txt +0 -0
  173. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.2.dist-info/licenses}/LICENSE +0 -0
@@ -3,20 +3,16 @@ import os
3
3
  import pdb
4
4
  import sys
5
5
 
6
- from io import TextIOWrapper
7
- from typing import List
8
- from urllib.parse import urlparse
9
6
 
7
+ from stoobly_agent.app.cli.ca_cert_cli import ca_cert_install
10
8
  from stoobly_agent.app.cli.helpers.certificate_authority import CertificateAuthority
11
- from stoobly_agent.app.cli.helpers.shell import exec_stream
12
9
  from stoobly_agent.app.cli.scaffold.app import App
10
+ from stoobly_agent.app.cli.scaffold.app_config import AppConfig
13
11
  from stoobly_agent.app.cli.scaffold.app_create_command import AppCreateCommand
14
12
  from stoobly_agent.app.cli.scaffold.constants import (
15
- DOCKER_NAMESPACE, WORKFLOW_CONTAINER_PROXY, WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
13
+ PLUGIN_CYPRESS, PLUGIN_PLAYWRIGHT, RUN_ON_DOCKER, RUN_ON_OPTIONS, SERVICES_NAMESPACE, WORKFLOW_CONTAINER_PROXY, WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
16
14
  )
17
- from stoobly_agent.app.cli.scaffold.constants import PLUGIN_CYPRESS, PLUGIN_PLAYWRIGHT
18
15
  from stoobly_agent.app.cli.scaffold.containerized_app import ContainerizedApp
19
- from stoobly_agent.app.cli.scaffold.docker.service.configure_gateway import configure_gateway
20
16
  from stoobly_agent.app.cli.scaffold.docker.workflow.decorators_factory import get_workflow_decorators
21
17
  from stoobly_agent.app.cli.scaffold.hosts_file_manager import HostsFileManager
22
18
  from stoobly_agent.app.cli.scaffold.service import Service
@@ -30,16 +26,16 @@ from stoobly_agent.app.cli.scaffold.validate_exceptions import ScaffoldValidateE
30
26
  from stoobly_agent.app.cli.scaffold.workflow import Workflow
31
27
  from stoobly_agent.app.cli.scaffold.workflow_create_command import WorkflowCreateCommand
32
28
  from stoobly_agent.app.cli.scaffold.workflow_copy_command import WorkflowCopyCommand
33
- from stoobly_agent.app.cli.scaffold.workflow_log_command import WorkflowLogCommand
34
29
  from stoobly_agent.app.cli.scaffold.workflow_namesapce import WorkflowNamespace
35
- from stoobly_agent.app.cli.scaffold.workflow_run_command import WorkflowRunCommand
30
+ from stoobly_agent.app.cli.scaffold.docker.workflow.run_command import DockerWorkflowRunCommand
31
+ from stoobly_agent.app.cli.scaffold.local.workflow.run_command import LocalWorkflowRunCommand
36
32
  from stoobly_agent.app.cli.scaffold.workflow_validate_command import WorkflowValidateCommand
37
33
  from stoobly_agent.config.constants import env_vars
38
34
  from stoobly_agent.config.data_dir import DataDir
39
35
  from stoobly_agent.lib.logger import bcolors, DEBUG, ERROR, INFO, Logger, WARNING
40
36
 
41
37
  from .helpers.print_service import FORMATS, print_services, select_print_options
42
- from .validators.scaffold import validate_app_name, validate_hostname, validate_namespace, validate_network, validate_service_name
38
+ from .validators.scaffold import validate_app_name, validate_hostname, validate_namespace, validate_service_name
43
39
 
44
40
  LOG_ID = 'Scaffold'
45
41
 
@@ -92,16 +88,21 @@ def hostname(ctx):
92
88
  @click.option('--app-dir-path', default=current_working_dir, help='Path to create the app scaffold.')
93
89
  @click.option('--docker-socket-path', default='/var/run/docker.sock', type=click.Path(exists=True, file_okay=True, dir_okay=False), help='Path to Docker socket.')
94
90
  @click.option('--plugin', multiple=True, type=click.Choice([PLUGIN_CYPRESS, PLUGIN_PLAYWRIGHT]), help='Scaffold integrations.')
91
+ @click.option('--proxy-port', default=8080, type=click.IntRange(1, 65535), help='Proxy service port.')
95
92
  @click.option('--quiet', is_flag=True, help='Disable log output.')
93
+ @click.option('--run-on', multiple=True, type=click.Choice(RUN_ON_OPTIONS), default=[RUN_ON_DOCKER], help='Runtime environments to support (default: docker).')
96
94
  @click.option('--ui-port', default=4200, type=click.IntRange(1, 65535), help='UI service port.')
97
95
  @click.argument('app_name', callback=validate_app_name)
98
96
  def create(**kwargs):
99
97
  __validate_app_dir(kwargs['app_dir_path'])
100
98
 
101
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
99
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
102
100
 
103
- if not kwargs['quiet'] and os.path.exists(app.scaffold_namespace_path):
104
- print(f"{kwargs['app_dir_path']} already exists, updating scaffold maintained files...")
101
+ if not kwargs['quiet']:
102
+ if os.path.exists(app.scaffold_namespace_path):
103
+ print(f"{kwargs['app_dir_path']} already exists, updating scaffold maintained files...")
104
+ else:
105
+ print(f"Creating scaffold in {kwargs['app_dir_path']}")
105
106
 
106
107
  res = AppCreateCommand(app, **kwargs).build()
107
108
 
@@ -118,7 +119,7 @@ def create(**kwargs):
118
119
  @click.option('--service', multiple=True, help='Select which services to run. Defaults to all.')
119
120
  @click.option('--workflow', multiple=True, help='Specify services by workflow(s). Defaults to all.')
120
121
  def mkcert(**kwargs):
121
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE, **kwargs)
122
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE, **kwargs)
122
123
  __validate_app(app)
123
124
 
124
125
  services = __get_services(
@@ -137,7 +138,6 @@ def mkcert(**kwargs):
137
138
  @click.option('--local', is_flag=True, help='Specifies upstream service is local. Overrides `--upstream-hostname` option.')
138
139
  @click.option('--port', type=click.IntRange(1, 65535), help='Service port.')
139
140
  @click.option('--priority', default=5, type=click.FloatRange(1.0, 9.0), help='Determines the service run order. Lower values run first.')
140
- @click.option('--proxy-mode', type=click.Choice(['regular', 'reverse']), help='Proxy mode can be regular or reverse.')
141
141
  @click.option('--quiet', is_flag=True, help='Disable log output.')
142
142
  @click.option('--scheme', type=click.Choice(['http', 'https']), help='Defaults to https if hostname is set.')
143
143
  @click.option('--upstream-hostname', callback=validate_hostname, help='Upstream service hostname.')
@@ -148,7 +148,7 @@ def mkcert(**kwargs):
148
148
  def create(**kwargs):
149
149
  __validate_app_dir(kwargs['app_dir_path'])
150
150
 
151
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
151
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
152
152
  service = Service(kwargs['service_name'], app)
153
153
 
154
154
  if not kwargs['quiet'] and os.path.exists(service.dir_path):
@@ -168,7 +168,7 @@ def create(**kwargs):
168
168
  @click.option('--all', is_flag=True, default=False, help='Display all services including core and user defined services')
169
169
  @click.option('--workflow', multiple=True, help='Specify workflow(s) to filter the services by. Defaults to all.')
170
170
  def _list(**kwargs):
171
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
171
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
172
172
  __validate_app(app)
173
173
 
174
174
  without_core = not kwargs['all']
@@ -209,7 +209,7 @@ def show(ctx, **kwargs):
209
209
  @click.option('--app-dir-path', default=current_working_dir, help='Path to application directory.')
210
210
  @click.argument('service_name')
211
211
  def delete(**kwargs):
212
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
212
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
213
213
  __validate_app(app)
214
214
 
215
215
  service = Service(kwargs['service_name'], app)
@@ -230,14 +230,13 @@ def delete(**kwargs):
230
230
  @click.option('--name', callback=validate_service_name, type=click.STRING, help='New name of the service to update to.')
231
231
  @click.option('--port', type=click.IntRange(1, 65535), help='Service port.')
232
232
  @click.option('--priority', type=click.FloatRange(1.0, 9.0), help='Determines the service run order. Lower values run first.')
233
- @click.option('--proxy-mode', type=click.Choice(['regular', 'reverse']), help='Proxy mode can be regular or reverse.')
234
233
  @click.option('--scheme', type=click.Choice(['http', 'https']), help='Defaults to https if hostname is set.')
235
234
  @click.option('--upstream-hostname', callback=validate_hostname, help='Upstream service hostname.')
236
235
  @click.option('--upstream-port', type=click.IntRange(1, 65535), help='Upstream service port.')
237
236
  @click.option('--upstream-scheme', type=click.Choice(['http', 'https']), help='Upstream service scheme.')
238
237
  @click.argument('service_name')
239
238
  def update(**kwargs):
240
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
239
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
241
240
  __validate_app(app)
242
241
 
243
242
  service = Service(kwargs['service_name'], app)
@@ -257,9 +256,6 @@ def update(**kwargs):
257
256
  if kwargs['priority']:
258
257
  service_config.priority = kwargs['priority']
259
258
 
260
- if kwargs['proxy_mode']:
261
- service_config.proxy_mode = kwargs['proxy_mode']
262
-
263
259
  if kwargs['scheme']:
264
260
  service_config.scheme = kwargs['scheme']
265
261
 
@@ -299,7 +295,7 @@ def update(**kwargs):
299
295
  def create(**kwargs):
300
296
  __validate_app_dir(kwargs['app_dir_path'])
301
297
 
302
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE, **kwargs)
298
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE, **kwargs)
303
299
 
304
300
  for service_name in kwargs['service']:
305
301
  config = { **kwargs }
@@ -325,7 +321,7 @@ def create(**kwargs):
325
321
  @click.argument('workflow_name')
326
322
  @click.argument('destination_workflow_name')
327
323
  def copy(**kwargs):
328
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE, **kwargs)
324
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE, **kwargs)
329
325
 
330
326
  for service_name in kwargs['service']:
331
327
  config = { **kwargs }
@@ -345,13 +341,10 @@ def copy(**kwargs):
345
341
  @click.option('--context-dir-path', default=data_dir.context_dir_path, help='Path to Stoobly data directory.')
346
342
  @click.option('--containerized', is_flag=True, help='Set if run from within a container.')
347
343
  @click.option('--dry-run', default=False, is_flag=True)
348
- @click.option('--extra-entrypoint-compose-path', help='Path to extra entrypoint compose file.')
349
344
  @click.option('--log-level', default=INFO, type=click.Choice([DEBUG, INFO, WARNING, ERROR]), help='''
350
345
  Log levels can be "debug", "info", "warning", or "error"
351
346
  ''')
352
347
  @click.option('--namespace', callback=validate_namespace, help='Workflow namespace.')
353
- @click.option('--network', callback=validate_network, help='Workflow network name.')
354
- @click.option('--rmi', is_flag=True, help='Remove images used by containers.')
355
348
  @click.option('--script-path', help='Path to intermediate script path.')
356
349
  @click.option('--service', multiple=True, help='Select which services to log. Defaults to all.')
357
350
  @click.option('--user-id', default=os.getuid(), help='OS user ID of the owner of context dir path.')
@@ -362,63 +355,42 @@ def down(**kwargs):
362
355
  containerized = kwargs['containerized']
363
356
 
364
357
  app_dir_path = current_working_dir if containerized else kwargs['app_dir_path']
365
- app = App(app_dir_path, DOCKER_NAMESPACE, **kwargs)
358
+ app = App(app_dir_path, SERVICES_NAMESPACE, **kwargs)
366
359
  __validate_app(app)
367
360
 
368
361
  __with_namespace_defaults(kwargs)
369
- __with_workflow_namespace(app, kwargs['namespace'])
370
362
 
371
363
  services = __get_services(
372
364
  app, service=kwargs['service'], workflow=[kwargs['workflow_name']]
373
365
  )
374
366
 
375
- commands: List[WorkflowRunCommand] = []
376
- for service in services:
377
- config = { **kwargs }
378
- config['service_name'] = service
379
- command = WorkflowRunCommand(app, **config)
380
- command.current_working_dir = current_working_dir
381
- commands.append(command)
382
-
367
+ command_args = { 'print_service_header': lambda service_name: __print_header(f"Step {service_name}") }
383
368
  script = __build_script(app, **kwargs)
384
-
385
- commands = sorted(commands, key=lambda command: command.service_config.priority)
386
- for index, command in enumerate(commands):
387
- __print_header(f"SERVICE {command.service_name}")
388
-
389
- extra_compose_path = None
390
-
391
- # By default, the entrypoint service should be last
392
- # However, this can change if the user has configured a service's priority to be higher
393
- if index == len(commands) - 1:
394
- extra_compose_path = kwargs['extra_entrypoint_compose_path']
395
-
396
- exec_command = command.down(
397
- extra_compose_path=extra_compose_path,
398
- namespace=kwargs['namespace'],
399
- rmi=kwargs['rmi'],
400
- user_id=kwargs['user_id']
369
+
370
+ # Determine which workflow command to use based on app configuration
371
+ app_config = AppConfig(app.scaffold_namespace_path)
372
+ if app_config.run_on_local:
373
+ # Use LocalWorkflowRunCommand for local execution
374
+ workflow_command = LocalWorkflowRunCommand(
375
+ app,
376
+ services=services,
377
+ script=script,
378
+ **kwargs
401
379
  )
402
- if not exec_command:
403
- continue
404
-
405
- print(exec_command, file=script)
406
-
407
- # After services are stopped, their network needs to be removed
408
- if len(commands) > 0:
409
- command: WorkflowRunCommand = commands[0]
410
-
411
- if kwargs['rmi']:
412
- remove_image_command = command.remove_image(kwargs['user_id'])
413
- print(remove_image_command, file=script)
414
-
415
- remove_egress_network_command = command.remove_egress_network()
416
- print(remove_egress_network_command, file=script)
417
-
418
- remove_ingress_network_command = command.remove_ingress_network()
419
- print(remove_ingress_network_command, file=script)
420
-
421
- __run_script(script, kwargs['dry_run'])
380
+ else:
381
+ # Use DockerWorkflowRunCommand for Docker execution
382
+ workflow_command = DockerWorkflowRunCommand(
383
+ app,
384
+ services=services,
385
+ script=script,
386
+ **kwargs
387
+ )
388
+
389
+ # Execute the workflow down
390
+ workflow_command.down(
391
+ **command_args,
392
+ **kwargs
393
+ )
422
394
 
423
395
  # Options are no longer valid
424
396
  if kwargs['containerized'] and os.path.exists(data_dir.mitmproxy_options_json_path):
@@ -441,7 +413,7 @@ def down(**kwargs):
441
413
  def logs(**kwargs):
442
414
  os.environ[env_vars.LOG_LEVEL] = kwargs['log_level']
443
415
 
444
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
416
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
445
417
  __validate_app(app)
446
418
 
447
419
  __with_namespace_defaults(kwargs)
@@ -453,37 +425,34 @@ def logs(**kwargs):
453
425
  app, service=kwargs['service'], without_core=True, workflow=[kwargs['workflow_name']]
454
426
  )
455
427
 
456
- commands: List[WorkflowLogCommand] = []
457
- for service in services:
458
- if len(kwargs['service']) == 0:
459
- # If no filter is specified, ignore CORE_SERVICES
460
- if service in CORE_SERVICES:
461
- continue
462
- else:
463
- # If a filter is specified, ignore all other services
464
- if service not in kwargs['service']:
465
- continue
466
-
467
- config = { **kwargs }
468
- config['service_name'] = service
469
- command = WorkflowLogCommand(app, **config)
470
- commands.append(command)
471
-
428
+ command_args = { 'print_service_header': lambda service_name: __print_header(f"SERVICE {service_name}") }
472
429
  script = __build_script(app, **kwargs)
473
-
474
- commands = sorted(commands, key=lambda command: command.service_config.priority)
475
- for index, command in enumerate(commands):
476
- __print_header(f"SERVICE {command.service_name}")
477
-
478
- follow = kwargs['follow'] and index == len(commands) - 1
479
- shell_commands = command.build(
480
- containers=kwargs['container'], follow=follow, namespace=kwargs['namespace']
430
+
431
+ # Determine which workflow command to use based on app configuration
432
+ app_config = AppConfig(app.scaffold_namespace_path)
433
+ if app_config.run_on_local:
434
+ # Use LocalWorkflowRunCommand for local execution
435
+ workflow_command = LocalWorkflowRunCommand(
436
+ app,
437
+ services=services,
438
+ script=script,
439
+ **kwargs
481
440
  )
441
+ else:
442
+ # Use DockerWorkflowRunCommand for Docker execution
443
+ workflow_command = DockerWorkflowRunCommand(
444
+ app,
445
+ services=services,
446
+ script=script,
447
+ **kwargs
448
+ )
449
+ command_args['print_service_header'] = lambda service_name: __print_header(f"SERVICE {service_name}")
482
450
 
483
- for shell_command in shell_commands:
484
- print(shell_command, file=script)
485
-
486
- __run_script(script, kwargs['dry_run'])
451
+ # Execute the workflow logs
452
+ workflow_command.logs(
453
+ **command_args,
454
+ **kwargs
455
+ )
487
456
 
488
457
  @workflow.command()
489
458
  @click.option('--app-dir-path', default=current_working_dir, help='Path to application directory.')
@@ -491,106 +460,99 @@ def logs(**kwargs):
491
460
  @click.option('--certs-dir-path', help='Path to certs directory. Defaults to the certs dir of the context.')
492
461
  @click.option('--containerized', is_flag=True, help='Set if run from within a container.')
493
462
  @click.option('--context-dir-path', default=data_dir.context_dir_path, help='Path to Stoobly data directory.')
494
- @click.option('--detached', is_flag=True, help='If set, will not run the highest priority service in the foreground.')
463
+ @click.option('--detached', is_flag=True, help='If set, will run the highest priority service in the background.')
495
464
  @click.option('--dry-run', default=False, is_flag=True, help='If set, prints commands.')
496
- @click.option('--extra-entrypoint-compose-path', help='Path to extra entrypoint compose file.')
497
465
  @click.option('--log-level', default=INFO, type=click.Choice([DEBUG, INFO, WARNING, ERROR]), help='''
498
466
  Log levels can be "debug", "info", "warning", or "error"
499
467
  ''')
500
468
  @click.option('--mkcert', is_flag=True, help='Set to generate SSL certs for HTTPS services.')
501
469
  @click.option('--namespace', callback=validate_namespace, help='Workflow namespace.')
502
- @click.option('--network', callback=validate_network, help='Workflow network name.')
503
- @click.option('--no-build', is_flag=True, help='Do not build images before starting containers.')
504
470
  @click.option('--no-publish', is_flag=True, help='Do not publish all ports.')
505
- @click.option('--pull', is_flag=True, help='Pull image before running.')
506
471
  @click.option('--script-path', help='Path to intermediate script path.')
507
472
  @click.option('--service', multiple=True, help='Select which services to run. Defaults to all.')
508
473
  @click.option('--user-id', default=os.getuid(), help='OS user ID of the owner of context dir path.')
509
474
  @click.option('--verbose', is_flag=True)
510
- @click.option('--without-base', is_flag=True, help='Disable building Stoobly base image.')
475
+ @click.option('-y', '--yes', is_flag=True, help='Auto-confirm CA certificate installation prompt.')
511
476
  @click.argument('workflow_name')
512
477
  def up(**kwargs):
513
478
  os.environ[env_vars.LOG_LEVEL] = kwargs['log_level']
514
479
 
515
480
  containerized = kwargs['containerized']
481
+ dry_run = kwargs['dry_run']
516
482
 
517
483
  # Because we are running a docker-compose command which depends on APP_DIR env var
518
484
  # when we are running this command within a container, the host's app_dir_path will likely differ
519
485
  app_dir_path = current_working_dir if containerized else kwargs['app_dir_path']
520
- app = App(app_dir_path, DOCKER_NAMESPACE, **kwargs)
486
+ app = App(app_dir_path, SERVICES_NAMESPACE, **kwargs)
521
487
  __validate_app(app)
522
488
 
523
489
  __with_namespace_defaults(kwargs)
524
- workflow_namespace = __with_workflow_namespace(app, kwargs['namespace'])
490
+
491
+ # First time if folder does not exist or is empty
492
+ first_time = not os.path.exists(app.ca_certs_dir_path) or not os.listdir(app.ca_certs_dir_path)
493
+ if first_time and not containerized and not dry_run:
494
+ # If ca certs dir path does not exist, run ca-cert install
495
+ if kwargs.get('yes'):
496
+ # Auto-confirm if -y/--yes option is provided
497
+ ca_cert_install(app.ca_certs_dir_path)
498
+ else:
499
+ confirm = input(f"Installing CA certificate is required for {kwargs['workflow_name']}ing requests, continue? (y/N) ")
500
+ if confirm == "y" or confirm == "Y":
501
+ ca_cert_install(app.ca_certs_dir_path)
502
+ else:
503
+ print("You can install the CA certificate later by running: stoobly-agent ca-cert install")
504
+ sys.exit(1)
525
505
 
526
506
  services = __get_services(
527
507
  app, service=kwargs['service'], workflow=[kwargs['workflow_name']]
528
508
  )
529
509
 
530
- if kwargs['mkcert']:
531
- _app = ContainerizedApp(app_dir_path, DOCKER_NAMESPACE) if containerized else app
532
- __services_mkcert(_app, services)
533
-
534
- # Gateway ports are dynamically set depending on the workflow run
535
- workflow = Workflow(kwargs['workflow_name'], app)
536
- configure_gateway(workflow_namespace, workflow.service_paths_from_services(services), kwargs['no_publish'])
537
-
538
- commands: List[WorkflowRunCommand] = []
539
- for service in services:
540
- config = { **kwargs }
541
- config['service_name'] = service
542
- command = WorkflowRunCommand(app, **config)
543
- command.current_working_dir = current_working_dir
544
- commands.append(command)
545
-
510
+ command_args = { 'print_service_header': lambda service_name: __print_header(f"SERVICE {service_name}") }
546
511
  script = __build_script(app, **kwargs)
547
512
 
548
- # Before services can be started, their image and network needs to be created
549
- if len(commands) > 0:
550
- command: WorkflowRunCommand = commands[0]
551
-
552
- init_commands = []
553
- if not kwargs['without_base']:
554
- create_image_command = command.create_image(user_id=kwargs['user_id'], verbose=kwargs['verbose'])
555
- init_commands.append(create_image_command)
556
-
557
- init_commands.append(command.create_egress_network())
558
- init_commands.append(command.create_ingress_network())
559
- joined_command = ' && '.join(init_commands)
560
-
561
- if not containerized:
562
- command.write_nameservers()
563
-
564
- print(joined_command, file=script)
565
-
566
- commands = sorted(commands, key=lambda command: command.service_config.priority)
567
- for index, command in enumerate(commands):
568
- __print_header(f"SERVICE {command.service_name}")
513
+ # Determine which workflow command to use based on app configuration
514
+ app_config = AppConfig(app.scaffold_namespace_path)
515
+ if app_config.run_on_local:
516
+ # Use LocalWorkflowRunCommand for local execution
517
+ workflow_command = LocalWorkflowRunCommand(
518
+ app,
519
+ services=services,
520
+ script=script,
521
+ **kwargs
522
+ )
523
+ else:
524
+ if kwargs['mkcert']:
525
+ _app = ContainerizedApp(app_dir_path, SERVICES_NAMESPACE) if containerized else app
526
+ __services_mkcert(_app, services)
527
+
528
+ # Use DockerWorkflowRunCommand for Docker execution
529
+ workflow_command = DockerWorkflowRunCommand(
530
+ app,
531
+ services=services,
532
+ script=script,
533
+ **kwargs
534
+ )
569
535
 
570
- attached = False
571
- extra_compose_path = None
536
+ if first_time and not containerized and not dry_run:
537
+ options = {}
572
538
 
573
- # By default, the entrypoint service should be last
574
- # However, this can change if the user has configured a service's priority to be higher
575
- if index == len(commands) - 1:
576
- attached = not kwargs['detached']
577
- extra_compose_path = kwargs['extra_entrypoint_compose_path']
539
+ if os.getcwd() != app_dir_path:
540
+ options['app_dir_path'] = app_dir_path
578
541
 
579
- exec_command = command.up(
580
- attached=attached,
581
- extra_compose_path=extra_compose_path,
582
- namespace=kwargs['namespace'],
583
- no_build=kwargs['no_build'],
584
- pull=kwargs['pull'],
585
- user_id=kwargs['user_id']
586
- )
587
- if not exec_command:
588
- continue
542
+ if kwargs['namespace'] != kwargs['workflow_name']:
543
+ options['namespace'] = kwargs['namespace']
589
544
 
590
- print(exec_command, file=script)
591
-
592
- __run_script(script, kwargs['dry_run'])
545
+ options_str = ' '.join([f"--{key} {value}" for key, value in options.items()])
546
+ if options_str:
547
+ options_str = f" {options_str}"
593
548
 
549
+ Logger.instance(LOG_ID).info(f"To view logs, run `stoobly-agent workflow logs{options_str} {kwargs['workflow_name']}`")
550
+
551
+ # Execute the workflow
552
+ workflow_command.up(
553
+ **command_args,
554
+ **kwargs
555
+ )
594
556
 
595
557
  @workflow.command(
596
558
  help="Validate a scaffold workflow"
@@ -598,7 +560,7 @@ def up(**kwargs):
598
560
  @click.option('--app-dir-path', default=current_working_dir, help='Path to validate the app scaffold.')
599
561
  @click.argument('workflow_name')
600
562
  def validate(**kwargs):
601
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
563
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
602
564
  __validate_app(app)
603
565
 
604
566
  workflow = Workflow(kwargs['workflow_name'], app)
@@ -634,7 +596,7 @@ def validate(**kwargs):
634
596
  @click.option('--service', multiple=True, help='Select specific services. Defaults to all.')
635
597
  @click.option('--workflow', multiple=True, help='Specify services by workflow(s). Defaults to all.')
636
598
  def install(**kwargs):
637
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
599
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
638
600
  __validate_app(app)
639
601
 
640
602
  services = __get_services(
@@ -666,7 +628,7 @@ def install(**kwargs):
666
628
  @click.option('--service', multiple=True, help='Select specific services. Defaults to all.')
667
629
  @click.option('--workflow', multiple=True, help='Specify services by workflow(s). Defaults to all.')
668
630
  def uninstall(**kwargs):
669
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
631
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
670
632
  __validate_app(app)
671
633
 
672
634
  services = __get_services(
@@ -757,16 +719,6 @@ def __get_services(app: App, **kwargs):
757
719
  def __print_header(text: str):
758
720
  Logger.instance(LOG_ID).info(f"{bcolors.OKBLUE}{text}{bcolors.ENDC}")
759
721
 
760
- def __run_script(script: TextIOWrapper, dry_run = False):
761
- script.close()
762
-
763
- with open(script.name, 'r') as fp:
764
- for line in fp:
765
- if not dry_run:
766
- exec_stream(line.strip())
767
- else:
768
- print(line.strip())
769
-
770
722
  def __scaffold_build(app, **kwargs):
771
723
  command = ServiceCreateCommand(app, **kwargs)
772
724
 
@@ -158,10 +158,10 @@ if is_local:
158
158
  Configure which tests to print. Defaults to {test_output_level.PASSED}.
159
159
  '''
160
160
  )
161
- @click.option('--public-directory-path', help='Path to public files. Used for mocking requests.')
161
+ @click.option('--public-directory-path', multiple=True, help='Path to public files. Used for mocking requests. Can take the form <FOLDER-PATH>[:<ORIGIN>].')
162
162
  @ConditionalDecorator(lambda f: click.option('--remote-project-key', help='Use remote project for endpoint definitions.')(f), is_remote)
163
163
  @ConditionalDecorator(lambda f: click.option('--report-key', help='Save results to report.')(f), is_remote)
164
- @click.option('--response-fixtures-path', help='Path to response fixtures yaml. Used for mocking requests.')
164
+ @click.option('--response-fixtures-path', multiple=True, help='Path to response fixtures yaml. Used for mocking requests. Can take the form <FILE-PATH>[:<ORIGIN>].')
165
165
  @ConditionalDecorator(lambda f: click.option('--save', is_flag=True, default=False, help='Save results.')(f), is_remote)
166
166
  @click.option('--scheme', help='Rewrite request scheme.')
167
167
  @click.option(
@@ -15,10 +15,10 @@ class TestOptions(TypedDict):
15
15
  lifecycle_hooks_path: str
16
16
  log_level: logger.LogLevel
17
17
  output_level: test_output_level.TestOutputLevel
18
- public_directory_path: str
18
+ public_directory_path: str # Comma-separated list of paths, optionally with origin suffix (e.g., "/path/to/files:example.com,/other/path")
19
19
  remote_project_key: str
20
20
  report_key: str
21
- response_fixtures_path: str
21
+ response_fixtures_path: str # Comma-separated list of paths, optionally with origin suffix (e.g., "/path/to/fixtures.yml:example.com,/other/fixtures.yml")
22
22
  save: str
23
23
  scheme: str
24
24
  strategy: test_strategy.TestStrategy
@@ -1,4 +1,4 @@
1
- from typing import TypedDict
1
+ from typing import TypedDict, List, Callable, Optional
2
2
 
3
3
  class ComposeOptions(TypedDict):
4
4
  namespace: str
@@ -14,5 +14,54 @@ class DownOptions(ComposeOptions):
14
14
 
15
15
  class UpOptions(ComposeOptions):
16
16
  attached: bool
17
- extra_compose_path: str
18
- pull: bool
17
+ pull: bool
18
+
19
+ # Workflow-specific option types
20
+ class WorkflowDownOptions(TypedDict, total=False):
21
+ print_service_header: Optional[Callable[[str], None]]
22
+ extra_entrypoint_compose_path: Optional[str]
23
+ namespace: Optional[str]
24
+ rmi: bool
25
+ user_id: Optional[int]
26
+ # CLI-specific options that get passed through
27
+ containerized: bool
28
+ dry_run: bool
29
+ log_level: str
30
+ script_path: Optional[str]
31
+ service: List[str]
32
+ app_dir_path: Optional[str]
33
+ context_dir_path: Optional[str]
34
+
35
+ class WorkflowUpOptions(TypedDict, total=False):
36
+ print_service_header: Optional[Callable[[str], None]]
37
+ extra_entrypoint_compose_path: Optional[str]
38
+ namespace: Optional[str]
39
+ pull: bool
40
+ user_id: Optional[int]
41
+ detached: bool
42
+ # CLI-specific options that get passed through
43
+ containerized: bool
44
+ dry_run: bool
45
+ log_level: str
46
+ script_path: Optional[str]
47
+ service: List[str]
48
+ no_publish: bool
49
+ verbose: bool
50
+ mkcert: bool
51
+ app_dir_path: Optional[str]
52
+ ca_certs_dir_path: Optional[str]
53
+ certs_dir_path: Optional[str]
54
+ context_dir_path: Optional[str]
55
+
56
+ class WorkflowLogsOptions(TypedDict, total=False):
57
+ print_service_header: Optional[Callable[[str], None]]
58
+ container: List[str]
59
+ follow: bool
60
+ namespace: Optional[str]
61
+ # CLI-specific options that get passed through
62
+ containerized: bool
63
+ dry_run: bool
64
+ log_level: str
65
+ script_path: Optional[str]
66
+ service: List[str]
67
+ app_dir_path: Optional[str]
@@ -127,7 +127,7 @@ def eval_request_with_retry(context: MockContext, eval_request, **options: MockO
127
127
  fixture = eval_fixtures(
128
128
  request,
129
129
  public_directory_path=intercept_settings.public_directory_path,
130
- response_fixtures=intercept_settings.response_fixtures
130
+ response_fixtures_path=intercept_settings.response_fixtures_path
131
131
  )
132
132
  if fixture:
133
133
  res = fixture