devservices 1.0.8__tar.gz → 1.0.10__tar.gz
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.
- {devservices-1.0.8 → devservices-1.0.10}/PKG-INFO +2 -2
- {devservices-1.0.8 → devservices-1.0.10}/README.md +1 -1
- {devservices-1.0.8 → devservices-1.0.10}/devservices/commands/down.py +68 -15
- {devservices-1.0.8 → devservices-1.0.10}/devservices/commands/list_dependencies.py +7 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/commands/list_services.py +16 -3
- {devservices-1.0.8 → devservices-1.0.10}/devservices/commands/logs.py +14 -2
- {devservices-1.0.8 → devservices-1.0.10}/devservices/commands/status.py +10 -1
- {devservices-1.0.8 → devservices-1.0.10}/devservices/commands/up.py +17 -3
- {devservices-1.0.8 → devservices-1.0.10}/devservices/configs/service_config.py +3 -1
- {devservices-1.0.8 → devservices-1.0.10}/devservices/exceptions.py +10 -4
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/console.py +3 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/dependencies.py +121 -28
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/docker_compose.py +29 -19
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/services.py +8 -1
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/state.py +48 -22
- {devservices-1.0.8 → devservices-1.0.10}/devservices.egg-info/PKG-INFO +2 -2
- {devservices-1.0.8 → devservices-1.0.10}/pyproject.toml +1 -1
- devservices-1.0.10/tests/commands/test_down.py +970 -0
- {devservices-1.0.8 → devservices-1.0.10}/tests/commands/test_list_dependencies.py +21 -0
- devservices-1.0.10/tests/commands/test_list_services.py +176 -0
- {devservices-1.0.8 → devservices-1.0.10}/tests/commands/test_logs.py +49 -9
- {devservices-1.0.8 → devservices-1.0.10}/tests/commands/test_purge.py +64 -27
- {devservices-1.0.8 → devservices-1.0.10}/tests/commands/test_status.py +21 -0
- {devservices-1.0.8 → devservices-1.0.10}/tests/commands/test_up.py +368 -217
- {devservices-1.0.8 → devservices-1.0.10}/tests/configs/test_service_config.py +1 -1
- {devservices-1.0.8 → devservices-1.0.10}/tests/utils/test_dependencies.py +619 -6
- {devservices-1.0.8 → devservices-1.0.10}/tests/utils/test_docker_compose.py +3 -9
- {devservices-1.0.8 → devservices-1.0.10}/tests/utils/test_services.py +65 -2
- devservices-1.0.10/tests/utils/test_state.py +84 -0
- devservices-1.0.8/tests/commands/test_down.py +0 -265
- devservices-1.0.8/tests/commands/test_list_services.py +0 -89
- devservices-1.0.8/tests/utils/test_state.py +0 -54
- {devservices-1.0.8 → devservices-1.0.10}/LICENSE.md +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/__init__.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/commands/__init__.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/commands/purge.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/commands/update.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/constants.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/main.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/__init__.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/check_for_update.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/devenv.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/docker.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/file_lock.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices/utils/install_binary.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices.egg-info/SOURCES.txt +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices.egg-info/dependency_links.txt +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices.egg-info/entry_points.txt +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices.egg-info/requires.txt +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/devservices.egg-info/top_level.txt +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/setup.cfg +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/testing/__init__.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/testing/utils.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/tests/__init__.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/tests/commands/test_update.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/tests/conftest.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/tests/utils/test_check_for_update.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/tests/utils/test_docker.py +0 -0
- {devservices-1.0.8 → devservices-1.0.10}/tests/utils/test_install_binary.py +0 -0
|
@@ -15,11 +15,13 @@ from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR
|
|
|
15
15
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY
|
|
16
16
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
17
17
|
from devservices.exceptions import ConfigError
|
|
18
|
+
from devservices.exceptions import ConfigNotFoundError
|
|
18
19
|
from devservices.exceptions import DependencyError
|
|
19
20
|
from devservices.exceptions import DockerComposeError
|
|
20
21
|
from devservices.exceptions import ServiceNotFoundError
|
|
21
22
|
from devservices.utils.console import Console
|
|
22
23
|
from devservices.utils.console import Status
|
|
24
|
+
from devservices.utils.dependencies import construct_dependency_graph
|
|
23
25
|
from devservices.utils.dependencies import get_non_shared_remote_dependencies
|
|
24
26
|
from devservices.utils.dependencies import install_and_verify_dependencies
|
|
25
27
|
from devservices.utils.dependencies import InstalledRemoteDependency
|
|
@@ -29,6 +31,7 @@ from devservices.utils.docker_compose import run_cmd
|
|
|
29
31
|
from devservices.utils.services import find_matching_service
|
|
30
32
|
from devservices.utils.services import Service
|
|
31
33
|
from devservices.utils.state import State
|
|
34
|
+
from devservices.utils.state import StateTables
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
def add_parser(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
@@ -56,6 +59,12 @@ def down(args: Namespace) -> None:
|
|
|
56
59
|
service_name = args.service_name
|
|
57
60
|
try:
|
|
58
61
|
service = find_matching_service(service_name)
|
|
62
|
+
except ConfigNotFoundError as e:
|
|
63
|
+
capture_exception(e)
|
|
64
|
+
console.failure(
|
|
65
|
+
f"{str(e)}. Please specify a service (i.e. `devservices down sentry`) or run the command from a directory with a devservices configuration."
|
|
66
|
+
)
|
|
67
|
+
exit(1)
|
|
59
68
|
except ConfigError as e:
|
|
60
69
|
capture_exception(e)
|
|
61
70
|
console.failure(str(e))
|
|
@@ -67,12 +76,20 @@ def down(args: Namespace) -> None:
|
|
|
67
76
|
modes = service.config.modes
|
|
68
77
|
|
|
69
78
|
state = State()
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
starting_services = set(state.get_service_entries(StateTables.STARTING_SERVICES))
|
|
80
|
+
started_services = set(state.get_service_entries(StateTables.STARTED_SERVICES))
|
|
81
|
+
active_services = starting_services.union(started_services)
|
|
82
|
+
if service.name not in active_services:
|
|
72
83
|
console.warning(f"{service.name} is not running")
|
|
73
84
|
exit(0)
|
|
74
85
|
|
|
75
|
-
|
|
86
|
+
active_starting_modes = state.get_active_modes_for_service(
|
|
87
|
+
service.name, StateTables.STARTING_SERVICES
|
|
88
|
+
)
|
|
89
|
+
active_started_modes = state.get_active_modes_for_service(
|
|
90
|
+
service.name, StateTables.STARTED_SERVICES
|
|
91
|
+
)
|
|
92
|
+
active_modes = active_starting_modes or active_started_modes
|
|
76
93
|
mode_dependencies = set()
|
|
77
94
|
for active_mode in active_modes:
|
|
78
95
|
active_mode_dependencies = modes.get(active_mode, [])
|
|
@@ -80,7 +97,6 @@ def down(args: Namespace) -> None:
|
|
|
80
97
|
|
|
81
98
|
with Status(
|
|
82
99
|
lambda: console.warning(f"Stopping {service.name}"),
|
|
83
|
-
lambda: console.success(f"{service.name} stopped"),
|
|
84
100
|
) as status:
|
|
85
101
|
try:
|
|
86
102
|
remote_dependencies = install_and_verify_dependencies(
|
|
@@ -88,7 +104,9 @@ def down(args: Namespace) -> None:
|
|
|
88
104
|
)
|
|
89
105
|
except DependencyError as de:
|
|
90
106
|
capture_exception(de)
|
|
91
|
-
status.failure(
|
|
107
|
+
status.failure(
|
|
108
|
+
f"{str(de)}. If this error persists, try running `devservices purge`"
|
|
109
|
+
)
|
|
92
110
|
exit(1)
|
|
93
111
|
try:
|
|
94
112
|
remote_dependencies = get_non_shared_remote_dependencies(
|
|
@@ -96,18 +114,53 @@ def down(args: Namespace) -> None:
|
|
|
96
114
|
)
|
|
97
115
|
except DependencyError as de:
|
|
98
116
|
capture_exception(de)
|
|
99
|
-
status.failure(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
_down(service, remote_dependencies, list(mode_dependencies), status)
|
|
103
|
-
except DockerComposeError as dce:
|
|
104
|
-
capture_exception(dce)
|
|
105
|
-
status.failure(f"Failed to stop {service.name}: {dce.stderr}")
|
|
117
|
+
status.failure(
|
|
118
|
+
f"{str(de)}. If this error persists, try running `devservices purge`"
|
|
119
|
+
)
|
|
106
120
|
exit(1)
|
|
107
121
|
|
|
122
|
+
# Check if any service depends on the service we are trying to bring down
|
|
123
|
+
# TODO: We should also take into account the active modes of the other services (this is not trivial to do)
|
|
124
|
+
other_started_services = active_services.difference({service.name})
|
|
125
|
+
dependent_service_name = None
|
|
126
|
+
for other_started_service in other_started_services:
|
|
127
|
+
other_service = find_matching_service(other_started_service)
|
|
128
|
+
other_service_active_starting_modes = state.get_active_modes_for_service(
|
|
129
|
+
other_service.name, StateTables.STARTING_SERVICES
|
|
130
|
+
)
|
|
131
|
+
other_service_active_started_modes = state.get_active_modes_for_service(
|
|
132
|
+
other_service.name, StateTables.STARTED_SERVICES
|
|
133
|
+
)
|
|
134
|
+
other_service_active_modes = (
|
|
135
|
+
other_service_active_starting_modes
|
|
136
|
+
or other_service_active_started_modes
|
|
137
|
+
)
|
|
138
|
+
dependency_graph = construct_dependency_graph(
|
|
139
|
+
other_service, other_service_active_modes
|
|
140
|
+
)
|
|
141
|
+
# If the service we are trying to bring down is in the dependency graph of another service, we should not bring it down
|
|
142
|
+
if service.name in dependency_graph.graph:
|
|
143
|
+
dependent_service_name = other_started_service
|
|
144
|
+
break
|
|
145
|
+
|
|
146
|
+
# If no other service depends on the service we are trying to bring down, we can bring it down
|
|
147
|
+
if dependent_service_name is None:
|
|
148
|
+
try:
|
|
149
|
+
_down(service, remote_dependencies, list(mode_dependencies), status)
|
|
150
|
+
except DockerComposeError as dce:
|
|
151
|
+
capture_exception(dce)
|
|
152
|
+
status.failure(f"Failed to stop {service.name}: {dce.stderr}")
|
|
153
|
+
exit(1)
|
|
154
|
+
else:
|
|
155
|
+
status.warning(
|
|
156
|
+
f"Leaving {service.name} running because it is being used by {dependent_service_name}"
|
|
157
|
+
)
|
|
158
|
+
|
|
108
159
|
# TODO: We should factor in healthchecks here before marking service as not running
|
|
109
|
-
state
|
|
110
|
-
state.
|
|
160
|
+
state.remove_service_entry(service.name, StateTables.STARTING_SERVICES)
|
|
161
|
+
state.remove_service_entry(service.name, StateTables.STARTED_SERVICES)
|
|
162
|
+
if dependent_service_name is None:
|
|
163
|
+
console.success(f"{service.name} stopped")
|
|
111
164
|
|
|
112
165
|
|
|
113
166
|
def _bring_down_dependency(
|
|
@@ -141,7 +194,7 @@ def _down(
|
|
|
141
194
|
service=service,
|
|
142
195
|
remote_dependencies=list(remote_dependencies),
|
|
143
196
|
current_env=current_env,
|
|
144
|
-
command="
|
|
197
|
+
command="stop",
|
|
145
198
|
options=[],
|
|
146
199
|
service_config_file_path=service_config_file_path,
|
|
147
200
|
mode_dependencies=mode_dependencies,
|
|
@@ -7,6 +7,7 @@ from argparse import Namespace
|
|
|
7
7
|
from sentry_sdk import capture_exception
|
|
8
8
|
|
|
9
9
|
from devservices.exceptions import ConfigError
|
|
10
|
+
from devservices.exceptions import ConfigNotFoundError
|
|
10
11
|
from devservices.exceptions import ServiceNotFoundError
|
|
11
12
|
from devservices.utils.console import Console
|
|
12
13
|
from devservices.utils.services import find_matching_service
|
|
@@ -32,6 +33,12 @@ def list_dependencies(args: Namespace) -> None:
|
|
|
32
33
|
|
|
33
34
|
try:
|
|
34
35
|
service = find_matching_service(service_name)
|
|
36
|
+
except ConfigNotFoundError as e:
|
|
37
|
+
capture_exception(e)
|
|
38
|
+
console.failure(
|
|
39
|
+
f"{str(e)}. Please specify a service (i.e. `devservices list-dependencies sentry`) or run the command from a directory with a devservices configuration."
|
|
40
|
+
)
|
|
41
|
+
exit(1)
|
|
35
42
|
except ConfigError as e:
|
|
36
43
|
capture_exception(e)
|
|
37
44
|
console.failure(str(e))
|
|
@@ -8,6 +8,7 @@ from devservices.utils.console import Console
|
|
|
8
8
|
from devservices.utils.devenv import get_coderoot
|
|
9
9
|
from devservices.utils.services import get_local_services
|
|
10
10
|
from devservices.utils.state import State
|
|
11
|
+
from devservices.utils.state import StateTables
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def add_parser(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
@@ -30,7 +31,9 @@ def list_services(args: Namespace) -> None:
|
|
|
30
31
|
coderoot = get_coderoot()
|
|
31
32
|
services = get_local_services(coderoot)
|
|
32
33
|
state = State()
|
|
33
|
-
|
|
34
|
+
starting_services = set(state.get_service_entries(StateTables.STARTING_SERVICES))
|
|
35
|
+
started_services = set(state.get_service_entries(StateTables.STARTED_SERVICES))
|
|
36
|
+
running_services = starting_services.union(started_services)
|
|
34
37
|
|
|
35
38
|
if not services:
|
|
36
39
|
console.warning("No services found")
|
|
@@ -46,8 +49,18 @@ def list_services(args: Namespace) -> None:
|
|
|
46
49
|
console.info("Running services:")
|
|
47
50
|
|
|
48
51
|
for service in services_to_show:
|
|
49
|
-
status = "
|
|
50
|
-
|
|
52
|
+
status = "stopped"
|
|
53
|
+
if service.name in starting_services:
|
|
54
|
+
status = "starting"
|
|
55
|
+
elif service.name in started_services:
|
|
56
|
+
status = "started"
|
|
57
|
+
active_starting_modes = state.get_active_modes_for_service(
|
|
58
|
+
service.name, StateTables.STARTING_SERVICES
|
|
59
|
+
)
|
|
60
|
+
active_started_modes = state.get_active_modes_for_service(
|
|
61
|
+
service.name, StateTables.STARTED_SERVICES
|
|
62
|
+
)
|
|
63
|
+
active_modes = active_starting_modes or active_started_modes
|
|
51
64
|
console.info(f"- {service.name}")
|
|
52
65
|
console.info(f" modes: {active_modes}")
|
|
53
66
|
console.info(f" status: {status}")
|
|
@@ -16,6 +16,7 @@ from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY
|
|
|
16
16
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
17
17
|
from devservices.constants import MAX_LOG_LINES
|
|
18
18
|
from devservices.exceptions import ConfigError
|
|
19
|
+
from devservices.exceptions import ConfigNotFoundError
|
|
19
20
|
from devservices.exceptions import DependencyError
|
|
20
21
|
from devservices.exceptions import DockerComposeError
|
|
21
22
|
from devservices.exceptions import ServiceNotFoundError
|
|
@@ -27,6 +28,7 @@ from devservices.utils.docker_compose import run_cmd
|
|
|
27
28
|
from devservices.utils.services import find_matching_service
|
|
28
29
|
from devservices.utils.services import Service
|
|
29
30
|
from devservices.utils.state import State
|
|
31
|
+
from devservices.utils.state import StateTables
|
|
30
32
|
|
|
31
33
|
|
|
32
34
|
def add_parser(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
@@ -46,6 +48,12 @@ def logs(args: Namespace) -> None:
|
|
|
46
48
|
service_name = args.service_name
|
|
47
49
|
try:
|
|
48
50
|
service = find_matching_service(service_name)
|
|
51
|
+
except ConfigNotFoundError as e:
|
|
52
|
+
capture_exception(e)
|
|
53
|
+
console.failure(
|
|
54
|
+
f"{str(e)}. Please specify a service (i.e. `devservices logs sentry`) or run the command from a directory with a devservices configuration."
|
|
55
|
+
)
|
|
56
|
+
exit(1)
|
|
49
57
|
except ConfigError as e:
|
|
50
58
|
capture_exception(e)
|
|
51
59
|
console.failure(str(e))
|
|
@@ -60,7 +68,9 @@ def logs(args: Namespace) -> None:
|
|
|
60
68
|
mode_dependencies = modes[mode_to_use]
|
|
61
69
|
|
|
62
70
|
state = State()
|
|
63
|
-
|
|
71
|
+
starting_services = set(state.get_service_entries(StateTables.STARTING_SERVICES))
|
|
72
|
+
started_services = set(state.get_service_entries(StateTables.STARTED_SERVICES))
|
|
73
|
+
running_services = starting_services.union(started_services)
|
|
64
74
|
if service.name not in running_services:
|
|
65
75
|
console.warning(f"Service {service.name} is not running")
|
|
66
76
|
return
|
|
@@ -69,7 +79,9 @@ def logs(args: Namespace) -> None:
|
|
|
69
79
|
remote_dependencies = install_and_verify_dependencies(service)
|
|
70
80
|
except DependencyError as de:
|
|
71
81
|
capture_exception(de)
|
|
72
|
-
console.failure(
|
|
82
|
+
console.failure(
|
|
83
|
+
f"{str(de)}. If this error persists, try running `devservices purge`"
|
|
84
|
+
)
|
|
73
85
|
exit(1)
|
|
74
86
|
try:
|
|
75
87
|
logs_output = _logs(service, remote_dependencies, mode_dependencies)
|
|
@@ -17,6 +17,7 @@ from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR
|
|
|
17
17
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY
|
|
18
18
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
19
19
|
from devservices.exceptions import ConfigError
|
|
20
|
+
from devservices.exceptions import ConfigNotFoundError
|
|
20
21
|
from devservices.exceptions import DependencyError
|
|
21
22
|
from devservices.exceptions import DockerComposeError
|
|
22
23
|
from devservices.exceptions import ServiceNotFoundError
|
|
@@ -86,6 +87,12 @@ def status(args: Namespace) -> None:
|
|
|
86
87
|
service_name = args.service_name
|
|
87
88
|
try:
|
|
88
89
|
service = find_matching_service(service_name)
|
|
90
|
+
except ConfigNotFoundError as e:
|
|
91
|
+
capture_exception(e)
|
|
92
|
+
console.failure(
|
|
93
|
+
f"{str(e)}. Please specify a service (i.e. `devservices status sentry`) or run the command from a directory with a devservices configuration."
|
|
94
|
+
)
|
|
95
|
+
exit(1)
|
|
89
96
|
except ConfigError as e:
|
|
90
97
|
capture_exception(e)
|
|
91
98
|
console.failure(str(e))
|
|
@@ -103,7 +110,9 @@ def status(args: Namespace) -> None:
|
|
|
103
110
|
remote_dependencies = install_and_verify_dependencies(service)
|
|
104
111
|
except DependencyError as de:
|
|
105
112
|
capture_exception(de)
|
|
106
|
-
console.failure(
|
|
113
|
+
console.failure(
|
|
114
|
+
f"{str(de)}. If this error persists, try running `devservices purge`"
|
|
115
|
+
)
|
|
107
116
|
exit(1)
|
|
108
117
|
try:
|
|
109
118
|
status_json_results = _status(service, remote_dependencies, mode_dependencies)
|
|
@@ -15,6 +15,7 @@ from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR
|
|
|
15
15
|
from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY
|
|
16
16
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
17
17
|
from devservices.exceptions import ConfigError
|
|
18
|
+
from devservices.exceptions import ConfigNotFoundError
|
|
18
19
|
from devservices.exceptions import ContainerHealthcheckFailedError
|
|
19
20
|
from devservices.exceptions import DependencyError
|
|
20
21
|
from devservices.exceptions import DockerComposeError
|
|
@@ -33,6 +34,7 @@ from devservices.utils.docker_compose import run_cmd
|
|
|
33
34
|
from devservices.utils.services import find_matching_service
|
|
34
35
|
from devservices.utils.services import Service
|
|
35
36
|
from devservices.utils.state import State
|
|
37
|
+
from devservices.utils.state import StateTables
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
def add_parser(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
@@ -60,6 +62,12 @@ def up(args: Namespace) -> None:
|
|
|
60
62
|
service_name = args.service_name
|
|
61
63
|
try:
|
|
62
64
|
service = find_matching_service(service_name)
|
|
65
|
+
except ConfigNotFoundError as e:
|
|
66
|
+
capture_exception(e)
|
|
67
|
+
console.failure(
|
|
68
|
+
f"{str(e)}. Please specify a service (i.e. `devservices up sentry`) or run the command from a directory with a devservices configuration."
|
|
69
|
+
)
|
|
70
|
+
exit(1)
|
|
63
71
|
except ConfigError as e:
|
|
64
72
|
capture_exception(e)
|
|
65
73
|
console.failure(str(e))
|
|
@@ -71,6 +79,8 @@ def up(args: Namespace) -> None:
|
|
|
71
79
|
modes = service.config.modes
|
|
72
80
|
mode = args.mode
|
|
73
81
|
|
|
82
|
+
state = State()
|
|
83
|
+
|
|
74
84
|
with Status(
|
|
75
85
|
lambda: console.warning(f"Starting '{service.name}' in mode: '{mode}'"),
|
|
76
86
|
lambda: console.success(f"{service.name} started"),
|
|
@@ -82,7 +92,9 @@ def up(args: Namespace) -> None:
|
|
|
82
92
|
)
|
|
83
93
|
except DependencyError as de:
|
|
84
94
|
capture_exception(de)
|
|
85
|
-
status.failure(
|
|
95
|
+
status.failure(
|
|
96
|
+
f"{str(de)}. If this error persists, try running `devservices purge`"
|
|
97
|
+
)
|
|
86
98
|
exit(1)
|
|
87
99
|
except ModeDoesNotExistError as mde:
|
|
88
100
|
status.failure(str(mde))
|
|
@@ -92,6 +104,8 @@ def up(args: Namespace) -> None:
|
|
|
92
104
|
except subprocess.CalledProcessError:
|
|
93
105
|
# Network already exists, ignore the error
|
|
94
106
|
pass
|
|
107
|
+
# Add the service to the starting services table
|
|
108
|
+
state.update_service_entry(service.name, mode, StateTables.STARTING_SERVICES)
|
|
95
109
|
try:
|
|
96
110
|
mode_dependencies = modes[mode]
|
|
97
111
|
_up(service, [mode], remote_dependencies, mode_dependencies, status)
|
|
@@ -100,8 +114,8 @@ def up(args: Namespace) -> None:
|
|
|
100
114
|
status.failure(f"Failed to start {service.name}: {dce.stderr}")
|
|
101
115
|
exit(1)
|
|
102
116
|
# TODO: We should factor in healthchecks here before marking service as running
|
|
103
|
-
state
|
|
104
|
-
state.
|
|
117
|
+
state.remove_service_entry(service.name, StateTables.STARTING_SERVICES)
|
|
118
|
+
state.update_service_entry(service.name, mode, StateTables.STARTED_SERVICES)
|
|
105
119
|
|
|
106
120
|
|
|
107
121
|
def _bring_up_dependency(
|
|
@@ -67,7 +67,9 @@ class ServiceConfig:
|
|
|
67
67
|
def load_service_config_from_file(repo_path: str) -> ServiceConfig:
|
|
68
68
|
config_path = os.path.join(repo_path, DEVSERVICES_DIR_NAME, CONFIG_FILE_NAME)
|
|
69
69
|
if not os.path.exists(config_path):
|
|
70
|
-
raise ConfigNotFoundError(
|
|
70
|
+
raise ConfigNotFoundError(
|
|
71
|
+
f"No devservices configuration found in {config_path}"
|
|
72
|
+
)
|
|
71
73
|
with open(config_path, "r", encoding="utf-8") as stream:
|
|
72
74
|
try:
|
|
73
75
|
config = yaml.safe_load(stream)
|
|
@@ -70,27 +70,33 @@ class DockerError(Exception):
|
|
|
70
70
|
class DockerComposeError(DockerError):
|
|
71
71
|
"""Base class for Docker Compose related errors."""
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
def __str__(self) -> str:
|
|
74
|
+
return f"DockerComposeError: {self.command} returned {self.returncode} error: {self.stderr}"
|
|
74
75
|
|
|
75
76
|
|
|
76
77
|
class ModeDoesNotExistError(Exception):
|
|
77
78
|
"""Raised when a mode does not exist."""
|
|
78
79
|
|
|
79
|
-
def __init__(self, service_name: str, mode: str):
|
|
80
|
+
def __init__(self, service_name: str, mode: str, available_modes: list[str]):
|
|
80
81
|
self.service_name = service_name
|
|
81
82
|
self.mode = mode
|
|
83
|
+
self.available_modes = available_modes
|
|
82
84
|
|
|
83
85
|
def __str__(self) -> str:
|
|
84
|
-
|
|
86
|
+
# All valid services should have at least one mode, so we don't check for an empty list
|
|
87
|
+
return f"ModeDoesNotExistError: Mode '{self.mode}' does not exist for service '{self.service_name}'.\nAvailable modes: {', '.join(self.available_modes)}"
|
|
85
88
|
|
|
86
89
|
|
|
87
90
|
class DependencyError(Exception):
|
|
88
91
|
"""Base class for dependency-related errors."""
|
|
89
92
|
|
|
90
|
-
def __init__(
|
|
93
|
+
def __init__(
|
|
94
|
+
self, repo_name: str, repo_link: str, branch: str, stderr: str | None = None
|
|
95
|
+
):
|
|
91
96
|
self.repo_name = repo_name
|
|
92
97
|
self.repo_link = repo_link
|
|
93
98
|
self.branch = branch
|
|
99
|
+
self.stderr = stderr
|
|
94
100
|
|
|
95
101
|
def __str__(self) -> str:
|
|
96
102
|
return f"DependencyError: {self.repo_name} ({self.repo_link}) on {self.branch}"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
import sys
|
|
4
5
|
import threading
|
|
5
6
|
import time
|
|
@@ -97,6 +98,8 @@ class Status:
|
|
|
97
98
|
self.on_success()
|
|
98
99
|
|
|
99
100
|
def _loading_animation(self) -> None:
|
|
101
|
+
if os.environ.get("CI", default="false") == "true":
|
|
102
|
+
return
|
|
100
103
|
idx = 0
|
|
101
104
|
while not self._stop_loading.is_set():
|
|
102
105
|
sys.stdout.write("\r" + ANIMATION_FRAMES[idx % len(ANIMATION_FRAMES)] + " ")
|