spectrum-cli 3.1.1 → 4.0.0

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 (60) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +81 -29
  3. package/index.js +6 -158
  4. package/package.json +4 -4
  5. package/src/changelog/commands.js +44 -0
  6. package/src/changelog/format.js +51 -0
  7. package/src/{changelog.js → changelog/fragments.js} +3 -136
  8. package/src/{hotfix-changelog.js → changelog/hotfix.js} +13 -18
  9. package/src/changelog/index.js +7 -0
  10. package/src/{open-release.js → changelog/open-release.js} +6 -6
  11. package/src/changelog/release-block.js +80 -0
  12. package/src/chart/deploy.js +216 -0
  13. package/src/chart/helmrelease.js +90 -0
  14. package/src/chart/index.js +30 -0
  15. package/src/chart/metadata.js +114 -0
  16. package/src/chart/registry.js +139 -0
  17. package/src/chart/routes.js +244 -0
  18. package/src/chart/start.js +98 -0
  19. package/src/chart/verify.js +166 -0
  20. package/src/cli/command-executor.js +181 -0
  21. package/src/cli/commands.js +136 -0
  22. package/src/{development.js → cli/development.js} +1 -1
  23. package/src/cli/help.js +55 -0
  24. package/src/cli/run-action.js +28 -0
  25. package/src/cli/update-check.js +51 -0
  26. package/src/{git.js → git/index.js} +4 -3
  27. package/src/hotfix/checks.js +144 -0
  28. package/src/hotfix/close.js +46 -0
  29. package/src/hotfix/deploy.js +37 -0
  30. package/src/hotfix/git.js +35 -0
  31. package/src/hotfix/index.js +5 -0
  32. package/src/hotfix/start.js +57 -0
  33. package/src/integrations/gitlab-url.js +16 -0
  34. package/src/preflight/changelog.js +130 -0
  35. package/src/preflight/chart.js +57 -0
  36. package/src/preflight/git.js +133 -0
  37. package/src/preflight/helmrelease.js +201 -0
  38. package/src/preflight/index.js +10 -0
  39. package/src/preflight/result.js +18 -0
  40. package/src/preflight/source.js +95 -0
  41. package/src/preflight/tags.js +139 -0
  42. package/src/release/close.js +39 -0
  43. package/src/release/index.js +7 -0
  44. package/src/{stable-tags.js → release/stable-tags.js} +1 -1
  45. package/src/release/start.js +51 -0
  46. package/src/release/steps.js +83 -0
  47. package/src/release/version.js +20 -0
  48. package/src/token/config.js +163 -0
  49. package/src/token/gitlab-api.js +59 -0
  50. package/src/token/index.js +6 -0
  51. package/src/token/rotate.js +157 -0
  52. package/src/chart.js +0 -1071
  53. package/src/command-executor.js +0 -70
  54. package/src/hotfix.js +0 -223
  55. package/src/preflight.js +0 -796
  56. package/src/release.js +0 -207
  57. package/src/token.js +0 -399
  58. /package/src/{changelog-config.js → changelog/config.js} +0 -0
  59. /package/src/{utils.js → common/utils.js} +0 -0
  60. /package/src/{version.js → common/version.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,40 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ This is the changelog of the `spectrum-cli` npm package. Its version comes from
9
+ `package.json`; the release commands use Git tags and `CHANGELOG.md` in the
10
+ **target project** and do not update that project's `package.json`.
11
+
12
+ ## 🚀 [4.0.0] - 2026-10-01
13
+
14
+ ### 💥 Breaking change
15
+
16
+ - `spectrum chart create <version>` заменена на `spectrum chart start`: версия берётся из верхнего заголовка `charts/<chart-name>/CHANGELOG.md` и больше не передаётся аргументом.
17
+ - `chart start` по умолчанию ждёт публикации чарта в Helm-registry. Прежний `--wait` заменён на `-n, --no-wait` для запуска без ожидания.
18
+ - Исходные модули перемещены из файлов `src/*.js` в каталоги с `index.js`; прямые импорты файлов со старыми путями требуют обновления.
19
+
20
+ ### 🆕 Added
21
+
22
+ - Все команды с действием поддерживают `-d, --dry` для запуска только предпроверок и `-s, --silence` для скрытия сообщений об успешно пройденных проверках. Для всех флагов доступны короткие формы.
23
+ - Перед созданием chart-тега проверяется, что версия из changelog ещё не существует среди локальных и удалённых Git-тегов и в Helm-registry.
24
+
25
+ ### 🛠 Changed
26
+
27
+ - Предпроверки сообщают, что именно проверено, выполняются все доступные проверки и завершают команду с ошибкой, если хотя бы одна не прошла; имя запущенной команды из сообщений убрано.
28
+ - Код CLI и тесты распределены по тематическим модулям; документация по установке, релизам и безопасности приведена в соответствие с текущим кодом.
29
+
30
+ ## 🚀 [3.2.0] - 2026-10-01
31
+
32
+ ### 🆕 Added
33
+
34
+ - Добавлена команда `spectrum changelog write`: выравнивает заголовки релизов и хотфиксов и форматирует `CHANGELOG.md` через Prettier.
35
+ - Добавлена команда `spectrum upgrade` для глобального обновления CLI через npm.
36
+ - Перед выполнением команд с действием CLI проверяет наличие новой версии в npm с таймаутом 200 мс и выводит версии и команду обновления; ошибка проверки не прерывает команду. `--help` и `--version` проверку не запускают.
37
+
38
+ ### 🪲 Fixed
39
+
40
+ - `spectrum hotfix start` собирает все текущие фрагменты из `.changelog/` независимо от истории Git.
41
+
8
42
  ## 🚀 [3.1.1] - 2026-09-24
9
43
 
10
44
  ### 🪲 Fixed
package/README.md CHANGED
@@ -14,6 +14,12 @@ npm install -g spectrum-cli
14
14
  spectrum --help
15
15
  ```
16
16
 
17
+ Перед выполнением каждой команды CLI проверяет опубликованную версию `spectrum-cli`
18
+ в npm Registry. Если доступна новая версия, показывает текущую и новую версии и
19
+ команду `spectrum upgrade`. Она запускает `npm install -g spectrum-cli`.
20
+ Проверка ограничена 200 мс; недоступность Registry не влияет на выполнение
21
+ команды и не выводит ошибку.
22
+
17
23
  ### 🔧 Из исходников
18
24
 
19
25
  ```bash
@@ -34,7 +40,7 @@ npm install
34
40
  # Показать справку
35
41
  spectrum --help
36
42
  # Показать текущую версию CLI
37
- spectrum -v | --version
43
+ spectrum -v # или spectrum --version
38
44
 
39
45
  # 🚀 Управление релизами
40
46
  spectrum release start # Схлопнуть fragments и атомарно отправить release commit в dev и main/master
@@ -47,9 +53,9 @@ spectrum hotfix deploy # После merge MR: stable-тег на
47
53
  spectrum hotfix close # После stable pipeline: main/master → dev
48
54
 
49
55
  # 📈 Теги chart
50
- spectrum chart create 1.2.3 # Создать и запушить chart-$name-$version (требует запись в CHANGELOG.md чарта)
51
- spectrum chart create 1.2.3 --wait # После пуша тега дождаться публикации версии в Helm-registry
52
- spectrum chart create 1.2.2 --force # Разрешить версию не больше последней опубликованной
56
+ spectrum chart start # Создать тег по CHANGELOG.md чарта и дождаться публикации в Helm-registry
57
+ spectrum chart start -n # Не ждать публикации после отправки тега
58
+ spectrum chart start --force # Разрешить версию не выше последнего remote-тега, если ее еще нет в registry и Git
53
59
  spectrum chart deploy # Обновить helmrelease.yaml до последнего chart-тега и запушить
54
60
  spectrum chart deploy --instances sd,cbch # Обновить только выбранные инстансы instances/<name>
55
61
  spectrum chart verify ~/repo # Сравнить ingress paths AS IS vs TO BE для Next.js исходников
@@ -57,11 +63,37 @@ spectrum chart verify ~/repo # Сравнить ingress paths AS IS vs TO BE д
57
63
  # 📝 Управление changelog
58
64
  spectrum changelog append "Сообщение" # Создать fragment в .changelog/
59
65
  spectrum changelog check # Проверить CHANGELOG.md и все fragments
66
+ spectrum changelog write # Выравнять заголовки CHANGELOG.md и запустить Prettier
60
67
 
61
68
  # 🔑 GitLab токены
62
69
  spectrum token rotate # Пролить GITLAB_PRIVATE_TOKEN в CI variables
63
70
  ```
64
71
 
72
+ Все команды с действием показывают, какая предпроверка успешно пройдена;
73
+ при ошибке выводят её имя и причину. Независимые предпроверки продолжают
74
+ выполняться после ошибки; зависимые проверки без нужных данных помечаются как
75
+ невыполненные. Шаги команды запускаются, только если все проверки прошли.
76
+ `-s, --silence` скрывает сообщения об успешно пройденных предпроверках.
77
+ Ошибки проверок и итоговое сообщение команды остаются видны; флаг можно
78
+ совмещать с `-d, --dry`.
79
+ `-d, --dry` выполняет все предпроверки,
80
+ показывает их результаты и не запускает шаги записи, создания тегов,
81
+ публикации или деплоя. Предпроверки могут обращаться к `origin`, registry и
82
+ GitLab; `token rotate -d` запрашивает токены и проверяет доступ к целям, но не
83
+ изменяет CI variables. Если конфиг токенов отсутствует, `--dry` завершится
84
+ ошибкой и не создаст его. Для `upgrade -d` предпроверок нет: команда сообщает
85
+ об успехе, не запуская npm.
86
+
87
+ | Короткий флаг | Полный флаг | Где действует |
88
+ | --- | --- | --- |
89
+ | `-d` | `--dry` | Все команды с действием: только предпроверки |
90
+ | `-s` | `--silence` | Все команды с действием: скрыть успешные предпроверки |
91
+ | `-f` | `--force` | `chart start`: разрешить версию не больше последнего тега на `origin`; проверки Git-тега и Helm-registry обязательны |
92
+ | `-n` | `--no-wait` | `chart start`: не ждать появления версии в Helm-registry после push; по умолчанию команда ждёт |
93
+ | `-i <names>` | `--instances <names>` | `chart deploy`: выбрать инстансы через запятую |
94
+ | `-h` | `--help` | Справка CLI и команд |
95
+ | `-v` | `--version` | Версия CLI |
96
+
65
97
  ### Справка по командам:
66
98
 
67
99
  ```bash
@@ -96,24 +128,29 @@ spectrum token --help
96
128
 
97
129
  ```
98
130
  spectrum-cli/
99
- ├── index.js # 🚀 Главный CLI интерфейс
100
- ├── .changelog/ # 🧩 Независимые записи для следующего релиза
101
- ├── src/ # 📁 Исходный код
102
- │ ├── utils.js # 🛠️ Утилиты и логирование
103
- │ ├── git.js # 📝 Git операции
104
- │ ├── version.js # 📦 SemVer-хелперы (парсинг, сравнение, бамп)
105
- │ ├── changelog-config.js # 🧩 Типы и правила changelog fragments
106
- │ ├── changelog.js # 📋 Создание и сборка changelog fragments
107
- │ ├── chart.js # 📈 Создание и push chart тегов
108
- │ ├── token.js # 🔑 Ротация GitLab PAT и CI variables
109
- │ ├── development.js # ⚡ Dev команды (внутренние)
110
- │ └── release.js # 🚀 Release процесс
111
- ├── package.json # 📦 Конфигурация проекта
112
- ├── install.sh # 🔧 Автоматический установщик
113
- ├── INSTALL.md # 📋 Инструкции по установке
114
- └── README.md # 📖 Документация
131
+ ├── index.js # Точка входа CLI
132
+ ├── .changelog/ # Записи для следующего релиза
133
+ ├── src/
134
+ │ ├── cli/ # Команды, справка и запуск действий
135
+ │ ├── common/ # Общие утилиты и версии
136
+ │ ├── git/ # Git операции
137
+ │ ├── preflight/ # Независимые предпроверки по областям
138
+ │ ├── changelog/ # Fragments, конфиг и релизные разделы
139
+ │ ├── chart/ # Метаданные, теги, registry, verify и deploy
140
+ │ ├── release/ # Версии и этапы обычного релиза
141
+ │ ├── hotfix/ # Проверки и этапы hotfix
142
+ │ ├── token/ # Конфиг, GitLab API и ротация
143
+ │ ├── integrations/ # Общие функции внешних сервисов
144
+ ├── __tests__/ # Модульные и интеграционные тесты
145
+ ├── package.json
146
+ ├── install.sh
147
+ ├── INSTALL.md
148
+ └── README.md
115
149
  ```
116
150
 
151
+ Входы модулей находятся в `index.js` соответствующих каталогов. Например,
152
+ `require('./src/chart')` загружает `src/chart/index.js`; в корне `src` файлов нет.
153
+
117
154
  ### Команды
118
155
 
119
156
  | Команда | Описание |
@@ -123,7 +160,7 @@ spectrum-cli/
123
160
  | `spectrum release close` | Закрыть релиз |
124
161
  | `spectrum changelog append` | Создать changelog fragment |
125
162
  | `spectrum changelog check` | Проверить changelog и fragments |
126
- | `spectrum chart create` | Создать и запушить chart тег |
163
+ | `spectrum chart start` | Создать и запушить chart тег |
127
164
  | `spectrum chart deploy` | Обновить chart версию в helmrelease |
128
165
  | `spectrum chart verify` | Проверить ingress paths chart |
129
166
  | `spectrum token rotate` | Пролить GITLAB_PRIVATE_TOKEN в CI |
@@ -135,7 +172,7 @@ spectrum-cli/
135
172
  - `spectrum release close`: чистая и актуальная main/master, версия из верхнего заголовка `CHANGELOG.md` и remote stable-тег поддерживаемой формы, указывающий на текущий commit.
136
173
  - `spectrum changelog append <message>`: `git-repo`, `changelog-exists`, валидные ID задачи, git identity и тип fragment. Команда не изменяет общий `CHANGELOG.md`.
137
174
  - `spectrum changelog check`: `git-repo`, `changelog-exists`, `changelog-prettier-check`, наличие и формат всех changelog fragments.
138
- - `spectrum chart create <version>`: `git-repo`, `clean-working-tree`, `on-main-branch`, `valid-semver` (переданный `<version>` — semver), `single-chart` (ровно один `charts/<chart-name>/Chart.yaml`), `tag-missing` (тега `chart-<name>-<version>` нет локально и на `origin`).
175
+ - `spectrum chart start`: `git-repo`, `clean-working-tree`, `on-main-branch`, `single-chart` (ровно один `charts/<chart-name>/Chart.yaml`), валидный верхний SemVer-заголовок в `charts/<chart-name>/CHANGELOG.md`, отсутствие тега `chart-<name>-<version>` локально и на `origin`, отсутствие этой версии чарта в Helm-registry. Для запроса registry нужен `GITLAB_PRIVATE_TOKEN`; ошибка доступа блокирует команду. `-f, --force` обходит только проверку повышения версии относительно последнего remote-тега. После push команда по умолчанию ждёт версию в registry; `-n, --no-wait` отключает ожидание.
139
176
  - `spectrum chart deploy`: `git-repo`, `clean-working-tree`, `on-main-branch` (текущая ветка `main`), `remote-origin` (настроен `origin`), `remote-reachable` (доступен `origin`), `single-chart`, `helmrelease-files` (найдены `helmrelease.yaml`).
140
177
  - `spectrum chart verify <source_path>`: `git-repo`, `single-values-yaml` (ровно один `charts/**/values.yaml`), `values-ingress-sections` (есть `ingress.paths.api/pages/assets`), `source-path-directory`, `next-project`, `build-command-support`.
141
178
  - `spectrum token rotate`: `load-config` (есть валидный `~/.config/spectrum-cli/config.yaml`), `ask-tokens` (owner PAT и `GITLAB_PRIVATE_TOKEN` только в памяти), `check-access` (все группы и проекты доступны owner PAT).
@@ -197,6 +234,12 @@ spectrum-cli/
197
234
 
198
235
  1. **`spectrum hotfix start`** обновляет сведения об origin и выбирает опубликованный
199
236
  stable-тег, достижимый из production. Цель — этот stable плюс один patch.
237
+ Как и `release start`, команда читает все файлы текущей `.changelog/` независимо
238
+ от того, когда они попали в Git. Проверяет их общими правилами changelog и
239
+ допускает только patch-типы; файлы `added` и `breaking` требуют обычного релиза.
240
+ Формат CHANGELOG.md проверяется только в текущей ветке. История может отличаться
241
+ от stable-тега: её исправления не блокируют хотфикс. Снимок production используется
242
+ для сохранения записей уже подготовленного хотфикса, без строгой проверки старых заголовков.
200
243
  Команда формирует верхний раздел `## 🩹 [X.Y.Z] - YYYY-MM-DD` и удаляет только
201
244
  собранные fragments. Она не делает commit, staging, push, merge или tag,
202
245
  не меняет файлы версий и сохраняет посторонние локальные изменения.
@@ -206,7 +249,7 @@ spectrum-cli/
206
249
  читаются без переписывания опубликованной истории. Без новых fragments подготовленный раздел
207
250
  остаётся без изменений. Например, от `v6.35.0` первый и повторные запуски
208
251
  готовят `6.35.1`; только после публикации `hotfix/6.35.1` следующий хотфикс получит
209
- `6.35.2`. Унаследованные от production fragments не собираются и не меняются.
252
+ `6.35.2`.
210
253
  3. Проверьте diff, закоммитьте и отправьте исправление по правилам проекта.
211
254
  **В MR из hotfix в production уже должны быть верхний patch-раздел и удаления
212
255
  использованных fragments.** Merge выполняется отдельно после ревью. Если
@@ -215,7 +258,7 @@ spectrum-cli/
215
258
  4. После доставки подготовленного исправления в production через MR или
216
259
  разрешённый проектом push и проверки RC выполните **`spectrum hotfix deploy`** на чистом
217
260
  `main/master`, точно совпадающем с origin. Команда проверяет следующий patch,
218
- неизменность опубликованной истории и отсутствие несобранных hotfix fragments,
261
+ отсутствие несобранных hotfix fragments,
219
262
  создаёт `hotfix/X.Y.Z` на проверенном SHA и отправляет **только этот тег**.
220
263
  Повтор после ошибки push допускает существующий локальный тег лишь на том же
221
264
  SHA; опубликованный тег не перемещается. Ветки не сливаются.
@@ -253,14 +296,14 @@ pipeline и фактического выката выполняется отд
253
296
  revision обязательных образов и копирует точные RC digest без пересборки. Эту
254
297
  CI-часть реализует подключенный release component, а не Spectrum CLI.
255
298
 
256
- ### `spectrum chart create <version>`
299
+ ### `spectrum chart start`
257
300
 
258
301
  1. Ищет `Chart.yaml` в `charts/<chart-name>/Chart.yaml` и читает поле `name`
259
302
  2. Проверяет, что текущая ветка — `main`
260
- 3. Проверяет semver для переданной версии
303
+ 3. Читает версию из верхнего заголовка `charts/<chart-name>/CHANGELOG.md` и проверяет SemVer
261
304
  4. Собирает тег `chart-<name>-<version>`
262
- 5. Проверяет, что такого тега еще нет
263
- 6. Создает тег и пушит его в `origin`
305
+ 5. Проверяет, что такого тега еще нет локально и на `origin`, а версия отсутствует в Helm-registry
306
+ 6. Создает тег и пушит его в `origin`, затем ждёт появления версии в registry; `-n, --no-wait` отключает ожидание
264
307
 
265
308
  ### `spectrum chart deploy`
266
309
 
@@ -367,9 +410,18 @@ Fragment должен содержать только непустые Markdown-
367
410
  > Совет: Приведите файл к нужному формату командой:
368
411
  >
369
412
  > ```bash
370
- > npx --yes prettier --write CHANGELOG.md
413
+ > spectrum changelog write
371
414
  > ```
372
415
 
416
+ ### `spectrum changelog write`
417
+
418
+ Команда приводит все релизные заголовки `CHANGELOG.md` к виду `## 🚀 [X.Y.Z]`,
419
+ `## 🩹 [X.Y.Z]` или `## [X.Y.Z]` с необязательной датой, затем запускает Prettier.
420
+ Старые даты через точки и текст записей сохраняются. Неверный заголовок, включая
421
+ `Unreleased`, останавливает команду без удаления записей. При ошибке Prettier
422
+ исходный `CHANGELOG.md` восстанавливается. Файлы `.changelog/` команда не меняет;
423
+ commit и push не выполняет.
424
+
373
425
  ## 🎯 Философия
374
426
 
375
427
  - **Простота** - минимум команд, максимум функциональности
package/index.js CHANGED
@@ -1,161 +1,9 @@
1
1
  #!/usr/bin/env node
2
- const { Command } = require("commander");
3
- const program = new Command();
4
-
5
- const git = require("./src/git");
6
- const release = require("./src/release");
7
- const hotfix = require("./src/hotfix");
8
- const changelog = require("./src/changelog");
9
- const chart = require("./src/chart");
10
- const token = require("./src/token");
11
- const { version: pkgVersion } = require("./package.json");
12
-
13
- async function runAction(action, ...args) {
14
- try {
15
- const result = await action(...args);
16
- if (!result) {
17
- process.exit(1);
18
- }
19
- } catch (error) {
20
- console.error(`❌ Ошибка: ${error.message}`);
21
- process.exit(1);
22
- }
23
- }
24
-
25
- program
26
- .name("spectrum")
27
- .description("🚀 Spectrum CLI для процесса разработки")
28
- .version(pkgVersion, "-v, --version");
29
-
30
- // Команды релиза
31
- const releaseCmd = program
32
- .command("release")
33
- .description("Команды управления релизом");
34
-
35
- releaseCmd
36
- .command("start")
37
- .description("Схлопнуть fragments и атомарно отправить release commit в dev и main/master")
38
- .action(() => runAction(release.releaseStart));
39
-
40
- releaseCmd
41
- .command("close")
42
- .description("Свести стабильный релиз из main/master в dev")
43
- .action(() => runAction(release.releaseClose));
44
-
45
- releaseCmd
46
- .command("deploy")
47
- .description("Создать и отправить только стабильный тег release/X.Y.Z")
48
- .action(() => runAction(git.gitCreateTagAndPush));
49
-
50
- const hotfixCmd = program.command("hotfix").description("Изолированный цикл срочного patch-релиза");
51
-
52
- hotfixCmd.command("start")
53
- .description("Подготовить 🩹 CHANGELOG на hotfix/* или main/master, без commit, push и merge")
54
- .action(() => runAction(hotfix.hotfixStart));
55
- hotfixCmd.command("deploy")
56
- .description("После merge хотфикса отправить stable-тег с main/master")
57
- .action(() => runAction(hotfix.hotfixDeploy));
58
- hotfixCmd.command("close")
59
- .description("После stable pipeline свести production в dev")
60
- .action(() => runAction(hotfix.hotfixClose));
61
-
62
- // Команды changelog
63
- const changelogCmd = program
64
- .command("changelog")
65
- .description("Команды управления changelog fragments");
66
-
67
- changelogCmd
68
- .command("append <message>")
69
- .description("Создать changelog fragment с номером задачи из ветки")
70
- .action((message) => runAction(() => changelog.changelogAppend(message)));
71
-
72
- changelogCmd
73
- .command("check")
74
- .description("Проверить CHANGELOG.md и changelog fragments")
75
- .action(() => runAction(changelog.changelogCheck));
76
-
77
- // Команды chart
78
- const chartCmd = program
79
- .command("chart")
80
- .description("Команды управления тегами chart");
81
-
82
- chartCmd
83
- .command("create <version>")
84
- .description("Создать и отправить chart-тег (chart-<name>-<version>)")
85
- .option("--force", "Разрешить версию не больше последней опубликованной")
86
- .option("--wait", "Дождаться публикации версии чарта в Helm-registry")
87
- .action((version, options) => runAction(() => chart.chartCreateTag(version, options)));
88
-
89
- chartCmd
90
- .command("verify <source_path>")
91
- .description("Проверить пути ingress chart относительно исходников Next.js")
92
- .action((sourcePath) => runAction(() => chart.chartVerify(sourcePath)));
93
-
94
- chartCmd
95
- .command("deploy")
96
- .description("Задеплоить последнюю версию chart в файлы helmrelease")
97
- .option("--instances <names>", "Список инстансов через запятую (по умолчанию все)")
98
- .action((options) => runAction(() => chart.chartDeploy(options)));
99
-
100
- const tokenCmd = program
101
- .command("token")
102
- .description("Команды управления GitLab токенами");
103
-
104
- tokenCmd
105
- .command("rotate")
106
- .description("Пролить GITLAB_PRIVATE_TOKEN в CI variables через owner PAT")
107
- .action(() => runAction(token.tokenRotate));
108
-
109
- // Переопределяем help, чтобы показать кастомный формат с алиасами
110
- program.configureHelp({
111
- formatHelp: (cmd, helper) => {
112
- const cmdUsage = helper.commandUsage(cmd);
113
- const cmdDescription = helper.commandDescription(cmd);
114
- const options = helper.visibleOptions(cmd);
115
- const commands = helper.visibleCommands(cmd);
116
-
117
- let output = "";
118
-
119
- // Использование
120
- if (cmdUsage) {
121
- output += `Использование: ${cmdUsage}\n\n`;
122
- }
123
-
124
- // Описание
125
- if (cmdDescription) {
126
- output += `${cmdDescription}\n\n`;
127
- }
128
-
129
- // Команды с алиасами
130
- if (commands.length > 0) {
131
- output += "Команды:\n";
132
- commands.forEach((cmd) => {
133
- const nameAndArgs = cmd.name() + cmd.usage().replace(/^[^\s]+\s*/, " ");
134
- const aliases = cmd.aliases();
135
- const description = cmd.description();
136
-
137
- let cmdLine = ` ${nameAndArgs}`;
138
- if (aliases.length > 0) {
139
- cmdLine = cmdLine.padEnd(25) + `[${aliases.join(", ")}]`;
140
- }
141
- cmdLine = cmdLine.padEnd(40) + description;
142
- output += cmdLine + "\n";
143
- });
144
- output += "\n";
145
- }
146
-
147
- // Опции
148
- if (options.length > 0) {
149
- output += "Опции:\n";
150
- options.forEach((option) => {
151
- const flags = helper.optionTerm(option);
152
- const description = helper.optionDescription(option);
153
- output += ` ${flags.padEnd(25)} ${description}\n`;
154
- });
155
- }
156
-
157
- return output;
158
- },
159
- });
2
+ const { Command } = require('commander');
3
+ const { registerCommands } = require('./src/cli/commands');
4
+ const { configureHelp } = require('./src/cli/help');
160
5
 
6
+ const program = new Command();
7
+ registerCommands(program);
8
+ configureHelp(program);
161
9
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spectrum-cli",
3
- "version": "3.1.1",
3
+ "version": "4.0.0",
4
4
  "description": "🚀 Modern CLI for development workflow automation - release management, versioning, and changelog generation",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -71,9 +71,9 @@
71
71
  "testEnvironment": "node",
72
72
  "collectCoverageFrom": [
73
73
  "index.js",
74
- "src/command-executor.js",
75
- "src/development.js",
76
- "src/utils.js"
74
+ "src/cli/command-executor.js",
75
+ "src/cli/development.js",
76
+ "src/common/utils.js"
77
77
  ],
78
78
  "testMatch": [
79
79
  "**/__tests__/**/*.js",
@@ -0,0 +1,44 @@
1
+ const { runCommand } = require('../cli/command-executor');
2
+ const { requireGitRepo, requireFileExists, requirePrettierAvailable, requireChangelogFormatted, requireChangelogFragments } = require('../preflight');
3
+ const { CHANGELOG_FILE } = require('./config');
4
+ const { prepareChangelogEntry, appendPreparedChangelogEntry } = require('./fragments');
5
+ const { writeCurrentChangelog } = require('./format');
6
+ function changelogAppend(message) {
7
+ return runCommand({
8
+ name: 'changelog append',
9
+ checks: [
10
+ { name: 'git-repo', run: requireGitRepo },
11
+ { name: 'changelog-exists', run: () => requireFileExists(CHANGELOG_FILE) },
12
+ { name: 'prepare-fragment', dependsOn: ['git-repo', 'changelog-exists'], run: () => prepareChangelogEntry(message) }
13
+ ],
14
+ steps: [
15
+ { name: 'write-fragment', run: appendPreparedChangelogEntry }
16
+ ]
17
+ });
18
+ }
19
+
20
+ function changelogCheck() {
21
+ return runCommand({
22
+ name: 'changelog check',
23
+ checks: [
24
+ { name: 'git-repo', run: requireGitRepo },
25
+ { name: 'changelog-exists', run: () => requireFileExists(CHANGELOG_FILE) },
26
+ { name: 'changelog-prettier-check', run: requireChangelogFormatted },
27
+ { name: 'changelog-fragments', run: requireChangelogFragments }
28
+ ]
29
+ });
30
+ }
31
+
32
+ function changelogWrite() {
33
+ return runCommand({
34
+ name: 'changelog write',
35
+ checks: [
36
+ { name: 'git-repo', run: requireGitRepo },
37
+ { name: 'changelog-exists', run: () => requireFileExists(CHANGELOG_FILE) },
38
+ { name: 'prettier-available', run: requirePrettierAvailable }
39
+ ],
40
+ steps: [{ name: 'write-changelog', run: writeCurrentChangelog }]
41
+ });
42
+ }
43
+
44
+ module.exports = { changelogAppend, changelogCheck, changelogWrite };
@@ -0,0 +1,51 @@
1
+ const fs = require('fs');
2
+ const { logError, execCommand } = require('../common/utils');
3
+ const { CHANGELOG_FILE } = require('./config');
4
+ function normalizeChangelogHeadings(text) {
5
+ const version = '(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)';
6
+ const date = '(\\d{4}-\\d{2}-\\d{2}|\\d{4}\\.\\d{2}\\.\\d{2}|\\d{2}\\.\\d{2}\\.\\d{4})';
7
+ const releaseHeading = new RegExp(`^##[ \\t]*(?:(🚀|🩹)[ \\t]*)?\\[${version}\\](?:[ \\t]+-[ \\t]+${date})?[ \\t]*\\r?$`);
8
+ return text.replace(/^##(?!#)[^\n]*$/gm, (heading) => {
9
+ const match = releaseHeading.exec(heading);
10
+ if (!match) throw new Error(`Некорректный заголовок ${CHANGELOG_FILE}: ${heading.trimEnd()}`);
11
+ const marker = match[1] ? `${match[1]} ` : '';
12
+ const releaseVersion = `${match[2]}.${match[3]}.${match[4]}`;
13
+ const releaseDate = match[5] ? ` - ${match[5]}` : '';
14
+ return `## ${marker}[${releaseVersion}]${releaseDate}${heading.endsWith('\r') ? '\r' : ''}`;
15
+ });
16
+ }
17
+
18
+ function writeCurrentChangelog(context) {
19
+ let original;
20
+ let mayHaveChanged = false;
21
+ try {
22
+ original = fs.readFileSync(CHANGELOG_FILE, 'utf8');
23
+ const normalized = normalizeChangelogHeadings(original);
24
+ if (normalized !== original) {
25
+ mayHaveChanged = true;
26
+ fs.writeFileSync(CHANGELOG_FILE, normalized);
27
+ }
28
+ mayHaveChanged = true;
29
+ if (!execCommand(`${context.prettierRunner} --write ${CHANGELOG_FILE}`) ||
30
+ !execCommand(`${context.prettierRunner} --check ${CHANGELOG_FILE}`)) {
31
+ throw new Error('Prettier не смог отформатировать CHANGELOG.md.');
32
+ }
33
+ const formatted = fs.readFileSync(CHANGELOG_FILE, 'utf8');
34
+ if (normalizeChangelogHeadings(formatted) !== formatted) {
35
+ throw new Error('После Prettier заголовки CHANGELOG.md не соответствуют формату релизов.');
36
+ }
37
+ return true;
38
+ } catch (error) {
39
+ if (mayHaveChanged && original !== undefined) {
40
+ try {
41
+ fs.writeFileSync(CHANGELOG_FILE, original);
42
+ } catch (restoreError) {
43
+ logError('❌', 'Не удалось восстановить %s: %s', CHANGELOG_FILE, restoreError.message);
44
+ }
45
+ }
46
+ logError('❌', 'Не удалось отформатировать %s: %s', CHANGELOG_FILE, error.message);
47
+ return false;
48
+ }
49
+ }
50
+
51
+ module.exports = { normalizeChangelogHeadings, writeCurrentChangelog };