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
stoobly_agent/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  COMMAND = 'stoobly-agent'
2
- VERSION = '1.10.0'
2
+ VERSION = '1.10.2'
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Entry point for stoobly_agent when run as a module.
4
+ """
5
+
6
+ from .cli import main
7
+
8
+ if __name__ == '__main__':
9
+ main()
10
+
@@ -104,11 +104,14 @@ class ApplicationHTTPRequestHandler(SimpleHTTPRequestHandler):
104
104
  headers.CLIENT.title(),
105
105
  custom_headers.DO_PROXY.title(),
106
106
  headers.EXPIRY.title(),
107
+ custom_headers.REQUEST_ORIGIN.title(),
108
+ headers.TOKEN_TYPE.title(),
109
+ headers.UID.title(),
110
+
111
+ # ProxyController headers
107
112
  headers.PROXY_HEADERS.title(),
108
113
  headers.REQUEST_PATH.title(),
109
114
  custom_headers.SERVICE_URL.title(),
110
- headers.TOKEN_TYPE.title(),
111
- headers.UID.title(),
112
115
  ])
113
116
  self.send_header(header, allowed_headers)
114
117
  rendered_headers.append(header)
@@ -48,14 +48,18 @@ def mkcert(**kwargs):
48
48
  )
49
49
  def install(**kwargs):
50
50
  ca_certs_dir_path = kwargs['ca_certs_dir_path']
51
+
52
+ ca_cert_install(ca_certs_dir_path)
53
+
54
+ @ca_cert.command()
55
+ def uninstall():
56
+ print("Not yet implemented. Stay tuned!")
57
+
58
+ def ca_cert_install(ca_certs_dir_path: str):
51
59
  installer = CertificateAuthority(ca_certs_dir_path)
52
60
 
53
61
  try:
54
62
  installer.install()
55
63
  except Exception as e:
56
64
  print(e, file=sys.stderr)
57
- sys.exit(1)
58
-
59
- @ca_cert.command()
60
- def uninstall():
61
- print("Not yet implemented. Stay tuned!")
65
+ sys.exit(1)
@@ -17,9 +17,9 @@ class ReplayCliOptions(TypedDict):
17
17
  lifecycle_hooks_path: str
18
18
  on_response: Callable
19
19
  project_key: str
20
- public_directory_path: str
20
+ public_directory_path: str # Comma-separated list of paths, optionally with origin prefix
21
21
  record: bool
22
- response_fixtures_path: str
22
+ response_fixtures_path: str # Comma-separated list of paths, optionally with origin prefix
23
23
  scenario_key: str
24
24
  scheme: str
25
25
  trace: Trace
@@ -10,7 +10,7 @@ from .helpers.handle_config_update_service import handle_intercept_active_update
10
10
 
11
11
  settings: Settings = Settings.instance()
12
12
 
13
- mode_options = [mode.MOCK, mode.RECORD, mode.REPLAY, mode.TEST]
13
+ mode_options = [mode.MOCK, mode.RECORD, mode.REPLAY]
14
14
 
15
15
  if settings.cli.features.remote:
16
16
  mode_options.append(mode.TEST)
@@ -87,9 +87,9 @@ def disable(**kwargs):
87
87
  help="Configure intercept"
88
88
  )
89
89
  @click.option('--mode', type=click.Choice(mode_options))
90
- @click.option('--order', type=click.Choice(order_options))
91
- @click.option('--policy', type=click.Choice(policy_options))
92
- @click.option('--strategy', type=click.Choice(strategy_options))
90
+ @click.option('--order', help=f"Order to use for recording. Valid options: {order_options}")
91
+ @click.option('--policy', help=f"Policy to use for recording. Valid options: {policy_options}")
92
+ @click.option('--strategy', help=f"Strategy to use for recording. Valid options: {strategy_options}")
93
93
  def configure(**kwargs):
94
94
  settings: Settings = Settings.instance()
95
95
 
@@ -172,7 +172,7 @@ def configure(**kwargs):
172
172
  help="Show intercept"
173
173
  )
174
174
  def show(**kwargs):
175
- settings = Settings.instance()
175
+ settings: Settings = Settings.instance()
176
176
 
177
177
  _mode = settings.proxy.intercept.mode
178
178
  project_key = ProjectKey(settings.proxy.intercept.project_key)
@@ -134,10 +134,10 @@ if is_local:
134
134
  Configure which tests to print. Defaults to {test_output_level.PASSED}.
135
135
  '''
136
136
  )
137
- @click.option('--public-directory-path', help='Path to public files. Used for mocking requests.')
137
+ @click.option('--public-directory-path', multiple=True, help='Path to public files. Used for mocking requests. Can take the form <FOLDER-PATH>[:<ORIGIN>].')
138
138
  @ConditionalDecorator(lambda f: click.option('--remote-project-key', help='Use remote project for endpoint definitions.')(f), is_remote and is_local)
139
139
  @ConditionalDecorator(lambda f: click.option('--report-key', help='Save to report.')(f), is_remote)
140
- @click.option('--response-fixtures-path', help='Path to response fixtures yaml. Used for mocking requests.')
140
+ @click.option('--response-fixtures-path', multiple=True, help='Path to response fixtures yaml. Used for mocking requests. Can take the form <FILE-PATH>[:<ORIGIN>].')
141
141
  @ConditionalDecorator(lambda f: click.option('--save', is_flag=True, default=False, help='Saves test results.')(f), is_remote)
142
142
  @click.option('--scheme', type=click.Choice(['http', 'https']), help='Rewrite request scheme.')
143
143
  @click.option('--strategy', default=test_strategy.DIFF, type=click.Choice([test_strategy.CONTRACT, test_strategy.CUSTOM, test_strategy.DIFF, test_strategy.FUZZY]), help='How to test responses.')
@@ -1,5 +1,6 @@
1
1
  import hashlib
2
2
  import os
3
+ import re
3
4
  import shutil
4
5
 
5
6
  from stoobly_agent.config.data_dir import DataDir, DATA_DIR_NAME
@@ -62,10 +63,6 @@ class App():
62
63
  def scaffold_namespace(self):
63
64
  return self.__scaffold_namespace
64
65
 
65
- @property
66
- def scaffold_namespace_path(self):
67
- return os.path.join(self.data_dir_path, self.scaffold_namespace)
68
-
69
66
  @property
70
67
  def dir_path(self):
71
68
  return self.__dir_path
@@ -101,7 +98,7 @@ class App():
101
98
 
102
99
  return services
103
100
 
104
- def copy_folders_and_hidden_files(self, src, dst):
101
+ def copy_folders_and_hidden_files(self, src: str, dst: str, ignore: list = []):
105
102
  os.makedirs(dst, exist_ok=True)
106
103
 
107
104
  # Walk through the source directory
@@ -109,6 +106,18 @@ class App():
109
106
  # Copy hidden files only
110
107
  for file_name in files:
111
108
  src_file_path = os.path.join(root, file_name)
109
+
110
+ ignored = False
111
+
112
+ # Skip files that match the ignore list pattern, use regex
113
+ for ignore_pattern in ignore:
114
+ if re.match(os.path.join(src, ignore_pattern), src_file_path):
115
+ ignored = True
116
+ break
117
+
118
+ if ignored:
119
+ continue
120
+
112
121
  dst_file_path = os.path.join(dst, os.path.relpath(root, src), file_name)
113
122
 
114
123
  if not file_name.startswith('.'):
@@ -44,10 +44,6 @@ class AppCommand(Command):
44
44
  DOCKER_COMPOSE_NETWORKS
45
45
  )
46
46
 
47
- @property
48
- def scaffold_namespace_path(self):
49
- return self.app.scaffold_namespace_path
50
-
51
47
  @property
52
48
  def app_templates_root_dir(self):
53
49
  return os.path.join(self.templates_root_dir, 'app')
@@ -1,7 +1,9 @@
1
1
  import os
2
2
 
3
3
  from .config import Config
4
- from .constants import APP_DOCKER_SOCKET_PATH_ENV, APP_NAME_ENV, APP_NETWORK_ENV, APP_PLUGINS_DELMITTER, APP_PLUGINS_ENV, APP_UI_PORT_ENV
4
+ from .constants import (
5
+ APP_DOCKER_SOCKET_PATH_ENV, APP_NAME_ENV, APP_PLUGINS_DELMITTER, APP_PLUGINS_ENV, APP_PROXY_PORT_ENV, APP_RUN_ON_ENV, APP_RUN_ON_DELIMITER, APP_UI_PORT_ENV, APP_VERSION_ENV, RUN_ON_DOCKER, RUN_ON_LOCAL
6
+ )
5
7
 
6
8
  class AppConfig(Config):
7
9
 
@@ -11,6 +13,8 @@ class AppConfig(Config):
11
13
  self.__docker_socket_path = '/var/run/docker.sock'
12
14
  self.__name = None
13
15
  self.__plugins = None
16
+ self.__proxy_port = None
17
+ self.__run_on = None
14
18
  self.__ui_port = None
15
19
 
16
20
  self.load()
@@ -39,24 +43,58 @@ class AppConfig(Config):
39
43
  def plugins(self, v: list):
40
44
  self.__plugins = v
41
45
 
46
+ @property
47
+ def run_on(self):
48
+ return self.__run_on or [RUN_ON_DOCKER]
49
+
50
+ @run_on.setter
51
+ def run_on(self, v: list):
52
+ self.__run_on = v
53
+
54
+ @property
55
+ def run_on_local(self):
56
+ return RUN_ON_LOCAL in self.run_on
57
+
58
+ @property
59
+ def proxy_port(self):
60
+ return self.__proxy_port or 8080
61
+
62
+ @proxy_port.setter
63
+ def proxy_port(self, v):
64
+ self.__proxy_port = v
65
+
42
66
  @property
43
67
  def ui_port(self):
44
- return self.__ui_port
68
+ return self.__ui_port or 4200
45
69
 
46
70
  @ui_port.setter
47
71
  def ui_port(self, v):
48
72
  self.__ui_port = v
49
73
 
74
+ @property
75
+ def version(self):
76
+ return self.__version or None
77
+
78
+ @version.setter
79
+ def version(self, v):
80
+ self.__version = v
81
+
50
82
  def load(self, config = None):
51
83
  config = config or self.read()
52
84
 
53
85
  self.name = config.get(APP_NAME_ENV)
86
+ self.proxy_port = config.get(APP_PROXY_PORT_ENV)
54
87
  self.ui_port = config.get(APP_UI_PORT_ENV)
88
+ self.version = config.get(APP_VERSION_ENV)
55
89
 
56
90
  if config.get(APP_PLUGINS_ENV):
57
91
  plugins: str = config.get(APP_PLUGINS_ENV)
58
92
  self.plugins = plugins.split(APP_PLUGINS_DELMITTER)
59
93
 
94
+ if config.get(APP_RUN_ON_ENV):
95
+ run_on: str = config.get(APP_RUN_ON_ENV)
96
+ self.run_on = run_on.split(APP_RUN_ON_DELIMITER)
97
+
60
98
  def write(self):
61
99
  config = {}
62
100
 
@@ -69,7 +107,16 @@ class AppConfig(Config):
69
107
  if self.plugins:
70
108
  config[APP_PLUGINS_ENV] = APP_PLUGINS_DELMITTER.join(self.plugins)
71
109
 
110
+ if self.run_on:
111
+ config[APP_RUN_ON_ENV] = APP_RUN_ON_DELIMITER.join(self.run_on)
112
+
113
+ if self.proxy_port:
114
+ config[APP_PROXY_PORT_ENV] = self.proxy_port
115
+
72
116
  if self.ui_port:
73
117
  config[APP_UI_PORT_ENV] = self.ui_port
118
+
119
+ if self.version:
120
+ config[APP_VERSION_ENV] = self.version
74
121
 
75
122
  super().write(config)
@@ -1,20 +1,25 @@
1
+ from math import e
1
2
  import os
2
3
  import pdb
3
- import shutil
4
- import yaml
5
4
 
6
- from mergedeep import merge
5
+ import shutil
7
6
  from typing import TypedDict
8
7
 
8
+ from stoobly_agent import VERSION
9
+ from stoobly_agent.app.cli.scaffold.docker.constants import DOCKER_COMPOSE_WORKFLOW
10
+
9
11
  from .app import App
10
12
  from .app_command import AppCommand
11
- from .constants import PLUGIN_CYPRESS, PLUGIN_PLAYWRIGHT, PLUGINS_FOLDER, WORKFLOW_TEST_TYPE
12
- from .docker.constants import DOCKER_COMPOSE_WORKFLOW_TEMPLATE, PLUGIN_CONTAINER_SERVICE_TEMPLATE, PLUGIN_DOCKER_ENTRYPOINT, PLUGIN_DOCKERFILE_TEMPLATE
13
- from .templates.constants import CORE_ENTRYPOINT_SERVICE_NAME, CORE_GATEWAY_SERVICE_NAME
13
+ from .constants import PLUGIN_CYPRESS, PLUGIN_PLAYWRIGHT, RUN_ON_DOCKER, RUN_ON_LOCAL
14
+ from .docker.template_files import plugin_docker_cypress, plugin_docker_playwright, plugin_local_cypress, plugin_local_playwright, remove_app_docker_files, remove_service_docker_files
15
+ from .templates.constants import CORE_GATEWAY_SERVICE_NAME, CORE_MOCK_UI_SERVICE_NAME, MAINTAINED_RUN
14
16
 
15
17
  class AppCreateOptions(TypedDict):
16
18
  docker_socket_path: str
17
19
  name: str
20
+ plugin: list
21
+ proxy_port: int
22
+ run_on: list
18
23
  ui_port: int
19
24
 
20
25
  class AppCreateCommand(AppCommand):
@@ -31,6 +36,12 @@ class AppCreateCommand(AppCommand):
31
36
  if kwargs.get('plugin'):
32
37
  self.app_config.plugins = kwargs['plugin']
33
38
 
39
+ if kwargs.get('proxy_port'):
40
+ self.app_config.proxy_port = kwargs['proxy_port']
41
+
42
+ if kwargs.get('run_on'):
43
+ self.app_config.run_on = kwargs['run_on']
44
+
34
45
  if kwargs.get('ui_port'):
35
46
  self.app_config.ui_port = kwargs['ui_port']
36
47
 
@@ -46,40 +57,154 @@ class AppCreateCommand(AppCommand):
46
57
  def app_plugins(self):
47
58
  return self.app_config.plugins
48
59
 
60
+ @property
61
+ def app_run_on(self):
62
+ return self.app_config.run_on
63
+
64
+ @property
65
+ def app_proxy_port(self):
66
+ return self.app_config.proxy_port
67
+
68
+ @property
49
69
  def app_ui_port(self):
50
70
  return self.app_config.ui_port
51
71
 
72
+ @property
73
+ def app_version(self):
74
+ return self.app_config.version
75
+
52
76
  def build(self):
77
+ self.__migrate()
78
+
53
79
  dest = self.scaffold_namespace_path
80
+ ignore = []
81
+ warnings = []
54
82
 
55
- self.app.copy_folders_and_hidden_files(self.app_templates_root_dir, dest)
83
+ if RUN_ON_LOCAL in self.app_run_on:
84
+ ignore.append(f"{CORE_GATEWAY_SERVICE_NAME}/.*")
85
+ ignore.append(f"{CORE_MOCK_UI_SERVICE_NAME}/.*")
56
86
 
57
- with open(os.path.join(dest, '.gitignore'), 'w') as fp:
58
- fp.write("\n".join(
59
- [os.path.join(CORE_GATEWAY_SERVICE_NAME, '.docker-compose.base.yml'), '**/.env']
60
- ))
87
+ if RUN_ON_DOCKER in self.app_run_on:
88
+ ignore.append(f".*/{MAINTAINED_RUN}")
61
89
 
62
- self.app_config.write()
90
+ # Copy all app templates
91
+ self.app.copy_folders_and_hidden_files(self.app_templates_root_dir, dest, ignore)
63
92
 
64
- # Provide plugins
65
- warnings = []
66
- if PLUGIN_CYPRESS in self.app_plugins:
67
- self.__plugin_cypress(dest, PLUGIN_CYPRESS)
93
+ # Remove Docker-specific files if not using Docker
94
+ if RUN_ON_DOCKER not in self.app_run_on:
95
+ remove_app_docker_files(dest)
96
+ remove_service_docker_files(dest)
68
97
 
98
+ if PLUGIN_CYPRESS in self.app_plugins:
69
99
  if not self.__cypress_initialized(self.app):
70
100
  warnings.append(f"missing cypress.config.(js|ts), please run `npx cypress open` in {self.app.context_dir_path}")
71
101
 
72
-
73
102
  if PLUGIN_PLAYWRIGHT in self.app_plugins:
74
- self.__plugin_playwright(dest, PLUGIN_PLAYWRIGHT)
75
-
76
103
  if not self.__playwright_initialized(self.app):
77
104
  warnings.append(f"missing playwright.config.(js|ts), please run `npm init playwright@latest` in {self.app.context_dir_path}")
78
105
 
106
+ if RUN_ON_DOCKER in self.app_run_on:
107
+ with open(os.path.join(dest, '.gitignore'), 'w') as fp:
108
+ fp.write("\n".join(
109
+ [os.path.join(CORE_GATEWAY_SERVICE_NAME, '.docker-compose.base.yml'), '**/.env']
110
+ ))
111
+
112
+ # Provide plugins
113
+ if PLUGIN_CYPRESS in self.app_plugins:
114
+ plugin_docker_cypress(self.templates_root_dir, PLUGIN_CYPRESS, dest)
115
+
116
+ if PLUGIN_PLAYWRIGHT in self.app_plugins:
117
+ plugin_docker_playwright(self.templates_root_dir, PLUGIN_PLAYWRIGHT, dest)
118
+ else:
119
+ if PLUGIN_CYPRESS in self.app_plugins:
120
+ plugin_local_cypress(self.templates_root_dir, PLUGIN_CYPRESS, dest)
121
+
122
+ if PLUGIN_PLAYWRIGHT in self.app_plugins:
123
+ plugin_local_playwright(self.templates_root_dir, PLUGIN_PLAYWRIGHT, dest)
124
+
125
+ with open(os.path.join(dest, '.gitignore'), 'w') as fp:
126
+ fp.write("\n".join(
127
+ ['**/.env']
128
+ ))
129
+
130
+ self.app_config.write()
131
+
79
132
  return {
80
133
  'warnings': warnings
81
134
  }
82
135
 
136
+ def __compare_versions(self, version1, version2):
137
+ """
138
+ Compare two semantic versions.
139
+
140
+ Args:
141
+ version1: First version string (e.g., '1.10.1')
142
+ version2: Second version string (e.g., '1.9.0')
143
+
144
+ Returns:
145
+ -1 if version1 < version2
146
+ 0 if version1 == version2
147
+ 1 if version1 > version2
148
+ """
149
+ try:
150
+ v1_parts = [int(x) for x in version1.split('.')]
151
+ v2_parts = [int(x) for x in version2.split('.')]
152
+
153
+ # Pad shorter version with zeros
154
+ max_len = max(len(v1_parts), len(v2_parts))
155
+ v1_parts.extend([0] * (max_len - len(v1_parts)))
156
+ v2_parts.extend([0] * (max_len - len(v2_parts)))
157
+
158
+ for v1_part, v2_part in zip(v1_parts, v2_parts):
159
+ if v1_part < v2_part:
160
+ return -1
161
+ elif v1_part > v2_part:
162
+ return 1
163
+
164
+ return 0
165
+ except (ValueError, AttributeError):
166
+ # If version parsing fails, treat as invalid and return -1 (version1 < version2)
167
+ return -1
168
+
169
+ def __migrate(self):
170
+ if not self.app_version or self.__compare_versions(self.app_version, '1.10.0') < 0:
171
+ new_scaffold_namespace_path = self.scaffold_namespace_path
172
+ if not os.path.exists(new_scaffold_namespace_path):
173
+ old_scaffold_namespace_path = os.path.join(self.data_dir_path, 'docker')
174
+ if os.path.exists(old_scaffold_namespace_path):
175
+ shutil.move(old_scaffold_namespace_path, new_scaffold_namespace_path)
176
+ else:
177
+ os.makedirs(new_scaffold_namespace_path)
178
+
179
+ # For each file in self.scaffold_namespace_path/<SERVICE-NAME>/<WORKFLOW-NAME>/bin
180
+ # move it to self.scaffold_namespace_path/<SERVICE-NAME>/<WORKFLOW-NAME>
181
+ for service_name in os.listdir(new_scaffold_namespace_path):
182
+ service_path = os.path.join(new_scaffold_namespace_path, service_name)
183
+ if not os.path.isdir(service_path):
184
+ continue
185
+
186
+ for workflow_name in os.listdir(service_path):
187
+ workflow_path = os.path.join(new_scaffold_namespace_path, service_name, workflow_name)
188
+ if not os.path.isdir(workflow_path):
189
+ continue
190
+
191
+ docker_compose_workflow_path = os.path.join(workflow_path, f".docker-compose.{workflow_name}.yml")
192
+ if os.path.exists(docker_compose_workflow_path):
193
+ os.rename(docker_compose_workflow_path, os.path.join(workflow_path, DOCKER_COMPOSE_WORKFLOW))
194
+
195
+ bin_path = os.path.join(workflow_path, 'bin')
196
+ if not os.path.isdir(bin_path):
197
+ continue
198
+
199
+ for file in os.listdir(bin_path):
200
+ shutil.move(os.path.join(bin_path, file), os.path.join(workflow_path, file))
201
+
202
+ # Remove the bin folder
203
+ shutil.rmtree(bin_path)
204
+
205
+ self.app_config.version = VERSION
206
+ self.app_config.write()
207
+
83
208
  def __cypress_initialized(self, app: App):
84
209
  if os.path.exists(os.path.join(app.context_dir_path, 'cypress.config.js')):
85
210
  return True
@@ -89,25 +214,6 @@ class AppCreateCommand(AppCommand):
89
214
 
90
215
  return False
91
216
 
92
- def __merge_compose_plugin(self, dest_path: str, template_path: str, plugin: str):
93
- if not os.path.exists(dest_path):
94
- open(dest_path, 'a').close()
95
-
96
- def load_yaml(path):
97
- with open(path, 'r') as f:
98
- return yaml.safe_load(f) or {}
99
-
100
- data1 = load_yaml(dest_path)
101
- data2 = load_yaml(template_path)
102
-
103
- services = data1.get('services') or {}
104
- if services.get(PLUGIN_CONTAINER_SERVICE_TEMPLATE.format(plugin=plugin, service=CORE_ENTRYPOINT_SERVICE_NAME)):
105
- return
106
-
107
- with open(dest_path, 'w') as out:
108
- merged = merge(data1, data2)
109
- yaml.dump(merged, out, default_flow_style=False)
110
-
111
217
  def __playwright_initialized(self, app: App):
112
218
  if os.path.exists(os.path.join(app.context_dir_path, 'playwright.config.js')):
113
219
  return True
@@ -115,41 +221,4 @@ class AppCreateCommand(AppCommand):
115
221
  if os.path.exists(os.path.join(app.context_dir_path, 'playwright.config.ts')):
116
222
  return True
117
223
 
118
- return False
119
-
120
- def __plugin_cypress(self, dest: str, plugin: str):
121
- dockerfile_name = PLUGIN_DOCKERFILE_TEMPLATE.format(plugin=plugin)
122
- dockerfile_dest_path = os.path.join(dest, CORE_ENTRYPOINT_SERVICE_NAME, WORKFLOW_TEST_TYPE, dockerfile_name)
123
-
124
- # Copy Dockerfile to workflow
125
- dockerfile_src_path = os.path.join(self.templates_root_dir, PLUGINS_FOLDER, plugin, WORKFLOW_TEST_TYPE, dockerfile_name)
126
- shutil.copyfile(dockerfile_src_path, dockerfile_dest_path)
127
-
128
- # Merge template into dest compose yml
129
- compose_dest_path = os.path.join(
130
- dest, CORE_ENTRYPOINT_SERVICE_NAME, WORKFLOW_TEST_TYPE, DOCKER_COMPOSE_WORKFLOW_TEMPLATE.format(workflow=WORKFLOW_TEST_TYPE)
131
- )
132
- template_path = os.path.join(
133
- self.templates_root_dir, PLUGINS_FOLDER, plugin, WORKFLOW_TEST_TYPE, DOCKER_COMPOSE_WORKFLOW_TEMPLATE.format(workflow=WORKFLOW_TEST_TYPE)
134
- )
135
- self.__merge_compose_plugin(compose_dest_path, template_path, plugin)
136
-
137
- def __plugin_playwright(self, dest: str, plugin: str):
138
- # Copy Dockerfile to workflow
139
- dockerfile_name = PLUGIN_DOCKERFILE_TEMPLATE.format(plugin=plugin)
140
- dockerfile_src_path = os.path.join(self.templates_root_dir, PLUGINS_FOLDER, plugin, WORKFLOW_TEST_TYPE, dockerfile_name)
141
- dockerfile_dest_path = os.path.join(dest, CORE_ENTRYPOINT_SERVICE_NAME, WORKFLOW_TEST_TYPE, dockerfile_name)
142
- shutil.copyfile(dockerfile_src_path, dockerfile_dest_path)
143
-
144
- entrypoint_src_path = os.path.join(self.templates_root_dir, PLUGINS_FOLDER, plugin, WORKFLOW_TEST_TYPE, PLUGIN_DOCKER_ENTRYPOINT)
145
- entrypoint_dest_path = os.path.join(dest, CORE_ENTRYPOINT_SERVICE_NAME, WORKFLOW_TEST_TYPE, PLUGIN_DOCKER_ENTRYPOINT)
146
- shutil.copyfile(entrypoint_src_path, entrypoint_dest_path)
147
-
148
- # Merge template into dest compose yml
149
- compose_dest_path = os.path.join(
150
- dest, CORE_ENTRYPOINT_SERVICE_NAME, WORKFLOW_TEST_TYPE, DOCKER_COMPOSE_WORKFLOW_TEMPLATE.format(workflow=WORKFLOW_TEST_TYPE)
151
- )
152
- template_path = os.path.join(
153
- self.templates_root_dir, PLUGINS_FOLDER, plugin, WORKFLOW_TEST_TYPE, DOCKER_COMPOSE_WORKFLOW_TEMPLATE.format(workflow=WORKFLOW_TEST_TYPE)
154
- )
155
- self.__merge_compose_plugin(compose_dest_path, template_path, plugin)
224
+ return False
@@ -11,21 +11,26 @@ APP_NETWORK_ENV = 'APP_NETWORK'
11
11
  APP_NAME_ENV = 'APP_NAME'
12
12
  APP_PLUGINS_ENV = 'APP_PLUGINS'
13
13
  APP_PLUGINS_DELMITTER = ','
14
+ APP_PROXY_PORT_ENV = 'APP_PROXY_PORT'
15
+ APP_RUN_ON_ENV = 'APP_RUN_ON'
16
+ APP_RUN_ON_DELIMITER = ','
14
17
  APP_UI_PORT_ENV = 'APP_UI_PORT'
18
+ APP_VERSION_ENV = 'APP_VERSION'
15
19
  BIN_FOLDER_NAME = 'bin'
16
20
  CA_CERTS_DIR_ENV = 'CA_CERTS_DIR'
17
21
  CERTS_DIR_ENV = 'CERTS_DIR'
18
- COMPOSE_TEMPLATE = '.docker-compose.{workflow}.yml'
19
22
  CONFIG_FILE = '.config.yml'
20
23
  CONTEXT_DIR_ENV = 'CONTEXT_DIR'
21
- DOCKER_NAMESPACE = 'docker'
22
24
  DOTENV_FILE = '.env'
23
25
  DOTENV_PATH_ENV = 'STOOBLY_DOTENV_PATH'
26
+ FIXTURES_FILE_NAME = 'fixtures.yml'
24
27
  NAMESERVERS_FILE = '.nameservers'
25
28
  PLUGIN_CYPRESS = 'cypress'
26
29
  PLUGIN_PLAYWRIGHT = 'playwright'
27
30
  PLUGINS_FOLDER = 'plugins'
28
31
  PUBLIC_FOLDER_NAME = 'public'
32
+ RUN_ON_DOCKER = 'docker'
33
+ RUN_ON_LOCAL = 'local'
29
34
  SERVICE_DETACHED = '${SERVICE_DETACHED}'
30
35
  SERVICE_DETACHED_ENV = 'SERVICE_DETACHED'
31
36
  SERVICE_DNS = '${SERVICE_DNS}'
@@ -37,8 +42,6 @@ SERVICE_ID_ENV = 'SERVICE_ID'
37
42
  SERVICE_LOCAL_ENV = 'SERVICE_LOCAL'
38
43
  SERVICE_NAME = '${SERVICE_NAME}'
39
44
  SERVICE_NAME_ENV = 'SERVICE_NAME'
40
- SERVICE_PROXY_MODE = '${SERVICE_PROXY_MODE}'
41
- SERVICE_PROXY_MODE_ENV = 'SERVICE_PROXY_MODE'
42
45
  SERVICE_SCHEME = '${SERVICE_SCHEME}'
43
46
  SERVICE_SCHEME_ENV = 'SERVICE_SCHEME'
44
47
  SERVICE_PORT = '${SERVICE_PORT}'
@@ -53,6 +56,7 @@ SERVICE_UPSTREAM_PORT = '${SERVICE_UPSTREAM_PORT}'
53
56
  SERVICE_UPSTREAM_PORT_ENV = 'SERVICE_UPSTREAM_PORT'
54
57
  SERVICE_UPSTREAM_SCHEME = '${SERVICE_UPSTREAM_SCHEME}'
55
58
  SERVICE_UPSTREAM_SCHEME_ENV = 'SERVICE_UPSTREAM_SCHEME'
59
+ SERVICES_NAMESPACE = 'services'
56
60
  STOOBLY_HOME_DIR = '/home/stoobly'
57
61
  STOOBLY_DATA_DIR = os.path.join(STOOBLY_HOME_DIR, DATA_DIR_NAME)
58
62
  STOOBLY_CERTS_DIR = os.path.join(STOOBLY_DATA_DIR, CERTS_DIR_NAME)
@@ -80,3 +84,4 @@ WORKFLOW_TEST_TYPE = 'test'
80
84
 
81
85
  CORE_WORKFLOWS = [WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]
82
86
  WORKFLOW_TEMPLATE_OPTION = Literal[WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]
87
+ RUN_ON_OPTIONS = [RUN_ON_DOCKER, RUN_ON_LOCAL]
@@ -8,7 +8,9 @@ DOCKER_COMPOSE_BASE = '.docker-compose.base.yml'
8
8
  DOCKER_COMPOSE_BASE_TEMPLATE = '.docker-compose.base.template.yml'
9
9
  DOCKER_COMPOSE_CUSTOM = 'docker-compose.yml'
10
10
  DOCKER_COMPOSE_NETWORKS = '.docker-compose.networks.yml'
11
- DOCKER_COMPOSE_WORKFLOW_TEMPLATE = '.docker-compose.{workflow}.yml'
11
+ DOCKER_COMPOSE_WORKFLOW = '.docker-compose.yml'
12
+ DOCKER_MAKEFILE = 'Makefile'
13
+ DOCKER_MAKEFILE_DOT = '.Makefile'
12
14
  DOCKERFILE_CONTEXT = '.Dockerfile.context'
13
15
  DOCKERFILE_SERVICE = 'Dockerfile.source'
14
16
  PLUGIN_CONTAINER_SERVICE_TEMPLATE = '{service}.{plugin}'
@@ -2,21 +2,21 @@ import pdb
2
2
 
3
3
  from typing import TypedDict
4
4
 
5
- from ...constants import DOCKER_NAMESPACE
5
+ from ...constants import SERVICES_NAMESPACE
6
6
  from ..constants import DOCKERFILE_SERVICE
7
- from .builder import ServiceBuilder
7
+ from .builder import DockerServiceBuilder
8
8
  from .types import BuildDecoratorOptions
9
9
 
10
10
  class BuildDecorator():
11
11
 
12
- def __init__(self, service_builder: ServiceBuilder):
12
+ def __init__(self, service_builder: DockerServiceBuilder):
13
13
  self.__service_builder = service_builder
14
14
 
15
15
  def decorate(self, **kwargs: BuildDecoratorOptions):
16
16
  service_builder = self.__service_builder
17
17
  build = {
18
18
  'context': '../..', # Assumes app root is 2 levels up
19
- 'dockerfile': f"./{DOCKER_NAMESPACE}/{service_builder.service_name}/{DOCKERFILE_SERVICE}"
19
+ 'dockerfile': f"./{SERVICES_NAMESPACE}/{service_builder.service_name}/{DOCKERFILE_SERVICE}"
20
20
  }
21
21
 
22
22
  if 'build_args' in kwargs: