elemctl 0.1.0__tar.gz → 0.2.0__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/.env.example +9 -0
- elemctl-0.2.0/MANIFEST.in +4 -0
- elemctl-0.2.0/NOTICE +19 -0
- elemctl-0.2.0/ORIGIN.md +52 -0
- {elemctl-0.1.0/src/elemctl.egg-info → elemctl-0.2.0}/PKG-INFO +10 -7
- {elemctl-0.1.0 → elemctl-0.2.0}/README.md +9 -6
- elemctl-0.2.0/docs/SPEC.md +332 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/pyproject.toml +1 -1
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/__init__.py +1 -1
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/cli.py +16 -40
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/client.py +0 -26
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/config.py +0 -2
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/deploy.py +0 -21
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/mcp_server.py +0 -10
- {elemctl-0.1.0 → elemctl-0.2.0/src/elemctl.egg-info}/PKG-INFO +10 -7
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/SOURCES.txt +5 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_cli.py +1 -2
- {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_client.py +0 -15
- {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_deploy.py +1 -13
- {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_mcp.py +0 -1
- {elemctl-0.1.0 → elemctl-0.2.0}/LICENSE +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/setup.cfg +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/auth.py +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/build.py +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/errors.py +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/transport.py +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/versions.py +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/dependency_links.txt +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/entry_points.txt +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/requires.txt +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/top_level.txt +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_build.py +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_config.py +0 -0
- {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_versions.py +0 -0
elemctl-0.2.0/NOTICE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
elemctl
|
|
2
|
+
Copyright 2026 KeyFire
|
|
3
|
+
|
|
4
|
+
Licensed under the MIT License (see LICENSE).
|
|
5
|
+
|
|
6
|
+
This software is a command-line tool, MCP server and Python library for the
|
|
7
|
+
1C:Enterprise.Element (1cmycloud) Console API v2.
|
|
8
|
+
|
|
9
|
+
"1C", "1C:Enterprise", "1C:Enterprise.Element" and "1cmycloud" are trademarks and/or
|
|
10
|
+
product names of their respective owners (1C Company and its affiliates). They are used
|
|
11
|
+
in this project for descriptive purposes only, to indicate the platform the tool is
|
|
12
|
+
compatible with.
|
|
13
|
+
|
|
14
|
+
This project is an independent development. It is NOT affiliated with, endorsed by,
|
|
15
|
+
sponsored by or supported by 1C Company.
|
|
16
|
+
|
|
17
|
+
The library depends only on the Python standard library. The optional MCP server extra
|
|
18
|
+
(elemctl[mcp]) uses the "mcp" package (MIT). Platform credentials are issued by the
|
|
19
|
+
platform to its own users and are not redistributed by this project.
|
elemctl-0.2.0/ORIGIN.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Origin
|
|
2
|
+
|
|
3
|
+
elemctl is an independent, **clean-room** implementation, written from scratch.
|
|
4
|
+
|
|
5
|
+
## What it is built from
|
|
6
|
+
|
|
7
|
+
- a written specification of the platform's external interface (`docs/SPEC.md`), which
|
|
8
|
+
records **facts about the 1C:Enterprise.Element (1cmycloud) Console API v2 contract**,
|
|
9
|
+
the build-file formats (`.xasm` / `.xlib`) and the product requirements — and nothing
|
|
10
|
+
else, and
|
|
11
|
+
- the **Python standard library**.
|
|
12
|
+
|
|
13
|
+
The API facts in the specification come from three first-hand sources:
|
|
14
|
+
|
|
15
|
+
1. **The platform's own Console API reference** — the Element help shipped by the
|
|
16
|
+
platform itself, with a page per endpoint (e.g. `POST /console/api/v2/applications`),
|
|
17
|
+
under <https://1cmycloud.com/console/help/element/9.2/docs/console/>. The help is
|
|
18
|
+
provided to platform users; at the time of writing it opens after signing in with a
|
|
19
|
+
platform account.
|
|
20
|
+
2. **The management console UI**, which every platform user has access to.
|
|
21
|
+
3. **Observation of the author's own requests and responses** while using the platform
|
|
22
|
+
under the author's own account. This covers behavioral details the reference does not
|
|
23
|
+
describe (e.g. the silent rollback on a failed project update).
|
|
24
|
+
|
|
25
|
+
No documentation beyond what the platform provides to its users was used. The tool talks
|
|
26
|
+
only to the documented Console API v2; internal (undocumented) console APIs are neither
|
|
27
|
+
called nor described anywhere in this repository.
|
|
28
|
+
|
|
29
|
+
No other tool's source code was read or copied. The implementation was designed from the
|
|
30
|
+
specification alone.
|
|
31
|
+
|
|
32
|
+
## What is definitely NOT in it
|
|
33
|
+
|
|
34
|
+
- **No third-party source code.** Nothing was ported or copied from any other
|
|
35
|
+
repository — public, private or corporate.
|
|
36
|
+
- **No platform code.** No decompilation, disassembly or other reverse engineering of
|
|
37
|
+
1C:Enterprise.Element components was performed; the platform's own client or server
|
|
38
|
+
code was never used or examined.
|
|
39
|
+
- **No reproduced proprietary materials.** The platform vendor's documentation and other
|
|
40
|
+
materials are not quoted or reproduced.
|
|
41
|
+
- **No secrets and no ties to anyone's infrastructure.** The code and the git history
|
|
42
|
+
contain no tokens, passwords, internal addresses, or identifiers of specific
|
|
43
|
+
applications, projects or stands.
|
|
44
|
+
|
|
45
|
+
## Credentials and runtime
|
|
46
|
+
|
|
47
|
+
Access to the platform uses `Client-Id` / `Client-Secret` credentials that the platform
|
|
48
|
+
issues to its own users in its management console. elemctl ships no credentials and
|
|
49
|
+
redistributes nothing belonging to the platform.
|
|
50
|
+
|
|
51
|
+
At runtime the library depends only on the Python standard library. The MCP server is an
|
|
52
|
+
optional extra (`elemctl[mcp]`) and uses the `mcp` package (FastMCP).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elemctl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: CLI, MCP-сервер и библиотека для Console API v2 платформы 1С:Предприятие.Элемент (1cmycloud)
|
|
5
5
|
Author: KeyFire
|
|
6
6
|
License-Expression: MIT
|
|
@@ -55,8 +55,7 @@ platform's audience - but the CLI output is plain JSON.*
|
|
|
55
55
|
в архив сборки с манифестом и git-метаданными, автоинкремент версии.
|
|
56
56
|
- **Деплой одной командой**: сборка -> загрузка -> применение -> перезапуск ->
|
|
57
57
|
**проверка фактического применения**.
|
|
58
|
-
- **Ветки среды разработки**: список, создание, привязка к приложению, merge
|
|
59
|
-
загрузка изменений из git-ветки.
|
|
58
|
+
- **Ветки среды разработки**: список, создание, привязка к приложению, merge.
|
|
60
59
|
- **Дампы**: создание и контроль готовности.
|
|
61
60
|
- **MCP-сервер**: те же операции как инструменты для AI-агентов
|
|
62
61
|
(Claude Code и другие MCP-клиенты).
|
|
@@ -100,7 +99,6 @@ pip install "elemctl[mcp]" # с MCP-сервером
|
|
|
100
99
|
| `ELEMENT_APP_ID` | приложение по умолчанию (необязательно) |
|
|
101
100
|
| `ELEMENT_PROJECT_ID` | проект по умолчанию (необязательно) |
|
|
102
101
|
| `ELEMENT_SPACE_ID` | пространство по умолчанию (необязательно) |
|
|
103
|
-
| `ELEMENT_BRANCH_ID` | ветка платформы по умолчанию (необязательно) |
|
|
104
102
|
|
|
105
103
|
Client-Id/Client-Secret выпускаются в панели управления 1cmycloud
|
|
106
104
|
(раздел интеграций Console API). Шаблон файла - [.env.example](.env.example).
|
|
@@ -179,9 +177,8 @@ Assembly.yaml # манифест: ProjectKind, Vendor, Name, Version,
|
|
|
179
177
|
|
|
180
178
|
- Инструмент **неофициальный** и не аффилирован с фирмой "1С"; Console API
|
|
181
179
|
может меняться без предупреждения.
|
|
182
|
-
-
|
|
183
|
-
|
|
184
|
-
наименее стабильный.
|
|
180
|
+
- Используется только документированный Console API v2 - внутренние API
|
|
181
|
+
консоли платформы инструмент не вызывает и не описывает.
|
|
185
182
|
- Создание приложения только по `--project-id` на части конфигураций платформы
|
|
186
183
|
даёт пустой каркас без данных проекта. Надёжный путь - источник-сборка:
|
|
187
184
|
`elemctl apps create <имя> --project-id <id> --latest-build` (MCP-инструмент
|
|
@@ -196,6 +193,12 @@ Assembly.yaml # манифест: ProjectKind, Vendor, Name, Version,
|
|
|
196
193
|
"Мягкой" очистки данных приложения в Console API нет, она выполняется в
|
|
197
194
|
консоли управления.
|
|
198
195
|
|
|
196
|
+
## Происхождение и правовые заметки
|
|
197
|
+
|
|
198
|
+
Код написан с нуля по спецификации внешнего интерфейса платформы - процесс и
|
|
199
|
+
гарантии описаны в [ORIGIN.md](ORIGIN.md). Товарные знаки и отсутствие
|
|
200
|
+
аффилиации с фирмой "1С" - в файле [NOTICE](NOTICE).
|
|
201
|
+
|
|
199
202
|
## Лицензия
|
|
200
203
|
|
|
201
204
|
[MIT](LICENSE)
|
|
@@ -27,8 +27,7 @@ platform's audience - but the CLI output is plain JSON.*
|
|
|
27
27
|
в архив сборки с манифестом и git-метаданными, автоинкремент версии.
|
|
28
28
|
- **Деплой одной командой**: сборка -> загрузка -> применение -> перезапуск ->
|
|
29
29
|
**проверка фактического применения**.
|
|
30
|
-
- **Ветки среды разработки**: список, создание, привязка к приложению, merge
|
|
31
|
-
загрузка изменений из git-ветки.
|
|
30
|
+
- **Ветки среды разработки**: список, создание, привязка к приложению, merge.
|
|
32
31
|
- **Дампы**: создание и контроль готовности.
|
|
33
32
|
- **MCP-сервер**: те же операции как инструменты для AI-агентов
|
|
34
33
|
(Claude Code и другие MCP-клиенты).
|
|
@@ -72,7 +71,6 @@ pip install "elemctl[mcp]" # с MCP-сервером
|
|
|
72
71
|
| `ELEMENT_APP_ID` | приложение по умолчанию (необязательно) |
|
|
73
72
|
| `ELEMENT_PROJECT_ID` | проект по умолчанию (необязательно) |
|
|
74
73
|
| `ELEMENT_SPACE_ID` | пространство по умолчанию (необязательно) |
|
|
75
|
-
| `ELEMENT_BRANCH_ID` | ветка платформы по умолчанию (необязательно) |
|
|
76
74
|
|
|
77
75
|
Client-Id/Client-Secret выпускаются в панели управления 1cmycloud
|
|
78
76
|
(раздел интеграций Console API). Шаблон файла - [.env.example](.env.example).
|
|
@@ -151,9 +149,8 @@ Assembly.yaml # манифест: ProjectKind, Vendor, Name, Version,
|
|
|
151
149
|
|
|
152
150
|
- Инструмент **неофициальный** и не аффилирован с фирмой "1С"; Console API
|
|
153
151
|
может меняться без предупреждения.
|
|
154
|
-
-
|
|
155
|
-
|
|
156
|
-
наименее стабильный.
|
|
152
|
+
- Используется только документированный Console API v2 - внутренние API
|
|
153
|
+
консоли платформы инструмент не вызывает и не описывает.
|
|
157
154
|
- Создание приложения только по `--project-id` на части конфигураций платформы
|
|
158
155
|
даёт пустой каркас без данных проекта. Надёжный путь - источник-сборка:
|
|
159
156
|
`elemctl apps create <имя> --project-id <id> --latest-build` (MCP-инструмент
|
|
@@ -168,6 +165,12 @@ Assembly.yaml # манифест: ProjectKind, Vendor, Name, Version,
|
|
|
168
165
|
"Мягкой" очистки данных приложения в Console API нет, она выполняется в
|
|
169
166
|
консоли управления.
|
|
170
167
|
|
|
168
|
+
## Происхождение и правовые заметки
|
|
169
|
+
|
|
170
|
+
Код написан с нуля по спецификации внешнего интерфейса платформы - процесс и
|
|
171
|
+
гарантии описаны в [ORIGIN.md](ORIGIN.md). Товарные знаки и отсутствие
|
|
172
|
+
аффилиации с фирмой "1С" - в файле [NOTICE](NOTICE).
|
|
173
|
+
|
|
171
174
|
## Лицензия
|
|
172
175
|
|
|
173
176
|
[MIT](LICENSE)
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# Спецификация elemctl
|
|
2
|
+
|
|
3
|
+
Документ описывает контракт Console API v2 платформы 1С:Предприятие.Элемент
|
|
4
|
+
(1cmycloud.com), формат файлов сборки и требования к инструменту elemctl.
|
|
5
|
+
Спецификация содержит только факты об интерфейсе платформы и требования к
|
|
6
|
+
продукту - реализация проектируется с нуля.
|
|
7
|
+
|
|
8
|
+
## 1. Назначение и состав пакета
|
|
9
|
+
|
|
10
|
+
Python-пакет `elemctl` из трёх слоёв поверх общего ядра:
|
|
11
|
+
|
|
12
|
+
1. **Библиотека** - программный клиент Console API v2 и операции высокого
|
|
13
|
+
уровня (сборка, деплой). Только стандартная библиотека Python.
|
|
14
|
+
2. **CLI** - консольная команда `elemctl` (entry point `elemctl` в
|
|
15
|
+
`[project.scripts]`).
|
|
16
|
+
3. **MCP-сервер** - те же операции как инструменты для AI-агентов; транспорт
|
|
17
|
+
stdio; зависимость `mcp>=1.2` подключается как optional extra
|
|
18
|
+
`elemctl[mcp]` (используется FastMCP из пакета `mcp`).
|
|
19
|
+
|
|
20
|
+
Требования пакета: имя `elemctl`, версия 0.1.0, Python >= 3.10, лицензия MIT,
|
|
21
|
+
автор KeyFire, layout `src/elemctl/`, extra `dev` с pytest. Файлы LICENSE,
|
|
22
|
+
README.md, .env.example и .gitignore предоставлены заказчиком и не меняются.
|
|
23
|
+
|
|
24
|
+
## 2. Конфигурация подключения
|
|
25
|
+
|
|
26
|
+
Параметры берутся из трёх источников, по убыванию приоритета:
|
|
27
|
+
|
|
28
|
+
1. явные аргументы (флаги CLI `--base-url`, `--client-id`, `--client-secret`);
|
|
29
|
+
2. переменные окружения;
|
|
30
|
+
3. .env-файл: путь из флага `--env-file`, а без него - файл `.env` в текущем
|
|
31
|
+
каталоге, если существует.
|
|
32
|
+
|
|
33
|
+
Переменные окружения:
|
|
34
|
+
|
|
35
|
+
| Переменная | Смысл | Обязательна |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `ELEMENT_BASE_URL` | базовый URL платформы, например `https://1cmycloud.com` | да |
|
|
38
|
+
| `ELEMENT_CLIENT_ID` | Client-Id для получения токена | да |
|
|
39
|
+
| `ELEMENT_CLIENT_SECRET` | Client-Secret | да |
|
|
40
|
+
| `ELEMENT_APP_ID` | приложение по умолчанию | нет |
|
|
41
|
+
| `ELEMENT_PROJECT_ID` | проект по умолчанию | нет |
|
|
42
|
+
| `ELEMENT_SPACE_ID` | пространство по умолчанию | нет |
|
|
43
|
+
|
|
44
|
+
Формат .env: строки `KEY=VALUE`; пустые строки и строки с `#` в начале
|
|
45
|
+
пропускаются; допускается префикс `export ` и одинарные/двойные кавычки
|
|
46
|
+
вокруг значения; кодировка UTF-8, возможен BOM (читать как `utf-8-sig`).
|
|
47
|
+
Хвостовой слэш у `ELEMENT_BASE_URL` обрезается.
|
|
48
|
+
|
|
49
|
+
## 3. Аутентификация
|
|
50
|
+
|
|
51
|
+
Получение токена: `POST {base}/console/sys/token`
|
|
52
|
+
|
|
53
|
+
- заголовок `Authorization: Basic base64(client_id:client_secret)`;
|
|
54
|
+
- тело `grant_type=client_credentials`, Content-Type
|
|
55
|
+
`application/x-www-form-urlencoded`.
|
|
56
|
+
|
|
57
|
+
Ответ - JSON-объект; токен лежит в первом непустом из полей `id_token`,
|
|
58
|
+
`token`, `value`, `access_token`. Особый случай: значение `access_token`
|
|
59
|
+
может быть строкой `"Not implemented"` - это не токен, поле игнорировать.
|
|
60
|
+
|
|
61
|
+
Все прочие запросы - с заголовком `Authorization: Bearer {токен}`.
|
|
62
|
+
|
|
63
|
+
Токен живёт около часа: кешировать его в файле в системном каталоге временных
|
|
64
|
+
файлов (`tempfile.gettempdir()`, НЕ жёсткий `/tmp` - инструмент работает и на
|
|
65
|
+
Windows) с TTL 1 час; ключ кеша должен различать пары base_url + client_id.
|
|
66
|
+
При ответе 401 обновить токен принудительно и повторить запрос один раз.
|
|
67
|
+
|
|
68
|
+
## 4. Контракт Console API v2
|
|
69
|
+
|
|
70
|
+
Общий префикс: `{base}/console/api/v2`. Тела запросов и ответов - JSON
|
|
71
|
+
(кроме загрузки сборки). Имена полей - в kebab-case.
|
|
72
|
+
|
|
73
|
+
### 4.1. Приложения
|
|
74
|
+
|
|
75
|
+
- `GET /applications` - список; необязательный query `name` (фильтр).
|
|
76
|
+
- `GET /applications/{id}` - карточка. Значимые поля ответа: `id`, `status`,
|
|
77
|
+
`uri` (адрес работающего приложения), `error` (текст ошибки, если есть),
|
|
78
|
+
`technology-version`, `date-updated`, `display-name`,
|
|
79
|
+
`publication-context`, `source` (объект с информацией об источнике,
|
|
80
|
+
содержит в т.ч. `project-version` - версию применённой сборки).
|
|
81
|
+
- `POST /applications` - создать. Тело:
|
|
82
|
+
- `source` - объект `{"type": "repository"}` плюс ровно один из ключей:
|
|
83
|
+
`project-version-id` (id сборки-источника) либо `image-id` (id проекта);
|
|
84
|
+
- `display-name`, `publication-context` - имя и путь публикации;
|
|
85
|
+
- `development-mode` - булево, создавать ли среду разработки;
|
|
86
|
+
- необязательные `space-id`, `technology-version`.
|
|
87
|
+
- `DELETE /applications/{id}` - удалить.
|
|
88
|
+
- `PUT /applications/{id}/status/start` - запустить.
|
|
89
|
+
- `PUT /applications/{id}/status/stop` - остановить.
|
|
90
|
+
- `POST /applications/{id}/project/update` - применить сборку к приложению.
|
|
91
|
+
Тело: `{"source": {"type": "repository", "image-id": "<id сборки>"}}`
|
|
92
|
+
либо `{"source": {"type": "repository", "project-id": "<id>",
|
|
93
|
+
"assembly-version": "<версия>"}}` (assembly-version необязательна).
|
|
94
|
+
- `POST /applications/{id}/dumps` - создать дамп. Тело: `include-users`,
|
|
95
|
+
`include-binary-data` (булевы), `description` (строка).
|
|
96
|
+
- `GET /applications/{id}/dumps/{dumpId}` - статус дампа.
|
|
97
|
+
|
|
98
|
+
Статусы приложения: стабильные `Running`, `Stopped`, `Error`; переходные
|
|
99
|
+
`Starting`, `Stopping`, `Initializing`, `Updating`, `Frozen`, `Creating`.
|
|
100
|
+
Во время переходов поле `status` может быть и пустым.
|
|
101
|
+
|
|
102
|
+
### 4.2. Версия технологии
|
|
103
|
+
|
|
104
|
+
- Чтение - из поля `technology-version` карточки приложения (отдельный
|
|
105
|
+
endpoint чтения есть не во всех версиях платформы - не использовать).
|
|
106
|
+
- Обновление: `POST /tasks/group-tasks/update-applications-technology`,
|
|
107
|
+
тело `{"technology-version": "<версия>", "applications": ["<app-id>"]}`.
|
|
108
|
+
Возвращает групповую задачу; её статус - `GET /tasks/group-tasks/{taskId}`.
|
|
109
|
+
|
|
110
|
+
### 4.3. Пространства и проекты
|
|
111
|
+
|
|
112
|
+
- `GET /spaces` - список пространств.
|
|
113
|
+
- `GET /projects` - список проектов; `GET /projects/{id}` - карточка;
|
|
114
|
+
`DELETE /projects/{id}` - удаление.
|
|
115
|
+
|
|
116
|
+
### 4.4. Сборки проекта (assemblies)
|
|
117
|
+
|
|
118
|
+
- Загрузка файла сборки - бинарный POST (Content-Type
|
|
119
|
+
`application/octet-stream`, тело - байты файла):
|
|
120
|
+
- `POST /projects/{id}/assemblies` - добавить сборку в существующий проект;
|
|
121
|
+
- `POST /projects` - создать новый проект из сборки.
|
|
122
|
+
Query-параметры (все необязательные): `SpaceId`, `BranchName`, `CommitId`,
|
|
123
|
+
`CommitMessage`. Внимание: имена этих query-параметров - в PascalCase.
|
|
124
|
+
Ответ содержит id созданной сборки в одном из полей: `image-id`,
|
|
125
|
+
`assembly-id` или `id` (проверять в этом порядке).
|
|
126
|
+
- `GET /projects/{id}/assemblies` - список сборок. Элемент содержит
|
|
127
|
+
`assembly-version` (строка вида `1.0-42`) и id (`id` либо `image-id`).
|
|
128
|
+
Ответ может быть как массивом, так и объектом со списком в поле `items`
|
|
129
|
+
или `assemblies`.
|
|
130
|
+
- `GET /projects/{id}/assemblies/{version}` - карточка сборки по версии;
|
|
131
|
+
`DELETE .../{version}` - удаление.
|
|
132
|
+
|
|
133
|
+
Сравнение версий сборок: по числовому суффиксу после последнего дефиса
|
|
134
|
+
(`1.0-10` новее `1.0-9`; лексикографическое сравнение даёт неверный порядок).
|
|
135
|
+
|
|
136
|
+
### 4.5. Ветки среды разработки
|
|
137
|
+
|
|
138
|
+
- `GET /branches` - список; необязательные query `project-id`, `name`.
|
|
139
|
+
- `GET /branches/{id}` - карточка. Поля: `name`, `kind`, `project`,
|
|
140
|
+
`application`, `source-branch`, `deletion-mark`, `version-stamp`.
|
|
141
|
+
- `POST /branches` - создать. Тело: `name`, `kind: "development"`,
|
|
142
|
+
`project: {"id": "<id>"}`, необязательно `application: {"id": "<id>"}`.
|
|
143
|
+
- `PUT /branches/{id}` - изменить. Платформа использует оптимистическую
|
|
144
|
+
блокировку: сначала прочитать карточку, затем отправить тело, собранное из
|
|
145
|
+
текущих значений - `name`, `kind`, `deletion-mark`, `version-stamp`
|
|
146
|
+
(обязательно вернуть как есть), `source-branch` и `application` - свернуть
|
|
147
|
+
до `{"id": ...}` (или `{"name": ...}`, если id нет). Для перепривязки к
|
|
148
|
+
приложению заменить `application` на `{"id": "<новый app-id>"}`.
|
|
149
|
+
- Принятие изменений ветки (merge) - тот же `PUT /branches/{id}` с
|
|
150
|
+
дополнительным ключом тела `write-parameters: {"merge": true}`.
|
|
151
|
+
- `DELETE /branches/{id}` - удалить ветку.
|
|
152
|
+
|
|
153
|
+
Инструмент работает ТОЛЬКО с документированным Console API v2. Внутренние
|
|
154
|
+
(недокументированные) API консоли платформы не используются и не описываются.
|
|
155
|
+
|
|
156
|
+
### 4.6. Задачи приложений
|
|
157
|
+
|
|
158
|
+
`GET /tasks/application-tasks` - список задач всех приложений (серверного
|
|
159
|
+
фильтра нет - фильтровать на клиенте). Поля задачи: `id`, `application-id`,
|
|
160
|
+
`status` (в т.ч. `Error`, `Failed`), `operation-type`, `error-message`,
|
|
161
|
+
`start-date` (ISO 8601, может оканчиваться на `Z`).
|
|
162
|
+
|
|
163
|
+
## 5. Формат файла сборки (.xasm / .xlib)
|
|
164
|
+
|
|
165
|
+
Файл сборки - ZIP-архив (deflate):
|
|
166
|
+
|
|
167
|
+
- в корне `Assembly.yaml` - манифест, плоские пары ключ-значение:
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
ManifestVersion: 1.0
|
|
171
|
+
ProjectKind: Application | Library
|
|
172
|
+
Vendor: <поставщик>
|
|
173
|
+
Name: <имя проекта>
|
|
174
|
+
Version: <версия, например 1.0-42>
|
|
175
|
+
Created: <UTC, формат YYYY.MM.DD HH:MM:SS>
|
|
176
|
+
BranchName: <имя git-ветки>
|
|
177
|
+
CommitId: <хэш коммита>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Для библиотеки (`ProjectKind: Library`) в конце добавляется строка
|
|
181
|
+
`Release:` (пустое значение); расширение файла `.xlib`, для приложения -
|
|
182
|
+
`.xasm`.
|
|
183
|
+
|
|
184
|
+
- далее файлы проекта путями `{vendor}/{name}/...` - относительно корня
|
|
185
|
+
репозитория. Каталог проекта обязан лежать по схеме
|
|
186
|
+
`{repo}/{vendor}/{name}/Проект.yaml`. Разделители путей в архиве - прямые
|
|
187
|
+
слэши (и на Windows).
|
|
188
|
+
|
|
189
|
+
Имя файла сборки: `{Имя} {Version}.xasm` (через пробел).
|
|
190
|
+
|
|
191
|
+
Метаданные проекта - из `Проект.yaml` (YAML, достаточно разбора плоских пар
|
|
192
|
+
`ключ: значение` верхнего уровня, вложенные строки с отступом пропускать):
|
|
193
|
+
`Имя`, `Поставщик`, `Версия` (базовая, например `1.0`), `ВидПроекта`
|
|
194
|
+
(значение `Библиотека` означает библиотеку, иначе приложение).
|
|
195
|
+
|
|
196
|
+
Версия сборки, если не задана явно: `{базовая версия}-{N+1}`, где N - счётчик
|
|
197
|
+
из версии последней сборки проекта; если сборок нет - `{базовая версия}-1`.
|
|
198
|
+
|
|
199
|
+
Git-метаданные (хэш коммита, имя ветки) - из git-репозитория, содержащего
|
|
200
|
+
каталог проекта; при недоступности git оставить пустыми.
|
|
201
|
+
|
|
202
|
+
Отбор файлов в архив:
|
|
203
|
+
|
|
204
|
+
- включаются только расширения: `.yaml .xbsl .xbql .md .txt .json`
|
|
205
|
+
(исходники), `.png .svg .jpg .jpeg .gif .webp .ico` (изображения),
|
|
206
|
+
`.css .html .js .woff .woff2 .ttf .eot` (веб-ресурсы);
|
|
207
|
+
- исключаются каталоги `.git`, `.claude`, `.github`, `__pycache__`,
|
|
208
|
+
`node_modules`, `.venv` и все скрытые (начинающиеся с точки);
|
|
209
|
+
- исключаются файлы `.gitignore`, `.env`, `.DS_Store` и файлы `*.xasm`,
|
|
210
|
+
`*.xlib`.
|
|
211
|
+
|
|
212
|
+
## 6. Поведенческие особенности платформы (обязательны к учёту)
|
|
213
|
+
|
|
214
|
+
1. **Тихий откат применения.** Если применение сборки к приложению падает
|
|
215
|
+
(например, ошибка компиляции), платформа молча откатывает приложение на
|
|
216
|
+
предыдущую сборку и запускает его - статус `Running` НЕ означает успех.
|
|
217
|
+
Достоверная проверка результата деплоя:
|
|
218
|
+
- задачи приложения (п. 4.6) со статусом `Error`/`Failed`, у которых
|
|
219
|
+
`start-date` не раньше момента начала деплоя (старые ошибки из истории
|
|
220
|
+
не учитывать!);
|
|
221
|
+
- сверка фактически применённой версии (`source.project-version` карточки
|
|
222
|
+
приложения) с версией загруженной сборки;
|
|
223
|
+
- информационно - контрольный GET по `uri` приложения (коды 401/403
|
|
224
|
+
нормальны для закрытых приложений и успеху не противоречат).
|
|
225
|
+
2. **Пустой каркас при создании.** Создание приложения с источником "проект"
|
|
226
|
+
(`image-id` = id проекта) на части конфигураций платформы даёт пустое
|
|
227
|
+
приложение без данных проекта. Надёжный источник - конкретная сборка
|
|
228
|
+
(`project-version-id`), например последняя сборка проекта.
|
|
229
|
+
3. **Удаление с черновиками.** Если в среде разработки приложения есть
|
|
230
|
+
неопубликованные правки, `DELETE /applications/{id}` возвращает 400 с
|
|
231
|
+
`FAILED_PRECONDITION` в теле. Принудительного удаления в API нет - только
|
|
232
|
+
панель управления; инструмент обязан дать понятную подсказку.
|
|
233
|
+
4. **Готовность нового приложения.** После создания приложение какое-то время
|
|
234
|
+
в переходных статусах и без `uri` - предусмотреть ожидание готовности
|
|
235
|
+
(появился `uri` и стабильный статус). Статус `Error` при ожидании -
|
|
236
|
+
немедленная ошибка.
|
|
237
|
+
5. **Перезапуск после применения.** `project/update` может сам перезапустить
|
|
238
|
+
приложение. После вызова дождаться выхода из переходных статусов; если
|
|
239
|
+
итог не `Running` - остановить (если не `Stopped`), дождаться `Stopped`,
|
|
240
|
+
запустить, дождаться `Running`. Разумные таймауты: ожидание остановки
|
|
241
|
+
~3 мин, запуска/стабилизации ~5 мин, опрос каждые ~10 с.
|
|
242
|
+
6. **Windows.** Временные файлы и кеши - только через `tempfile`; вывод
|
|
243
|
+
консоли перевести в UTF-8 (`reconfigure` для stdout/stderr), иначе
|
|
244
|
+
кириллица ломается.
|
|
245
|
+
|
|
246
|
+
## 7. Требования к CLI
|
|
247
|
+
|
|
248
|
+
Общие флаги (до подкоманды): `--base-url`, `--client-id`, `--client-secret`,
|
|
249
|
+
`--env-file`, `--timeout` (сек, по умолчанию 60), `--version`.
|
|
250
|
+
|
|
251
|
+
Вывод: результат - JSON в stdout (`ensure_ascii=False`, отступ 2); прогресс
|
|
252
|
+
длительных операций - строки в stderr; ошибки - JSON с полем `error` в
|
|
253
|
+
stderr и код возврата 1.
|
|
254
|
+
|
|
255
|
+
Команды (в скобках - существенные флаги):
|
|
256
|
+
|
|
257
|
+
- `token` - получить и напечатать токен.
|
|
258
|
+
- `apps list [--name]`, `apps get [APP_ID]`, `apps find NAME`,
|
|
259
|
+
`apps create NAME [--project-id --version-id --latest-build --space-id
|
|
260
|
+
--tech-version --no-dev-mode --wait]`, `apps delete APP_ID`,
|
|
261
|
+
`apps start [APP_ID]`, `apps stop [APP_ID]`.
|
|
262
|
+
- `apps find` ищет по точному совпадению (без учёта регистра) имени среди
|
|
263
|
+
полей `name`, `display-name`, `publication-context`; вывод
|
|
264
|
+
`{"id": ..., "found": true|false}`, код возврата 1 если не найдено.
|
|
265
|
+
- `--latest-build` - взять источником последнюю сборку проекта (защита от
|
|
266
|
+
пустого каркаса, п. 6.2); `--wait` - дождаться готовности (п. 6.4) и
|
|
267
|
+
вывести финальную карточку.
|
|
268
|
+
- `spaces list`.
|
|
269
|
+
- `projects list`, `projects get [PROJECT_ID]`, `projects delete PROJECT_ID`.
|
|
270
|
+
- `builds list [--project-id]`, `builds get VERSION [--project-id]`,
|
|
271
|
+
`builds upload FILE [--project-id --space-id --branch --commit
|
|
272
|
+
--commit-message]`, `builds delete VERSION [--project-id]`.
|
|
273
|
+
- `build [--project-dir --output --build-version --last-build --commit
|
|
274
|
+
--branch --kind {application,library}]` - локально собрать архив, вывести
|
|
275
|
+
`{"file": путь}`. Без `--project-dir` каталог проекта ищется автоматически
|
|
276
|
+
(первый каталог с `Проект.yaml` вглубь от текущего). `--kind` по умолчанию
|
|
277
|
+
определяется по `ВидПроекта`.
|
|
278
|
+
- `deploy [--app-id --project-id --project-dir --output --build-version
|
|
279
|
+
--branch --commit --commit-message --dry-run]` -
|
|
280
|
+
полный цикл: сборка -> загрузка -> применение -> перезапуск -> проверка
|
|
281
|
+
фактического применения (п. 6.1). Вывод - JSON-отчёт с полями: `app-id`,
|
|
282
|
+
`uri`, `status`, `version`, `assembly-id`, `applied-version`, `applied`
|
|
283
|
+
(true/false/null - null когда фактическую версию определить не удалось),
|
|
284
|
+
`uri-status`, `problems` (список строк), `ok` (булево). Код возврата 0
|
|
285
|
+
только при `ok`. `--dry-run` - только сборка.
|
|
286
|
+
- `branches list [--project-id --name]`, `branches get ID`,
|
|
287
|
+
`branches create NAME [--project-id --app-id]`,
|
|
288
|
+
`branches update ID [--app-id]`, `branches delete ID`,
|
|
289
|
+
`branches merge ID`.
|
|
290
|
+
- `dumps create [APP_ID] [--description]`, `dumps get APP_ID DUMP_ID`.
|
|
291
|
+
- `tasks list [--app-id]`, `tasks get-group TASK_ID`.
|
|
292
|
+
- `tech get [APP_ID]`, `tech set APP_ID VERSION`.
|
|
293
|
+
- `mcp` - запустить MCP-сервер; без установленного extra - понятная ошибка
|
|
294
|
+
с подсказкой `pip install "elemctl[mcp]"`.
|
|
295
|
+
|
|
296
|
+
Позиционные APP_ID/PROJECT_ID, помеченные выше как необязательные, при
|
|
297
|
+
отсутствии берутся из конфигурации (`ELEMENT_APP_ID`/`ELEMENT_PROJECT_ID`);
|
|
298
|
+
если и там пусто - ошибка.
|
|
299
|
+
|
|
300
|
+
## 8. Требования к MCP-серверу
|
|
301
|
+
|
|
302
|
+
Имя сервера `elemctl`, транспорт stdio, реквизиты - из тех же переменных
|
|
303
|
+
окружения/.env. В instructions сервера предупредить о тихом откате применения
|
|
304
|
+
(п. 6.1). Инструменты (докстринги - краткие, по-русски):
|
|
305
|
+
|
|
306
|
+
`list_apps(name="")`, `get_app(app_id)`, `find_app(name)`,
|
|
307
|
+
`create_app(name, project_id="", version_id="", space_id="",
|
|
308
|
+
development_mode=True)` - при задании только project_id источником
|
|
309
|
+
автоматически берётся последняя сборка проекта (п. 6.2);
|
|
310
|
+
`start_app(app_id)`, `stop_app(app_id)`, `delete_app(app_id)` (в докстринге -
|
|
311
|
+
предупреждение о необратимости и смене URL), `list_spaces()`,
|
|
312
|
+
`list_projects()`, `list_builds(project_id)`,
|
|
313
|
+
`build_assembly(project_dir="", output_dir="", version="")`,
|
|
314
|
+
`deploy(app_id, project_id, project_dir="", version="", branch="",
|
|
315
|
+
commit_message="")` - возвращает отчёт деплоя плюс поле `log` со строками
|
|
316
|
+
прогресса; `apply_build(app_id, version_id)`, `verify_deploy(app_id,
|
|
317
|
+
expected_version="", since_minutes=30)` - проверка применения по п. 6.1;
|
|
318
|
+
`list_app_tasks(app_id="")`, `list_branches(project_id="", name="")`,
|
|
319
|
+
`merge_branch(branch_id)`.
|
|
320
|
+
|
|
321
|
+
## 9. Требования к качеству
|
|
322
|
+
|
|
323
|
+
- Тесты pytest без обращений к сети: разбор .env и приоритеты конфигурации,
|
|
324
|
+
отбор файлов и содержимое архива сборки (включая манифест), автоинкремент
|
|
325
|
+
и числовое сравнение версий, логика итога деплоя (`ok`/`applied`),
|
|
326
|
+
подсказка при `FAILED_PRECONDITION`, поиск приложения по имени.
|
|
327
|
+
- Докстринги и комментарии - литературный русский; кавычки в тексте прямые
|
|
328
|
+
`"`, тире - среднее `–` (не длинное), многоточие - три точки `...`.
|
|
329
|
+
- Библиотека не печатает в stdout/stderr сама - прогресс отдаётся через
|
|
330
|
+
передаваемый вызывающей стороной callback.
|
|
331
|
+
- Ошибки API - собственное исключение с деталями ответа сервера
|
|
332
|
+
(сериализуемыми в JSON).
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "elemctl"
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.2.0"
|
|
10
10
|
description = "CLI, MCP-сервер и библиотека для Console API v2 платформы 1С:Предприятие.Элемент (1cmycloud)"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.10"
|
|
@@ -16,7 +16,7 @@ from . import __version__
|
|
|
16
16
|
from .build import build_assembly
|
|
17
17
|
from .client import ElementClient, extract_assembly_id
|
|
18
18
|
from .config import Config
|
|
19
|
-
from .deploy import
|
|
19
|
+
from .deploy import deploy_from_sources
|
|
20
20
|
from .errors import ApiError, ConfigError, ElemctlError
|
|
21
21
|
|
|
22
22
|
|
|
@@ -279,26 +279,21 @@ def cmd_deploy(args):
|
|
|
279
279
|
config = _config(args)
|
|
280
280
|
client = make_client(config)
|
|
281
281
|
app_id = _require(args.app_id, config.app_id, "--app-id (или ELEMENT_APP_ID)")
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
branch=args.branch,
|
|
298
|
-
commit=args.commit,
|
|
299
|
-
commit_message=args.commit_message or "",
|
|
300
|
-
log=_progress,
|
|
301
|
-
)
|
|
282
|
+
project_id = _require(
|
|
283
|
+
args.project_id, config.project_id, "--project-id (или ELEMENT_PROJECT_ID)"
|
|
284
|
+
)
|
|
285
|
+
report = deploy_from_sources(
|
|
286
|
+
client,
|
|
287
|
+
app_id,
|
|
288
|
+
project_id,
|
|
289
|
+
project_dir=args.project_dir,
|
|
290
|
+
output_dir=args.output,
|
|
291
|
+
version=args.build_version or "",
|
|
292
|
+
branch=args.branch,
|
|
293
|
+
commit=args.commit,
|
|
294
|
+
commit_message=args.commit_message or "",
|
|
295
|
+
log=_progress,
|
|
296
|
+
)
|
|
302
297
|
_emit(report.to_dict())
|
|
303
298
|
return 0 if report.ok else 1
|
|
304
299
|
|
|
@@ -345,16 +340,6 @@ def cmd_branches_merge(args):
|
|
|
345
340
|
return 0
|
|
346
341
|
|
|
347
342
|
|
|
348
|
-
def cmd_branches_sync(args):
|
|
349
|
-
config = _config(args)
|
|
350
|
-
client = make_client(config)
|
|
351
|
-
branch_id = _require(args.branch_id, config.branch_id, "branch-id (аргумент ID или ELEMENT_BRANCH_ID)")
|
|
352
|
-
app_id = _require(args.app_id, config.app_id, "--app-id (или ELEMENT_APP_ID)")
|
|
353
|
-
response = client.sync_branch(app_id, branch_id)
|
|
354
|
-
_emit(response if response is not None else {"ok": True, "app-id": app_id, "branch-id": branch_id})
|
|
355
|
-
return 0
|
|
356
|
-
|
|
357
|
-
|
|
358
343
|
def cmd_dumps_create(args):
|
|
359
344
|
config = _config(args)
|
|
360
345
|
client = make_client(config)
|
|
@@ -537,8 +522,6 @@ def build_parser():
|
|
|
537
522
|
p.add_argument("--branch", help="имя ветки в метаданные (по умолчанию из git)")
|
|
538
523
|
p.add_argument("--commit", help="хэш коммита в метаданные (по умолчанию из git)")
|
|
539
524
|
p.add_argument("--commit-message", help="сообщение коммита (метаданные загрузки)")
|
|
540
|
-
p.add_argument("--from-branch", action="store_true", help="вместо сборки исходников – загрузка из git-ветки платформы")
|
|
541
|
-
p.add_argument("--branch-id", help="ветка платформы для --from-branch (или ELEMENT_BRANCH_ID)")
|
|
542
525
|
p.add_argument("--dry-run", action="store_true", help="только сборка, без загрузки")
|
|
543
526
|
p.set_defaults(handler=cmd_deploy)
|
|
544
527
|
|
|
@@ -574,13 +557,6 @@ def build_parser():
|
|
|
574
557
|
p.add_argument("branch_id", metavar="ID")
|
|
575
558
|
p.set_defaults(handler=cmd_branches_merge)
|
|
576
559
|
|
|
577
|
-
p = branches_sub.add_parser(
|
|
578
|
-
"sync", help="загрузить изменения из git-ветки платформы в приложение (внутренний UI API)"
|
|
579
|
-
)
|
|
580
|
-
p.add_argument("branch_id", nargs="?", metavar="ID")
|
|
581
|
-
p.add_argument("--app-id")
|
|
582
|
-
p.set_defaults(handler=cmd_branches_sync)
|
|
583
|
-
|
|
584
560
|
# dumps ----------------------------------------------------------------
|
|
585
561
|
dumps = sub.add_parser("dumps", help="дампы приложений")
|
|
586
562
|
dumps_sub = dumps.add_subparsers(dest="subcommand", metavar="действие", required=True)
|
|
@@ -423,32 +423,6 @@ class ElementClient:
|
|
|
423
423
|
"""Удалить ветку."""
|
|
424
424
|
return self._api("DELETE", f"/branches/{branch_id}")
|
|
425
425
|
|
|
426
|
-
def sync_branch(self, app_id, branch_id):
|
|
427
|
-
"""Загрузить изменения из git-ветки платформы в приложение.
|
|
428
|
-
|
|
429
|
-
Внимание: это внутренний UI API консоли (не Console API v2),
|
|
430
|
-
его контракт наименее стабильный.
|
|
431
|
-
"""
|
|
432
|
-
body = {
|
|
433
|
-
"module": "e1c::console::Applications::ApplicationConfigurationUpdateForm",
|
|
434
|
-
"method": "UpdateAppConfiguration",
|
|
435
|
-
"params": [
|
|
436
|
-
{
|
|
437
|
-
"type": "e1c::console::Applications::Applications.Reference",
|
|
438
|
-
"value": app_id,
|
|
439
|
-
},
|
|
440
|
-
{
|
|
441
|
-
"type": "e1c::console::Team::Branches.Reference",
|
|
442
|
-
"value": branch_id,
|
|
443
|
-
},
|
|
444
|
-
{"type": "Std::Boolean", "value": False},
|
|
445
|
-
{"type": "Std::Boolean", "value": False},
|
|
446
|
-
],
|
|
447
|
-
}
|
|
448
|
-
return self._request(
|
|
449
|
-
"POST", "/console/ui/module/call", query={"locale": "ru"}, json_body=body
|
|
450
|
-
)
|
|
451
|
-
|
|
452
426
|
# -- задачи приложений ----------------------------------------------------
|
|
453
427
|
|
|
454
428
|
def list_app_tasks(self, app_id=""):
|
|
@@ -20,7 +20,6 @@ ENV_KEYS = {
|
|
|
20
20
|
"app_id": "ELEMENT_APP_ID",
|
|
21
21
|
"project_id": "ELEMENT_PROJECT_ID",
|
|
22
22
|
"space_id": "ELEMENT_SPACE_ID",
|
|
23
|
-
"branch_id": "ELEMENT_BRANCH_ID",
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
DEFAULT_TIMEOUT = 60.0
|
|
@@ -63,7 +62,6 @@ class Config:
|
|
|
63
62
|
app_id: str = ""
|
|
64
63
|
project_id: str = ""
|
|
65
64
|
space_id: str = ""
|
|
66
|
-
branch_id: str = ""
|
|
67
65
|
timeout: float = field(default=DEFAULT_TIMEOUT)
|
|
68
66
|
|
|
69
67
|
def __post_init__(self):
|
|
@@ -126,27 +126,6 @@ def deploy_from_sources(
|
|
|
126
126
|
return report
|
|
127
127
|
|
|
128
128
|
|
|
129
|
-
def deploy_from_platform_branch(client, app_id, branch_id, *, log=None):
|
|
130
|
-
"""Деплой загрузкой изменений из git-ветки платформы (внутренний UI API).
|
|
131
|
-
|
|
132
|
-
Проверка применения та же, но без сверки версии (её у загрузки из
|
|
133
|
-
ветки нет), поэтому applied остаётся None.
|
|
134
|
-
"""
|
|
135
|
-
log = log or (lambda message: None)
|
|
136
|
-
started_at = datetime.now(timezone.utc)
|
|
137
|
-
|
|
138
|
-
log(f"загружаем изменения из ветки {branch_id} в приложение {app_id}...")
|
|
139
|
-
client.sync_branch(app_id, branch_id)
|
|
140
|
-
log("загрузка запущена, ждём стабилизации приложения...")
|
|
141
|
-
|
|
142
|
-
card = client.ensure_running(app_id, log=log)
|
|
143
|
-
log("приложение в статусе Running, проверяем задачи приложения...")
|
|
144
|
-
|
|
145
|
-
report = _verify(client, app_id, card=card, expected_version="", since=started_at)
|
|
146
|
-
_log_outcome(report, log)
|
|
147
|
-
return report
|
|
148
|
-
|
|
149
|
-
|
|
150
129
|
def verify_deploy(client, app_id, *, expected_version="", since=None, log=None):
|
|
151
130
|
"""Самостоятельная проверка применения (без деплоя).
|
|
152
131
|
|
|
@@ -20,7 +20,6 @@ from .build import build_assembly
|
|
|
20
20
|
from .client import ElementClient, extract_assembly_id
|
|
21
21
|
from .config import Config
|
|
22
22
|
from .deploy import (
|
|
23
|
-
deploy_from_platform_branch,
|
|
24
23
|
deploy_from_sources,
|
|
25
24
|
verify_deploy as _verify_deploy,
|
|
26
25
|
)
|
|
@@ -159,15 +158,6 @@ def create_server(config=None):
|
|
|
159
158
|
payload["log"] = lines
|
|
160
159
|
return payload
|
|
161
160
|
|
|
162
|
-
@server.tool(name="deploy_from_platform_branch")
|
|
163
|
-
def deploy_from_platform_branch_tool(app_id: str, branch_id: str) -> dict:
|
|
164
|
-
"""Загрузить изменения из git-ветки платформы в приложение и проверить итог (без сверки версии)."""
|
|
165
|
-
lines: list[str] = []
|
|
166
|
-
report = deploy_from_platform_branch(client(), app_id, branch_id, log=lines.append)
|
|
167
|
-
payload = report.to_dict()
|
|
168
|
-
payload["log"] = lines
|
|
169
|
-
return payload
|
|
170
|
-
|
|
171
161
|
@server.tool()
|
|
172
162
|
def apply_build(app_id: str, version_id: str) -> dict:
|
|
173
163
|
"""Применить загруженную сборку (по id) к приложению; после применения проверьте итог инструментом verify_deploy."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elemctl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: CLI, MCP-сервер и библиотека для Console API v2 платформы 1С:Предприятие.Элемент (1cmycloud)
|
|
5
5
|
Author: KeyFire
|
|
6
6
|
License-Expression: MIT
|
|
@@ -55,8 +55,7 @@ platform's audience - but the CLI output is plain JSON.*
|
|
|
55
55
|
в архив сборки с манифестом и git-метаданными, автоинкремент версии.
|
|
56
56
|
- **Деплой одной командой**: сборка -> загрузка -> применение -> перезапуск ->
|
|
57
57
|
**проверка фактического применения**.
|
|
58
|
-
- **Ветки среды разработки**: список, создание, привязка к приложению, merge
|
|
59
|
-
загрузка изменений из git-ветки.
|
|
58
|
+
- **Ветки среды разработки**: список, создание, привязка к приложению, merge.
|
|
60
59
|
- **Дампы**: создание и контроль готовности.
|
|
61
60
|
- **MCP-сервер**: те же операции как инструменты для AI-агентов
|
|
62
61
|
(Claude Code и другие MCP-клиенты).
|
|
@@ -100,7 +99,6 @@ pip install "elemctl[mcp]" # с MCP-сервером
|
|
|
100
99
|
| `ELEMENT_APP_ID` | приложение по умолчанию (необязательно) |
|
|
101
100
|
| `ELEMENT_PROJECT_ID` | проект по умолчанию (необязательно) |
|
|
102
101
|
| `ELEMENT_SPACE_ID` | пространство по умолчанию (необязательно) |
|
|
103
|
-
| `ELEMENT_BRANCH_ID` | ветка платформы по умолчанию (необязательно) |
|
|
104
102
|
|
|
105
103
|
Client-Id/Client-Secret выпускаются в панели управления 1cmycloud
|
|
106
104
|
(раздел интеграций Console API). Шаблон файла - [.env.example](.env.example).
|
|
@@ -179,9 +177,8 @@ Assembly.yaml # манифест: ProjectKind, Vendor, Name, Version,
|
|
|
179
177
|
|
|
180
178
|
- Инструмент **неофициальный** и не аффилирован с фирмой "1С"; Console API
|
|
181
179
|
может меняться без предупреждения.
|
|
182
|
-
-
|
|
183
|
-
|
|
184
|
-
наименее стабильный.
|
|
180
|
+
- Используется только документированный Console API v2 - внутренние API
|
|
181
|
+
консоли платформы инструмент не вызывает и не описывает.
|
|
185
182
|
- Создание приложения только по `--project-id` на части конфигураций платформы
|
|
186
183
|
даёт пустой каркас без данных проекта. Надёжный путь - источник-сборка:
|
|
187
184
|
`elemctl apps create <имя> --project-id <id> --latest-build` (MCP-инструмент
|
|
@@ -196,6 +193,12 @@ Assembly.yaml # манифест: ProjectKind, Vendor, Name, Version,
|
|
|
196
193
|
"Мягкой" очистки данных приложения в Console API нет, она выполняется в
|
|
197
194
|
консоли управления.
|
|
198
195
|
|
|
196
|
+
## Происхождение и правовые заметки
|
|
197
|
+
|
|
198
|
+
Код написан с нуля по спецификации внешнего интерфейса платформы - процесс и
|
|
199
|
+
гарантии описаны в [ORIGIN.md](ORIGIN.md). Товарные знаки и отсутствие
|
|
200
|
+
аффилиации с фирмой "1С" - в файле [NOTICE](NOTICE).
|
|
201
|
+
|
|
199
202
|
## Лицензия
|
|
200
203
|
|
|
201
204
|
[MIT](LICENSE)
|
|
@@ -20,7 +20,6 @@ def clean_environment(monkeypatch, tmp_path):
|
|
|
20
20
|
"ELEMENT_APP_ID",
|
|
21
21
|
"ELEMENT_PROJECT_ID",
|
|
22
22
|
"ELEMENT_SPACE_ID",
|
|
23
|
-
"ELEMENT_BRANCH_ID",
|
|
24
23
|
):
|
|
25
24
|
monkeypatch.delenv(key, raising=False)
|
|
26
25
|
monkeypatch.chdir(tmp_path)
|
|
@@ -30,7 +29,7 @@ def test_version_flag(capsys):
|
|
|
30
29
|
with pytest.raises(SystemExit) as excinfo:
|
|
31
30
|
cli.main(["--version"])
|
|
32
31
|
assert excinfo.value.code == 0
|
|
33
|
-
assert "elemctl 0.
|
|
32
|
+
assert "elemctl 0.2.0" in capsys.readouterr().out
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
def test_build_command(project_factory, tmp_path, capsys):
|
|
@@ -175,21 +175,6 @@ def test_update_branch_optimistic_locking_and_merge(api):
|
|
|
175
175
|
assert "project" not in body
|
|
176
176
|
|
|
177
177
|
|
|
178
|
-
def test_sync_branch_ui_api_contract(api):
|
|
179
|
-
client, transport = api
|
|
180
|
-
transport.add("POST", "/console/ui/module/call", {"ok": True})
|
|
181
|
-
|
|
182
|
-
client.sync_branch("app-1", "br-1")
|
|
183
|
-
|
|
184
|
-
call = transport.calls_to("POST", "/console/ui/module/call")[0]
|
|
185
|
-
assert call["query"] == "locale=ru"
|
|
186
|
-
body = json.loads(call["data"].decode("utf-8"))
|
|
187
|
-
assert body["module"].endswith("ApplicationConfigurationUpdateForm")
|
|
188
|
-
assert body["method"] == "UpdateAppConfiguration"
|
|
189
|
-
assert body["params"][0]["value"] == "app-1"
|
|
190
|
-
assert body["params"][1]["value"] == "br-1"
|
|
191
|
-
|
|
192
|
-
|
|
193
178
|
def test_list_app_tasks_client_side_filter(api):
|
|
194
179
|
client, transport = api
|
|
195
180
|
transport.add(
|
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from datetime import datetime, timedelta, timezone
|
|
6
6
|
|
|
7
|
-
from elemctl.deploy import
|
|
7
|
+
from elemctl.deploy import deploy_from_sources, verify_deploy
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class FakeDeployClient:
|
|
@@ -42,9 +42,6 @@ class FakeDeployClient:
|
|
|
42
42
|
def apply_build(self, app_id, **kwargs):
|
|
43
43
|
self.apply_calls.append((app_id, kwargs))
|
|
44
44
|
|
|
45
|
-
def sync_branch(self, app_id, branch_id):
|
|
46
|
-
self.synced = (app_id, branch_id)
|
|
47
|
-
|
|
48
45
|
def ensure_running(self, app_id, log=None):
|
|
49
46
|
return self._card()
|
|
50
47
|
|
|
@@ -216,15 +213,6 @@ def test_report_to_dict_kebab_case(project_factory, tmp_path):
|
|
|
216
213
|
assert payload["ok"] is True
|
|
217
214
|
|
|
218
215
|
|
|
219
|
-
def test_deploy_from_platform_branch_no_version_check():
|
|
220
|
-
client = FakeDeployClient(applied_version="1.0-3")
|
|
221
|
-
report = deploy_from_platform_branch(client, "app-1", "br-1")
|
|
222
|
-
assert client.synced == ("app-1", "br-1")
|
|
223
|
-
# Сверки версии нет: applied остаётся None, итог по задачам.
|
|
224
|
-
assert report.applied is None
|
|
225
|
-
assert report.ok is True
|
|
226
|
-
|
|
227
|
-
|
|
228
216
|
def test_verify_deploy_standalone():
|
|
229
217
|
client = FakeDeployClient(applied_version="1.0-7")
|
|
230
218
|
since = datetime.now(timezone.utc) - timedelta(minutes=30)
|
|
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
|