@vv0rkz/js-template 1.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/README.md +150 -0
- package/bin/cli.js +118 -0
- package/bin/init.js +141 -0
- package/package.json +41 -0
- package/tools-gh/check-demo-for-release.js +30 -0
- package/tools-gh/create-bug.js +26 -0
- package/tools-gh/create-task.js +26 -0
- package/tools-gh/push-release-to-main.js +48 -0
- package/tools-gh/update-readme.js +151 -0
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @vv0rkz/js-template
|
|
2
|
+
|
|
3
|
+
⚡ Переиспользуемый шаблон для JS проектов с husky, changelog, GitHub tools
|
|
4
|
+
|
|
5
|
+
## 🚀 Установка
|
|
6
|
+
|
|
7
|
+
npm install -D @vv0rkz/js-template
|
|
8
|
+
npx jst init
|
|
9
|
+
|
|
10
|
+
## 💻 Использование
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Короткая команда (рекомендуется)
|
|
14
|
+
|
|
15
|
+
npm run _ tasks
|
|
16
|
+
npm run _ release
|
|
17
|
+
npm run _ create-task "Новая фича"
|
|
18
|
+
|
|
19
|
+
# Или полная
|
|
20
|
+
npm run jst tasks
|
|
21
|
+
npm run jst release
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 📋 Команды
|
|
25
|
+
|
|
26
|
+
### Управление проектом
|
|
27
|
+
|
|
28
|
+
- `jst init` — инициализация проекта
|
|
29
|
+
|
|
30
|
+
### Разработка
|
|
31
|
+
|
|
32
|
+
- `jst changelog` — создать changelog
|
|
33
|
+
- `jst release` — полный релиз (проверка + changelog + README)
|
|
34
|
+
- `jst update-readme` — обновить README
|
|
35
|
+
- `jst push-release` — запушить релиз в main
|
|
36
|
+
|
|
37
|
+
### Управление задачами
|
|
38
|
+
|
|
39
|
+
- `jst tasks` — список открытых задач
|
|
40
|
+
- `jst create-task [название]` — создать задачу
|
|
41
|
+
- `jst bugs` — список открытых багов
|
|
42
|
+
- `jst create-bug [название]` — создать баг
|
|
43
|
+
- `jst all-issues` — все открытые issues
|
|
44
|
+
|
|
45
|
+
## 📦 Что устанавливается
|
|
46
|
+
|
|
47
|
+
- ✅ Husky + хуки (commit-msg, pre-push, post-commit)
|
|
48
|
+
- ✅ Commitlint конфиг (проверка коммитов)
|
|
49
|
+
- ✅ Changelogen конфиг (автогенерация changelog)
|
|
50
|
+
- ✅ GitHub tools скрипты (управление задачами)
|
|
51
|
+
- ✅ .gitignore (готовый файл)
|
|
52
|
+
|
|
53
|
+
## 🎯 Пример использования
|
|
54
|
+
|
|
55
|
+
### Установка в новый проект
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
mkdir my-awesome-js-project
|
|
59
|
+
cd my-awesome-js-project
|
|
60
|
+
npm init -y
|
|
61
|
+
npm install -D @vv0rkz/js-template
|
|
62
|
+
npx jst init
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Работа с задачами
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
Создать задачу
|
|
69
|
+
npm run _ create-task "Добавить темную тему"
|
|
70
|
+
|
|
71
|
+
Посмотреть все задачи
|
|
72
|
+
npm run _ tasks
|
|
73
|
+
|
|
74
|
+
Создать баг
|
|
75
|
+
npm run _ create-bug "Кнопка не работает"
|
|
76
|
+
|
|
77
|
+
Посмотреть баги
|
|
78
|
+
npm run _ bugs
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Релиз версии
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Сделать фичу
|
|
85
|
+
git add .
|
|
86
|
+
git commit -m "feat: добавлена темная тема"
|
|
87
|
+
|
|
88
|
+
Создать релиз
|
|
89
|
+
npm run _ release
|
|
90
|
+
|
|
91
|
+
Запушить в main
|
|
92
|
+
npm run _ push-release
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 📁 Структура проекта после установки
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
my-project/
|
|
99
|
+
├── .husky/
|
|
100
|
+
│ ├── commit-msg # Проверка формата коммитов
|
|
101
|
+
│ ├── pre-push # Запуск тестов перед push
|
|
102
|
+
│ └── post-commit # Сообщение после коммита
|
|
103
|
+
├── tools-gh/ # GitHub утилиты
|
|
104
|
+
│ ├── create-task.js
|
|
105
|
+
│ ├── create-bug.js
|
|
106
|
+
│ ├── update-readme.js
|
|
107
|
+
│ └── ...
|
|
108
|
+
├── .gitignore # Готовый .gitignore
|
|
109
|
+
├── changelog.config.js # Конфиг для changelog
|
|
110
|
+
├── commitlint.config.js # Правила для коммитов
|
|
111
|
+
└── package.json # С готовыми скриптами
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 🛠️ Технологии
|
|
115
|
+
|
|
116
|
+
- [Husky](https://typicode.github.io/husky/) — Git hooks
|
|
117
|
+
- [Commitlint](https://commitlint.js.org/) — Проверка коммитов
|
|
118
|
+
- [Changelogen](https://github.com/unjs/changelogen) — Генерация changelog
|
|
119
|
+
- [GitHub CLI](https://cli.github.com/) — Управление issues
|
|
120
|
+
|
|
121
|
+
## 📝 Формат коммитов
|
|
122
|
+
|
|
123
|
+
feat: новая функция
|
|
124
|
+
fix: исправление бага
|
|
125
|
+
docs: изменения в документации
|
|
126
|
+
refactor: рефакторинг кода
|
|
127
|
+
perf: улучшение производительности
|
|
128
|
+
test: добавление тестов
|
|
129
|
+
chore: обновление зависимостей
|
|
130
|
+
|
|
131
|
+
## 📄 Лицензия
|
|
132
|
+
|
|
133
|
+
MIT © [vv0rkz](https://github.com/vv0rkz)
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# 🚀 Публикация
|
|
137
|
+
cd js-template
|
|
138
|
+
npm login
|
|
139
|
+
npm publish --access public
|
|
140
|
+
# 💻 Использование в проекте
|
|
141
|
+
|
|
142
|
+
# В новом проекте
|
|
143
|
+
npm install -D @vv0rkz/js-template
|
|
144
|
+
npx jst init
|
|
145
|
+
|
|
146
|
+
# Работа через короткую команду _
|
|
147
|
+
npm run _ tasks
|
|
148
|
+
npm run _ release
|
|
149
|
+
npm run _ create-task "Моя задача"
|
|
150
|
+
```
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from 'url'
|
|
3
|
+
import { dirname, join } from 'path'
|
|
4
|
+
import { spawnSync } from 'child_process'
|
|
5
|
+
import { existsSync } from 'fs'
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const toolsDir = join(__dirname, '../tools-gh')
|
|
9
|
+
|
|
10
|
+
const args = process.argv.slice(2)
|
|
11
|
+
const command = args[0]
|
|
12
|
+
const commandArgs = args.slice(1)
|
|
13
|
+
|
|
14
|
+
// Проверка наличия tools-gh в текущем проекте
|
|
15
|
+
const projectToolsDir = join(process.cwd(), 'tools-gh')
|
|
16
|
+
const useProjectTools = existsSync(projectToolsDir)
|
|
17
|
+
const scriptsDir = useProjectTools ? projectToolsDir : toolsDir
|
|
18
|
+
|
|
19
|
+
const commands = {
|
|
20
|
+
init: () => {
|
|
21
|
+
const initScript = join(__dirname, 'init.js')
|
|
22
|
+
spawnSync('node', [initScript], { stdio: 'inherit' })
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
changelog: () => {
|
|
26
|
+
spawnSync('npx', ['changelogen', ...commandArgs], { stdio: 'inherit', shell: true })
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
release: () => {
|
|
30
|
+
console.log('🚀 Запуск релиза...\n')
|
|
31
|
+
|
|
32
|
+
const checkDemo = spawnSync('node', [join(scriptsDir, 'check-demo-for-release.js')], { stdio: 'inherit' })
|
|
33
|
+
if (checkDemo.status !== 0) {
|
|
34
|
+
console.error('❌ Проверка демо не прошла')
|
|
35
|
+
process.exit(1)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const changelog = spawnSync('npx', ['changelogen', '--release'], { stdio: 'inherit', shell: true })
|
|
39
|
+
if (changelog.status !== 0) {
|
|
40
|
+
console.error('❌ Ошибка создания changelog')
|
|
41
|
+
process.exit(1)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
spawnSync('node', [join(scriptsDir, 'update-readme.js')], { stdio: 'inherit' })
|
|
45
|
+
console.log('\n✅ Релиз успешно создан!')
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
'update-readme': () => {
|
|
49
|
+
spawnSync('node', [join(scriptsDir, 'update-readme.js')], { stdio: 'inherit' })
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
'push-release': () => {
|
|
53
|
+
spawnSync('node', [join(scriptsDir, 'push-release-to-main.js')], { stdio: 'inherit' })
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
bugs: () => {
|
|
57
|
+
spawnSync('gh', ['issue', 'list', '--label', 'bug', '--state', 'open'], { stdio: 'inherit', shell: true })
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
'create-bug': () => {
|
|
61
|
+
if (commandArgs.length === 0) {
|
|
62
|
+
spawnSync('node', [join(scriptsDir, 'create-bug.js')], { stdio: 'inherit' })
|
|
63
|
+
} else {
|
|
64
|
+
const title = commandArgs.join(' ')
|
|
65
|
+
spawnSync('gh', ['issue', 'create', '--label', 'bug', '--title', title], { stdio: 'inherit', shell: true })
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
tasks: () => {
|
|
70
|
+
spawnSync('gh', ['issue', 'list', '--label', 'task', '--state', 'open'], { stdio: 'inherit', shell: true })
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
'create-task': () => {
|
|
74
|
+
if (commandArgs.length === 0) {
|
|
75
|
+
spawnSync('node', [join(scriptsDir, 'create-task.js')], { stdio: 'inherit' })
|
|
76
|
+
} else {
|
|
77
|
+
const title = commandArgs.join(' ')
|
|
78
|
+
spawnSync('gh', ['issue', 'create', '--label', 'task', '--title', title], { stdio: 'inherit', shell: true })
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
'all-issues': () => {
|
|
83
|
+
spawnSync('gh', ['issue', 'list', '--state', 'open'], { stdio: 'inherit', shell: true })
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (commands[command]) {
|
|
88
|
+
commands[command]()
|
|
89
|
+
} else {
|
|
90
|
+
console.log(`
|
|
91
|
+
⚡ JS Template CLI
|
|
92
|
+
|
|
93
|
+
Использование: jst <команда> [аргументы]
|
|
94
|
+
|
|
95
|
+
📋 ПРОЕКТ:
|
|
96
|
+
jst init Инициализация проекта
|
|
97
|
+
|
|
98
|
+
🔧 РАЗРАБОТКА:
|
|
99
|
+
jst changelog Создать changelog
|
|
100
|
+
jst release Полный релиз (проверка + changelog + README)
|
|
101
|
+
jst update-readme Обновить README
|
|
102
|
+
jst push-release Запушить релиз в main
|
|
103
|
+
|
|
104
|
+
📝 ЗАДАЧИ:
|
|
105
|
+
jst tasks Список открытых задач
|
|
106
|
+
jst create-task [название] Создать задачу
|
|
107
|
+
jst bugs Список открытых багов
|
|
108
|
+
jst create-bug [название] Создать баг
|
|
109
|
+
jst all-issues Все открытые issues
|
|
110
|
+
|
|
111
|
+
📚 ПРИМЕРЫ:
|
|
112
|
+
jst init
|
|
113
|
+
jst create-task "Добавить темную тему"
|
|
114
|
+
jst release
|
|
115
|
+
jst tasks
|
|
116
|
+
`)
|
|
117
|
+
process.exit(command ? 1 : 0)
|
|
118
|
+
}
|
package/bin/init.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from 'url'
|
|
3
|
+
import { dirname, join } from 'path'
|
|
4
|
+
import { copyFileSync, mkdirSync, existsSync, readFileSync, writeFileSync, readdirSync, statSync } from 'fs'
|
|
5
|
+
import { execSync } from 'child_process'
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const templateDir = join(__dirname, '../templates')
|
|
9
|
+
const targetDir = process.cwd()
|
|
10
|
+
|
|
11
|
+
console.log('⚡ JS Template by @vv0rkz — Инициализация проекта\n')
|
|
12
|
+
|
|
13
|
+
// 1. Копирование конфигов
|
|
14
|
+
console.log('📋 Копирование конфигов...')
|
|
15
|
+
const filesToCopy = ['.gitignore', 'changelog.config.js', 'commitlint.config.js']
|
|
16
|
+
|
|
17
|
+
filesToCopy.forEach((file) => {
|
|
18
|
+
const src = join(templateDir, file)
|
|
19
|
+
const dest = join(targetDir, file)
|
|
20
|
+
|
|
21
|
+
if (existsSync(dest)) {
|
|
22
|
+
console.log(` ⚠️ ${file} уже существует, пропускаем`)
|
|
23
|
+
} else {
|
|
24
|
+
copyFileSync(src, dest)
|
|
25
|
+
console.log(` ✅ ${file}`)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// 2. Копирование .husky
|
|
30
|
+
console.log('\n🐶 Настройка husky хуков...')
|
|
31
|
+
const huskyDir = join(targetDir, '.husky')
|
|
32
|
+
if (!existsSync(huskyDir)) {
|
|
33
|
+
mkdirSync(huskyDir, { recursive: true })
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Копирование всей папки .husky
|
|
37
|
+
const huskyTemplateDir = join(templateDir, '.husky')
|
|
38
|
+
if (existsSync(huskyTemplateDir)) {
|
|
39
|
+
const copyDir = (src, dest) => {
|
|
40
|
+
if (!existsSync(dest)) {
|
|
41
|
+
mkdirSync(dest, { recursive: true })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const entries = readdirSync(src)
|
|
45
|
+
for (const entry of entries) {
|
|
46
|
+
const srcPath = join(src, entry)
|
|
47
|
+
const destPath = join(dest, entry)
|
|
48
|
+
|
|
49
|
+
if (statSync(srcPath).isDirectory()) {
|
|
50
|
+
copyDir(srcPath, destPath)
|
|
51
|
+
} else {
|
|
52
|
+
copyFileSync(srcPath, destPath)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
copyDir(huskyTemplateDir, huskyDir)
|
|
58
|
+
console.log(' ✅ Хуки скопированы')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 3. Копирование tools-gh
|
|
62
|
+
console.log('\n🔧 Копирование GitHub скриптов...')
|
|
63
|
+
const toolsDir = join(targetDir, 'tools-gh')
|
|
64
|
+
if (!existsSync(toolsDir)) {
|
|
65
|
+
mkdirSync(toolsDir, { recursive: true })
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const toolsSourceDir = join(__dirname, '../tools-gh')
|
|
69
|
+
if (existsSync(toolsSourceDir)) {
|
|
70
|
+
const toolFiles = readdirSync(toolsSourceDir)
|
|
71
|
+
toolFiles.forEach((file) => {
|
|
72
|
+
const src = join(toolsSourceDir, file)
|
|
73
|
+
const dest = join(toolsDir, file)
|
|
74
|
+
if (statSync(src).isFile()) {
|
|
75
|
+
copyFileSync(src, dest)
|
|
76
|
+
console.log(` ✅ ${file}`)
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 4. Добавление скриптов в package.json
|
|
82
|
+
console.log('\n📦 Обновление package.json...')
|
|
83
|
+
const packageJsonPath = join(targetDir, 'package.json')
|
|
84
|
+
if (existsSync(packageJsonPath)) {
|
|
85
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
|
86
|
+
|
|
87
|
+
// Добавляем только минимум скриптов
|
|
88
|
+
packageJson.scripts = {
|
|
89
|
+
...packageJson.scripts,
|
|
90
|
+
prepare: 'husky',
|
|
91
|
+
jst: 'jst',
|
|
92
|
+
_: 'jst',
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Добавляем зависимость
|
|
96
|
+
if (!packageJson.devDependencies) {
|
|
97
|
+
packageJson.devDependencies = {}
|
|
98
|
+
}
|
|
99
|
+
packageJson.devDependencies['@vv0rkz/js-template'] = '^1.0.0'
|
|
100
|
+
|
|
101
|
+
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
102
|
+
console.log(' ✅ Скрипты добавлены')
|
|
103
|
+
console.log(' npm run jst или npm run _')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 5. Установка зависимостей
|
|
107
|
+
console.log('\n📥 Установка зависимостей...')
|
|
108
|
+
try {
|
|
109
|
+
execSync('npm install --save-dev @commitlint/cli @commitlint/config-conventional husky changelogen', {
|
|
110
|
+
stdio: 'inherit',
|
|
111
|
+
cwd: targetDir,
|
|
112
|
+
})
|
|
113
|
+
console.log(' ✅ Зависимости установлены')
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error(' ❌ Ошибка установки зависимостей')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 6. Инициализация husky
|
|
119
|
+
console.log('\n🔗 Активация husky...')
|
|
120
|
+
try {
|
|
121
|
+
execSync('npx husky init', { stdio: 'inherit', cwd: targetDir })
|
|
122
|
+
console.log(' ✅ Husky активирован')
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.log(' ⚠️ Husky уже инициализирован')
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
console.log(`
|
|
128
|
+
🎉 JS Template успешно установлен!
|
|
129
|
+
|
|
130
|
+
📖 БЫСТРЫЕ КОМАНДЫ:
|
|
131
|
+
npm run jst changelog # или: npm run _ changelog
|
|
132
|
+
npm run jst release # или: npm run _ release
|
|
133
|
+
npm run jst tasks # или: npm run _ tasks
|
|
134
|
+
npm run jst create-task # или: npm run _ create-task
|
|
135
|
+
|
|
136
|
+
📚 ПОЛНЫЙ СПИСОК:
|
|
137
|
+
npm run jst
|
|
138
|
+
|
|
139
|
+
🚀 Начни работу:
|
|
140
|
+
npm run _ create-task "Моя первая задача"
|
|
141
|
+
`)
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vv0rkz/js-template",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Reusable setup for JS projects with husky, changelog, gh tools",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"jst": "./bin/cli.js",
|
|
8
|
+
"js-template": "./bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"templates",
|
|
13
|
+
"tools-gh"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "echo 'Tests not implemented yet' && exit 0"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"template",
|
|
20
|
+
"husky",
|
|
21
|
+
"changelog",
|
|
22
|
+
"github",
|
|
23
|
+
"workflow",
|
|
24
|
+
"commitlint"
|
|
25
|
+
],
|
|
26
|
+
"author": "vv0rkz",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/vv0rkz/js-template.git"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@commitlint/cli": "^20.1.0",
|
|
34
|
+
"@commitlint/config-conventional": "^20.0.0",
|
|
35
|
+
"changelogen": "^0.6.2",
|
|
36
|
+
"husky": "^9.1.7"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"browser-sync": "^3.0.4"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, existsSync } from "fs"
|
|
3
|
+
import { execSync } from "child_process"
|
|
4
|
+
|
|
5
|
+
// Читаем текущую версию
|
|
6
|
+
const packageJson = JSON.parse(readFileSync("package.json", "utf8"))
|
|
7
|
+
const [major, minor, patch] = packageJson.version.split(".").map(Number)
|
|
8
|
+
|
|
9
|
+
// Анализируем коммиты чтобы определить тип версии
|
|
10
|
+
const commitMessages = execSync("git log --oneline -10", { encoding: "utf8" })
|
|
11
|
+
|
|
12
|
+
let nextVersion
|
|
13
|
+
if (commitMessages.includes("feat:")) {
|
|
14
|
+
nextVersion = `v${major}.${minor + 1}.0` // minor release
|
|
15
|
+
} else {
|
|
16
|
+
nextVersion = `v${major}.${minor}.${patch + 1}` // patch release
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
console.log(`📦 Предполагаемая следующая версия: ${nextVersion}`)
|
|
20
|
+
|
|
21
|
+
// Проверяем демо
|
|
22
|
+
const hasDemo = existsSync(`docs/${nextVersion}.gif`) || existsSync(`docs/${nextVersion}.png`)
|
|
23
|
+
|
|
24
|
+
if (!hasDemo) {
|
|
25
|
+
console.log(`❌ Релиз ${nextVersion} требует демо!`)
|
|
26
|
+
console.log(`📸 Создай: docs/${nextVersion}.gif`)
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log(`✅ Демо для ${nextVersion} готово!`)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from 'child_process'
|
|
3
|
+
|
|
4
|
+
const args = process.argv.slice(2)
|
|
5
|
+
const title = args.join(' ')
|
|
6
|
+
|
|
7
|
+
if (!title) {
|
|
8
|
+
console.log('❌ Использование: jst create-bug "описание бага"')
|
|
9
|
+
console.log(' или: npm run _ create-bug "описание бага"')
|
|
10
|
+
process.exit(1)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// Создаем issue в GitHub
|
|
15
|
+
execSync(`gh issue create --title "Bug: ${title}" --body "Баг обнаружен" --label "bug" --assignee "@me"`, {
|
|
16
|
+
stdio: 'inherit',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
console.log('🐛 Баг зарегистрирован!')
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error('❌ Ошибка создания бага:', error.message)
|
|
22
|
+
console.log('\n💡 Убедись что:')
|
|
23
|
+
console.log(' 1. Установлен GitHub CLI: gh --version')
|
|
24
|
+
console.log(' 2. Выполнена авторизация: gh auth login')
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from 'child_process'
|
|
3
|
+
|
|
4
|
+
const args = process.argv.slice(2)
|
|
5
|
+
const title = args.join(' ')
|
|
6
|
+
|
|
7
|
+
if (!title) {
|
|
8
|
+
console.log('❌ Использование: jst create-task "описание задачи"')
|
|
9
|
+
console.log(' или: npm run _ create-task "описание задачи"')
|
|
10
|
+
process.exit(1)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
console.log('📝 Создаю задачу...')
|
|
15
|
+
execSync(`gh issue create --title "Task: ${title}" --body "Задача: ${title}" --label "task"`, {
|
|
16
|
+
stdio: 'inherit',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
console.log('✅ Задача создана! Используй номер в коммитах: feat: #номер описание')
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error('❌ Ошибка создания задачи:', error.message)
|
|
22
|
+
console.log('\n💡 Убедись что:')
|
|
23
|
+
console.log(' 1. Установлен GitHub CLI: gh --version')
|
|
24
|
+
console.log(' 2. Выполнена авторизация: gh auth login')
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from 'child_process'
|
|
3
|
+
|
|
4
|
+
console.log('🚀 Мердж релизной ветки в main...')
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
// 1. Получаем текущую ветку
|
|
8
|
+
const currentBranch = execSync('git branch --show-current').toString().trim()
|
|
9
|
+
|
|
10
|
+
if (currentBranch === 'main' || currentBranch === 'master') {
|
|
11
|
+
console.log('⚠️ Вы уже находитесь на главной ветке!')
|
|
12
|
+
process.exit(0)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(`📁 Текущая ветка: ${currentBranch}`)
|
|
16
|
+
|
|
17
|
+
// 2. Проверяем есть ли изменения для коммита
|
|
18
|
+
const status = execSync('git status --porcelain').toString().trim()
|
|
19
|
+
if (status) {
|
|
20
|
+
console.log('❌ Есть незакоммиченные изменения!')
|
|
21
|
+
console.log(" Сначала сделай коммит: git add . && git commit -m 'your message'")
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 3. Определяем главную ветку (main или master)
|
|
26
|
+
let mainBranch = 'main'
|
|
27
|
+
try {
|
|
28
|
+
execSync('git rev-parse --verify main', { stdio: 'ignore' })
|
|
29
|
+
} catch {
|
|
30
|
+
mainBranch = 'master'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 4. Мерджим в main/master
|
|
34
|
+
console.log(`🔀 Переключаемся на ${mainBranch} и мерджим...`)
|
|
35
|
+
execSync(`git checkout ${mainBranch}`, { stdio: 'inherit' })
|
|
36
|
+
execSync(`git merge ${currentBranch} --no-ff -m "Release ${currentBranch}"`, { stdio: 'inherit' })
|
|
37
|
+
|
|
38
|
+
// 5. Пушим всё
|
|
39
|
+
console.log('📤 Пушим изменения...')
|
|
40
|
+
execSync(`git push origin ${mainBranch}`, { stdio: 'inherit' })
|
|
41
|
+
execSync('git push --tags', { stdio: 'inherit' })
|
|
42
|
+
|
|
43
|
+
console.log(`✅ Релиз из ветки ${currentBranch} завершён!`)
|
|
44
|
+
console.log(`💡 Теперь можешь удалить ветку: git branch -d ${currentBranch}`)
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('❌ Ошибка при мердже:', error.message)
|
|
47
|
+
process.exit(1)
|
|
48
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs'
|
|
3
|
+
import { execSync } from 'child_process'
|
|
4
|
+
|
|
5
|
+
console.log('🎨 Обновляю README релизами с демо...')
|
|
6
|
+
|
|
7
|
+
// Проверяем наличие файлов
|
|
8
|
+
if (!existsSync('CHANGELOG.md')) {
|
|
9
|
+
console.log('❌ CHANGELOG.md не найден')
|
|
10
|
+
console.log('💡 Сначала запусти: npm run _ changelog')
|
|
11
|
+
process.exit(1)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!existsSync('README.md')) {
|
|
15
|
+
console.log('❌ README.md не найден')
|
|
16
|
+
process.exit(1)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const changelog = readFileSync('CHANGELOG.md', 'utf8')
|
|
20
|
+
let readme = readFileSync('README.md', 'utf8')
|
|
21
|
+
|
|
22
|
+
// Получаем информацию о репозитории
|
|
23
|
+
let repoUrl
|
|
24
|
+
try {
|
|
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
|
+
if (remoteUrl.includes('github.com')) {
|
|
28
|
+
repoUrl = remoteUrl.replace('git@github.com:', 'https://github.com/').replace('.git', '')
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.log('⚠️ Не удалось определить URL репозитория')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Парсим changelog - ТОЛЬКО версии с демо
|
|
35
|
+
const versionBlocks = changelog.split('## v').slice(1)
|
|
36
|
+
let prettyChangelog = '## 📋 История версий\n\n'
|
|
37
|
+
const processedVersions = new Set()
|
|
38
|
+
|
|
39
|
+
versionBlocks.forEach((versionBlock) => {
|
|
40
|
+
const versionMatch = versionBlock.match(/^(\d+\.\d+\.\d+)/)
|
|
41
|
+
if (!versionMatch) return
|
|
42
|
+
|
|
43
|
+
const version = `v${versionMatch[1]}`
|
|
44
|
+
if (processedVersions.has(version)) return
|
|
45
|
+
processedVersions.add(version)
|
|
46
|
+
|
|
47
|
+
// ПРОВЕРЯЕМ ДЕМО - если нет демо, пропускаем
|
|
48
|
+
const hasDemo = existsSync(`docs/${version}.gif`) || existsSync(`docs/${version}.png`)
|
|
49
|
+
if (!hasDemo) {
|
|
50
|
+
console.log(`⏭️ Пропускаем ${version} - нет демо`)
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Пропускаем если нет фич
|
|
55
|
+
if (!versionBlock.includes('### ✨ Фичи') && !versionBlock.includes('### 🚀')) {
|
|
56
|
+
console.log(`⏭️ Пропускаем ${version} - нет фич`)
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Извлекаем фичи
|
|
61
|
+
const features = []
|
|
62
|
+
const lines = versionBlock.split('\n')
|
|
63
|
+
let inFeaturesSection = false
|
|
64
|
+
|
|
65
|
+
for (const line of lines) {
|
|
66
|
+
if (line.includes('### ✨ Фичи') || line.includes('### 🚀')) {
|
|
67
|
+
inFeaturesSection = true
|
|
68
|
+
continue
|
|
69
|
+
}
|
|
70
|
+
if (inFeaturesSection && line.includes('### ')) break
|
|
71
|
+
if (inFeaturesSection && line.trim().startsWith('-') && features.length < 3) {
|
|
72
|
+
const cleanFeature = line
|
|
73
|
+
.replace(/^- /, '')
|
|
74
|
+
.replace(/\(\[#\d+\]\([^)]+\)\)/g, '')
|
|
75
|
+
.replace(/\[#\d+\]\([^)]+\)/g, '')
|
|
76
|
+
.replace(/#\d+\s*/, '')
|
|
77
|
+
.replace(/\[[^\]]+\]\([^)]+\)/g, '')
|
|
78
|
+
.trim()
|
|
79
|
+
|
|
80
|
+
if (cleanFeature && !cleanFeature.toLowerCase().includes('тест') && cleanFeature.length > 10) {
|
|
81
|
+
features.push(cleanFeature)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (features.length === 0) return
|
|
87
|
+
|
|
88
|
+
console.log(`✅ Добавляем ${version} - есть демо и ${features.length} фич`)
|
|
89
|
+
|
|
90
|
+
// Форматируем версию
|
|
91
|
+
prettyChangelog += `### 🟢 ${version}\n\n`
|
|
92
|
+
|
|
93
|
+
// Добавляем демо (гарантированно есть)
|
|
94
|
+
if (existsSync(`docs/${version}.gif`)) {
|
|
95
|
+
prettyChangelog += `**Демо работы** \n<img src="docs/${version}.gif" width="400" />\n\n`
|
|
96
|
+
} else {
|
|
97
|
+
prettyChangelog += `**Демо работы** \n<img src="docs/${version}.png" width="400" />\n\n`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Добавляем функционал
|
|
101
|
+
prettyChangelog += `**Функционал:**\n`
|
|
102
|
+
features.forEach((feature) => {
|
|
103
|
+
prettyChangelog += `- ${feature}\n`
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
// Добавляем ссылку на релиз (если есть URL репозитория)
|
|
107
|
+
if (repoUrl) {
|
|
108
|
+
prettyChangelog += `\n**Релиз:** ${repoUrl}/releases/tag/${version}\n\n`
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
prettyChangelog += `---\n\n`
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// Заменяем секцию между маркерами
|
|
115
|
+
if (readme.includes('<!-- AUTOGENERATED_SECTION START -->')) {
|
|
116
|
+
const startMarker = '<!-- AUTOGENERATED_SECTION START -->'
|
|
117
|
+
const endMarker = '<!-- AUTOGENERATED_SECTION END -->'
|
|
118
|
+
|
|
119
|
+
const startIndex = readme.indexOf(startMarker)
|
|
120
|
+
const endIndex = readme.indexOf(endMarker, startIndex + startMarker.length)
|
|
121
|
+
|
|
122
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
123
|
+
readme = readme.substring(0, startIndex + startMarker.length) + '\n' + prettyChangelog + readme.substring(endIndex)
|
|
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
|
+
}
|