stoobly-agent 1.0.6__py3-none-any.whl → 1.0.8__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 (29) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/cli/scaffold/constants.py +9 -1
  3. stoobly_agent/app/cli/scaffold/docker/constants.py +6 -0
  4. stoobly_agent/app/cli/scaffold/docker/workflow/builder.py +0 -2
  5. stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py +1 -1
  6. stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py +0 -1
  7. stoobly_agent/app/cli/scaffold/managed_services_docker_compose.py +9 -0
  8. stoobly_agent/app/cli/scaffold/service_command.py +3 -1
  9. stoobly_agent/app/cli/scaffold/service_config.py +2 -1
  10. stoobly_agent/app/cli/scaffold/service_docker_compose.py +15 -0
  11. stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +234 -0
  12. stoobly_agent/app/cli/scaffold/templates/constants.py +3 -3
  13. stoobly_agent/app/cli/scaffold/validate_command.py +59 -0
  14. stoobly_agent/app/cli/scaffold/validate_exceptions.py +5 -0
  15. stoobly_agent/app/cli/scaffold/workflow.py +22 -1
  16. stoobly_agent/app/cli/scaffold/workflow_run_command.py +2 -1
  17. stoobly_agent/app/cli/scaffold/workflow_validate_command.py +94 -0
  18. stoobly_agent/app/cli/scaffold_cli.py +40 -2
  19. stoobly_agent/config/data_dir.py +14 -6
  20. stoobly_agent/test/app/cli/scaffold/e2e_test.py +428 -0
  21. stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
  22. stoobly_agent/test/mock_data/scaffold/docker-compose-assets-service.yml +18 -0
  23. stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml +16 -0
  24. stoobly_agent/test/mock_data/scaffold/index.html +12 -0
  25. {stoobly_agent-1.0.6.dist-info → stoobly_agent-1.0.8.dist-info}/METADATA +2 -1
  26. {stoobly_agent-1.0.6.dist-info → stoobly_agent-1.0.8.dist-info}/RECORD +29 -19
  27. {stoobly_agent-1.0.6.dist-info → stoobly_agent-1.0.8.dist-info}/LICENSE +0 -0
  28. {stoobly_agent-1.0.6.dist-info → stoobly_agent-1.0.8.dist-info}/WHEEL +0 -0
  29. {stoobly_agent-1.0.6.dist-info → stoobly_agent-1.0.8.dist-info}/entry_points.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import pdb
1
2
  import os
2
3
  import shutil
3
4
 
@@ -16,6 +17,8 @@ class DataDir:
16
17
  if DataDir._instances.get(path):
17
18
  raise RuntimeError('Call instance() instead')
18
19
  else:
20
+ self.__path = path
21
+
19
22
  if path:
20
23
  self.__data_dir_path = os.path.join(path, DATA_DIR_NAME)
21
24
  else:
@@ -35,6 +38,9 @@ class DataDir:
35
38
  if not os.path.exists(self.__data_dir_path):
36
39
  self.create(os.path.dirname(self.__data_dir_path))
37
40
 
41
+ def __repr__(self) -> str:
42
+ return self.path
43
+
38
44
  @classmethod
39
45
  def instance(cls, path: str = None):
40
46
  if not cls._instances:
@@ -58,7 +64,7 @@ class DataDir:
58
64
 
59
65
  @property
60
66
  def path(self):
61
- if os.environ.get(ENV) == 'test':
67
+ if not self.__path and os.environ.get(ENV) == 'test':
62
68
  test_path = os.path.join(self.__data_dir_path, 'tmp', DATA_DIR_NAME)
63
69
 
64
70
  if not os.path.exists(test_path):
@@ -122,13 +128,13 @@ class DataDir:
122
128
  options = json.loads(contents)
123
129
  _conf_dir = options.get('confdir')
124
130
 
125
- if _conf_dir or not os.path.exists(_conf_dir):
131
+ if _conf_dir and os.path.exists(_conf_dir):
126
132
  conf_dir = _conf_dir
127
133
  except Exception:
128
134
  pass
129
-
130
- if not os.path.exists(conf_dir):
131
- os.makedirs(conf_dir)
135
+ else:
136
+ if not os.path.exists(conf_dir):
137
+ os.makedirs(conf_dir)
132
138
 
133
139
  return conf_dir
134
140
 
@@ -212,8 +218,10 @@ class DataDir:
212
218
  if not os.path.exists(self.__data_dir_path):
