@vv0rkz/js-template 1.6.0 → 1.6.2
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/bin/cli.js +2 -69
- package/bin/init.js +18 -0
- package/package.json +1 -1
- package/tools-gh/release.js +102 -0
- package/tools-gh/update-readme.js +9 -33
package/bin/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { spawnSync } from 'child_process'
|
|
3
3
|
import { platform } from 'os'
|
|
4
4
|
import { dirname, join } from 'path'
|
|
5
5
|
import { fileURLToPath } from 'url'
|
|
@@ -36,74 +36,7 @@ const commands = {
|
|
|
36
36
|
},
|
|
37
37
|
|
|
38
38
|
release: () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// 1. Проверка демо
|
|
42
|
-
const checkDemo = spawnSync('node', [join(toolsDir, 'check-demo-for-release.js')], { stdio: 'inherit' })
|
|
43
|
-
if (checkDemo.status !== 0) {
|
|
44
|
-
console.error('❌ Проверка демо не прошла')
|
|
45
|
-
process.exit(1)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// 2. Определяем тип bump из коммитов после последнего тега
|
|
49
|
-
let lastTag = 'HEAD~10' // fallback
|
|
50
|
-
try {
|
|
51
|
-
lastTag = execSync('git describe --tags --abbrev=0', { encoding: 'utf8' }).trim()
|
|
52
|
-
console.log(`📌 Последний тег: ${lastTag}`)
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.log('⚠️ Теги не найдены, анализирую последние 10 коммитов')
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const commitMessages = execSync(`git log ${lastTag}..HEAD --oneline`, { encoding: 'utf8' })
|
|
58
|
-
const bumpType = commitMessages.includes('feat:') ? 'minor' : 'patch'
|
|
59
|
-
|
|
60
|
-
console.log(`📊 Коммиты после ${lastTag}:`)
|
|
61
|
-
console.log(commitMessages)
|
|
62
|
-
console.log(`🔢 Определён bump type: ${bumpType}\n`)
|
|
63
|
-
|
|
64
|
-
// 3. Создаём changelog
|
|
65
|
-
console.log('📝 Создание changelog...')
|
|
66
|
-
const changelog = spawnSync(npxCmd, ['changelogen', '--release', '--bump', bumpType], {
|
|
67
|
-
stdio: 'pipe',
|
|
68
|
-
encoding: 'utf8',
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
if (changelog.status !== 0) {
|
|
72
|
-
console.error('❌ Ошибка создания changelog\n')
|
|
73
|
-
|
|
74
|
-
// Выводим полный текст ошибки
|
|
75
|
-
if (changelog.stdout) {
|
|
76
|
-
console.log('📤 Вывод команды:')
|
|
77
|
-
console.log(changelog.stdout)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (changelog.stderr) {
|
|
81
|
-
console.log('📤 Ошибки:')
|
|
82
|
-
console.log(changelog.stderr)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
console.log('\n💡 Возможные причины:')
|
|
86
|
-
console.log(' 1. Конфликт тегов - проверь: git tag')
|
|
87
|
-
console.log(' 2. Незакоммиченные изменения - проверь: git status')
|
|
88
|
-
console.log(' 3. Неправильный changelog.config.js')
|
|
89
|
-
console.log('\n🔧 Попробуй вручную:')
|
|
90
|
-
console.log(` npx changelogen --release --bump ${bumpType}`)
|
|
91
|
-
process.exit(1)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Выводим успешный результат
|
|
95
|
-
console.log(changelog.stdout)
|
|
96
|
-
|
|
97
|
-
// 4. Обновляем README
|
|
98
|
-
console.log('\n📝 Обновление README...')
|
|
99
|
-
const updateReadme = spawnSync('node', [join(toolsDir, 'update-readme.js')], { stdio: 'inherit' })
|
|
100
|
-
if (updateReadme.status !== 0) {
|
|
101
|
-
console.log('⚠️ README не обновлён (возможно нет секции AUTOGENERATED)')
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
console.log('\n✅ Релиз успешно создан!')
|
|
105
|
-
console.log('💡 Теперь можно:')
|
|
106
|
-
console.log(' npm run _ push-release # Создать PR и смерджить в main')
|
|
39
|
+
spawnSync('node', [join(toolsDir, 'release.js')], { stdio: 'inherit' })
|
|
107
40
|
},
|
|
108
41
|
|
|
109
42
|
'update-readme': () => {
|
package/bin/init.js
CHANGED
|
@@ -192,6 +192,24 @@ const initReadme = spawnSync('node', [join(toolsDir, 'init-readme.js')], { stdio
|
|
|
192
192
|
if (initReadme.status === 0) {
|
|
193
193
|
console.log(' ✅ README.md создан')
|
|
194
194
|
}
|
|
195
|
+
// 9. Проверка на версию
|
|
196
|
+
const packageJson = JSON.parse(readFileSync('package.json', 'utf8'))
|
|
197
|
+
|
|
198
|
+
// Проверка версии
|
|
199
|
+
const currentVersion = packageJson.version || '1.0.0'
|
|
200
|
+
if (currentVersion.startsWith('0.')) {
|
|
201
|
+
console.log('\n⚠️ ВНИМАНИЕ: Текущая версия ' + currentVersion + ' (0.x.x)')
|
|
202
|
+
console.log('💡 Рекомендуется начинать с версии 1.0.0 для корректной работы changelogen')
|
|
203
|
+
console.log(' Причина: https://github.com/conventional-changelog/standard-version/issues/539\n')
|
|
204
|
+
|
|
205
|
+
const answer = await askQuestion('Изменить версию на 1.0.0? (Y/n): ')
|
|
206
|
+
|
|
207
|
+
if (answer.toLowerCase() !== 'n' && answer.toLowerCase() !== 'no') {
|
|
208
|
+
packageJson.version = '1.0.0'
|
|
209
|
+
writeFileSync('package.json', JSON.stringify(packageJson, null, 2))
|
|
210
|
+
console.log('✅ Версия изменена на 1.0.0')
|
|
211
|
+
}
|
|
212
|
+
}
|
|
195
213
|
|
|
196
214
|
console.log(`
|
|
197
215
|
🎉 JS Template успешно установлен!
|
package/package.json
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync, spawnSync } from 'child_process'
|
|
3
|
+
import { platform } from 'os'
|
|
4
|
+
import { dirname, join } from 'path'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const isWin = platform() === 'win32'
|
|
9
|
+
const npxCmd = isWin ? 'npx.cmd' : 'npx'
|
|
10
|
+
|
|
11
|
+
console.log('🚀 Запуск релиза...\n')
|
|
12
|
+
|
|
13
|
+
// 1. Проверка демо
|
|
14
|
+
const checkDemo = spawnSync('node', [join(__dirname, 'check-demo-for-release.js')], { stdio: 'inherit' })
|
|
15
|
+
if (checkDemo.status !== 0) {
|
|
16
|
+
console.error('❌ Проверка демо не прошла')
|
|
17
|
+
process.exit(1)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 2. Получаем текущую версию
|
|
21
|
+
const currentVersion = JSON.parse(execSync('npm pkg get version', { encoding: 'utf8' })).replace(/"/g, '')
|
|
22
|
+
console.log(`📦 Текущая версия: ${currentVersion}`)
|
|
23
|
+
|
|
24
|
+
// 3. Предупреждение для 0.x.x
|
|
25
|
+
if (currentVersion.startsWith('0.')) {
|
|
26
|
+
console.log('\n⚠️ ВНИМАНИЕ: Версия 0.x.x имеет особое поведение!')
|
|
27
|
+
console.log('💡 changelogen для версий < 1.0.0:')
|
|
28
|
+
console.log(' • feat: коммиты → patch bump (0.1.0 → 0.1.1)')
|
|
29
|
+
console.log(' • fix: коммиты → patch bump (0.1.0 → 0.1.1)')
|
|
30
|
+
console.log(' • BREAKING CHANGE → minor bump (0.1.0 → 0.2.0)')
|
|
31
|
+
console.log('')
|
|
32
|
+
console.log('📖 Подробнее: https://github.com/conventional-changelog/standard-version/issues/539')
|
|
33
|
+
console.log('✅ Рекомендация: используй версии ≥ 1.0.0 для правильного semver')
|
|
34
|
+
console.log(' Обнови: npm pkg set version=1.0.0 && git tag v1.0.0\n')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 4. Анализ коммитов
|
|
38
|
+
let lastTag = ''
|
|
39
|
+
try {
|
|
40
|
+
lastTag = execSync('git describe --tags --abbrev=0', { encoding: 'utf8' }).trim()
|
|
41
|
+
console.log(`📌 Последний тег: ${lastTag}`)
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.log('📌 Теги не найдены (первый релиз)')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const commitMessages = lastTag
|
|
47
|
+
? execSync(`git log ${lastTag}..HEAD --format=%s`, { encoding: 'utf8' })
|
|
48
|
+
: execSync('git log --format=%s -10', { encoding: 'utf8' })
|
|
49
|
+
|
|
50
|
+
const commits = commitMessages.split('\n').filter(Boolean)
|
|
51
|
+
|
|
52
|
+
const featCount = commits.filter((c) => c.startsWith('feat:')).length
|
|
53
|
+
const fixCount = commits.filter((c) => c.startsWith('fix:')).length
|
|
54
|
+
const refactorCount = commits.filter((c) => c.startsWith('refactor:')).length
|
|
55
|
+
const perfCount = commits.filter((c) => c.startsWith('perf:')).length
|
|
56
|
+
const docsCount = commits.filter((c) => c.startsWith('docs:')).length
|
|
57
|
+
const buildCount = commits.filter((c) => c.startsWith('build:')).length
|
|
58
|
+
|
|
59
|
+
console.log('\n📊 Анализ коммитов:')
|
|
60
|
+
if (featCount > 0) console.log(` ✨ feat: ${featCount}`)
|
|
61
|
+
if (fixCount > 0) console.log(` 🐛 fix: ${fixCount}`)
|
|
62
|
+
if (refactorCount > 0) console.log(` ♻️ refactor: ${refactorCount}`)
|
|
63
|
+
if (perfCount > 0) console.log(` ⚡ perf: ${perfCount}`)
|
|
64
|
+
if (docsCount > 0) console.log(` 📚 docs: ${docsCount}`)
|
|
65
|
+
if (buildCount > 0) console.log(` 🏗️ build: ${buildCount}`)
|
|
66
|
+
|
|
67
|
+
// 5. Определяем bump type
|
|
68
|
+
const isV0 = currentVersion.startsWith('0.')
|
|
69
|
+
let bumpType = 'patch'
|
|
70
|
+
|
|
71
|
+
if (isV0) {
|
|
72
|
+
// Для 0.x.x используем --major чтобы получить minor bump при feat
|
|
73
|
+
bumpType = featCount > 0 ? 'major' : 'patch'
|
|
74
|
+
console.log(`\n🔢 Bump type: ${bumpType === 'major' ? 'major (для 0.x.x это даст minor)' : 'patch'}`)
|
|
75
|
+
} else {
|
|
76
|
+
// Для ≥1.0.0 нормальное поведение
|
|
77
|
+
bumpType = featCount > 0 ? 'minor' : 'patch'
|
|
78
|
+
console.log(`\n🔢 Bump type: ${bumpType}`)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 6. Создаём changelog
|
|
82
|
+
console.log('\n📝 Создание changelog...')
|
|
83
|
+
const changelog = spawnSync(npxCmd, ['changelogen', '--release', `--${bumpType}`], {
|
|
84
|
+
stdio: 'inherit',
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
if (changelog.status !== 0) {
|
|
88
|
+
console.error('\n❌ Ошибка создания changelog')
|
|
89
|
+
console.log('💡 Попробуй вручную: npx changelogen --release')
|
|
90
|
+
process.exit(1)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 7. Обновляем README
|
|
94
|
+
console.log('\n📝 Обновление README...')
|
|
95
|
+
const updateReadme = spawnSync('node', [join(__dirname, 'update-readme.js')], { stdio: 'inherit' })
|
|
96
|
+
if (updateReadme.status !== 0) {
|
|
97
|
+
console.log('⚠️ README не обновлён (возможно нет секции AUTOGENERATED)')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log('\n✅ Релиз успешно создан!')
|
|
101
|
+
console.log('💡 Теперь можно:')
|
|
102
|
+
console.log(' npm run _ push-release # Создать PR и смерджить в main')
|
|
@@ -23,7 +23,6 @@ let readme = readFileSync('README.md', 'utf8')
|
|
|
23
23
|
let repoUrl
|
|
24
24
|
try {
|
|
25
25
|
const remoteUrl = execSync('git config --get remote.origin.url').toString().trim()
|
|
26
|
-
// Преобразуем git@github.com:user/repo.git в https://github.com/user/repo
|
|
27
26
|
if (remoteUrl.includes('github.com')) {
|
|
28
27
|
repoUrl = remoteUrl.replace('git@github.com:', 'https://github.com/').replace('.git', '')
|
|
29
28
|
}
|
|
@@ -51,8 +50,10 @@ versionBlocks.forEach((versionBlock) => {
|
|
|
51
50
|
return
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
// Пропускаем если нет фич
|
|
55
|
-
if (!versionBlock.includes('### ✨
|
|
53
|
+
// Пропускаем если нет фич (поддержка разных форматов заголовков)
|
|
54
|
+
if (!versionBlock.includes('### ✨ Новые фичи') &&
|
|
55
|
+
!versionBlock.includes('### ✨ Фичи') &&
|
|
56
|
+
!versionBlock.includes('### 🚀')) {
|
|
56
57
|
console.log(`⏭️ Пропускаем ${version} - нет фич`)
|
|
57
58
|
return
|
|
58
59
|
}
|
|
@@ -63,7 +64,10 @@ versionBlocks.forEach((versionBlock) => {
|
|
|
63
64
|
let inFeaturesSection = false
|
|
64
65
|
|
|
65
66
|
for (const line of lines) {
|
|
66
|
-
|
|
67
|
+
// Поддержка разных форматов заголовков фич
|
|
68
|
+
if (line.includes('### ✨ Новые фичи') ||
|
|
69
|
+
line.includes('### ✨ Фичи') ||
|
|
70
|
+
line.includes('### 🚀')) {
|
|
67
71
|
inFeaturesSection = true
|
|
68
72
|
continue
|
|
69
73
|
}
|
|
@@ -120,32 +124,4 @@ if (readme.includes('<!-- AUTOGENERATED_SECTION START -->')) {
|
|
|
120
124
|
const endIndex = readme.indexOf(endMarker, startIndex + startMarker.length)
|
|
121
125
|
|
|
122
126
|
if (startIndex !== -1 && endIndex !== -1) {
|
|
123
|
-
readme = readme.substring(0, startIndex +
|
|
124
|
-
console.log('✅ Секция обновлена')
|
|
125
|
-
}
|
|
126
|
-
} else {
|
|
127
|
-
console.log('⚠️ Маркер <!-- AUTOGENERATED_SECTION START --> не найден в README.md')
|
|
128
|
-
console.log('💡 Добавь в README.md:')
|
|
129
|
-
console.log(' <!-- AUTOGENERATED_SECTION START -->')
|
|
130
|
-
console.log(' <!-- AUTOGENERATED_SECTION END -->')
|
|
131
|
-
process.exit(1)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Сохраняем
|
|
135
|
-
writeFileSync('README.md', readme)
|
|
136
|
-
console.log('✅ README обновлён с релизами, у которых есть демо!')
|
|
137
|
-
|
|
138
|
-
// Пытаемся закоммитить и запушить
|
|
139
|
-
try {
|
|
140
|
-
const status = execSync('git status --porcelain README.md').toString().trim()
|
|
141
|
-
if (status) {
|
|
142
|
-
execSync('git add README.md', { stdio: 'inherit' })
|
|
143
|
-
execSync('git commit -m "docs: update README with demo releases"', { stdio: 'inherit' })
|
|
144
|
-
execSync('git push', { stdio: 'inherit' })
|
|
145
|
-
console.log('🚀 Изменения запушены!')
|
|
146
|
-
} else {
|
|
147
|
-
console.log('💡 README не изменился')
|
|
148
|
-
}
|
|
149
|
-
} catch (error) {
|
|
150
|
-
console.log('💡 README обновлён локально (не удалось запушить автоматически)')
|
|
151
|
-
}
|
|
127
|
+
readme = readme.substring(0, startIndex + star
|