elemctl 0.2.0__tar.gz → 0.2.1__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.
- {elemctl-0.2.0 → elemctl-0.2.1}/PKG-INFO +1 -1
- {elemctl-0.2.0 → elemctl-0.2.1}/docs/SPEC.md +4 -1
- {elemctl-0.2.0 → elemctl-0.2.1}/pyproject.toml +1 -1
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/__init__.py +1 -1
- elemctl-0.2.1/src/elemctl/__main__.py +14 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/cli.py +7 -1
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl.egg-info/PKG-INFO +1 -1
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl.egg-info/SOURCES.txt +1 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/tests/test_cli.py +34 -2
- {elemctl-0.2.0 → elemctl-0.2.1}/.env.example +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/LICENSE +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/MANIFEST.in +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/NOTICE +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/ORIGIN.md +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/README.md +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/setup.cfg +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/auth.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/build.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/client.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/config.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/deploy.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/errors.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/mcp_server.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/transport.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl/versions.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl.egg-info/dependency_links.txt +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl.egg-info/entry_points.txt +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl.egg-info/requires.txt +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/src/elemctl.egg-info/top_level.txt +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/tests/test_build.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/tests/test_client.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/tests/test_config.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/tests/test_deploy.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/tests/test_mcp.py +0 -0
- {elemctl-0.2.0 → elemctl-0.2.1}/tests/test_versions.py +0 -0
|
@@ -261,7 +261,10 @@ stderr и код возврата 1.
|
|
|
261
261
|
`apps start [APP_ID]`, `apps stop [APP_ID]`.
|
|
262
262
|
- `apps find` ищет по точному совпадению (без учёта регистра) имени среди
|
|
263
263
|
полей `name`, `display-name`, `publication-context`; вывод
|
|
264
|
-
`{"id": ..., "found": true|false}`, код возврата
|
|
264
|
+
`{"id": ..., "found": true|false}`, код возврата 0 в обоих случаях –
|
|
265
|
+
отсутствие приложения это ответ, а не ошибка. Ненулевой код возврата
|
|
266
|
+
означает сбой запроса и сопровождается JSON'ом с полем `error` в stderr.
|
|
267
|
+
В скриптах проверять поле `found`, а не код возврата.
|
|
265
268
|
- `--latest-build` - взять источником последнюю сборку проекта (защита от
|
|
266
269
|
пустого каркаса, п. 6.2); `--wait` - дождаться готовности (п. 6.4) и
|
|
267
270
|
вывести финальную карточку.
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "elemctl"
|
|
9
|
-
version = "0.2.
|
|
9
|
+
version = "0.2.1"
|
|
10
10
|
description = "CLI, MCP-сервер и библиотека для Console API v2 платформы 1С:Предприятие.Элемент (1cmycloud)"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.10"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Запуск пакета как модуля: python -m elemctl <аргументы>.
|
|
2
|
+
|
|
3
|
+
Нужен тем, кто вызывает elemctl текущим интерпретатором, не полагаясь на
|
|
4
|
+
консольную точку входа в PATH (например, обёртки в чужих репозиториях).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from .cli import main
|
|
12
|
+
|
|
13
|
+
if __name__ == "__main__":
|
|
14
|
+
sys.exit(main())
|
|
@@ -97,11 +97,17 @@ def cmd_apps_get(args):
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
def cmd_apps_find(args):
|
|
100
|
+
"""Поиск приложения по имени. Отсутствие приложения – это ответ, а не ошибка.
|
|
101
|
+
|
|
102
|
+
Код возврата 0 в обоих случаях: признак несёт поле found. Ненулевой код возврата
|
|
103
|
+
означает сбой запроса (нет доступа, сеть, конфигурация) и сопровождается JSON'ом
|
|
104
|
+
с полем error в stderr – иначе вызывающий не отличит "стенда нет" от "не смогли спросить".
|
|
105
|
+
"""
|
|
100
106
|
client = make_client(_config(args))
|
|
101
107
|
app = client.find_app(args.name)
|
|
102
108
|
if app is None:
|
|
103
109
|
_emit({"id": None, "found": False})
|
|
104
|
-
return
|
|
110
|
+
return 0
|
|
105
111
|
_emit({"id": app.get("id"), "found": True})
|
|
106
112
|
return 0
|
|
107
113
|
|
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
6
9
|
from pathlib import Path
|
|
7
10
|
|
|
8
11
|
import pytest
|
|
9
12
|
|
|
13
|
+
import elemctl
|
|
10
14
|
from elemctl import cli
|
|
15
|
+
from elemctl.errors import ApiError
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
@pytest.fixture(autouse=True)
|
|
@@ -29,7 +34,17 @@ def test_version_flag(capsys):
|
|
|
29
34
|
with pytest.raises(SystemExit) as excinfo:
|
|
30
35
|
cli.main(["--version"])
|
|
31
36
|
assert excinfo.value.code == 0
|
|
32
|
-
assert "elemctl
|
|
37
|
+
assert f"elemctl {elemctl.__version__}" in capsys.readouterr().out
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_module_entry_point():
|
|
41
|
+
"""python -m elemctl – запасной путь для вызывающих без консольной точки входа в PATH."""
|
|
42
|
+
import_root = Path(elemctl.__file__).resolve().parent.parent
|
|
43
|
+
env = {**os.environ, "PYTHONPATH": str(import_root)}
|
|
44
|
+
result = subprocess.run([sys.executable, "-m", "elemctl", "--version"],
|
|
45
|
+
capture_output=True, text=True, env=env)
|
|
46
|
+
assert result.returncode == 0, result.stderr
|
|
47
|
+
assert f"elemctl {elemctl.__version__}" in result.stdout
|
|
33
48
|
|
|
34
49
|
|
|
35
50
|
def test_build_command(project_factory, tmp_path, capsys):
|
|
@@ -77,11 +92,28 @@ def test_apps_find_found_and_not_found(monkeypatch, capsys):
|
|
|
77
92
|
assert rc == 0
|
|
78
93
|
assert json.loads(capsys.readouterr().out) == {"id": "app-42", "found": True}
|
|
79
94
|
|
|
95
|
+
# Отсутствие приложения – штатный ответ: код возврата 0, признак несёт поле found.
|
|
80
96
|
rc = cli.main(["apps", "find", "нет-такого"])
|
|
81
|
-
assert rc ==
|
|
97
|
+
assert rc == 0
|
|
82
98
|
assert json.loads(capsys.readouterr().out) == {"id": None, "found": False}
|
|
83
99
|
|
|
84
100
|
|
|
101
|
+
def test_apps_find_request_failure_is_an_error(monkeypatch, capsys):
|
|
102
|
+
"""Сбой запроса отличим от "не найдено": ненулевой код и error в stderr."""
|
|
103
|
+
|
|
104
|
+
class FailingClient:
|
|
105
|
+
def find_app(self, name):
|
|
106
|
+
raise ApiError("нет доступа", status=403)
|
|
107
|
+
|
|
108
|
+
monkeypatch.setattr(cli, "make_client", lambda config: FailingClient())
|
|
109
|
+
|
|
110
|
+
rc = cli.main(["apps", "find", "site-dev"])
|
|
111
|
+
assert rc == 1
|
|
112
|
+
captured = capsys.readouterr()
|
|
113
|
+
assert captured.out == ""
|
|
114
|
+
assert "error" in json.loads(captured.err)
|
|
115
|
+
|
|
116
|
+
|
|
85
117
|
def test_error_is_json_on_stderr(capsys):
|
|
86
118
|
# app-id не задан ни аргументом, ни конфигурацией.
|
|
87
119
|
rc = cli.main(["apps", "get"])
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|