stoobly-agent 1.10.0__py3-none-any.whl → 1.10.1__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 (41) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/api/application_http_request_handler.py +5 -2
  3. stoobly_agent/app/cli/scaffold/constants.py +1 -3
  4. stoobly_agent/app/cli/scaffold/docker/service/build_decorator.py +2 -2
  5. stoobly_agent/app/cli/scaffold/docker/service/builder.py +17 -6
  6. stoobly_agent/app/cli/scaffold/docker/workflow/builder.py +0 -9
  7. stoobly_agent/app/cli/scaffold/docker/workflow/command_decorator.py +2 -1
  8. stoobly_agent/app/cli/scaffold/service_config.py +1 -25
  9. stoobly_agent/app/cli/scaffold/service_docker_compose.py +3 -3
  10. stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +10 -7
  11. stoobly_agent/app/cli/scaffold/templates/app/build/.docker-compose.base.yml +2 -2
  12. stoobly_agent/app/cli/scaffold/templates/app/build/mock/bin/configure +1 -1
  13. stoobly_agent/app/cli/scaffold/templates/app/build/record/bin/configure +26 -1
  14. stoobly_agent/app/cli/scaffold/templates/app/build/test/bin/configure +1 -1
  15. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/.docker-compose.base.yml +2 -2
  16. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/bin/configure +1 -1
  17. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/bin/configure +1 -1
  18. stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/configure +1 -1
  19. stoobly_agent/app/cli/scaffold/templates/build/workflows/record/.configure +21 -1
  20. stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/configure +2 -10
  21. stoobly_agent/app/cli/scaffold/templates/workflow/record/bin/configure +19 -45
  22. stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/configure +2 -10
  23. stoobly_agent/app/cli/scaffold_cli.py +21 -23
  24. stoobly_agent/app/proxy/intercept_settings.py +1 -1
  25. stoobly_agent/app/proxy/record/upload_request_service.py +3 -6
  26. stoobly_agent/app/proxy/utils/publish_change_service.py +20 -23
  27. stoobly_agent/app/settings/__init__.py +10 -7
  28. stoobly_agent/config/data_dir.py +1 -0
  29. stoobly_agent/public/index.html +1 -1
  30. stoobly_agent/public/main-es2015.5a9aa16433404c3f423a.js +1 -0
  31. stoobly_agent/public/main-es5.5a9aa16433404c3f423a.js +1 -0
  32. stoobly_agent/test/app/cli/scaffold/cli_invoker.py +2 -2
  33. stoobly_agent/test/app/cli/scaffold/cli_test.py +3 -3
  34. stoobly_agent/test/app/cli/scaffold/e2e_test.py +11 -11
  35. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.1.dist-info}/METADATA +1 -1
  36. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.1.dist-info}/RECORD +39 -39
  37. stoobly_agent/public/main-es2015.089b46f303768fbe864f.js +0 -1
  38. stoobly_agent/public/main-es5.089b46f303768fbe864f.js +0 -1
  39. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.1.dist-info}/LICENSE +0 -0
  40. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.1.dist-info}/WHEEL +0 -0
  41. {stoobly_agent-1.10.0.dist-info → stoobly_agent-1.10.1.dist-info}/entry_points.txt +0 -0
@@ -12,7 +12,7 @@ from stoobly_agent.app.cli.helpers.shell import exec_stream
12
12
  from stoobly_agent.app.cli.scaffold.app import App
13
13
  from stoobly_agent.app.cli.scaffold.app_create_command import AppCreateCommand
14
14
  from stoobly_agent.app.cli.scaffold.constants import (
15
- DOCKER_NAMESPACE, WORKFLOW_CONTAINER_PROXY, WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
15
+ SERVICES_NAMESPACE, WORKFLOW_CONTAINER_PROXY, WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
16
16
  )
17
17
  from stoobly_agent.app.cli.scaffold.constants import PLUGIN_CYPRESS, PLUGIN_PLAYWRIGHT
18
18
  from stoobly_agent.app.cli.scaffold.containerized_app import ContainerizedApp
@@ -98,10 +98,13 @@ def hostname(ctx):
98
98
  def create(**kwargs):