213
219
  os.mkdir(self.__data_dir_path)
214
220
 
221
+ # Create the certs_dir_path if it doesn't exist
222
+ self.certs_dir_path
215
223
  # Create tmp folder
216
- os.mkdir(os.path.join(self.__data_dir_path, 'tmp'))
224
+ os.makedirs(os.path.join(self.__data_dir_path, 'tmp'), exist_ok=True)
217
225
 
218
226
  with open(os.path.join(self.__data_dir_path, '.gitignore'), 'w') as fp:
219
227
  fp.write(
@@ -0,0 +1,428 @@
1
+ from pathlib import Path
2
+ import pathlib
3
+ import pdb
4
+ import shutil
5
+
6
+ from click.testing import CliRunner
7
+ import docker
8
+ import pytest
9
+
10
+ from stoobly_agent.app.cli import scaffold
11
+ from stoobly_agent.app.cli.scaffold.app import App
12
+ from stoobly_agent.app.cli.scaffold.constants import (
13
+ WORKFLOW_RECORD_TYPE,
14
+ WORKFLOW_TEST_TYPE,
15
+ )
16
+ from stoobly_agent.app.cli.scaffold.constants import DOCKER_NAMESPACE
17
+ from stoobly_agent.app.cli.scaffold.managed_services_docker_compose import (
18
+ ManagedServicesDockerCompose,
19
+ )
20
+ from stoobly_agent.app.cli.scaffold.service_docker_compose import ServiceDockerCompose
21
+ from stoobly_agent.app.cli.scaffold.service_workflow_validate_command import (
22
+ ServiceWorkflowValidateCommand,
23
+ )
24
+ from stoobly_agent.app.cli.scaffold.workflow_validate_command import (
25
+ WorkflowValidateCommand,
26
+ )
27
+ from stoobly_agent.config.data_dir import DATA_DIR_NAME, DataDir
28
+ from stoobly_agent.test.test_helper import reset
29
+
30
+
31
+ @pytest.mark.e2e
32
+ class TestScaffoldE2e():
33
+
34
+ @pytest.fixture(scope='module', autouse=True)
35
+ def settings(self):
36
+ return reset()
37
+
38
+ @pytest.fixture(scope='module')
39
+ def runner(self):
40
+ yield CliRunner()
41
+
42
+ @pytest.fixture(scope='class')
43
+ def docker_client(self):
44
+ yield docker.from_env()
45
+
46
+ @pytest.fixture(scope='class')
47
+ def app_name(self):
48
+ yield "0.0.1"
49
+
50
+ @pytest.fixture(scope='class', autouse=True)
51
+ def temp_dir(self):
52
+ data_dir_path = DataDir.instance().path
53
+ tmp_path = data_dir_path[:data_dir_path.rfind('/')]
54
+
55
+ yield tmp_path
56
+
57
+ @pytest.fixture(scope='class', autouse=True)
58
+ def app_dir_path(self, temp_dir, app_name):
59
+ yield temp_dir
60
+
61
+ @pytest.fixture(scope='class')
62
+ def mock_data_directory_path(self):
63
+ yield Path(__file__).parent.parent.parent.parent / 'mock_data'
64
+
65
+ @pytest.fixture(scope='class')
66
+ def local_service_mock_docker_compose_path(self, mock_data_directory_path):
67
+ path = mock_data_directory_path / "scaffold" / "docker-compose-local-service.yml"
68
+ yield path
69
+
70
+ @pytest.fixture(scope='class')
71
+ def hostname(self):
72
+ yield "http.badssl.com"
73
+
74
+ @pytest.fixture(scope='class')
75
+ def https_service_hostname(self):
76
+ yield "example.com"
77
+
78
+ @pytest.fixture(scope='class')
79
+ def external_service_name(self):
80
+ yield "external-service"
81
+
82
+ @pytest.fixture(scope='class')
83
+ def external_https_service_name(self):
84
+ yield "external-https-service"
85
+
86
+ @pytest.fixture(scope='class')
87
+ def local_hostname(self):
88
+ yield "my-httpbin.com"
89
+
90
+ @pytest.fixture(scope='class')
91
+ def local_service_name(self):
92
+ yield "my-httpbin"
93
+
94
+
95
+ class TestRecordWorkflow():
96
+ @pytest.fixture(scope='class', autouse=True)
97
+ def target_workflow_name(self):
98
+ yield WORKFLOW_RECORD_TYPE
99
+
100
+ @pytest.fixture(scope='class')
101
+ def managed_services_docker_compose(self, target_workflow_name):
102
+ yield ManagedServicesDockerCompose(target_workflow_name=target_workflow_name)
103
+
104
+ @pytest.fixture(scope='class')
105
+ def external_service_docker_compose(self, app_dir_path, target_workflow_name, external_service_name, hostname):
106
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=external_service_name, hostname=hostname)
107
+
108
+ @pytest.fixture(scope='class')
109
+ def external_https_service_docker_compose(self, app_dir_path, target_workflow_name, external_https_service_name, https_service_hostname):
110
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=external_https_service_name, hostname=https_service_hostname)
111
+
112
+ @pytest.fixture(scope='class')
113
+ def local_service_docker_compose(self, app_dir_path, target_workflow_name, local_service_name, local_hostname):
114
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=local_service_name, hostname=local_hostname)
115
+
116
+ @pytest.fixture(scope='class', autouse=True)
117
+ def setup_docker_composes(self, managed_services_docker_compose, external_service_docker_compose, local_service_docker_compose):
118
+ self.managed_services_docker_compose = managed_services_docker_compose
119
+ self.external_service_docker_compose = external_service_docker_compose
120
+ self.local_service_docker_compose = local_service_docker_compose
121
+
122
+ @pytest.fixture(scope="class", autouse=True)
123
+ def create_scaffold_setup(self, runner, app_dir_path, app_name, target_workflow_name, external_service_docker_compose, external_https_service_docker_compose, local_service_docker_compose, local_service_mock_docker_compose_path):
124
+ TestScaffoldE2e.cli_app_create(runner, app_dir_path, app_name)
125
+
126
+ # Create external user defined service
127
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, external_service_docker_compose.hostname, external_service_docker_compose.service_name, False)
128
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, external_https_service_docker_compose.hostname, external_https_service_docker_compose.service_name, True)
129
+
130
+ # Create local user defined service
131
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, local_service_docker_compose.hostname, local_service_docker_compose.service_name, False)
132
+
133
+ # Validate docker-compose path exists
134
+ destination_path = Path(local_service_docker_compose.docker_compose_path)
135
+ assert destination_path.is_file()
136
+ # Add user defined Docker Compose file for the local service
137
+ shutil.copyfile(local_service_mock_docker_compose_path, destination_path)
138
+
139
+ # Record workflow doesn't have a fixtures folder
140
+
141
+ # Generate certs
142
+ TestScaffoldE2e.cli_app_mkcert(runner, app_dir_path)
143
+
144
+ TestScaffoldE2e.cli_workflow_run(runner, app_dir_path, target_workflow_name)
145
+
146
+ @pytest.fixture(scope="class", autouse=True)
147
+ def cleanup_after_all(self, runner, app_dir_path, target_workflow_name):
148
+ yield
149
+ TestScaffoldE2e.cli_workflow_stop(runner, app_dir_path, target_workflow_name)
150
+
151
+ def test_core_components(self, app_dir_path, target_workflow_name):
152
+ app = App(app_dir_path, DOCKER_NAMESPACE)
153
+ config = {
154
+ 'workflow_name': target_workflow_name,
155
+ 'service_name': 'build'
156
+ }
157
+
158
+ command = WorkflowValidateCommand(app, **config)
159
+ command.validate()
160
+
161
+ def test_external_service(self, external_service_docker_compose: ServiceDockerCompose, app_dir_path, target_workflow_name):
162
+ app = App(app_dir_path, DOCKER_NAMESPACE)
163
+ config = {
164
+ 'workflow_name': target_workflow_name,
165
+ 'service_name': external_service_docker_compose.service_name
166
+ }
167
+
168
+ command = ServiceWorkflowValidateCommand(app, **config)
169
+ command.validate()
170
+
171
+ def test_local_service(self, app_dir_path, target_workflow_name, local_service_docker_compose: ServiceDockerCompose):
172
+ app = App(app_dir_path, DOCKER_NAMESPACE)
173
+ config = {
174
+ 'workflow_name': target_workflow_name,
175
+ 'service_name': local_service_docker_compose.service_name
176
+ }
177
+
178
+ command = ServiceWorkflowValidateCommand(app, **config)
179
+ command.validate()
180
+
181
+
182
+ class TestTestWorkflow():
183
+ @pytest.fixture(scope='class')
184
+ def assets_service_mock_docker_compose_path(self, mock_data_directory_path):
185
+ path = mock_data_directory_path / "scaffold" / "docker-compose-assets-service.yml"
186
+ yield path
187
+
188
+ @pytest.fixture(scope='class')
189
+ def assets_service_assets_path(self, mock_data_directory_path):
190
+ path = mock_data_directory_path / "scaffold" / "index.html"
191
+ yield path
192
+
193
+ @pytest.fixture(scope='class', autouse=True)
194
+ def target_workflow_name(self):
195
+ yield WORKFLOW_TEST_TYPE
196
+
197
+ @pytest.fixture(scope='class')
198
+ def assets_service_name(self):
199
+ yield "assets"
200
+
201
+ @pytest.fixture(scope='class')
202
+ def assets_hostname(self):
203
+ yield "assets"
204
+
205
+ @pytest.fixture(scope='class')
206
+ def managed_services_docker_compose(self, target_workflow_name):
207
+ yield ManagedServicesDockerCompose(target_workflow_name=target_workflow_name)
208
+
209
+ @pytest.fixture(scope='class')
210
+ def external_service_docker_compose(self, app_dir_path, target_workflow_name, external_service_name, hostname):
211
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=external_service_name, hostname=hostname)
212
+
213
+ @pytest.fixture(scope='class')
214
+ def local_service_docker_compose(self, app_dir_path, target_workflow_name, local_service_name, local_hostname):
215
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=local_service_name, hostname=local_hostname)
216
+
217
+ @pytest.fixture(scope='class')
218
+ def assets_service_docker_compose(self, app_dir_path, target_workflow_name, assets_service_name, assets_hostname):
219
+ yield ServiceDockerCompose(app_dir_path=app_dir_path, target_workflow_name=target_workflow_name, service_name=assets_service_name, hostname=assets_hostname)
220
+
221
+ @pytest.fixture(scope='class', autouse=True)
222
+ def setup_docker_composes(self, managed_services_docker_compose, external_service_docker_compose, local_service_docker_compose, assets_service_docker_compose):
223
+ self.managed_services_docker_compose = managed_services_docker_compose
224
+ self.external_service_docker_compose = external_service_docker_compose
225
+ self.local_service_docker_compose = local_service_docker_compose
226
+ self.assets_service_docker_compose = assets_service_docker_compose
227
+
228
+ @pytest.fixture(scope="class", autouse=True)
229
+ def create_scaffold_setup(self, runner, app_name, app_dir_path, target_workflow_name, external_service_docker_compose, local_service_docker_compose, assets_service_docker_compose, mock_data_directory_path, assets_service_mock_docker_compose_path):
230
+
231
+ TestScaffoldE2e.cli_app_create(runner, app_dir_path, app_name)
232
+
233
+ # Create external user defined service
234
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, external_service_docker_compose.hostname, external_service_docker_compose.service_name, False)
235
+ # Create local user defined services
236
+ TestScaffoldE2e.cli_service_create(runner, app_dir_path, local_service_docker_compose.hostname, local_service_docker_compose.service_name, False)
237
+ TestScaffoldE2e.cli_service_create_assets(runner, app_dir_path, assets_service_docker_compose.hostname, assets_service_docker_compose.service_name, False)
238
+
239
+ # Don't run the local user defined service in the 'test' workflow
240
+ # So don't copy the Docker Compose file over
241
+
242
+ # Add user defined Docker Compose file for the assets service
243
+ destination_path = Path(assets_service_docker_compose.docker_compose_path)
244
+ assert destination_path.is_file()
245
+ shutil.copyfile(assets_service_mock_docker_compose_path, destination_path)
246
+
247
+ TestScaffoldE2e.cli_service_create_assets(runner, app_dir_path, assets_service_docker_compose.hostname, assets_service_docker_compose.service_name, False)
248
+
249
+ # Add assets for assets service
250
+ data_dir_path = DataDir.instance().path
251
+ destination_assets_path = f"{data_dir_path}/docker/{assets_service_docker_compose.service_name}/{target_workflow_name}/index.html"
252
+ destination_path = Path(destination_assets_path)
253
+ assets_mock_path = mock_data_directory_path / "scaffold" / "index.html"
254
+ shutil.copyfile(assets_mock_path, destination_path)
255
+
256
+ # Created shared file in fixtures folder
257
+ app = App(app_dir_path, DOCKER_NAMESPACE)
258
+ config = {
259
+ 'workflow_name': target_workflow_name,
260
+ 'service_name': external_service_docker_compose.service_name
261
+ }
262
+ command = ServiceWorkflowValidateCommand(app, **config)
263
+ with open(f"{command.fixtures_dir_path}/shared_file.txt", 'w') as file:
264
+ file.write('this is a shared file')
265
+
266
+ TestScaffoldE2e.cli_workflow_run(runner, app_dir_path, target_workflow_name=target_workflow_name)
267
+
268
+ @pytest.fixture(scope="class", autouse=True)
269
+ def cleanup_after_all(self, runner, app_dir_path, target_workflow_name):
270
+ yield
271
+ TestScaffoldE2e.cli_workflow_stop(runner, app_dir_path, target_workflow_name)
272
+
273
+ def test_no_core_components(self, app_dir_path, target_workflow_name):
274
+ app = App(app_dir_path, DOCKER_NAMESPACE)
275
+ config = {
276
+ 'workflow_name': target_workflow_name,
277
+ 'service_name': 'build'
278
+ }
279
+
280
+ command = WorkflowValidateCommand(app, **config)
281
+ command.validate()
282
+
283
+ def test_user_services(self, app_dir_path, target_workflow_name, external_service_docker_compose, local_service_docker_compose):
284
+ app = App(app_dir_path, DOCKER_NAMESPACE)
285
+
286
+ config = {
287
+ 'workflow_name': target_workflow_name,
288
+ 'service_name': external_service_docker_compose.service_name
289
+ }
290
+ command = ServiceWorkflowValidateCommand(app, **config)
291
+ command.validate()
292
+
293
+ config = {
294
+ 'workflow_name': target_workflow_name,
295
+ 'service_name': local_service_docker_compose.service_name
296
+ }
297
+ command = ServiceWorkflowValidateCommand(app, **config)
298
+ command.validate()
299
+
300
+ def test_tests(self):
301
+ # This is covered by test_assets
302
+ pass
303
+
304
+ def test_assets(self, app_dir_path, target_workflow_name):
305
+
306
+ app = App(app_dir_path, DOCKER_NAMESPACE)
307
+ config = {
308
+ 'workflow_name': target_workflow_name,
309
+ 'service_name': 'assets'
310
+ }
311
+
312
+ command = ServiceWorkflowValidateCommand(app, **config)
313
+ command.validate()
314
+
315
+ @staticmethod
316
+ def cli_app_create(runner: CliRunner, app_dir_path: str, app_name: str):
317
+ pathlib.Path(f"{app_dir_path}/{DATA_DIR_NAME}").mkdir(parents=True, exist_ok=True)
318
+
319
+ result = runner.invoke(scaffold, ['app', 'create',
320
+ '--app-dir-path', app_dir_path,
321
+ '--force',
322
+ app_name
323
+ ])
324
+
325
+ assert result.exit_code == 0
326
+ output = result.stdout
327
+ assert not output
328
+
329
+ @staticmethod
330
+ def cli_app_mkcert(runner: CliRunner, app_dir_path: str):
331
+ result = runner.invoke(scaffold, ['app', 'mkcert',
332
+ '--app-dir-path', app_dir_path,
333
+ '--context-dir-path', app_dir_path,
334
+ ])
335
+
336
+ assert result.exit_code == 0
337
+ output = result.stdout
338
+ assert not output
339
+
340
+
341
+ @staticmethod
342
+ def cli_service_create(runner: CliRunner, app_dir_path: str, hostname: str, service_name: str, https: bool):
343
+ scheme = 'http'
344
+ port = '80'
345
+ if https == True:
346
+ scheme = 'https'
347
+ port = '443'
348
+
349
+ result = runner.invoke(scaffold, ['service', 'create',
350
+ '--app-dir-path', app_dir_path,
351
+ '--env', 'TEST',
352
+ '--force',
353
+ '--hostname', hostname,
354
+ '--scheme', scheme,
355
+ '--port', port,
356
+ '--workflow', 'mock',
357
+ '--workflow', 'record',
358
+ '--workflow', 'test',
359
+ service_name
360
+ ])
361
+ assert result.exit_code == 0
362
+ output = result.stdout
363
+ assert not output
364
+
365
+ # Specific flags for assets
366
+ @staticmethod
367
+ def cli_service_create_assets(runner: CliRunner, app_dir_path: str, hostname: str, service_name: str, https: bool):
368
+ scheme = 'http'
369
+ port = '80'
370
+ if https == True:
371
+ scheme = 'https'
372
+ port = '443'
373
+ proxy_mode_reverse_spec = f"reverse:{scheme}://{hostname}:8080"
374
+
375
+ result = runner.invoke(scaffold, ['service', 'create',
376
+ '--app-dir-path', app_dir_path,
377
+ '--force',
378
+ '--hostname', hostname,
379
+ '--scheme', scheme,
380
+ '--port', port,
381
+ '--proxy-mode', proxy_mode_reverse_spec,
382
+ '--detached',
383
+ '--workflow', 'test',
384
+ service_name
385
+ ])
386
+ assert result.exit_code == 0
387
+ output = result.stdout
388
+ assert not output
389
+
390
+ @staticmethod
391
+ def cli_workflow_create(runner: CliRunner, app_dir_path: str, service_name: str):
392
+ result = runner.invoke(scaffold, ['workflow', 'create',
393
+ '--app-dir-path', app_dir_path,
394
+ '--service', service_name,
395
+ '--template', 'mock',
396
+ 'ci',
397
+ ])
398
+
399
+ assert result.exit_code == 0
400
+ output = result.stdout
401
+ assert not output
402
+
403
+ @staticmethod
404
+ def cli_workflow_run(runner: CliRunner, app_dir_path: str, target_workflow_name: str):
405
+ command = ['workflow', 'run',
406
+ '--app-dir-path', app_dir_path,
407
+ '--context-dir-path', app_dir_path,
408
+ target_workflow_name,
409
+ ]
410
+ result = runner.invoke(scaffold, command)
411
+
412
+ assert result.exit_code == 0
413
+ output = result.stdout
414
+ assert output
415
+
416
+ @staticmethod
417
+ def cli_workflow_stop(runner: CliRunner, app_dir_path: str, target_workflow_name: str):
418
+ command = ['workflow', 'stop',
419
+ '--app-dir-path', app_dir_path,
420
+ '--context-dir-path', app_dir_path,
421
+ target_workflow_name,
422
+ ]
423
+ result = runner.invoke(scaffold, command)
424
+
425
+ assert result.exit_code == 0
426
+ output = result.stdout
427
+ assert output
428
+
@@ -1 +1 @@
1
- 1.0.5
1
+ 1.0.7
@@ -0,0 +1,18 @@
1
+ # Define services here
2
+
3
+ networks:
4
+ app:
5
+ external: true
6
+ name: ${APP_NETWORK}
7
+
8
+ services:
9
+ assets:
10
+ image: nginx:1.27
11
+ hostname: assets
12
+ networks:
13
+ - app
14
+ volumes:
15
+ - ./index.html:/usr/share/nginx/html/index.html
16
+ profiles: &id001
17
+ - test
18
+
@@ -0,0 +1,16 @@
1
+ # Define services here
2
+
3
+ networks:
4
+ gateway:
5
+ external: true
6
+ name: ${APP_NETWORK}
7
+
8
+ services:
9
+ my-httpbin:
10
+ image: kennethreitz/httpbin:latest
11
+ hostname: my-httpbin.com
12
+ networks:
13
+ - gateway
14
+ profiles: &id001
15
+ - record
16
+
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Welcome to NGINX</title>
7
+ </head>
8
+ <body>
9
+ <h1>Hello, NGINX is serving this page!</h1>
10
+ </body>
11
+ </html>
12
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: stoobly-agent
3
- Version: 1.0.6
3
+ Version: 1.0.8
4
4
  Summary: Record, mock, and test HTTP(s) requests. CLI agent for Stoobly
5
5
  License: Apache-2.0
6
6
  Author: Matt Le
@@ -16,6 +16,7 @@ Requires-Dist: click (>=8.1.0,<9.0.0)
16
16
  Requires-Dist: diff-match-patch (>=20230430,<20230431)
17
17
  Requires-Dist: distro (>=1.6.0,<1.7.0)
18
18
  Requires-Dist: dnspython (>=2.6.1,<2.7.0)
19
+ Requires-Dist: docker (>=7.1.0,<8.0)
19
20
  Requires-Dist: httptools (>=0.4.0)
20
21
  Requires-Dist: jmespath (>=1.0.0)
21
22
  Requires-Dist: mergedeep (>=1.3.0,<1.3.4)