devservices 0.0.2__tar.gz → 0.0.3__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-0.0.2 → devservices-0.0.3}/PKG-INFO +1 -1
- devservices-0.0.3/README.md +22 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/commands/logs.py +2 -2
- {devservices-0.0.2 → devservices-0.0.3}/devservices/commands/start.py +2 -2
- {devservices-0.0.2 → devservices-0.0.3}/devservices/commands/status.py +3 -3
- {devservices-0.0.2 → devservices-0.0.3}/devservices/commands/stop.py +2 -2
- {devservices-0.0.2 → devservices-0.0.3}/devservices/configs/service_config.py +10 -5
- {devservices-0.0.2 → devservices-0.0.3}/devservices/constants.py +1 -1
- {devservices-0.0.2 → devservices-0.0.3}/devservices/main.py +8 -3
- {devservices-0.0.2 → devservices-0.0.3}/devservices.egg-info/PKG-INFO +1 -1
- {devservices-0.0.2 → devservices-0.0.3}/pyproject.toml +2 -2
- {devservices-0.0.2 → devservices-0.0.3}/tests/commands/test_start.py +2 -2
- {devservices-0.0.2 → devservices-0.0.3}/tests/commands/test_stop.py +2 -2
- {devservices-0.0.2 → devservices-0.0.3}/tests/configs/test_service_config.py +19 -8
- {devservices-0.0.2 → devservices-0.0.3}/tests/testutils.py +1 -1
- devservices-0.0.2/README.md +0 -1
- {devservices-0.0.2 → devservices-0.0.3}/devservices/__init__.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/commands/__init__.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/commands/list_dependencies.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/commands/list_services.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/exceptions.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/utils/__init__.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/utils/console.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/utils/devenv.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/utils/docker_compose.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices/utils/services.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices.egg-info/SOURCES.txt +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices.egg-info/dependency_links.txt +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices.egg-info/entry_points.txt +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices.egg-info/requires.txt +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/devservices.egg-info/top_level.txt +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/setup.cfg +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/tests/__init__.py +0 -0
- {devservices-0.0.2 → devservices-0.0.3}/tests/conftest.py +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# devservices
|
|
2
|
+
|
|
3
|
+
A standalone cli tool used to manage dependencies for services. It simplifies the process of starting, stopping, and managing services for development purposes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`devservices` reads configuration files located in the `devservices` directory of your repository. These configurations define services, their dependencies, and various modes of operation.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
devservices provides several commands to manage your services:
|
|
12
|
+
|
|
13
|
+
### Commands
|
|
14
|
+
|
|
15
|
+
NOTE: service-name is an optional parameter. If not provided, devservices will attempt to automatically find a devservices configuration in the current directory in order to proceed.
|
|
16
|
+
|
|
17
|
+
- `devservices start <service-name>`: Start a service and its dependencies.
|
|
18
|
+
- `devservices stop <service-name>`: Stop a service including its dependencies.
|
|
19
|
+
- `devservices status <service-name>`: Display the current status of all services, including their dependencies and ports.
|
|
20
|
+
- `devservices logs <service-name>`: View logs for a specific service.
|
|
21
|
+
- `devservices list-services`: List all available Sentry services.
|
|
22
|
+
- `devservices list-dependencies <service-name>`: List all dependencies for a service and whether they are enabled/disabled.
|
|
@@ -6,8 +6,8 @@ from argparse import _SubParsersAction
|
|
|
6
6
|
from argparse import ArgumentParser
|
|
7
7
|
from argparse import Namespace
|
|
8
8
|
|
|
9
|
+
from devservices.constants import CONFIG_FILE_NAME
|
|
9
10
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
10
|
-
from devservices.constants import DOCKER_COMPOSE_FILE_NAME
|
|
11
11
|
from devservices.exceptions import DockerComposeError
|
|
12
12
|
from devservices.utils.docker_compose import run_docker_compose_command
|
|
13
13
|
from devservices.utils.services import find_matching_service
|
|
@@ -37,7 +37,7 @@ def logs(args: Namespace) -> None:
|
|
|
37
37
|
mode_to_use = "default"
|
|
38
38
|
mode_dependencies = " ".join(modes[mode_to_use])
|
|
39
39
|
service_config_file_path = os.path.join(
|
|
40
|
-
service.repo_path, DEVSERVICES_DIR_NAME,
|
|
40
|
+
service.repo_path, DEVSERVICES_DIR_NAME, CONFIG_FILE_NAME
|
|
41
41
|
)
|
|
42
42
|
try:
|
|
43
43
|
logs = run_docker_compose_command(
|
|
@@ -5,8 +5,8 @@ from argparse import _SubParsersAction
|
|
|
5
5
|
from argparse import ArgumentParser
|
|
6
6
|
from argparse import Namespace
|
|
7
7
|
|
|
8
|
+
from devservices.constants import CONFIG_FILE_NAME
|
|
8
9
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
9
|
-
from devservices.constants import DOCKER_COMPOSE_FILE_NAME
|
|
10
10
|
from devservices.exceptions import DockerComposeError
|
|
11
11
|
from devservices.utils.console import Status
|
|
12
12
|
from devservices.utils.docker_compose import run_docker_compose_command
|
|
@@ -34,7 +34,7 @@ def start(args: Namespace) -> None:
|
|
|
34
34
|
mode_to_start = "default"
|
|
35
35
|
mode_dependencies = " ".join(modes[mode_to_start])
|
|
36
36
|
service_config_file_path = os.path.join(
|
|
37
|
-
service.repo_path, DEVSERVICES_DIR_NAME,
|
|
37
|
+
service.repo_path, DEVSERVICES_DIR_NAME, CONFIG_FILE_NAME
|
|
38
38
|
)
|
|
39
39
|
with Status(f"Starting {service.name}", f"{service.name} started") as status:
|
|
40
40
|
try:
|
|
@@ -7,8 +7,8 @@ from argparse import _SubParsersAction
|
|
|
7
7
|
from argparse import ArgumentParser
|
|
8
8
|
from argparse import Namespace
|
|
9
9
|
|
|
10
|
+
from devservices.constants import CONFIG_FILE_NAME
|
|
10
11
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
11
|
-
from devservices.constants import DOCKER_COMPOSE_FILE_NAME
|
|
12
12
|
from devservices.exceptions import DockerComposeError
|
|
13
13
|
from devservices.utils.docker_compose import run_docker_compose_command
|
|
14
14
|
from devservices.utils.services import find_matching_service
|
|
@@ -49,7 +49,7 @@ def format_status_output(status_json: str) -> str:
|
|
|
49
49
|
output.append("Ports:")
|
|
50
50
|
for port in ports:
|
|
51
51
|
output.append(
|
|
52
|
-
f" {port['PublishedPort']} -> {port['TargetPort']}/{port['Protocol']}"
|
|
52
|
+
f" {port['URL']}:{port['PublishedPort']} -> {port['TargetPort']}/{port['Protocol']}"
|
|
53
53
|
)
|
|
54
54
|
else:
|
|
55
55
|
output.append("No ports exposed")
|
|
@@ -72,7 +72,7 @@ def status(args: Namespace) -> None:
|
|
|
72
72
|
mode_to_view = "default"
|
|
73
73
|
mode_dependencies = " ".join(modes[mode_to_view])
|
|
74
74
|
service_config_file_path = os.path.join(
|
|
75
|
-
service.repo_path, DEVSERVICES_DIR_NAME,
|
|
75
|
+
service.repo_path, DEVSERVICES_DIR_NAME, CONFIG_FILE_NAME
|
|
76
76
|
)
|
|
77
77
|
try:
|
|
78
78
|
status_json = run_docker_compose_command(
|
|
@@ -5,8 +5,8 @@ from argparse import _SubParsersAction
|
|
|
5
5
|
from argparse import ArgumentParser
|
|
6
6
|
from argparse import Namespace
|
|
7
7
|
|
|
8
|
+
from devservices.constants import CONFIG_FILE_NAME
|
|
8
9
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
9
|
-
from devservices.constants import DOCKER_COMPOSE_FILE_NAME
|
|
10
10
|
from devservices.exceptions import DockerComposeError
|
|
11
11
|
from devservices.utils.console import Status
|
|
12
12
|
from devservices.utils.docker_compose import run_docker_compose_command
|
|
@@ -34,7 +34,7 @@ def stop(args: Namespace) -> None:
|
|
|
34
34
|
mode_to_stop = "default"
|
|
35
35
|
mode_dependencies = " ".join(modes[mode_to_stop])
|
|
36
36
|
service_config_file_path = os.path.join(
|
|
37
|
-
service.repo_path, DEVSERVICES_DIR_NAME,
|
|
37
|
+
service.repo_path, DEVSERVICES_DIR_NAME, CONFIG_FILE_NAME
|
|
38
38
|
)
|
|
39
39
|
with Status(f"Stopping {service.name}", f"{service.name} stopped") as status:
|
|
40
40
|
try:
|
|
@@ -5,8 +5,8 @@ from dataclasses import dataclass
|
|
|
5
5
|
|
|
6
6
|
import yaml
|
|
7
7
|
|
|
8
|
+
from devservices.constants import CONFIG_FILE_NAME
|
|
8
9
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
9
|
-
from devservices.constants import DOCKER_COMPOSE_FILE_NAME
|
|
10
10
|
from devservices.exceptions import ConfigNotFoundError
|
|
11
11
|
from devservices.exceptions import ConfigParseError
|
|
12
12
|
from devservices.exceptions import ConfigValidationError
|
|
@@ -14,10 +14,17 @@ from devservices.exceptions import ConfigValidationError
|
|
|
14
14
|
VALID_VERSIONS = [0.1]
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
@dataclass
|
|
18
|
+
class RemoteConfig:
|
|
19
|
+
repo_name: str
|
|
20
|
+
branch: str
|
|
21
|
+
repo_link: str
|
|
22
|
+
|
|
23
|
+
|
|
17
24
|
@dataclass
|
|
18
25
|
class Dependency:
|
|
19
26
|
description: str
|
|
20
|
-
|
|
27
|
+
remote: RemoteConfig | None = None
|
|
21
28
|
|
|
22
29
|
|
|
23
30
|
@dataclass
|
|
@@ -56,9 +63,7 @@ class ServiceConfig:
|
|
|
56
63
|
|
|
57
64
|
|
|
58
65
|
def load_service_config_from_file(repo_path: str) -> ServiceConfig:
|
|
59
|
-
config_path = os.path.join(
|
|
60
|
-
repo_path, DEVSERVICES_DIR_NAME, DOCKER_COMPOSE_FILE_NAME
|
|
61
|
-
)
|
|
66
|
+
config_path = os.path.join(repo_path, DEVSERVICES_DIR_NAME, CONFIG_FILE_NAME)
|
|
62
67
|
if not os.path.exists(config_path):
|
|
63
68
|
raise ConfigNotFoundError(f"Config file not found in directory: {config_path}")
|
|
64
69
|
with open(config_path, "r") as stream:
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
import atexit
|
|
5
|
+
from importlib import metadata
|
|
5
6
|
|
|
6
7
|
import sentry_sdk
|
|
7
8
|
from sentry_sdk.integrations.argv import ArgvIntegration
|
|
@@ -29,11 +30,15 @@ def cleanup() -> None:
|
|
|
29
30
|
|
|
30
31
|
def main() -> None:
|
|
31
32
|
parser = argparse.ArgumentParser(
|
|
32
|
-
|
|
33
|
+
prog="devservices",
|
|
34
|
+
description="CLI tool for managing service dependencies.",
|
|
35
|
+
usage="devservices [-h] [--version] COMMAND ...",
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
"--version", action="version", version=metadata.version("devservices")
|
|
33
39
|
)
|
|
34
|
-
parser.add_argument("--version", action="version", version="%(prog)s 0.0.1")
|
|
35
40
|
|
|
36
|
-
subparsers = parser.add_subparsers(dest="command",
|
|
41
|
+
subparsers = parser.add_subparsers(dest="command", title="commands", metavar="")
|
|
37
42
|
|
|
38
43
|
# Add subparsers for each command
|
|
39
44
|
start.add_parser(subparsers)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools>=
|
|
2
|
+
requires = ["setuptools>=70", "wheel"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "devservices"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.3"
|
|
8
8
|
# 3.10 is just for internal pypi compat
|
|
9
9
|
requires-python = ">=3.10"
|
|
10
10
|
dependencies = [
|
|
@@ -9,8 +9,8 @@ from unittest import mock
|
|
|
9
9
|
import pytest
|
|
10
10
|
|
|
11
11
|
from devservices.commands.start import start
|
|
12
|
+
from devservices.constants import CONFIG_FILE_NAME
|
|
12
13
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
13
|
-
from devservices.constants import DOCKER_COMPOSE_FILE_NAME
|
|
14
14
|
from tests.testutils import create_config_file
|
|
15
15
|
|
|
16
16
|
|
|
@@ -44,7 +44,7 @@ def test_start_simple(mock_run: mock.Mock, tmp_path: Path) -> None:
|
|
|
44
44
|
"docker",
|
|
45
45
|
"compose",
|
|
46
46
|
"-f",
|
|
47
|
-
f"{tmp_path}/{DEVSERVICES_DIR_NAME}/{
|
|
47
|
+
f"{tmp_path}/{DEVSERVICES_DIR_NAME}/{CONFIG_FILE_NAME}",
|
|
48
48
|
"up",
|
|
49
49
|
"-d",
|
|
50
50
|
"redis",
|
|
@@ -9,8 +9,8 @@ from unittest import mock
|
|
|
9
9
|
import pytest
|
|
10
10
|
|
|
11
11
|
from devservices.commands.stop import stop
|
|
12
|
+
from devservices.constants import CONFIG_FILE_NAME
|
|
12
13
|
from devservices.constants import DEVSERVICES_DIR_NAME
|
|
13
|
-
from devservices.constants import DOCKER_COMPOSE_FILE_NAME
|
|
14
14
|
from tests.testutils import create_config_file
|
|
15
15
|
|
|
16
16
|
|
|
@@ -45,7 +45,7 @@ def test_stop_simple(mock_run: mock.Mock, tmp_path: Path) -> None:
|
|
|
45
45
|
"docker",
|
|
46
46
|
"compose",
|
|
47
47
|
"-f",
|
|
48
|
-
f"{tmp_path}/{DEVSERVICES_DIR_NAME}/{
|
|
48
|
+
f"{tmp_path}/{DEVSERVICES_DIR_NAME}/{CONFIG_FILE_NAME}",
|
|
49
49
|
"down",
|
|
50
50
|
"redis",
|
|
51
51
|
"clickhouse",
|
|
@@ -25,7 +25,11 @@ from tests.testutils import create_config_file
|
|
|
25
25
|
{
|
|
26
26
|
"example-dependency-1": {
|
|
27
27
|
"description": "Example dependency 1",
|
|
28
|
-
"
|
|
28
|
+
"remote": {
|
|
29
|
+
"repo_name": "example-dependency-1",
|
|
30
|
+
"branch": "main",
|
|
31
|
+
"repo_link": "https://example.com",
|
|
32
|
+
},
|
|
29
33
|
},
|
|
30
34
|
"example-dependency-2": {
|
|
31
35
|
"description": "Example dependency 2",
|
|
@@ -38,7 +42,11 @@ from tests.testutils import create_config_file
|
|
|
38
42
|
{
|
|
39
43
|
"example-dependency-1": {
|
|
40
44
|
"description": "Example dependency 1",
|
|
41
|
-
"
|
|
45
|
+
"remote": {
|
|
46
|
+
"repo_name": "example-dependency-1",
|
|
47
|
+
"branch": "main",
|
|
48
|
+
"repo_link": "https://example.com",
|
|
49
|
+
},
|
|
42
50
|
},
|
|
43
51
|
"example-dependency-2": {
|
|
44
52
|
"description": "Example dependency 2",
|
|
@@ -69,7 +77,10 @@ def test_load_service_config_from_file(
|
|
|
69
77
|
"version": 0.1,
|
|
70
78
|
"service_name": service_name,
|
|
71
79
|
"dependencies": {
|
|
72
|
-
key: {
|
|
80
|
+
key: {
|
|
81
|
+
"description": value["description"],
|
|
82
|
+
"remote": value.get("remote"),
|
|
83
|
+
}
|
|
73
84
|
for key, value in dependencies.items()
|
|
74
85
|
},
|
|
75
86
|
"modes": modes,
|
|
@@ -100,7 +111,7 @@ def test_load_service_config_from_file_missing_config(tmp_path: Path) -> None:
|
|
|
100
111
|
load_service_config_from_file(str(tmp_path))
|
|
101
112
|
assert (
|
|
102
113
|
str(e.value)
|
|
103
|
-
== f"Config file not found in directory: {tmp_path / 'devservices' / '
|
|
114
|
+
== f"Config file not found in directory: {tmp_path / 'devservices' / 'config.yml'}"
|
|
104
115
|
)
|
|
105
116
|
|
|
106
117
|
|
|
@@ -287,7 +298,7 @@ def test_load_service_config_from_file_invalid_yaml(tmp_path: Path) -> None:
|
|
|
287
298
|
default: ["example-dependency"]"""
|
|
288
299
|
devservices_dir = Path(tmp_path, "devservices")
|
|
289
300
|
devservices_dir.mkdir(parents=True, exist_ok=True)
|
|
290
|
-
tmp_file = Path(devservices_dir, "
|
|
301
|
+
tmp_file = Path(devservices_dir, "config.yml")
|
|
291
302
|
with tmp_file.open("w") as f:
|
|
292
303
|
f.write(config)
|
|
293
304
|
|
|
@@ -295,7 +306,7 @@ def test_load_service_config_from_file_invalid_yaml(tmp_path: Path) -> None:
|
|
|
295
306
|
load_service_config_from_file(str(tmp_path))
|
|
296
307
|
assert (
|
|
297
308
|
str(e.value)
|
|
298
|
-
== f"Error parsing config file: mapping values are not allowed here\n in \"{tmp_path / 'devservices' / '
|
|
309
|
+
== f"Error parsing config file: mapping values are not allowed here\n in \"{tmp_path / 'devservices' / 'config.yml'}\", line 2, column 12"
|
|
299
310
|
)
|
|
300
311
|
|
|
301
312
|
|
|
@@ -311,7 +322,7 @@ def test_load_service_config_from_file_invalid_yaml_tag(tmp_path: Path) -> None:
|
|
|
311
322
|
default: ["example-dependency"]"""
|
|
312
323
|
devservices_dir = Path(tmp_path, "devservices")
|
|
313
324
|
devservices_dir.mkdir(parents=True, exist_ok=True)
|
|
314
|
-
tmp_file = Path(devservices_dir, "
|
|
325
|
+
tmp_file = Path(devservices_dir, "config.yml")
|
|
315
326
|
with tmp_file.open("w") as f:
|
|
316
327
|
f.write(config)
|
|
317
328
|
|
|
@@ -319,5 +330,5 @@ def test_load_service_config_from_file_invalid_yaml_tag(tmp_path: Path) -> None:
|
|
|
319
330
|
load_service_config_from_file(str(tmp_path))
|
|
320
331
|
assert (
|
|
321
332
|
str(e.value)
|
|
322
|
-
== f"Error parsing config file: could not determine a constructor for the tag 'tag:yaml.org,2002:invalid_tag'\n in \"{tmp_path / 'devservices' / '
|
|
333
|
+
== f"Error parsing config file: could not determine a constructor for the tag 'tag:yaml.org,2002:invalid_tag'\n in \"{tmp_path / 'devservices' / 'config.yml'}\", line 7, column 19"
|
|
323
334
|
)
|
|
@@ -10,6 +10,6 @@ def create_config_file(
|
|
|
10
10
|
) -> None:
|
|
11
11
|
devservices_dir = Path(tmp_path, "devservices")
|
|
12
12
|
devservices_dir.mkdir(parents=True, exist_ok=True)
|
|
13
|
-
tmp_file = Path(devservices_dir, "
|
|
13
|
+
tmp_file = Path(devservices_dir, "config.yml")
|
|
14
14
|
with tmp_file.open("w") as f:
|
|
15
15
|
yaml.dump(config, f, sort_keys=False, default_flow_style=False)
|
devservices-0.0.2/README.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# devservices
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|