spectrum-cli 1.2.1 → 2.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### 💥 Breaking change
11
+
12
+ _Список обратно несовместимых изменений._
13
+
10
14
  ### 🆕 Added
11
15
 
12
16
  _Список новой функциональности._
@@ -35,6 +39,13 @@ _Список правок для обеспечения безопасност
35
39
 
36
40
  _Список правок для обеспечения технической поддержки._
37
41
 
42
+ ## 🚀 [1.2.2] - 2026-03-10
43
+
44
+ ### 🛠 Changed
45
+
46
+ - Команда `spectrum release start` теперь требует запуск из develop-ветки.
47
+ - Команда `spectrum release close` теперь требует запуск из main-ветки.
48
+
38
49
  ## 🚀 [1.2.1] - 2026-03-05
39
50
 
40
51
  ### 🗑 Removed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spectrum-cli",
3
- "version": "1.2.1",
3
+ "version": "2.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": {
package/src/UNRELEASED.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ### 💥 Breaking change
4
+
5
+ _Список обратно несовместимых изменений._
6
+
3
7
  ### 🆕 Added
4
8
 
5
9
  _Список новой функциональности._
package/src/changelog.js CHANGED
@@ -195,7 +195,7 @@ function detectSectionFromBranch() {
195
195
  const sections = {
196
196
  support: ['### 📦 Support', '### 🔐 Security'],
197
197
  bugfix: ['### 🪲 Fixed'],
198
- feature: ['### 🆕 Added', '### 🛠 Changed', '### 📜 Deprecated', '### 🗑 Removed']
198
+ feature: ['### 💥 Breaking change', '### 🆕 Added', '### 🛠 Changed', '### 📜 Deprecated', '### 🗑 Removed']
199
199
  };
200
200
 
201
201
  if (branchLower.includes('support')) {
@@ -212,6 +212,7 @@ function detectSectionFromBranch() {
212
212
  async function selectSection(availableSections) {
213
213
  if (availableSections.length === 0) {
214
214
  availableSections = [
215
+ '### 💥 Breaking change',
215
216
  '### 🆕 Added',
216
217
  '### 🛠 Changed',
217
218
  '### 📜 Deprecated',
package/src/preflight.js CHANGED
@@ -72,6 +72,19 @@ function requireCurrentBranch(expectedBranch) {
72
72
  return ok({ currentBranch });
73
73
  }
74
74
 
75
+ function requireOnDevBranch() {
76
+ const devBranch = getDevelopBranch();
77
+ const currentBranch = getCurrentBranch();
78
+ if (!currentBranch) {
79
+ return fail('Не удалось определить текущую ветку.');
80
+ }
81
+ if (currentBranch !== devBranch) {
82
+ return fail(`Текущая ветка "${currentBranch}", ожидалась "${devBranch}".`);
83
+ }
84
+ return ok({ devBranch, currentBranch });
85
+ }
86
+
87
+
75
88
  function requireOnMainBranch() {
76
89
  const mainBranch = getMainBranch();
77
90
  const currentBranch = getCurrentBranch();
@@ -532,6 +545,7 @@ module.exports = {
532
545
  requireCleanWorkingTree,
533
546
  requireMainAndDevBranches,
534
547
  requireCurrentBranch,
548
+ requireOnDevBranch,
535
549
  requireOnMainBranch,
536
550
  requireRemoteOrigin,
537
551
  requireRemoteReachable,
package/src/release.js CHANGED
@@ -1,15 +1,18 @@
1
1
  #!/usr/bin/env node
2
+ const fs = require('fs');
2
3
  const { goToDevBranch, goToMainBranch, updateCurrentBranch } = require('./git');
3
- const { changelogChangeHeader, changelogRemoveEmptyChapters, changelogAddUnreleasedBlock, changelogCommit } = require('./changelog');
4
+ const { changelogChangeHeader, changelogRemoveEmptyChapters, changelogAddUnreleasedBlock } = require('./changelog');
4
5
  const path = require('path');
5
- const { getVersion, logSuccess, logError, execCommand, getCurrentBranch, getMainBranch, getMergeRequestUrl } = require('./utils');
6
+ const { getVersion, logSuccess, logError, execCommand, getCurrentBranch, getMainBranch, getMergeRequestUrl, getPackageManager } = require('./utils');
6
7
  const { runCommand } = require('./command-executor');
8
+ const { upVersion, updateVersionFile } = require('./version');
7
9
  const {
8
10
  requireGitRepo,
9
11
  requireCleanWorkingTree,
10
12
  requireCurrentBranchUpToDateWithRemote,
11
13
  requireMainAndDevBranches,
12
- requireOnReleaseBranch,
14
+ requireOnDevBranch,
15
+ requireOnMainBranch,
13
16
  requireReleaseBranchMissing,
14
17
  requirePackageVersion,
15
18
  requireFileExists,
@@ -57,6 +60,68 @@ function releaseCheckChangelogLint() {
57
60
  return true;
58
61
  }
59
62
 
63
+ function detectBumpType() {
64
+ const changelog = fs.readFileSync('CHANGELOG.md', 'utf8');
65
+ const lines = changelog.split('\n');
66
+
67
+ let inUnreleased = false;
68
+ let currentSection = null;
69
+ const sectionsWithEntries = new Set();
70
+
71
+ for (const line of lines) {
72
+ if (line.startsWith('## [Unreleased]')) {
73
+ inUnreleased = true;
74
+ continue;
75
+ }
76
+ if (inUnreleased && line.startsWith('## ')) {
77
+ break;
78
+ }
79
+ if (inUnreleased && line.startsWith('### ')) {
80
+ currentSection = line.trim();
81
+ continue;
82
+ }
83
+ if (inUnreleased && currentSection && line.startsWith('- ')) {
84
+ sectionsWithEntries.add(currentSection);
85
+ }
86
+ }
87
+
88
+ if (sectionsWithEntries.has('### 💥 Breaking change')) {
89
+ return 'major';
90
+ }
91
+ if (sectionsWithEntries.has('### 🆕 Added')) {
92
+ return 'minor';
93
+ }
94
+ return 'patch';
95
+ }
96
+
97
+ function runInstall() {
98
+ const pm = getPackageManager() || 'npm';
99
+ if (!execCommand(`${pm} install`)) {
100
+ logError('❌', 'Не удалось выполнить %s install.', pm);
101
+ return false;
102
+ }
103
+ logSuccess('📦', 'Lock-файл обновлен (%s install).', pm);
104
+ return true;
105
+ }
106
+
107
+ function releaseCommit() {
108
+ const lockFiles = { npm: 'package-lock.json', yarn: 'yarn.lock', bun: 'bun.lockb' };
109
+ const pm = getPackageManager();
110
+ const filesToAdd = ['CHANGELOG.md', 'package.json'];
111
+ if (pm && lockFiles[pm]) {
112
+ filesToAdd.push(lockFiles[pm]);
113
+ }
114
+
115
+ const addSuccess = execCommand(`git add ${filesToAdd.join(' ')}`);
116
+ const commitSuccess = execCommand('git commit --message "📝 Обновить changelog и версию." --no-verify');
117
+
118
+ if (addSuccess && commitSuccess) {
119
+ logSuccess('📝', 'Коммит с обновленным changelog и версией создан.');
120
+ return true;
121
+ }
122
+ return false;
123
+ }
124
+
60
125
  function releaseClose() {
61
126
  return runCommand({
62
127
  name: 'release close',
@@ -64,7 +129,7 @@ function releaseClose() {
64
129
  { name: 'git-repo', run: requireGitRepo },
65
130
  { name: 'clean-working-tree', run: requireCleanWorkingTree },
66
131
  { name: 'branch-up-to-date', run: requireCurrentBranchUpToDateWithRemote },
67
- { name: 'on-release-branch', run: requireOnReleaseBranch },
132
+ { name: 'on-main-branch', run: requireOnMainBranch },
68
133
  { name: 'main-and-dev-branches', run: requireMainAndDevBranches }
69
134
  ],
70
135
  steps: [
@@ -107,18 +172,30 @@ function releaseStart() {
107
172
  { name: 'branch-up-to-date', run: requireCurrentBranchUpToDateWithRemote },
108
173
  { name: 'main-and-dev-branches', run: requireMainAndDevBranches },
109
174
  { name: 'package-version', run: requirePackageVersion },
175
+ { name: 'on-dev-branch', run: requireOnDevBranch },
110
176
  { name: 'changelog-exists', run: () => requireFileExists('CHANGELOG.md') },
111
177
  { name: 'unreleased-template-exists', run: () => requireFileExists(path.join(__dirname, 'UNRELEASED.md')) },
112
178
  { name: 'changelog-prettier-check', run: requireChangelogFormatted },
113
- { name: 'release-branch-missing', run: (ctx) => requireReleaseBranchMissing(`release/${ctx.version}`) }
179
+ {
180
+ name: 'detect-bump-type',
181
+ run: (ctx) => {
182
+ const bumpType = detectBumpType();
183
+ const newVersion = upVersion(ctx.version, bumpType);
184
+ const branchCheck = requireReleaseBranchMissing(`release/${newVersion}`);
185
+ if (!branchCheck.ok) return branchCheck;
186
+ return { ok: true, data: { bumpType, newVersion } };
187
+ }
188
+ }
114
189
  ],
115
190
  steps: [
191
+ { name: 'bump-version', run: (ctx) => updateVersionFile(ctx.bumpType) },
192
+ { name: 'run-install', run: runInstall },
116
193
  { name: 'change-header', run: changelogChangeHeader },
117
194
  { name: 'remove-empty-chapters', run: changelogRemoveEmptyChapters },
118
195
  { name: 'add-unreleased-block', run: changelogAddUnreleasedBlock },
119
196
  { name: 'lint-changelog', run: releaseCheckChangelogLint },
120
197
  { name: 'create-release-branch', run: releaseCreate },
121
- { name: 'commit-changelog', run: changelogCommit },
198
+ { name: 'commit-release', run: releaseCommit },
122
199
  { name: 'push-release', run: releasePush }
123
200
  ]
124
201
  });
@@ -128,5 +205,6 @@ module.exports = {
128
205
  releaseCreate,
129
206
  releasePush,
130
207
  releaseClose,
131
- releaseStart
208
+ releaseStart,
209
+ detectBumpType
132
210
  };
package/src/version.js CHANGED
@@ -51,5 +51,6 @@ function setVersion(versionType) {
51
51
 
52
52
  module.exports = {
53
53
  upVersion,
54
+ updateVersionFile,
54
55
  setVersion
55
56
  };