stoobly-agent 1.9.5__py3-none-any.whl → 1.9.7__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.
- stoobly_agent/__init__.py +1 -1
- stoobly_agent/app/cli/ca_cert_cli.py +18 -3
- stoobly_agent/app/cli/scaffold/constants.py +1 -0
- stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py +4 -4
- stoobly_agent/app/cli/scaffold/service.py +6 -0
- stoobly_agent/app/cli/scaffold/service_command.py +8 -0
- stoobly_agent/app/cli/scaffold/service_update_command.py +70 -0
- stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +3 -2
- stoobly_agent/app/cli/scaffold/templates/app/.Makefile +3 -3
- stoobly_agent/app/cli/scaffold/workflow_copy_command.py +1 -2
- stoobly_agent/app/cli/scaffold/workflow_create_command.py +1 -2
- stoobly_agent/app/cli/scaffold/workflow_run_command.py +2 -2
- stoobly_agent/app/cli/scaffold_cli.py +36 -31
- stoobly_agent/app/cli/validators/scaffold.py +39 -0
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
- {stoobly_agent-1.9.5.dist-info → stoobly_agent-1.9.7.dist-info}/METADATA +1 -1
- {stoobly_agent-1.9.5.dist-info → stoobly_agent-1.9.7.dist-info}/RECORD +20 -18
- {stoobly_agent-1.9.5.dist-info → stoobly_agent-1.9.7.dist-info}/LICENSE +0 -0
- {stoobly_agent-1.9.5.dist-info → stoobly_agent-1.9.7.dist-info}/WHEEL +0 -0
- {stoobly_agent-1.9.5.dist-info → stoobly_agent-1.9.7.dist-info}/entry_points.txt +0 -0
stoobly_agent/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
COMMAND = 'stoobly-agent'
|
2
|
-
VERSION = '1.9.
|
2
|
+
VERSION = '1.9.7'
|
@@ -15,8 +15,18 @@ def ca_cert(ctx):
|
|
15
15
|
pass
|
16
16
|
|
17
17
|
@ca_cert.command()
|
18
|
-
@click.option(
|
19
|
-
|
18
|
+
@click.option(
|
19
|
+
'--ca-certs-dir-path',
|
20
|
+
default=DataDir.instance().ca_certs_dir_path,
|
21
|
+
help='Path to ca certs directory used to sign SSL certs.',
|
22
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True)
|
23
|
+
)
|
24
|
+
@click.option(
|
25
|
+
'--certs-dir-path',
|
26
|
+
default=DataDir.instance().certs_dir_path,
|
27
|
+
help='Output directory.',
|
28
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True)
|
29
|
+
)
|
20
30
|
@click.argument('hostname')
|
21
31
|
def mkcert(**kwargs):
|
22
32
|
ca_certs_dir_path = kwargs['ca_certs_dir_path']
|
@@ -30,7 +40,12 @@ def mkcert(**kwargs):
|
|
30
40
|
sys.exit(1)
|
31
41
|
|
32
42
|
@ca_cert.command()
|
33
|
-
@click.option(
|
43
|
+
@click.option(
|
44
|
+
'--ca-certs-dir-path',
|
45
|
+
default=DataDir.instance().ca_certs_dir_path,
|
46
|
+
help='Path to ca certs directory.',
|
47
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True)
|
48
|
+
)
|
34
49
|
def install(**kwargs):
|
35
50
|
ca_certs_dir_path = kwargs['ca_certs_dir_path']
|
36
51
|
installer = CertificateAuthority(ca_certs_dir_path)
|
@@ -61,4 +61,5 @@ WORKFLOW_TEMPLATE = '${WORKFLOW_TEMPLATE}'
|
|
61
61
|
WORKFLOW_TEMPLATE_ENV = 'WORKFLOW_TEMPLATE'
|
62
62
|
WORKFLOW_TEST_TYPE = 'test'
|
63
63
|
|
64
|
+
CORE_WORKFLOWS = [WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]
|
64
65
|
WORKFLOW_TEMPLATE_OPTION = Literal[WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]
|
@@ -10,7 +10,7 @@ from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
|
|
10
10
|
from stoobly_agent.app.cli.scaffold.docker.constants import APP_INGRESS_NETWORK_NAME, APP_EGRESS_NETWORK_NAME, DOCKER_COMPOSE_BASE, DOCKER_COMPOSE_BASE_TEMPLATE
|
11
11
|
from stoobly_agent.app.cli.scaffold.templates.constants import CORE_GATEWAY_SERVICE_NAME
|
12
12
|
|
13
|
-
def configure_gateway(
|
13
|
+
def configure_gateway(namespace: str, service_paths: List[str], no_publish = False):
|
14
14
|
if len(service_paths) == 0:
|
15
15
|
return
|
16
16
|
|
@@ -36,7 +36,7 @@ def configure_gateway(workflow_name, service_paths: List[str], no_publish = Fals
|
|
36
36
|
gateway_base['ports'] = ports
|
37
37
|
|
38
38
|
app_dir_path = os.path.dirname(os.path.dirname(service_dir_path))
|
39
|
-
__with_traefik_config(
|
39
|
+
__with_traefik_config(namespace, service_paths, app_dir_path, gateway_base)
|
40
40
|
__with_networks(gateway_base, hostnames)
|
41
41
|
|
42
42
|
with open(docker_compose_dest_path, 'w') as fp:
|
@@ -50,7 +50,7 @@ def __with_networks(config: dict, hostnames: List[str]):
|
|
50
50
|
'aliases': hostnames
|
51
51
|
}
|
52
52
|
|
53
|
-
def __with_traefik_config(
|
53
|
+
def __with_traefik_config(namespace: str, service_paths: List[str], app_dir_path: str, compose: dict):
|
54
54
|
config_dest = '/etc/traefik/traefik.yml'
|
55
55
|
|
56
56
|
if not compose['volumes']:
|
@@ -98,7 +98,7 @@ def __with_traefik_config(workflow_name: str, service_paths: List[str], app_dir_
|
|
98
98
|
})
|
99
99
|
|
100
100
|
# Create traefik.yml in .stoobly/tmp
|
101
|
-
traefik_template_relative_path = os.path.join(DATA_DIR_NAME, TMP_DIR_NAME,
|
101
|
+
traefik_template_relative_path = os.path.join(DATA_DIR_NAME, TMP_DIR_NAME, namespace, 'traefik.yml')
|
102
102
|
traefik_template_dest_path = os.path.join(app_dir_path, traefik_template_relative_path)
|
103
103
|
|
104
104
|
if not os.path.exists(os.path.dirname(traefik_template_dest_path)):
|
@@ -20,5 +20,11 @@ class Service():
|
|
20
20
|
def service_name(self):
|
21
21
|
return self.__service_name
|
22
22
|
|
23
|
+
@property
|
24
|
+
def workflows(self):
|
25
|
+
# Each directory in the service directory path is a workflow
|
26
|
+
workflows = [ f.name for f in os.scandir(self.dir_path) if f.is_dir() ]
|
27
|
+
return workflows
|
28
|
+
|
23
29
|
def workflow_dir_path(self, workflow_name: str):
|
24
30
|
return os.path.join(self.dir_path, workflow_name)
|
@@ -18,6 +18,10 @@ class ServiceCommand(AppCommand):
|
|
18
18
|
def service_config(self):
|
19
19
|
return self.__config
|
20
20
|
|
21
|
+
@service_config.setter
|
22
|
+
def service_config(self, value):
|
23
|
+
self.__config = value
|
24
|
+
|
21
25
|
@property
|
22
26
|
def service_config_path(self):
|
23
27
|
return self.__config.path
|
@@ -26,6 +30,10 @@ class ServiceCommand(AppCommand):
|
|
26
30
|
def service_name(self):
|
27
31
|
return self.__service_name
|
28
32
|
|
33
|
+
@service_name.setter
|
34
|
+
def service_name(self, value):
|
35
|
+
self.__service_name = value
|
36
|
+
|
29
37
|
@property
|
30
38
|
def service_exists(self):
|
31
39
|
return os.path.exists(self.service_path)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import os
|
2
|
+
import pdb
|
3
|
+
|
4
|
+
from stoobly_agent.app.cli.scaffold.app import App
|
5
|
+
from stoobly_agent.app.cli.scaffold.constants import CORE_WORKFLOWS
|
6
|
+
from stoobly_agent.app.cli.scaffold.docker.workflow.decorators_factory import get_workflow_decorators
|
7
|
+
from stoobly_agent.app.cli.scaffold.service import Service
|
8
|
+
from stoobly_agent.app.cli.scaffold.service_command import ServiceCommand
|
9
|
+
from stoobly_agent.app.cli.scaffold.service_create_command import ServiceCreateCommand
|
10
|
+
from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
|
11
|
+
from stoobly_agent.app.cli.scaffold.workflow_config import WorkflowConfig
|
12
|
+
from stoobly_agent.app.cli.scaffold.workflow_create_command import WorkflowCreateCommand
|
13
|
+
|
14
|
+
from stoobly_agent.lib.logger import Logger
|
15
|
+
|
16
|
+
|
17
|
+
LOG_ID = 'ServiceUpdateCommand'
|
18
|
+
|
19
|
+
class ServiceUpdateCommand(ServiceCommand):
|
20
|
+
|
21
|
+
def __init__(self, app: App, **kwargs):
|
22
|
+
super().__init__(app, **kwargs)
|
23
|
+
|
24
|
+
def rename(self, new_service_name: str) -> Service:
|
25
|
+
self.__rename_service_dir(self.service_path, new_service_name)
|
26
|
+
|
27
|
+
self.service = Service(new_service_name, self.app)
|
28
|
+
self.service_config = ServiceConfig(self.service.dir_path)
|
29
|
+
|
30
|
+
self.__update_internal_container_specs(new_service_name)
|
31
|
+
|
32
|
+
return self.service
|
33
|
+
|
34
|
+
def __rename_service_dir(self, dir_path: str, new_name: str) -> None:
|
35
|
+
new_dir_path = os.path.join(self.app.scaffold_namespace_path, new_name)
|
36
|
+
os.rename(dir_path, new_dir_path)
|
37
|
+
|
38
|
+
def __update_internal_container_specs(self, new_service_name: str) -> None:
|
39
|
+
workflows = self.service.workflows
|
40
|
+
|
41
|
+
kwargs = {}
|
42
|
+
kwargs['app_dir_path'] = self.app.dir_path
|
43
|
+
kwargs['service_name'] = new_service_name
|
44
|
+
kwargs['workflow'] = workflows
|
45
|
+
command = ServiceCreateCommand(self.app, **kwargs)
|
46
|
+
command.build()
|
47
|
+
|
48
|
+
custom_workflows_set = set(workflows) - set(CORE_WORKFLOWS)
|
49
|
+
custom_workflows = list(custom_workflows_set)
|
50
|
+
|
51
|
+
for workflow in custom_workflows:
|
52
|
+
kwargs = {}
|
53
|
+
kwargs['app_dir_path'] = self.app.dir_path
|
54
|
+
kwargs['force'] = True
|
55
|
+
kwargs['service_name'] = new_service_name
|
56
|
+
kwargs['workflow_name'] = workflow
|
57
|
+
|
58
|
+
workflow_path = self.service.workflow_dir_path(workflow)
|
59
|
+
workflow_config = WorkflowConfig(workflow_path, **kwargs)
|
60
|
+
kwargs['template'] = workflow_config.template
|
61
|
+
|
62
|
+
command = WorkflowCreateCommand(self.app, **kwargs)
|
63
|
+
|
64
|
+
service_config = self.service_config
|
65
|
+
workflow_decorators = get_workflow_decorators(kwargs['template'], service_config)
|
66
|
+
|
67
|
+
command.build(
|
68
|
+
template=kwargs['template'],
|
69
|
+
workflow_decorators=workflow_decorators
|
70
|
+
)
|
@@ -116,12 +116,13 @@ class ServiceWorkflowValidateCommand(ServiceCommand, ValidateCommand):
|
|
116
116
|
|
117
117
|
def validate_internal_hostname(self, url: str) -> None:
|
118
118
|
print(f"Validating hostname inside Docker network, url: {url}")
|
119
|
-
|
119
|
+
|
120
|
+
network = f"{self.workflow_name}.{self.app_config.network}"
|
120
121
|
timeout_seconds = 1
|
121
122
|
output = self.docker_client.containers.run(
|
122
123
|
image='curlimages/curl:8.11.0',
|
123
124
|
command=f"curl --max-time {timeout_seconds} {url} --verbose",
|
124
|
-
network=APP_EGRESS_NETWORK_TEMPLATE.format(network=
|
125
|
+
network=APP_EGRESS_NETWORK_TEMPLATE.format(network=network),
|
125
126
|
stderr=True,
|
126
127
|
remove=True,
|
127
128
|
)
|
@@ -35,7 +35,7 @@ dockerfile_path=$(app_namespace_dir)/.Dockerfile.context
|
|
35
35
|
exec_docker_compose_file_path=$(app_namespace_dir)/stoobly-ui/exec/.docker-compose.exec.yml
|
36
36
|
exec_namespace=$(shell echo "$(workflow_namespace).$(context_dir)" | (md5 2>/dev/null || md5sum 2>/dev/null || shasum 2>/dev/null) | awk '{print $$1}')
|
37
37
|
workflow_namespace=$(if $(namespace),$(namespace),$(workflow))
|
38
|
-
workflow_script=.stoobly/tmp/$(
|
38
|
+
workflow_script=.stoobly/tmp/$(workflow_namespace)/run.sh
|
39
39
|
|
40
40
|
# Options
|
41
41
|
certs_dir_options=--ca-certs-dir-path $(ca_certs_dir) --certs-dir-path $(certs_dir)
|
@@ -52,8 +52,8 @@ docker_command=docker
|
|
52
52
|
docker_compose_command=$(docker_command) compose
|
53
53
|
exec_down=$(docker_compose_command) -f "$(exec_docker_compose_file_path)" $(stoobly_exec_options) down
|
54
54
|
exec_env=APP_DIR="$(app_dir)" CA_CERTS_DIR="$(ca_certs_dir)" USER_ID="$(USER_ID)"
|
55
|
-
exec_up=$(docker_compose_command) -f "$(exec_docker_compose_file_path)" $(stoobly_exec_options) up --remove-orphans
|
56
|
-
source_env=set -a; [ -f .env ] && source .env; set +a
|
55
|
+
exec_up=$(docker_compose_command) -f "$(exec_docker_compose_file_path)" $(stoobly_exec_options) up --abort-on-container-exit --remove-orphans
|
56
|
+
source_env=(set -a; [ -f .env ] && source .env; set +a)
|
57
57
|
|
58
58
|
# Build base image
|
59
59
|
stoobly_exec_build=$(docker_command) build $(stoobly_exec_build_args) $(app_namespace_dir)
|
@@ -3,11 +3,10 @@ import pdb
|
|
3
3
|
import shutil
|
4
4
|
|
5
5
|
from .app import App
|
6
|
-
from .constants import COMPOSE_TEMPLATE
|
6
|
+
from .constants import COMPOSE_TEMPLATE
|
7
7
|
from .service_workflow import ServiceWorkflow
|
8
8
|
from .workflow_command import WorkflowCommand
|
9
9
|
|
10
|
-
CORE_WORKFLOWS = [WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]
|
11
10
|
|
12
11
|
class WorkflowCopyCommand(WorkflowCommand):
|
13
12
|
|
@@ -5,7 +5,7 @@ import shutil
|
|
5
5
|
from typing import List, TypedDict, Union
|
6
6
|
|
7
7
|
from .app import App
|
8
|
-
from .constants import
|
8
|
+
from .constants import WORKFLOW_TEMPLATE_OPTION
|
9
9
|
from .docker.service.builder import ServiceBuilder
|
10
10
|
from .docker.workflow.mock_decorator import MockDecorator
|
11
11
|
from .docker.workflow.reverse_proxy_decorator import ReverseProxyDecorator
|
@@ -13,7 +13,6 @@ from .docker.workflow.builder import WorkflowBuilder
|
|
13
13
|
from .templates.factory import custom_files, maintained_files
|
14
14
|
from .workflow_command import WorkflowCommand
|
15
15
|
|
16
|
-
CORE_WORKFLOWS = [WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]
|
17
16
|
|
18
17
|
class BuildOptions(TypedDict):
|
19
18
|
builder_class: type
|
@@ -48,8 +48,8 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
48
48
|
self.__ca_certs_dir_path = kwargs.get('ca_certs_dir_path') or app.ca_certs_dir_path
|
49
49
|
self.__certs_dir_path = kwargs.get('certs_dir_path') or app.certs_dir_path
|
50
50
|
self.__context_dir_path = kwargs.get('context_dir_path') or app.context_dir_path
|
51
|
-
self.__network = kwargs.get('network') or self.app_config.network
|
52
|
-
|
51
|
+
self.__network = f"{kwargs.get('network') or {self.workflow_name}}.{self.app_config.network}"
|
52
|
+
|
53
53
|
@property
|
54
54
|
def app_dir_path(self):
|
55
55
|
return self.__app_dir_path
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import click
|
2
2
|
import os
|
3
3
|
import pdb
|
4
|
-
import re
|
5
4
|
import sys
|
6
5
|
|
7
6
|
from io import TextIOWrapper
|
@@ -23,6 +22,7 @@ from stoobly_agent.app.cli.scaffold.service import Service
|
|
23
22
|
from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
|
24
23
|
from stoobly_agent.app.cli.scaffold.service_create_command import ServiceCreateCommand
|
25
24
|
from stoobly_agent.app.cli.scaffold.service_delete_command import ServiceDeleteCommand
|
25
|
+
from stoobly_agent.app.cli.scaffold.service_update_command import ServiceUpdateCommand
|
26
26
|
from stoobly_agent.app.cli.scaffold.service_workflow_validate_command import ServiceWorkflowValidateCommand
|
27
27
|
from stoobly_agent.app.cli.scaffold.templates.constants import CORE_SERVICES
|
28
28
|
from stoobly_agent.app.cli.scaffold.validate_exceptions import ScaffoldValidateException
|
@@ -37,6 +37,7 @@ from stoobly_agent.config.data_dir import DataDir
|
|
37
37
|
from stoobly_agent.lib.logger import bcolors, DEBUG, ERROR, INFO, Logger, WARNING
|
38
38
|
|
39
39
|
from .helpers.print_service import FORMATS, print_services, select_print_options
|
40
|
+
from .validators.scaffold import validate_app_name, validate_hostname, validate_namespace, validate_service_name
|
40
41
|
|
41
42
|
LOG_ID = 'Scaffold'
|
42
43
|
|
@@ -90,7 +91,7 @@ def hostname(ctx):
|
|
90
91
|
@click.option('--network', help='App default network name. Defaults to app name.')
|
91
92
|
@click.option('--quiet', is_flag=True, help='Disable log output.')
|
92
93
|
@click.option('--ui-port', default=4200, type=click.IntRange(1, 65535), help='UI service port.')
|
93
|
-
@click.argument('app_name')
|
94
|
+
@click.argument('app_name', callback=validate_app_name)
|
94
95
|
def create(**kwargs):
|
95
96
|
__validate_app_dir(kwargs['app_dir_path'])
|
96
97
|
|
@@ -129,7 +130,7 @@ def mkcert(**kwargs):
|
|
129
130
|
@click.option('--app-dir-path', default=current_working_dir, help='Path to application directory.')
|
130
131
|
@click.option('--detached', is_flag=True, help='Use isolated and non-persistent context directory.')
|
131
132
|
@click.option('--env', multiple=True, help='Specify an environment variable.')
|
132
|
-
@click.option('--hostname', help='Service hostname.')
|
133
|
+
@click.option('--hostname', callback=validate_hostname, help='Service hostname.')
|
133
134
|
@click.option('--port', type=click.IntRange(1, 65535), help='Service port.')
|
134
135
|
@click.option('--priority', default=5, type=click.FloatRange(1.0, 9.0), help='Determines the service run order. Lower values run first.')
|
135
136
|
@click.option('--proxy-mode', help='''
|
@@ -141,17 +142,10 @@ def mkcert(**kwargs):
|
|
141
142
|
@click.option('--quiet', is_flag=True, help='Disable log output.')
|
142
143
|
@click.option('--scheme', type=click.Choice(['http', 'https']), help='Defaults to https if hostname is set.')
|
143
144
|
@click.option('--workflow', multiple=True, type=click.Choice([WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]), help='Include pre-defined workflows.')
|
144
|
-
@click.argument('service_name')
|
145
|
+
@click.argument('service_name', callback=validate_service_name)
|
145
146
|
def create(**kwargs):
|
146
147
|
__validate_app_dir(kwargs['app_dir_path'])
|
147
148
|
|
148
|
-
if '/' in kwargs['service_name']:
|
149
|
-
print(f"Error: {kwargs['service_name']} is invalid. It cannot container '/", file=sys.stderr)
|
150
|
-
sys.exit(1)
|
151
|
-
|
152
|
-
if kwargs.get('hostname'):
|
153
|
-
__validate_hostname(kwargs.get('hostname'))
|
154
|
-
|
155
149
|
if kwargs.get("proxy_mode"):
|
156
150
|
__validate_proxy_mode(kwargs.get("proxy_mode"))
|
157
151
|
|
@@ -214,11 +208,11 @@ def delete(**kwargs):
|
|
214
208
|
help="Update a service config"
|
215
209
|
)
|
216
210
|
@click.option('--app-dir-path', default=current_working_dir, help='Path to application directory.')
|
217
|
-
@click.option('--hostname', help='Service hostname.')
|
211
|
+
@click.option('--hostname', callback=validate_hostname, help='Service hostname.')
|
218
212
|
@click.option('--port', type=click.IntRange(1, 65535), help='Service port.')
|
219
213
|
@click.option('--priority', default=5, type=click.FloatRange(1.0, 9.0), help='Determines the service run order. Lower values run first.')
|
220
214
|
@click.option('--scheme', type=click.Choice(['http', 'https']), help='Defaults to https if hostname is set.')
|
221
|
-
@click.option('--name', type=click.STRING, help='New name of the service to update to.')
|
215
|
+
@click.option('--name', callback=validate_service_name, type=click.STRING, help='New name of the service to update to.')
|
222
216
|
@click.option('--proxy-mode', help='''
|
223
217
|
Proxy mode can be "regular", "transparent", "socks5",
|
224
218
|
"reverse:SPEC", or "upstream:SPEC". For reverse and
|
@@ -237,8 +231,6 @@ def update(**kwargs):
|
|
237
231
|
service_config = ServiceConfig(service.dir_path)
|
238
232
|
|
239
233
|
if kwargs['hostname']:
|
240
|
-
__validate_hostname(kwargs['hostname'])
|
241
|
-
|
242
234
|
old_hostname = service_config.hostname
|
243
235
|
|
244
236
|
if old_hostname != kwargs['hostname']:
|
@@ -261,6 +253,19 @@ def update(**kwargs):
|
|
261
253
|
if kwargs['scheme']:
|
262
254
|
service_config.scheme = kwargs['scheme']
|
263
255
|
|
256
|
+
if kwargs['name']:
|
257
|
+
old_service_name = service.service_name
|
258
|
+
new_service_name = kwargs['name']
|
259
|
+
|
260
|
+
print(f"Renaming service from: {old_service_name}, to: {new_service_name}")
|
261
|
+
|
262
|
+
kwargs['service_path'] = service.dir_path
|
263
|
+
command = ServiceUpdateCommand(app, **kwargs)
|
264
|
+
service = command.rename(new_service_name)
|
265
|
+
service_config = command.service_config
|
266
|
+
|
267
|
+
print(f"Successfully renamed service to: {new_service_name}")
|
268
|
+
|
264
269
|
if kwargs['proxy_mode']:
|
265
270
|
__validate_proxy_mode(kwargs['proxy_mode'])
|
266
271
|
service_config.proxy_mode = kwargs['proxy_mode']
|
@@ -329,7 +334,7 @@ def copy(**kwargs):
|
|
329
334
|
@click.option('--log-level', default=INFO, type=click.Choice([DEBUG, INFO, WARNING, ERROR]), help='''
|
330
335
|
Log levels can be "debug", "info", "warning", or "error"
|
331
336
|
''')
|
332
|
-
@click.option('--namespace', help='Workflow namespace.')
|
337
|
+
@click.option('--namespace', callback=validate_namespace, help='Workflow namespace.')
|
333
338
|
@click.option('--network', help='Workflow network name.')
|
334
339
|
@click.option('--rmi', is_flag=True, help='Remove images used by containers.')
|
335
340
|
@click.option('--script-path', help='Path to intermediate script path.')
|
@@ -342,9 +347,7 @@ def down(**kwargs):
|
|
342
347
|
app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE, **kwargs)
|
343
348
|
__validate_app(app)
|
344
349
|
|
345
|
-
|
346
|
-
if kwargs['namespace'] and not kwargs['network']:
|
347
|
-
kwargs['network'] = kwargs['namespace']
|
350
|
+
__with_namespace_defaults(kwargs)
|
348
351
|
|
349
352
|
services = __get_services(
|
350
353
|
app, service=kwargs['service'], workflow=[kwargs['workflow_name']]
|
@@ -412,7 +415,7 @@ def down(**kwargs):
|
|
412
415
|
@click.option('--log-level', default=INFO, type=click.Choice([DEBUG, INFO, WARNING, ERROR]), help='''
|
413
416
|
Log levels can be "debug", "info", "warning", or "error"
|
414
417
|
''')
|
415
|
-
@click.option('--namespace', help='Workflow namespace.')
|
418
|
+
@click.option('--namespace', callback=validate_namespace, help='Workflow namespace.')
|
416
419
|
@click.option('--script-path', help='Path to intermediate script path.')
|
417
420
|
@click.option('--service', multiple=True, help='Select which services to log. Defaults to all.')
|
418
421
|
@click.argument('workflow_name')
|
@@ -422,6 +425,8 @@ def logs(**kwargs):
|
|
422
425
|
app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
|
423
426
|
__validate_app(app)
|
424
427
|
|
428
|
+
__with_namespace_defaults(kwargs)
|
429
|
+
|
425
430
|
if len(kwargs['container']) == 0:
|
426
431
|
kwargs['container'] = [WORKFLOW_CONTAINER_PROXY]
|
427
432
|
|
@@ -474,7 +479,7 @@ def logs(**kwargs):
|
|
474
479
|
Log levels can be "debug", "info", "warning", or "error"
|
475
480
|
''')
|
476
481
|
@click.option('--mkcert', is_flag=True, help='Set to generate SSL certs for HTTPS services.')
|
477
|
-
@click.option('--namespace', help='Workflow namespace.')
|
482
|
+
@click.option('--namespace', callback=validate_namespace, help='Workflow namespace.')
|
478
483
|
@click.option('--network', help='Workflow network name.')
|
479
484
|
@click.option('--no-build', is_flag=True, help='Do not build images before starting containers.')
|
480
485
|
@click.option('--no-publish', is_flag=True, help='Do not publish all ports.')
|
@@ -496,9 +501,7 @@ def up(**kwargs):
|
|
496
501
|
app = App(app_dir_path, DOCKER_NAMESPACE, **kwargs)
|
497
502
|
__validate_app(app)
|
498
503
|
|
499
|
-
|
500
|
-
if kwargs['namespace'] and not kwargs['network']:
|
501
|
-
kwargs['network'] = kwargs['namespace']
|
504
|
+
__with_namespace_defaults(kwargs)
|
502
505
|
|
503
506
|
services = __get_services(
|
504
507
|
app, service=kwargs['service'], workflow=[kwargs['workflow_name']]
|
@@ -677,7 +680,7 @@ def __build_script(**kwargs):
|
|
677
680
|
script_path = kwargs['script_path']
|
678
681
|
if not script_path:
|
679
682
|
script_file_name = 'run.sh'
|
680
|
-
script_path = os.path.join(data_dir.tmp_dir_path, kwargs['workflow_name'], script_file_name)
|
683
|
+
script_path = os.path.join(data_dir.tmp_dir_path, kwargs.get('namespace') or kwargs['workflow_name'] or '', script_file_name)
|
681
684
|
|
682
685
|
script_dir = os.path.dirname(script_path)
|
683
686
|
if not os.path.exists(script_dir):
|
@@ -818,11 +821,13 @@ def __validate_proxy_mode(proxy_mode: str) -> None:
|
|
818
821
|
|
819
822
|
# TODO: validate SPEC
|
820
823
|
|
821
|
-
def
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
824
|
+
def __with_namespace_defaults(kwargs):
|
825
|
+
if not kwargs.get('namespace'):
|
826
|
+
kwargs['namespace'] = kwargs.get('workflow_name')
|
827
|
+
|
828
|
+
# If network there was a network option, but it is not set, default network to namespace
|
829
|
+
if 'network' in kwargs and not kwargs['network']:
|
830
|
+
kwargs['network'] = kwargs['namespace']
|
826
831
|
|
827
832
|
def __workflow_create(app, **kwargs):
|
828
833
|
command = WorkflowCreateCommand(app, **kwargs)
|
@@ -833,4 +838,4 @@ def __workflow_create(app, **kwargs):
|
|
833
838
|
command.build(
|
834
839
|
template=kwargs['template'],
|
835
840
|
workflow_decorators=workflow_decorators
|
836
|
-
)
|
841
|
+
)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import re
|
2
|
+
import sys
|
3
|
+
|
4
|
+
from stoobly_agent.app.cli.scaffold.templates.constants import CORE_SERVICES
|
5
|
+
|
6
|
+
def validate_app_name(ctx, param, app_name: str) -> str:
|
7
|
+
app_name_regex = re.compile(r'^[a-zA-Z0-9._-]+$')
|
8
|
+
if not re.search(app_name_regex, app_name):
|
9
|
+
print(f"Error: app name {app_name} is invalid.", file=sys.stderr)
|
10
|
+
sys.exit(1)
|
11
|
+
return app_name
|
12
|
+
|
13
|
+
def validate_hostname(ctx, param, hostname: str) -> str:
|
14
|
+
if not hostname:
|
15
|
+
return
|
16
|
+
hostname_regex = re.compile(r'^[a-zA-Z0-9.-]+$')
|
17
|
+
if not re.search(hostname_regex, hostname):
|
18
|
+
print(f"Error: hostname {hostname} is invalid.", file=sys.stderr)
|
19
|
+
sys.exit(1)
|
20
|
+
return hostname
|
21
|
+
|
22
|
+
def validate_namespace(ctx, param, namespace: str) -> str:
|
23
|
+
if not namespace:
|
24
|
+
return
|
25
|
+
namespace_regex = re.compile(r'^[a-z0-9_-]+$')
|
26
|
+
if not re.search(namespace_regex, namespace) or namespace[0] in ['-', '_']:
|
27
|
+
print(f"Error: namespace {namespace} is invalid.", file=sys.stderr)
|
28
|
+
sys.exit(1)
|
29
|
+
return namespace
|
30
|
+
|
31
|
+
def validate_service_name(ctx, param, service_name: str) -> str:
|
32
|
+
if service_name in CORE_SERVICES:
|
33
|
+
print(f"Error: {service_name} is a core service", file=sys.stderr)
|
34
|
+
sys.exit(1)
|
35
|
+
service_name_regex = re.compile(r'^[a-zA-Z0-9._-]+$')
|
36
|
+
if not re.search(service_name_regex, service_name):
|
37
|
+
print(f"Error: service name {service_name} is invalid.", file=sys.stderr)
|
38
|
+
sys.exit(1)
|
39
|
+
return service_name
|
@@ -1 +1 @@
|
|
1
|
-
1.9.
|
1
|
+
1.9.6
|
@@ -1,4 +1,4 @@
|
|
1
|
-
stoobly_agent/__init__.py,sha256=
|
1
|
+
stoobly_agent/__init__.py,sha256=Hl61BiQl9f9AF1FOpbPAtXQt4rJsqBc_U216ZisxBQU,44
|
2
2
|
stoobly_agent/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
stoobly_agent/app/api/__init__.py,sha256=ctkB8KR-eXO0SFhj602huHiyvQ3PslFWd8fkcufgrAI,1000
|
4
4
|
stoobly_agent/app/api/application_http_request_handler.py,sha256=Vvz53yB0bR7J-QqMAkLlhcZrA4P64ZEN7w8cMbgl6o0,5261
|
@@ -17,7 +17,7 @@ stoobly_agent/app/api/scenarios_controller.py,sha256=zJViyme9l36mlJDQONRu4N-A0kd
|
|
17
17
|
stoobly_agent/app/api/simple_http_request_handler.py,sha256=ZdJ4kKEcPDpck74dJu--M7zw76wQzpo_AQArZwN9Bes,4466
|
18
18
|
stoobly_agent/app/api/statuses_controller.py,sha256=gQsl28h-3mZ_bByEHpc4mRy3KFvUz5PeAgVB0cPx_Ao,1791
|
19
19
|
stoobly_agent/app/cli/__init__.py,sha256=uS4KJgMAhm0JVnEUC-ONW-Bq6A8I9v7Fk-_Ka7gXlrU,470
|
20
|
-
stoobly_agent/app/cli/ca_cert_cli.py,sha256=
|
20
|
+
stoobly_agent/app/cli/ca_cert_cli.py,sha256=KVIUmmZcMHW2UXZJTmXqTVk2lEbp0YbxB6C4EL5t2Q4,1629
|
21
21
|
stoobly_agent/app/cli/config_cli.py,sha256=Ljr2Ir8P0dhGXALQQcq7fwthrcipPlvxS2G_0bNE6fY,15727
|
22
22
|
stoobly_agent/app/cli/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
23
|
stoobly_agent/app/cli/decorators/config.py,sha256=AWrDGZm_gjCWFYlRwdla3iE6H7OSlM4FxkaXRNovBZA,2428
|
@@ -73,7 +73,7 @@ stoobly_agent/app/cli/scaffold/app_config.py,sha256=UGVJ7DVmXh-o_gYBlAAEjngNIUZP
|
|
73
73
|
stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=0ogYliGbq1PYP5rFs-ML33q_Z4t_rAgPWjhk7rhnGw0,1153
|
74
74
|
stoobly_agent/app/cli/scaffold/command.py,sha256=aoTsdkkBzyu7TkVSMdNQQGk0Gj874jNgFcjR14y3TuM,254
|
75
75
|
stoobly_agent/app/cli/scaffold/config.py,sha256=HZU5tkvr3dkPr4JMXZtrJlu2wxxO-134Em6jReFFcq0,688
|
76
|
-
stoobly_agent/app/cli/scaffold/constants.py,sha256=
|
76
|
+
stoobly_agent/app/cli/scaffold/constants.py,sha256=e0aKyB80i1heJCubAvxt8DlzykAvYH37xeAcl9UTTgI,2496
|
77
77
|
stoobly_agent/app/cli/scaffold/containerized_app.py,sha256=dAjn4RwcZV3aEL0POUmrbF_DC-r9h6s1zx7gT2t45v0,175
|
78
78
|
stoobly_agent/app/cli/scaffold/docker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
79
79
|
stoobly_agent/app/cli/scaffold/docker/app_builder.py,sha256=7z5pk5JKlRDHx2USxY-WurttLyyUkIVYfl34_u1x9dE,501
|
@@ -82,7 +82,7 @@ stoobly_agent/app/cli/scaffold/docker/constants.py,sha256=1khQdgTaQ89ykGRNdTQh_e
|
|
82
82
|
stoobly_agent/app/cli/scaffold/docker/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
83
83
|
stoobly_agent/app/cli/scaffold/docker/service/build_decorator.py,sha256=ZU7z4bkvdS3OK5O4fJhlA9_PNwnFtZW6t7vNF7V5obQ,1003
|
84
84
|
stoobly_agent/app/cli/scaffold/docker/service/builder.py,sha256=4cIMSYvgrkGWVuuYymiwlrR829O91qQl9ML8FhaDMj4,5857
|
85
|
-
stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=
|
85
|
+
stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=8GQ2wUBwb45uSxhzkEMloezJT1hVu8v_3PudWLTU9ig,3910
|
86
86
|
stoobly_agent/app/cli/scaffold/docker/service/types.py,sha256=qB-yYHlu-PZDc0HYgTUvE5bWNpHxaSThC3JUG8okR1k,88
|
87
87
|
stoobly_agent/app/cli/scaffold/docker/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88
88
|
stoobly_agent/app/cli/scaffold/docker/workflow/build_decorator.py,sha256=VKD9hXbJGRIWHS5IeYXeX0-FQ0F43zG8VmsegL6eYwA,703
|
@@ -94,17 +94,18 @@ stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py,sha256
|
|
94
94
|
stoobly_agent/app/cli/scaffold/env.py,sha256=e-Ve4p3RUgzFx22B3SIYttvJ_yLuDtA27oDACZ8n-6E,1140
|
95
95
|
stoobly_agent/app/cli/scaffold/hosts_file_manager.py,sha256=zNX5wh6zXQ4J2BA0YYdD7_CPqDz02b_ghXsY3oTjjB4,4999
|
96
96
|
stoobly_agent/app/cli/scaffold/managed_services_docker_compose.py,sha256=-wLBXUi7DCWsfm5KzZzd_kdJKOTl1NT924XR7dyjbSY,574
|
97
|
-
stoobly_agent/app/cli/scaffold/service.py,sha256=
|
98
|
-
stoobly_agent/app/cli/scaffold/service_command.py,sha256=
|
97
|
+
stoobly_agent/app/cli/scaffold/service.py,sha256=74JwjTRRkk6lo-k9hre1iGztbKa9zDqjPVx3Qgpze-s,699
|
98
|
+
stoobly_agent/app/cli/scaffold/service_command.py,sha256=NxJakoq1Dy79LEIJ8QSsKEwsofIfN13GN0UGpp9i6qY,1230
|
99
99
|
stoobly_agent/app/cli/scaffold/service_config.py,sha256=edL356wqpfJgFdeSrWof-CAUB1Tgi4nO1Jx9nkql9Qc,3903
|
100
100
|
stoobly_agent/app/cli/scaffold/service_create_command.py,sha256=1B6TK3JDAjouikCV84WDrX7b0crdPMPIo1caMwhi-L8,2815
|
101
101
|
stoobly_agent/app/cli/scaffold/service_delete_command.py,sha256=_nBDQjm8eL62MQpzSCxgUHlW04ZXKG8MDlN1BXxlqww,986
|
102
102
|
stoobly_agent/app/cli/scaffold/service_docker_compose.py,sha256=OMUN1-ujQYIZXxDvS4XBf5C9wGalQULkwOiBBQPZbHY,820
|
103
|
+
stoobly_agent/app/cli/scaffold/service_update_command.py,sha256=oWusBKfvjt4RnK03_V3CJYWrfsCI4_LcR7W12eLXMR4,2579
|
103
104
|
stoobly_agent/app/cli/scaffold/service_workflow.py,sha256=sQ_Edy_wGHKMXpD0DmhnOWkGEKz7gSgEGNI8f7aXOdg,444
|
104
|
-
stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=
|
105
|
+
stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=veigidzR4EwGi8dc0v_l4Ik7cZikDBnLcvwcHNc1Wzg,11457
|
105
106
|
stoobly_agent/app/cli/scaffold/templates/__init__.py,sha256=x8C_a0VoO_vUbosp4_6IC1U7Ge9NnUdVKDPpVMtMkeY,171
|
106
107
|
stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context,sha256=Okk4Q0Fj7Wi5NU58gQfpjpFwAL3RUBJyRe56kteQfcA,158
|
107
|
-
stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=
|
108
|
+
stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=4CTrKRHho9fl7NOGrQM0lJTfn-X09ddQKBq9Zsbjbww,9278
|
108
109
|
stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.base.yml,sha256=6tFqXh3ine8vaD0FCL5TMoY5NjKx2wLUR8XpW3tJtew,245
|
109
110
|
stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.networks.yml,sha256=I4PbJpQjFHb5IbAUWNvYM6okDEtmwtKFDQg-yog05WM,141
|
110
111
|
stoobly_agent/app/cli/scaffold/templates/app/Makefile,sha256=TEmPG7Bf0KZOnmfsgdzza3UdwcVMmM5Lj1YdLc4cgjA,79
|
@@ -197,13 +198,13 @@ stoobly_agent/app/cli/scaffold/validate_exceptions.py,sha256=Jtjl4OkbbSRWm0hy7Kf
|
|
197
198
|
stoobly_agent/app/cli/scaffold/workflow.py,sha256=KlbWT9CIo9EpZxKU1WVZtmodhxK7CpmLUHPNk4Mh6DA,1570
|
198
199
|
stoobly_agent/app/cli/scaffold/workflow_command.py,sha256=eI9I5LLgO0U3b46QhHusy-4BV2zUDVai6jErcluYCRI,3344
|
199
200
|
stoobly_agent/app/cli/scaffold/workflow_config.py,sha256=ghnbcnCyb6ECdylUJCAJ6A8ulzaFY9bu7RvRuYeiRkk,901
|
200
|
-
stoobly_agent/app/cli/scaffold/workflow_copy_command.py,sha256=
|
201
|
-
stoobly_agent/app/cli/scaffold/workflow_create_command.py,sha256
|
201
|
+
stoobly_agent/app/cli/scaffold/workflow_copy_command.py,sha256=wi8qHH_M2e6jXIPuumx65Zd4Zt7hTBb6b3Z4vt4xYeQ,1320
|
202
|
+
stoobly_agent/app/cli/scaffold/workflow_create_command.py,sha256=-fwsr6_LvGT8BbBWdGY3Qd8cSQhBOSJiMr1r8s2R86w,3390
|
202
203
|
stoobly_agent/app/cli/scaffold/workflow_env.py,sha256=x8V5pJmIiklD3f2q2-qq-CORf4YaXYq_r2JpR2MmSwk,416
|
203
204
|
stoobly_agent/app/cli/scaffold/workflow_log_command.py,sha256=Bke4lMOMxuDUFuAx9nlXHbKgYMO4KAg9ASHvjz4aVWc,1372
|
204
|
-
stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=
|
205
|
+
stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=AZhLd1N260RjXEiUSRppqfhQMwVyRnn0jpapRu4FwyM,11114
|
205
206
|
stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=Uo_yo6rVR1ZR7xpvsQvlH48AyMBVLRupd4G-bRjzm_Q,5584
|
206
|
-
stoobly_agent/app/cli/scaffold_cli.py,sha256=
|
207
|
+
stoobly_agent/app/cli/scaffold_cli.py,sha256=3V4F_Bd8th6p_nu6u82qzncVBdqNd5cRJZaj7tyIdxA,32492
|
207
208
|
stoobly_agent/app/cli/scenario_cli.py,sha256=3J1EiJOvunkfWrEkOsanw-XrKkOk78ij_GjBlE9p7CE,8229
|
208
209
|
stoobly_agent/app/cli/snapshot_cli.py,sha256=1Dw5JgDlmG6vctrawIRO7CdB73vAQk_wRBnPG2lVOrQ,11929
|
209
210
|
stoobly_agent/app/cli/trace_cli.py,sha256=K7E-vx3JUcqEDSWOdIOi_AieKNQz7dBfmRrVvKDkzFI,4605
|
@@ -214,6 +215,7 @@ stoobly_agent/app/cli/types/request.py,sha256=QthojE5sfx7OvKu-vVNnSUfGk8n4pLzuBQ
|
|
214
215
|
stoobly_agent/app/cli/types/scenario.py,sha256=28WxmOlbm2Bsek1uu7yc4hJGz-d5oHbYAro7LlFWRoc,81
|
215
216
|
stoobly_agent/app/cli/types/snapshot_migration.py,sha256=4_Re46FKjsflcTOO3qhNsbWWmdEU67SFsF-XE_FKG3M,1859
|
216
217
|
stoobly_agent/app/cli/types/test.py,sha256=1c458B7DFBWsEk5Q1CrZ2CUi84YzEzcs-W4qTcudwAk,714
|
218
|
+
stoobly_agent/app/cli/validators/scaffold.py,sha256=ERmdjcryf8YmTHNTHyptKjomATpZo-17bPAPb_ps8ao,1388
|
217
219
|
stoobly_agent/app/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
218
220
|
stoobly_agent/app/models/adapters/__init__.py,sha256=cEEE--Bvrvk6DAsHx_uPgFhLnZJETP4zSBtWjMqyIKc,233
|
219
221
|
stoobly_agent/app/models/adapters/joined_request_adapter.py,sha256=fSq16n3AAlxi8KJdBESHp3JGio_M9uzMnHbnQU8VI3w,3598
|
@@ -708,7 +710,7 @@ stoobly_agent/test/app/models/factories/resource/local_db/helpers/log_test.py,sh
|
|
708
710
|
stoobly_agent/test/app/models/factories/resource/local_db/helpers/tiebreak_scenario_request_test.py,sha256=a1SFLyEyRRLuADvAw6ckQQKORFXvyK1lyrbkaLWx8oU,3399
|
709
711
|
stoobly_agent/test/app/models/factories/resource/local_db/request_adapter_test.py,sha256=Pzq1cBPnP9oSWG-p0c-VoymoHxgp483QmNwmV1b78RA,8453
|
710
712
|
stoobly_agent/test/app/models/factories/resource/local_db/response_adapter_test.py,sha256=9P95EKH5rZGOrmRkRIDlQZqtiLJHk9735og18Ffwpfw,2204
|
711
|
-
stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=
|
713
|
+
stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=0vY2lU8oU9tB_UhSABsgfVlYkLE7wf6JMFZoxaKHBS0,6
|
712
714
|
stoobly_agent/test/app/models/schemas/.stoobly/db/stoobly_agent.sqlite3,sha256=ch8gNx6zIelLKQx65gwFx_LRNqUD3EC5xcHZ0ukIQiU,188416
|
713
715
|
stoobly_agent/test/app/models/schemas/.stoobly/settings.yml,sha256=vLwMjweKOdod6tSLtIlyBefPQuNXq9wio4kBaODKtAU,726
|
714
716
|
stoobly_agent/test/app/models/schemas/.stoobly/tmp/options.json,sha256=OTRzarwus48CTrItedXCrgQttJHSEZonEYc7R_knvYg,2212
|
@@ -749,8 +751,8 @@ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1W
|
|
749
751
|
stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
|
750
752
|
stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
|
751
753
|
stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
|
752
|
-
stoobly_agent-1.9.
|
753
|
-
stoobly_agent-1.9.
|
754
|
-
stoobly_agent-1.9.
|
755
|
-
stoobly_agent-1.9.
|
756
|
-
stoobly_agent-1.9.
|
754
|
+
stoobly_agent-1.9.7.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
|
755
|
+
stoobly_agent-1.9.7.dist-info/METADATA,sha256=cd9Awg6zQx8UUifbVQnobldsJhRQOXPJWEljsP1I7_0,3087
|
756
|
+
stoobly_agent-1.9.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
757
|
+
stoobly_agent-1.9.7.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
|
758
|
+
stoobly_agent-1.9.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|