99
99
  __validate_app_dir(kwargs['app_dir_path'])
100
100
 
101
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
101
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
102
102
 
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...")
103
+ if not kwargs['quiet']:
104
+ if os.path.exists(app.scaffold_namespace_path):
105
+ print(f"{kwargs['app_dir_path']} already exists, updating scaffold maintained files...")
106
+ else:
107
+ print(f"Creating scaffold in {kwargs['app_dir_path']}")
105
108
 
106
109
  res = AppCreateCommand(app, **kwargs).build()
107
110
 
@@ -118,7 +121,7 @@ def create(**kwargs):
118
121
  @click.option('--service', multiple=True, help='Select which services to run. Defaults to all.')
119
122
  @click.option('--workflow', multiple=True, help='Specify services by workflow(s). Defaults to all.')
120
123
  def mkcert(**kwargs):
121
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE, **kwargs)
124
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE, **kwargs)
122
125
  __validate_app(app)
123
126
 
124
127
  services = __get_services(
@@ -137,7 +140,6 @@ def mkcert(**kwargs):
137
140
  @click.option('--local', is_flag=True, help='Specifies upstream service is local. Overrides `--upstream-hostname` option.')
138
141
  @click.option('--port', type=click.IntRange(1, 65535), help='Service port.')
139
142
  @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
143
  @click.option('--quiet', is_flag=True, help='Disable log output.')
142
144
  @click.option('--scheme', type=click.Choice(['http', 'https']), help='Defaults to https if hostname is set.')
143
145
  @click.option('--upstream-hostname', callback=validate_hostname, help='Upstream service hostname.')
@@ -148,7 +150,7 @@ def mkcert(**kwargs):
148
150
  def create(**kwargs):
149
151
  __validate_app_dir(kwargs['app_dir_path'])
150
152
 
151
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
153
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
152
154
  service = Service(kwargs['service_name'], app)
153
155
 
154
156
  if not kwargs['quiet'] and os.path.exists(service.dir_path):
@@ -168,7 +170,7 @@ def create(**kwargs):
168
170
  @click.option('--all', is_flag=True, default=False, help='Display all services including core and user defined services')
169
171
  @click.option('--workflow', multiple=True, help='Specify workflow(s) to filter the services by. Defaults to all.')
170
172
  def _list(**kwargs):
171
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
173
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
172
174
  __validate_app(app)
173
175
 
174
176
  without_core = not kwargs['all']
@@ -209,7 +211,7 @@ def show(ctx, **kwargs):
209
211
  @click.option('--app-dir-path', default=current_working_dir, help='Path to application directory.')
210
212
  @click.argument('service_name')
211
213
  def delete(**kwargs):
212
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
214
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
213
215
  __validate_app(app)
214
216
 
215
217
  service = Service(kwargs['service_name'], app)
@@ -230,14 +232,13 @@ def delete(**kwargs):
230
232
  @click.option('--name', callback=validate_service_name, type=click.STRING, help='New name of the service to update to.')
231
233
  @click.option('--port', type=click.IntRange(1, 65535), help='Service port.')
232
234
  @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
235
  @click.option('--scheme', type=click.Choice(['http', 'https']), help='Defaults to https if hostname is set.')
235
236
  @click.option('--upstream-hostname', callback=validate_hostname, help='Upstream service hostname.')
236
237
  @click.option('--upstream-port', type=click.IntRange(1, 65535), help='Upstream service port.')
237
238
  @click.option('--upstream-scheme', type=click.Choice(['http', 'https']), help='Upstream service scheme.')
238
239
  @click.argument('service_name')
239
240
  def update(**kwargs):
240
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
241
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
241
242
  __validate_app(app)
242
243
 
243
244
  service = Service(kwargs['service_name'], app)
@@ -257,9 +258,6 @@ def update(**kwargs):
257
258
  if kwargs['priority']:
258
259
  service_config.priority = kwargs['priority']
259
260
 
260
- if kwargs['proxy_mode']:
261
- service_config.proxy_mode = kwargs['proxy_mode']
262
-
263
261
  if kwargs['scheme']:
264
262
  service_config.scheme = kwargs['scheme']
265
263
 
@@ -299,7 +297,7 @@ def update(**kwargs):
299
297
  def create(**kwargs):
300
298
  __validate_app_dir(kwargs['app_dir_path'])
301
299
 
302
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE, **kwargs)
300
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE, **kwargs)
303
301
 
