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.
Files changed (34) hide show
  1. elemctl-0.2.0/.env.example +9 -0
  2. elemctl-0.2.0/MANIFEST.in +4 -0
  3. elemctl-0.2.0/NOTICE +19 -0
  4. elemctl-0.2.0/ORIGIN.md +52 -0
  5. {elemctl-0.1.0/src/elemctl.egg-info → elemctl-0.2.0}/PKG-INFO +10 -7
  6. {elemctl-0.1.0 → elemctl-0.2.0}/README.md +9 -6
  7. elemctl-0.2.0/docs/SPEC.md +332 -0
  8. {elemctl-0.1.0 → elemctl-0.2.0}/pyproject.toml +1 -1
  9. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/__init__.py +1 -1
  10. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/cli.py +16 -40
  11. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/client.py +0 -26
  12. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/config.py +0 -2
  13. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/deploy.py +0 -21
  14. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/mcp_server.py +0 -10
  15. {elemctl-0.1.0 → elemctl-0.2.0/src/elemctl.egg-info}/PKG-INFO +10 -7
  16. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/SOURCES.txt +5 -0
  17. {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_cli.py +1 -2
  18. {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_client.py +0 -15
  19. {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_deploy.py +1 -13
  20. {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_mcp.py +0 -1
  21. {elemctl-0.1.0 → elemctl-0.2.0}/LICENSE +0 -0
  22. {elemctl-0.1.0 → elemctl-0.2.0}/setup.cfg +0 -0
  23. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/auth.py +0 -0
  24. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/build.py +0 -0
  25. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/errors.py +0 -0
  26. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/transport.py +0 -0
  27. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl/versions.py +0 -0
  28. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/dependency_links.txt +0 -0
  29. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/entry_points.txt +0 -0
  30. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/requires.txt +0 -0
  31. {elemctl-0.1.0 → elemctl-0.2.0}/src/elemctl.egg-info/top_level.txt +0 -0
  32. {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_build.py +0 -0
  33. {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_config.py +0 -0
  34. {elemctl-0.1.0 → elemctl-0.2.0}/tests/test_versions.py +0 -0
@@ -0,0 +1,9 @@
1
+ # Подключение к Console API (обязательные)
2
+ ELEMENT_BASE_URL=https://1cmycloud.com
3
+ ELEMENT_CLIENT_ID=
4
+ ELEMENT_CLIENT_SECRET=
5
+
6
+ # Значения по умолчанию (необязательные)
7
+ ELEMENT_APP_ID=
8
+ ELEMENT_PROJECT_ID=
9
+ ELEMENT_SPACE_ID=
@@ -0,0 +1,4 @@
1
+ include NOTICE
2
+ include ORIGIN.md
3
+ include .env.example
4
+ recursive-include docs *.md
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.
@@ -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.1.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
- - Операция `branches sync` (загрузка изменений из git-ветки в приложение)
183
- использует внутренний UI API платформы, а не Console API v2 - контракт
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
- - Операция `branches sync` (загрузка изменений из git-ветки в приложение)
155
- использует внутренний UI API платформы, а не Console API v2 - контракт
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.1.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"
@@ -11,7 +11,7 @@ from .client import ElementClient
11
11
  from .config import Config
12
12
  from .errors import ApiError, BuildError, ConfigError, ElemctlError, TransportError
13
13
 
14
- __version__ = "0.1.0"
14
+ __version__ = "0.2.0"
15
15
 
16
16
  __all__ = [
17
17
  "ApiError",
@@ -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 deploy_from_platform_branch, deploy_from_sources
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
- if args.from_branch:
284
- branch_id = _require(args.branch_id, config.branch_id, "--branch-id (или ELEMENT_BRANCH_ID)")
285
- report = deploy_from_platform_branch(client, app_id, branch_id, log=_progress)
286
- else:
287
- project_id = _require(
288
- args.project_id, config.project_id, "--project-id (или ELEMENT_PROJECT_ID)"
289
- )
290
- report = deploy_from_sources(
291
- client,
292
- app_id,
293
- project_id,
294
- project_dir=args.project_dir,
295
- output_dir=args.output,
296
- version=args.build_version or "",
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.1.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
- - Операция `branches sync` (загрузка изменений из git-ветки в приложение)
183
- использует внутренний UI API платформы, а не Console API v2 - контракт
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)
@@ -1,6 +1,11 @@
1
+ .env.example
1
2
  LICENSE
3
+ MANIFEST.in
4
+ NOTICE
5
+ ORIGIN.md
2
6
  README.md
3
7
  pyproject.toml
8
+ docs/SPEC.md
4
9
  src/elemctl/__init__.py
5
10
  src/elemctl/auth.py
6
11
  src/elemctl/build.py
@@ -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.1.0" in capsys.readouterr().out
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 deploy_from_platform_branch, deploy_from_sources, verify_deploy
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)
@@ -23,7 +23,6 @@ EXPECTED_TOOLS = {
23
23
  "list_builds",
24
24
  "build_assembly",
25
25
  "deploy",
26
- "deploy_from_platform_branch",
27
26
  "apply_build",
28
27
  "verify_deploy",
29
28
  "list_app_tasks",
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