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 +11 -0
- package/package.json +1 -1
- package/src/UNRELEASED.md +4 -0
- package/src/changelog.js +2 -1
- package/src/preflight.js +14 -0
- package/src/release.js +85 -7
- package/src/version.js +1 -0
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
package/src/UNRELEASED.md
CHANGED
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
|
|
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
|
-
|
|
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-
|
|
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
|
-
{
|
|
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-
|
|
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
|
};
|