304
302
  for service_name in kwargs['service']:
305
303
  config = { **kwargs }
@@ -325,7 +323,7 @@ def create(**kwargs):
325
323
  @click.argument('workflow_name')
326
324
  @click.argument('destination_workflow_name')
327
325
  def copy(**kwargs):
328
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE, **kwargs)
326
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE, **kwargs)
329
327
 
330
328
  for service_name in kwargs['service']:
331
329
  config = { **kwargs }
@@ -362,7 +360,7 @@ def down(**kwargs):
362
360
  containerized = kwargs['containerized']
363
361
 
364
362
  app_dir_path = current_working_dir if containerized else kwargs['app_dir_path']
365
- app = App(app_dir_path, DOCKER_NAMESPACE, **kwargs)
363
+ app = App(app_dir_path, SERVICES_NAMESPACE, **kwargs)
366
364
  __validate_app(app)
367
365
 
368
366
  __with_namespace_defaults(kwargs)
@@ -441,7 +439,7 @@ def down(**kwargs):
441
439
  def logs(**kwargs):
442
440
  os.environ[env_vars.LOG_LEVEL] = kwargs['log_level']
443
441
 
444
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
442
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
445
443
  __validate_app(app)
446
444
 
447
445
  __with_namespace_defaults(kwargs)
@@ -517,7 +515,7 @@ def up(**kwargs):
517
515
  # Because we are running a docker-compose command which depends on APP_DIR env var
518
516
  # when we are running this command within a container, the host's app_dir_path will likely differ
519
517
  app_dir_path = current_working_dir if containerized else kwargs['app_dir_path']
520
- app = App(app_dir_path, DOCKER_NAMESPACE, **kwargs)
518
+ app = App(app_dir_path, SERVICES_NAMESPACE, **kwargs)
521
519
  __validate_app(app)
522
520
 
523
521
  __with_namespace_defaults(kwargs)
@@ -528,7 +526,7 @@ def up(**kwargs):
528
526
  )
529
527
 
530
528
  if kwargs['mkcert']:
531
- _app = ContainerizedApp(app_dir_path, DOCKER_NAMESPACE) if containerized else app
529
+ _app = ContainerizedApp(app_dir_path, SERVICES_NAMESPACE) if containerized else app
532
530
  __services_mkcert(_app, services)
533
531
 
534
532
  # Gateway ports are dynamically set depending on the workflow run
@@ -598,7 +596,7 @@ def up(**kwargs):
598
596
  @click.option('--app-dir-path', default=current_working_dir, help='Path to validate the app scaffold.')
599
597
  @click.argument('workflow_name')
600
598
  def validate(**kwargs):
601
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
599
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
602
600
  __validate_app(app)
603
601
 
604
602
  workflow = Workflow(kwargs['workflow_name'], app)
@@ -634,7 +632,7 @@ def validate(**kwargs):
634
632
  @click.option('--service', multiple=True, help='Select specific services. Defaults to all.')
635
633
  @click.option('--workflow', multiple=True, help='Specify services by workflow(s). Defaults to all.')
636
634
  def install(**kwargs):
637
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
635
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
638
636
  __validate_app(app)
639
637
 
