@vv0rkz/js-template 1.3.0 → 1.4.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/bin/init.js +65 -11
- package/package.json +1 -1
- package/templates/README.md +70 -0
- package/tools-gh/create-bug.js +32 -5
- package/tools-gh/create-task.js +32 -5
- package/tools-gh/init-readme.js +68 -32
package/bin/init.js
CHANGED
|
@@ -2,29 +2,83 @@
|
|
|
2
2
|
import { fileURLToPath } from 'url'
|
|
3
3
|
import { dirname, join } from 'path'
|
|
4
4
|
import { copyFileSync, mkdirSync, existsSync, readFileSync, writeFileSync, readdirSync, statSync } from 'fs'
|
|
5
|
-
import { execSync } from 'child_process'
|
|
5
|
+
import { execSync, spawnSync } from 'child_process'
|
|
6
|
+
import * as readline from 'readline'
|
|
6
7
|
|
|
7
8
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
8
9
|
const templateDir = join(__dirname, '../templates')
|
|
9
10
|
const targetDir = process.cwd()
|
|
11
|
+
const toolsDir = join(__dirname, '../tools-gh')
|
|
10
12
|
|
|
11
13
|
console.log('⚡ JS Template by @vv0rkz — Инициализация проекта\n')
|
|
12
14
|
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
+
// Функция для интерактивного вопроса
|
|
16
|
+
function askQuestion(query) {
|
|
17
|
+
const rl = readline.createInterface({
|
|
18
|
+
input: process.stdin,
|
|
19
|
+
output: process.stdout,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return new Promise((resolve) =>
|
|
23
|
+
rl.question(query, (ans) => {
|
|
24
|
+
rl.close()
|
|
25
|
+
resolve(ans)
|
|
26
|
+
})
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 0. Проверка git репозитория
|
|
31
|
+
console.log('🔍 Проверка git...')
|
|
32
|
+
const hasGit = existsSync(join(targetDir, '.git'))
|
|
33
|
+
|
|
34
|
+
if (!hasGit) {
|
|
35
|
+
console.log(' ⚠️ Git репозиторий не найден')
|
|
36
|
+
const answer = await askQuestion(' ❓ Инициализировать git репозиторий? (Y/n): ')
|
|
37
|
+
|
|
38
|
+
if (answer.toLowerCase() !== 'n' && answer.toLowerCase() !== 'no') {
|
|
39
|
+
try {
|
|
40
|
+
execSync('git init', { stdio: 'inherit', cwd: targetDir })
|
|
41
|
+
console.log(' ✅ Git репозиторий создан')
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.log(' ❌ Ошибка создания git репозитория')
|
|
44
|
+
console.log(' Создай вручную: git init')
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
console.log(' ⏭️ Git пропущен')
|
|
48
|
+
console.log(' ⚠️ Без git некоторые функции могут не работать (husky, gh)')
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
console.log(' ✅ Git репозиторий найден')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 1. Копирование конфигов с интерактивной перезаписью
|
|
55
|
+
console.log('\n📋 Копирование конфигов...')
|
|
15
56
|
const filesToCopy = ['.gitignore', 'changelog.config.js', 'commitlint.config.js']
|
|
16
57
|
|
|
17
|
-
|
|
58
|
+
for (const file of filesToCopy) {
|
|
18
59
|
const src = join(templateDir, file)
|
|
19
60
|
const dest = join(targetDir, file)
|
|
20
61
|
|
|
62
|
+
if (!existsSync(src)) {
|
|
63
|
+
console.log(` ⚠️ ${file} не найден в template (пропускаем)`)
|
|
64
|
+
continue
|
|
65
|
+
}
|
|
66
|
+
|
|
21
67
|
if (existsSync(dest)) {
|
|
22
|
-
|
|
68
|
+
// Файл существует - спрашиваем что делать
|
|
69
|
+
const answer = await askQuestion(` ❓ ${file} уже существует. Перезаписать? (y/N): `)
|
|
70
|
+
|
|
71
|
+
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
72
|
+
copyFileSync(src, dest)
|
|
73
|
+
console.log(` ✅ ${file} (перезаписан)`)
|
|
74
|
+
} else {
|
|
75
|
+
console.log(` ⏭️ ${file} (пропущен)`)
|
|
76
|
+
}
|
|
23
77
|
} else {
|
|
24
78
|
copyFileSync(src, dest)
|
|
25
79
|
console.log(` ✅ ${file}`)
|
|
26
80
|
}
|
|
27
|
-
}
|
|
81
|
+
}
|
|
28
82
|
|
|
29
83
|
// 2. Копирование .husky
|
|
30
84
|
console.log('\n🐶 Настройка husky хуков...')
|
|
@@ -33,7 +87,6 @@ if (!existsSync(huskyDir)) {
|
|
|
33
87
|
mkdirSync(huskyDir, { recursive: true })
|
|
34
88
|
}
|
|
35
89
|
|
|
36
|
-
// Копирование всей папки .husky
|
|
37
90
|
const huskyTemplateDir = join(templateDir, '.husky')
|
|
38
91
|
if (existsSync(huskyTemplateDir)) {
|
|
39
92
|
const copyDir = (src, dest) => {
|
|
@@ -56,9 +109,11 @@ if (existsSync(huskyTemplateDir)) {
|
|
|
56
109
|
|
|
57
110
|
copyDir(huskyTemplateDir, huskyDir)
|
|
58
111
|
console.log(' ✅ Хуки скопированы')
|
|
112
|
+
} else {
|
|
113
|
+
console.log(' ⚠️ .husky не найден в template')
|
|
59
114
|
}
|
|
60
115
|
|
|
61
|
-
// 3. НЕ копируем tools-gh
|
|
116
|
+
// 3. НЕ копируем tools-gh
|
|
62
117
|
console.log('\n🔧 GitHub скрипты...')
|
|
63
118
|
console.log(' ✅ Используются из @vv0rkz/js-template (не копируются)')
|
|
64
119
|
|
|
@@ -68,7 +123,6 @@ const packageJsonPath = join(targetDir, 'package.json')
|
|
|
68
123
|
if (existsSync(packageJsonPath)) {
|
|
69
124
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
|
70
125
|
|
|
71
|
-
// Добавляем только минимум скриптов
|
|
72
126
|
packageJson.scripts = {
|
|
73
127
|
...packageJson.scripts,
|
|
74
128
|
prepare: 'husky',
|
|
@@ -76,11 +130,10 @@ if (existsSync(packageJsonPath)) {
|
|
|
76
130
|
_: 'jst',
|
|
77
131
|
}
|
|
78
132
|
|
|
79
|
-
// Добавляем зависимость
|
|
80
133
|
if (!packageJson.devDependencies) {
|
|
81
134
|
packageJson.devDependencies = {}
|
|
82
135
|
}
|
|
83
|
-
packageJson.devDependencies['@vv0rkz/js-template'] = '^1.
|
|
136
|
+
packageJson.devDependencies['@vv0rkz/js-template'] = '^1.4.0'
|
|
84
137
|
|
|
85
138
|
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
86
139
|
console.log(' ✅ Скрипты добавлены')
|
|
@@ -107,6 +160,7 @@ try {
|
|
|
107
160
|
} catch (error) {
|
|
108
161
|
console.log(' ⚠️ Husky уже инициализирован')
|
|
109
162
|
}
|
|
163
|
+
|
|
110
164
|
// 7. Настройка GitHub labels
|
|
111
165
|
console.log('\n🏷️ Настройка GitHub labels...')
|
|
112
166
|
try {
|
package/package.json
CHANGED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
{{PROJECT_DESCRIPTION}}
|
|
4
|
+
|
|
5
|
+
<!-- AUTOGENERATED_SECTION START -->
|
|
6
|
+
<!-- AUTOGENERATED_SECTION END -->
|
|
7
|
+
|
|
8
|
+
## 🛠️ Для разработчиков
|
|
9
|
+
|
|
10
|
+
### 📋 Workflow разработки
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
[ Придумал фичу / Нашёл баг ]
|
|
14
|
+
↓
|
|
15
|
+
[ Создание задачи ] → npm run _ create-task/create-bug
|
|
16
|
+
↓
|
|
17
|
+
[ Разработка в ветке vX.Y.Z-description ]
|
|
18
|
+
↓
|
|
19
|
+
[ Коммиты с валидацией ] → feat/fix: #номер описание
|
|
20
|
+
↓
|
|
21
|
+
[ Добавление демо ] → docs/vX.Y.Z.gif
|
|
22
|
+
↓
|
|
23
|
+
[ Релиз ] → npm run _ release
|
|
24
|
+
↓
|
|
25
|
+
[ Авто-обновление CHANGELOG, README ]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**🚀 Пример (калькулятор):**
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# 1) Создание задачи
|
|
32
|
+
npm run _ create-task "Нормализация чисел: 0123 → 123"
|
|
33
|
+
# → Создаётся issue #9
|
|
34
|
+
|
|
35
|
+
# 2) Создание ветки в формате vX.Y.Z-description
|
|
36
|
+
git checkout -b v2.3.0-normalize-numbers
|
|
37
|
+
|
|
38
|
+
# 3) Коммиты в формате feat: #N (где #N номер созданного issue)
|
|
39
|
+
git commit -m "feat: #9 добавлена нормализация чисел"
|
|
40
|
+
|
|
41
|
+
# 4) Релиз
|
|
42
|
+
npm run _ release
|
|
43
|
+
# ✅ Создаётся:
|
|
44
|
+
# - CHANGELOG.md с фичей #9
|
|
45
|
+
# - Git tag v2.3.0
|
|
46
|
+
# - README обновляется автономно
|
|
47
|
+
📋 Бэклог задач:
|
|
48
|
+
|
|
49
|
+
Открытые задачи (tasks)
|
|
50
|
+
|
|
51
|
+
Активные баги (bugs)
|
|
52
|
+
|
|
53
|
+
Все issues
|
|
54
|
+
|
|
55
|
+
🔧 Workflow
|
|
56
|
+
Проект использует @vv0rkz/js-template для автоматизации:
|
|
57
|
+
|
|
58
|
+
✅ Git hooks (husky) — проверка коммитов
|
|
59
|
+
|
|
60
|
+
✅ Changelog генерация (changelogen)
|
|
61
|
+
|
|
62
|
+
✅ GitHub issues integration
|
|
63
|
+
|
|
64
|
+
✅ Автоматическое обновление версий
|
|
65
|
+
|
|
66
|
+
📄 Лицензия
|
|
67
|
+
{{LICENSE}} © {{AUTHOR}}
|
|
68
|
+
|
|
69
|
+
Создано с помощью @vv0rkz/js-template
|
|
70
|
+
```
|
package/tools-gh/create-bug.js
CHANGED
|
@@ -11,6 +11,8 @@ if (!title) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
|
+
console.log('🐛 Создаю баг...')
|
|
15
|
+
|
|
14
16
|
// Создаем issue в GitHub
|
|
15
17
|
execSync(`gh issue create --title "Bug: ${title}" --body "Баг обнаружен" --label "bug" --assignee "@me"`, {
|
|
16
18
|
stdio: 'inherit',
|
|
@@ -18,9 +20,34 @@ try {
|
|
|
18
20
|
|
|
19
21
|
console.log('🐛 Баг зарегистрирован!')
|
|
20
22
|
} catch (error) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
// Если ошибка с label - создаём его автоматически
|
|
24
|
+
if (error.message.includes("'bug' not found") || error.stderr?.includes("'bug' not found")) {
|
|
25
|
+
console.log("\n⚠️ Label 'bug' не найден. Создаю автоматически...")
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
// Создаём label
|
|
29
|
+
execSync('gh label create bug --color "D73A4A" --description "Баг который нужно исправить"', { stdio: 'ignore' })
|
|
30
|
+
console.log("✅ Label 'bug' создан")
|
|
31
|
+
|
|
32
|
+
// Пытаемся создать баг ещё раз
|
|
33
|
+
console.log('🐛 Создаю баг...')
|
|
34
|
+
execSync(`gh issue create --title "Bug: ${title}" --body "Баг обнаружен" --label "bug" --assignee "@me"`, {
|
|
35
|
+
stdio: 'inherit',
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
console.log('🐛 Баг зарегистрирован!')
|
|
39
|
+
} catch (retryError) {
|
|
40
|
+
console.error('❌ Ошибка создания бага:', retryError.message)
|
|
41
|
+
console.log('\n💡 Попробуй:')
|
|
42
|
+
console.log(' npm run _ setup-labels')
|
|
43
|
+
process.exit(1)
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
console.error('❌ Ошибка создания бага:', error.message)
|
|
47
|
+
console.log('\n💡 Убедись что:')
|
|
48
|
+
console.log(' 1. Установлен GitHub CLI: gh --version')
|
|
49
|
+
console.log(' 2. Выполнена авторизация: gh auth login')
|
|
50
|
+
console.log(' 3. Создан репозиторий на GitHub')
|
|
51
|
+
process.exit(1)
|
|
52
|
+
}
|
|
26
53
|
}
|
package/tools-gh/create-task.js
CHANGED
|
@@ -12,15 +12,42 @@ if (!title) {
|
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
14
|
console.log('📝 Создаю задачу...')
|
|
15
|
+
|
|
16
|
+
// Пытаемся создать задачу с label
|
|
15
17
|
execSync(`gh issue create --title "Task: ${title}" --body "Задача: ${title}" --label "task"`, {
|
|
16
18
|
stdio: 'inherit',
|
|
17
19
|
})
|
|
18
20
|
|
|
19
21
|
console.log('✅ Задача создана! Используй номер в коммитах: feat: #номер описание')
|
|
20
22
|
} catch (error) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
// Если ошибка с label - создаём его автоматически
|
|
24
|
+
if (error.message.includes("'task' not found") || error.stderr?.includes("'task' not found")) {
|
|
25
|
+
console.log("\n⚠️ Label 'task' не найден. Создаю автоматически...")
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
// Создаём label
|
|
29
|
+
execSync('gh label create task --color "0E8A16" --description "Задача для реализации"', { stdio: 'ignore' })
|
|
30
|
+
console.log("✅ Label 'task' создан")
|
|
31
|
+
|
|
32
|
+
// Пытаемся создать задачу ещё раз
|
|
33
|
+
console.log('📝 Создаю задачу...')
|
|
34
|
+
execSync(`gh issue create --title "Task: ${title}" --body "Задача: ${title}" --label "task"`, {
|
|
35
|
+
stdio: 'inherit',
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
console.log('✅ Задача создана!')
|
|
39
|
+
} catch (retryError) {
|
|
40
|
+
console.error('❌ Ошибка создания задачи:', retryError.message)
|
|
41
|
+
console.log('\n💡 Попробуй:')
|
|
42
|
+
console.log(' npm run _ setup-labels')
|
|
43
|
+
process.exit(1)
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
console.error('❌ Ошибка создания задачи:', error.message)
|
|
47
|
+
console.log('\n💡 Убедись что:')
|
|
48
|
+
console.log(' 1. Установлен GitHub CLI: gh --version')
|
|
49
|
+
console.log(' 2. Выполнена авторизация: gh auth login')
|
|
50
|
+
console.log(' 3. Создан репозиторий на GitHub')
|
|
51
|
+
process.exit(1)
|
|
52
|
+
}
|
|
26
53
|
}
|
package/tools-gh/init-readme.js
CHANGED
|
@@ -1,61 +1,97 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync, writeFileSync, existsSync } from 'fs'
|
|
3
|
+
import { fileURLToPath } from 'url'
|
|
4
|
+
import { dirname, join } from 'path'
|
|
5
|
+
import * as readline from 'readline'
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const templateDir = join(__dirname, '../templates')
|
|
3
9
|
|
|
4
10
|
console.log('📝 Генерация стартового README.md...')
|
|
5
11
|
|
|
12
|
+
// Функция для интерактивного вопроса
|
|
13
|
+
function askQuestion(query) {
|
|
14
|
+
const rl = readline.createInterface({
|
|
15
|
+
input: process.stdin,
|
|
16
|
+
output: process.stdout,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
return new Promise((resolve) =>
|
|
20
|
+
rl.question(query, (ans) => {
|
|
21
|
+
rl.close()
|
|
22
|
+
resolve(ans)
|
|
23
|
+
})
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Проверяем существование README
|
|
28
|
+
if (existsSync('README.md')) {
|
|
29
|
+
const answer = await askQuestion('⚠️ README.md уже существует. Перезаписать? (y/N): ')
|
|
30
|
+
|
|
31
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
32
|
+
console.log('⏭️ Создание README отменено')
|
|
33
|
+
process.exit(0)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log('✅ README.md будет перезаписан\n')
|
|
37
|
+
}
|
|
38
|
+
|
|
6
39
|
// Читаем package.json
|
|
7
40
|
const packageJson = JSON.parse(readFileSync('package.json', 'utf8'))
|
|
8
41
|
|
|
9
|
-
const projectName = packageJson.name
|
|
42
|
+
const projectName = packageJson.name || 'Project'
|
|
10
43
|
const description = packageJson.description || 'Описание проекта'
|
|
11
44
|
const author = packageJson.author || 'vv0rkz'
|
|
12
45
|
const license = packageJson.license || 'MIT'
|
|
13
|
-
const repoUrl = packageJson.repository?.url?.replace('git+', '').replace('.git', '') || ''
|
|
14
|
-
|
|
15
|
-
// Минималистичный шаблон README
|
|
16
|
-
const readmeTemplate = `# ${projectName}
|
|
17
46
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
47
|
+
// Получаем URL репозитория
|
|
48
|
+
let repoUrl = ''
|
|
49
|
+
if (packageJson.repository?.url) {
|
|
50
|
+
repoUrl = packageJson.repository.url.replace('git+', '').replace('.git', '')
|
|
51
|
+
} else {
|
|
52
|
+
repoUrl = `https://github.com/${author}/${projectName}`
|
|
53
|
+
}
|
|
21
54
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
55
|
+
// Читаем шаблон
|
|
56
|
+
const templatePath = join(templateDir, 'README.md')
|
|
57
|
+
let readmeContent = ''
|
|
25
58
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
\`\`\`
|
|
59
|
+
if (existsSync(templatePath)) {
|
|
60
|
+
readmeContent = readFileSync(templatePath, 'utf8')
|
|
29
61
|
|
|
30
|
-
|
|
62
|
+
// Подставляем значения
|
|
63
|
+
readmeContent = readmeContent
|
|
64
|
+
.replace(/\{\{PROJECT_NAME\}\}/g, projectName)
|
|
65
|
+
.replace(/\{\{PROJECT_DESCRIPTION\}\}/g, description)
|
|
66
|
+
.replace(/\{\{REPO_URL\}\}/g, repoUrl)
|
|
67
|
+
.replace(/\{\{AUTHOR\}\}/g, author)
|
|
68
|
+
.replace(/\{\{LICENSE\}\}/g, license)
|
|
31
69
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
\`\`\`
|
|
70
|
+
console.log('✅ README.md создан из шаблона!')
|
|
71
|
+
} else {
|
|
72
|
+
// Fallback если шаблона нет
|
|
73
|
+
readmeContent = `# ${projectName}
|
|
37
74
|
|
|
38
|
-
|
|
75
|
+
${description}
|
|
39
76
|
|
|
40
77
|
<!-- AUTOGENERATED_SECTION START -->
|
|
41
78
|
<!-- AUTOGENERATED_SECTION END -->
|
|
42
79
|
|
|
80
|
+
## 🔧 Workflow
|
|
81
|
+
|
|
82
|
+
Проект использует [@vv0rkz/js-template](https://github.com/vv0rkz/js-template)
|
|
83
|
+
|
|
43
84
|
## 📄 Лицензия
|
|
44
85
|
|
|
45
|
-
${license} © ${author}
|
|
86
|
+
${license} © [${author}](${repoUrl})
|
|
46
87
|
`
|
|
47
|
-
|
|
48
|
-
// Проверяем существование README
|
|
49
|
-
if (existsSync('README.md')) {
|
|
50
|
-
console.log('⚠️ README.md уже существует')
|
|
51
|
-
console.log('💡 Удали файл или переименуй, чтобы создать новый')
|
|
52
|
-
process.exit(1)
|
|
88
|
+
console.log('✅ README.md создан (fallback)!')
|
|
53
89
|
}
|
|
54
90
|
|
|
55
|
-
// Сохраняем
|
|
56
|
-
writeFileSync('README.md',
|
|
57
|
-
|
|
91
|
+
// Сохраняем
|
|
92
|
+
writeFileSync('README.md', readmeContent)
|
|
93
|
+
|
|
58
94
|
console.log('\n📝 Теперь:')
|
|
59
|
-
console.log(' 1. Отредактируй
|
|
95
|
+
console.log(' 1. Отредактируй README.md под свой проект')
|
|
60
96
|
console.log(' 2. Добавь скриншоты/демо')
|
|
61
97
|
console.log(' 3. npm run _ update-readme — для обновления истории версий')
|