640
638
  services = __get_services(
@@ -666,7 +664,7 @@ def install(**kwargs):
666
664
  @click.option('--service', multiple=True, help='Select specific services. Defaults to all.')
667
665
  @click.option('--workflow', multiple=True, help='Specify services by workflow(s). Defaults to all.')
668
666
  def uninstall(**kwargs):
669
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
667
+ app = App(kwargs['app_dir_path'], SERVICES_NAMESPACE)
670
668
  __validate_app(app)
671
669
 
672
670
  services = __get_services(
@@ -280,7 +280,7 @@ class InterceptSettings:
280
280
  if self.__headers and custom_headers.REQUEST_ORIGIN in self.__headers:
281
281
  return self.__headers[custom_headers.REQUEST_ORIGIN]
282
282
 
283
- return request_origin.WEB
283
+ return request_origin.PROXY
284
284
 
285
285
  def for_response(self):
286
286
  self.__for_response = True
@@ -63,10 +63,7 @@ def upload_request(
63
63
  scenario_key=scenario_key
64
64
  )
65
65
 
66
- # If request_origin is WEB, then we are in proxy
67
- # This means that we have access to Cache singleton and do not need send a request to update the status
68
- sync = intercept_settings.request_origin == request_origin.WEB
69
- res = __upload_request_with_body_params(request_model, body_params, sync)
66
+ res = __upload_request_with_body_params(request_model, body_params)
70
67
 
71
68
  if intercept_settings.settings.is_debug():
72
69
  file_path = __debug_request(flow.request, joined_request.build())
@@ -107,11 +104,11 @@ def upload_staged_request(
107
104
 
108
105
  return __upload_request_with_body_params(request_model, body_params)
109
106
 
110
- def __upload_request_with_body_params(request_model: RequestModel, body_params: dict, sync=True):
107
+ def __upload_request_with_body_params(request_model: RequestModel, body_params: dict):
111
108
  request, status = request_model.create(**body_params)
112
109
 
113
110
  if status < 400:
114
- publish_requests_modified(body_params['project_id'], sync=sync)
111
+ publish_requests_modified(body_params['project_id'])
115
112
 
116
113
  return request
117
114
 
@@ -1,41 +1,35 @@
1
- import os
2
1
  import pdb
2
+ import requests
3
3
  import threading
4
4
 
5
- from typing import TypedDict
6
-
7
5
  from stoobly_agent.app.settings import Settings
8
- from stoobly_agent.config.constants.statuses import REQUESTS_MODIFIED
6
+ from stoobly_agent.config.constants.statuses import REQUESTS_MODIFIED, SETTINGS_MODIFIED
9
7
  from stoobly_agent.lib.api.agent_api import AgentApi
10
8
  from stoobly_agent.lib.cache import Cache
11
9
  from stoobly_agent.lib.logger import Logger
12
10
 
13
- class Options(TypedDict):
14
- sync: bool
15
-
16
- # Announce that a new request has been created
17
- def publish_change(status: str, value, **options: Options):
18
- if options.get('sync'):
19
- return __publish_change_sync(status, value)
11
+ LOG_ID = 'PublishChange'
20
12
 
13
+ def publish_settings_modified(value):
14
+ return __publish_change_sync(SETTINGS_MODIFIED, value)
15
+
16
+ def publish_requests_modified(value):
21
17
  settings: Settings = Settings.instance()
22
18
 
23
- # If ui is not active, return
24
- if not settings.ui.active:
25
- return False
19
+ # If not headless...
20
+ if settings.ui.active:
21
+ return __publish_change_sync(REQUESTS_MODIFIED, value)
26
22
 
27
23
  ui_url = settings.ui.url
28
-
29
24
  if not ui_url:
30
- Logger.instance().warn('Settings.ui.url not configured')
31
25
  return False
32
- else:
33
- thread = threading.Thread(target=__put_status, args=(ui_url, status, value))
34
- thread.start()
35
- return True
36
26
 
37
- def publish_requests_modified(value, **options: Options):
38
- return publish_change(REQUESTS_MODIFIED, value, **options)
27
+ return __publish_change_async(REQUESTS_MODIFIED, value, ui_url)
28
+
29
+ def __publish_change_async(status, value, ui_url: str):
30
+ thread = threading.Thread(target=__put_status, args=(ui_url, status, value))
31
+ thread.start()
32
+ return True
39
33
 
40
34
  def __publish_change_sync(status: str, value):
41
35
  cache = Cache.instance()
@@ -44,4 +38,7 @@ def __publish_change_sync(status: str, value):
44
38
 
45
39
  def __put_status(ui_url, status, value):
46
40
  api: AgentApi = AgentApi(ui_url)
47
- api.update_status(status, value)
41
+ try:
42
+ api.update_status(status, value)
43
+ except requests.exceptions.ConnectionError:
44
+ Logger.instance(LOG_ID).error(f"could not connect to {ui_url}")
@@ -8,7 +8,7 @@ from watchdog.observers import Observer
8
8
  from watchdog.events import PatternMatchingEventHandler
9
9
  from yamale import *
10
10
 
11
- from stoobly_agent.config.constants import env_vars, statuses
11
+ from stoobly_agent.config.constants import env_vars
12
12
  from stoobly_agent.config.data_dir import DataDir
13
13
  from stoobly_agent.config.source_dir import SourceDir
14
14
  from stoobly_agent.lib.logger import Logger
@@ -19,6 +19,7 @@ from .remote_settings import RemoteSettings
19
19
  from .ui_settings import UISettings
20
20
 
21
21
  LOG_ID = 'Settings'
22
+ SETTINGS_YML = 'settings.yml'
22
23
 
23
24
  class Settings:
24
25
  _instances = None
@@ -102,7 +103,7 @@ class Settings:
102
103
  if self.__watching:
103
104
  return False
104
105
 
105
- patterns = ['settings.yml']
106
+ patterns = [SETTINGS_YML]
106
107
  ignore_patterns = None
107
108
  ignore_directories = False
108
109
  case_sensitive = True
@@ -180,11 +181,12 @@ class Settings:
180
181
  if not contents:
181
182
  return
182
183
 
183
- path = self.__settings_file_path
184
- lock = FileLock(path + ".lock") # lock file alongside the target
184
+ lock_file = f".{SETTINGS_YML}.lock"
185
+ lock_file_path = os.path.join(os.path.dirname(self.__settings_file_path), lock_file)
186
+ lock = FileLock(lock_file_path) # lock file alongside the target
185
187
 
186
188
  with lock:
187
- with open(path, 'w') as fp:
189
+ with open(self.__settings_file_path, 'w') as fp:
188
190
  yaml.dump(contents, fp, allow_unicode=True)
189
191
 
190
192
  ### Helpers
@@ -215,13 +217,14 @@ class Settings:
215
217
 
216
218
  def __reload_settings(self, event):
217
219
  if not self.__load_lock:
218
- from stoobly_agent.app.proxy.utils.publish_change_service import publish_change
220
+ from stoobly_agent.app.proxy.utils.publish_change_service import publish_settings_modified
219
221
 
220
222
  self.__load_lock = True
221
223
 
222
224
  Logger.instance(LOG_ID).debug('Reloading settings')
223
225
  self.__load_settings()
224
226
 
225
- publish_change(statuses.SETTINGS_MODIFIED, self.__settings, sync=True)
227
+ if self.__ui_settings.active:
228
+ publish_settings_modified(self.__settings)
226
229
 
227
230
  self.__load_lock = False
@@ -202,6 +202,7 @@ class DataDir:
202
202
  with open(os.path.join(self.__data_dir_path, '.gitignore'), 'w') as fp:
203
203
  fp.write(
204
204
  "\n".join([
205
+ '.settings.yml.lock',
205
206
  'ca_certs',
206
207
  'certs',
207
208
  'db',
@@ -113,6 +113,6 @@
113
113
  </div>
114
114
 
115
115
  <root></root>
116
- <script src="runtime-es2015.f8c814b38b27708e91c1.js" type="module"></script><script src="runtime-es5.f8c814b38b27708e91c1.js" nomodule="" defer=""></script><script src="polyfills-es5.7530172ddcec11a10eb3.js" nomodule="" defer=""></script><script src="polyfills-es2015.8ce2adc69f283f6c4c5e.js" type="module"></script><script src="main-es2015.089b46f303768fbe864f.js" type="module"></script><script src="main-es5.089b46f303768fbe864f.js" nomodule="" defer=""></script></body>
116
+ <script src="runtime-es2015.f8c814b38b27708e91c1.js" type="module"></script><script src="runtime-es5.f8c814b38b27708e91c1.js" nomodule="" defer=""></script><script src="polyfills-es5.7530172ddcec11a10eb3.js" nomodule="" defer=""></script><script src="polyfills-es2015.8ce2adc69f283f6c4c5e.js" type="module"></script><script src="main-es2015.5a9aa16433404c3f423a.js" type="module"></script><script src="main-es5.5a9aa16433404c3f423a.js" nomodule="" defer=""></script></body>
117
117
 
118
118
  </html>