@icarusmx/creta 1.2.1 → 1.3.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/creta.js +21 -25
- package/lib/pr-tutorial.js +604 -0
- package/package.json +1 -1
package/bin/creta.js
CHANGED
|
@@ -6,6 +6,7 @@ import fs from 'fs'
|
|
|
6
6
|
import path from 'path'
|
|
7
7
|
import { fileURLToPath } from 'url'
|
|
8
8
|
import { CretaCodeSession } from '../lib/session.js'
|
|
9
|
+
import { PullRequestTutorial } from '../lib/pr-tutorial.js'
|
|
9
10
|
import { Lesson1SystemDecomposition } from '../lessons/lesson1-system-decomposition.js'
|
|
10
11
|
import { Lesson2ObjectRequests } from '../lessons/lesson2-object-requests.js'
|
|
11
12
|
import { Lesson3OnlyWay } from '../lessons/lesson3-only-way.js'
|
|
@@ -1414,33 +1415,28 @@ async function startProyectosSelectorFallback() {
|
|
|
1414
1415
|
}
|
|
1415
1416
|
|
|
1416
1417
|
async function startPullRequestTutorial() {
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
console.log("")
|
|
1421
|
-
console.log("📚 Aprenderás:")
|
|
1422
|
-
console.log(" • Cómo hacer fork de un repositorio")
|
|
1423
|
-
console.log(" • Crear una rama (branch) para tu cambio")
|
|
1424
|
-
console.log(" • Hacer commits con buenas prácticas")
|
|
1425
|
-
console.log(" • Crear una pull request profesional")
|
|
1426
|
-
console.log("")
|
|
1427
|
-
console.log("🚧 [PRÓXIMAMENTE]")
|
|
1428
|
-
console.log("")
|
|
1429
|
-
console.log("Esta funcionalidad está en desarrollo.")
|
|
1430
|
-
console.log("Pronto podrás practicar el flujo completo de contribución.")
|
|
1431
|
-
console.log("")
|
|
1418
|
+
try {
|
|
1419
|
+
const tutorial = new PullRequestTutorial()
|
|
1420
|
+
await tutorial.start()
|
|
1432
1421
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1422
|
+
// Volver al menú principal después de completar el tutorial
|
|
1423
|
+
await returnToMainMenu()
|
|
1424
|
+
} catch (error) {
|
|
1425
|
+
console.error("\n❌ Error al ejecutar el tutorial:", error.message)
|
|
1426
|
+
console.log("\nSi el problema persiste, contacta al equipo de Creta.")
|
|
1437
1427
|
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
resolve()
|
|
1428
|
+
const rl = createInterface({
|
|
1429
|
+
input: process.stdin,
|
|
1430
|
+
output: process.stdout
|
|
1442
1431
|
})
|
|
1443
|
-
})
|
|
1444
1432
|
|
|
1445
|
-
|
|
1433
|
+
await new Promise((resolve) => {
|
|
1434
|
+
rl.question("\nPresiona Enter para volver al menú principal...", () => {
|
|
1435
|
+
rl.close()
|
|
1436
|
+
resolve()
|
|
1437
|
+
})
|
|
1438
|
+
})
|
|
1439
|
+
|
|
1440
|
+
await startMainMenu()
|
|
1441
|
+
}
|
|
1446
1442
|
}
|
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Tutorial interactivo: Crea una Pull Request
|
|
4
|
+
// Guía paso a paso para aprender el flujo completo de contribución con Git
|
|
5
|
+
|
|
6
|
+
import { createInterface } from 'readline'
|
|
7
|
+
import { execSync } from 'child_process'
|
|
8
|
+
import fs from 'fs'
|
|
9
|
+
import path from 'path'
|
|
10
|
+
|
|
11
|
+
export class PullRequestTutorial {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.rl = createInterface({
|
|
14
|
+
input: process.stdin,
|
|
15
|
+
output: process.stdout
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
// Repo de práctica (usaremos el mismo repo de Creta)
|
|
19
|
+
this.practiceRepo = 'icarusmx/creta-practice'
|
|
20
|
+
this.repoUrl = `https://github.com/${this.practiceRepo}`
|
|
21
|
+
this.projectDir = null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async start() {
|
|
25
|
+
await this.introduction()
|
|
26
|
+
await this.checkPrerequisites()
|
|
27
|
+
await this.step1_ForkExplanation()
|
|
28
|
+
await this.step2_CloneRepo()
|
|
29
|
+
await this.step3_CreateBranch()
|
|
30
|
+
await this.step4_MakeChanges()
|
|
31
|
+
await this.step5_CommitChanges()
|
|
32
|
+
await this.step6_PushBranch()
|
|
33
|
+
await this.step7_CreatePR()
|
|
34
|
+
await this.conclusion()
|
|
35
|
+
|
|
36
|
+
this.rl.close()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async introduction() {
|
|
40
|
+
console.clear()
|
|
41
|
+
console.log("🔀 Tutorial: Crea tu primera Pull Request")
|
|
42
|
+
console.log("=" .repeat(50))
|
|
43
|
+
console.log("")
|
|
44
|
+
console.log("📚 En este tutorial aprenderás:")
|
|
45
|
+
console.log("")
|
|
46
|
+
console.log("1. Qué es una Pull Request y por qué son importantes")
|
|
47
|
+
console.log("2. Cómo hacer fork de un repositorio")
|
|
48
|
+
console.log("3. Cómo crear una rama (branch) para tu cambio")
|
|
49
|
+
console.log("4. Cómo hacer commits con buenas prácticas")
|
|
50
|
+
console.log("5. Cómo crear una Pull Request profesional")
|
|
51
|
+
console.log("")
|
|
52
|
+
console.log("⏱️ Duración estimada: 10-15 minutos")
|
|
53
|
+
console.log("")
|
|
54
|
+
console.log("💡 Tip: Tendrás que ejecutar comandos reales en tu terminal.")
|
|
55
|
+
console.log(" ¡No te preocupes! Te guiaremos paso a paso.")
|
|
56
|
+
|
|
57
|
+
await this.waitForEnter("\nPresiona Enter para comenzar...")
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async checkPrerequisites() {
|
|
61
|
+
console.clear()
|
|
62
|
+
console.log("🔍 Verificando prerequisitos...")
|
|
63
|
+
console.log("=" .repeat(50))
|
|
64
|
+
console.log("")
|
|
65
|
+
|
|
66
|
+
// Check git
|
|
67
|
+
console.log("Verificando Git...")
|
|
68
|
+
try {
|
|
69
|
+
const gitVersion = execSync('git --version', { encoding: 'utf8' }).trim()
|
|
70
|
+
console.log(`✅ ${gitVersion}`)
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.log("❌ Git no está instalado")
|
|
73
|
+
console.log("")
|
|
74
|
+
console.log("Por favor instala Git:")
|
|
75
|
+
console.log(" macOS: brew install git")
|
|
76
|
+
console.log(" Linux: sudo apt install git")
|
|
77
|
+
console.log(" Windows: https://git-scm.com/download/win")
|
|
78
|
+
console.log("")
|
|
79
|
+
await this.waitForEnter("Presiona Enter para salir...")
|
|
80
|
+
process.exit(1)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log("")
|
|
84
|
+
|
|
85
|
+
// Check GitHub CLI
|
|
86
|
+
console.log("Verificando GitHub CLI (gh)...")
|
|
87
|
+
try {
|
|
88
|
+
const ghVersion = execSync('gh --version', { encoding: 'utf8' }).trim().split('\n')[0]
|
|
89
|
+
console.log(`✅ ${ghVersion}`)
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.log("❌ GitHub CLI (gh) no está instalado")
|
|
92
|
+
console.log("")
|
|
93
|
+
console.log("Por favor instala gh:")
|
|
94
|
+
console.log(" macOS: brew install gh")
|
|
95
|
+
console.log(" Linux: Ver https://github.com/cli/cli/blob/trunk/docs/install_linux.md")
|
|
96
|
+
console.log(" Windows: Ver https://github.com/cli/cli#installation")
|
|
97
|
+
console.log("")
|
|
98
|
+
console.log("Después de instalar, ejecuta: gh auth login")
|
|
99
|
+
console.log("")
|
|
100
|
+
await this.waitForEnter("Presiona Enter para salir...")
|
|
101
|
+
process.exit(1)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log("")
|
|
105
|
+
|
|
106
|
+
// Check gh authentication
|
|
107
|
+
console.log("Verificando autenticación en GitHub...")
|
|
108
|
+
try {
|
|
109
|
+
execSync('gh auth status', { encoding: 'utf8', stdio: 'pipe' })
|
|
110
|
+
console.log("✅ Autenticado en GitHub")
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.log("❌ No estás autenticado en GitHub")
|
|
113
|
+
console.log("")
|
|
114
|
+
console.log("Por favor ejecuta: gh auth login")
|
|
115
|
+
console.log("Y sigue las instrucciones para autenticarte.")
|
|
116
|
+
console.log("")
|
|
117
|
+
await this.waitForEnter("Presiona Enter para salir...")
|
|
118
|
+
process.exit(1)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.log("")
|
|
122
|
+
console.log("🎉 ¡Todo listo! Tienes todas las herramientas necesarias.")
|
|
123
|
+
|
|
124
|
+
await this.waitForEnter("\nPresiona Enter para continuar...")
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async step1_ForkExplanation() {
|
|
128
|
+
console.clear()
|
|
129
|
+
console.log("Paso 1: Entender el Fork")
|
|
130
|
+
console.log("=" .repeat(50))
|
|
131
|
+
console.log("")
|
|
132
|
+
console.log("🤔 ¿Qué es un fork?")
|
|
133
|
+
console.log("")
|
|
134
|
+
console.log("Un fork es una COPIA de un repositorio que queda en TU cuenta de GitHub.")
|
|
135
|
+
console.log("Es como sacar una fotocopia de un libro para poder escribir en él.")
|
|
136
|
+
console.log("")
|
|
137
|
+
console.log("¿Por qué necesitamos hacer fork?")
|
|
138
|
+
console.log(" • No tienes permisos para modificar el repositorio original")
|
|
139
|
+
console.log(" • Trabajas en tu copia sin afectar el original")
|
|
140
|
+
console.log(" • Después propones tus cambios mediante una Pull Request")
|
|
141
|
+
|
|
142
|
+
await this.waitForEnter("\nPresiona Enter para hacer el fork...")
|
|
143
|
+
|
|
144
|
+
console.log("")
|
|
145
|
+
console.log("📋 Vamos a hacer fork del repositorio de práctica de Creta:")
|
|
146
|
+
console.log(` ${this.repoUrl}`)
|
|
147
|
+
console.log("")
|
|
148
|
+
console.log("Ejecutando: gh repo fork icarusmx/creta-practice --clone=false")
|
|
149
|
+
console.log("")
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
// Primero verificar si el repo existe o si ya tiene un fork
|
|
153
|
+
try {
|
|
154
|
+
const checkFork = execSync(`gh repo view ${this.practiceRepo}`, {
|
|
155
|
+
encoding: 'utf8',
|
|
156
|
+
stdio: 'pipe'
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
// Si llegamos aquí, el repo existe, intentar hacer fork
|
|
160
|
+
try {
|
|
161
|
+
execSync(`gh repo fork ${this.practiceRepo} --clone=false`, {
|
|
162
|
+
encoding: 'utf8',
|
|
163
|
+
stdio: 'inherit'
|
|
164
|
+
})
|
|
165
|
+
console.log("✅ Fork creado exitosamente")
|
|
166
|
+
} catch (forkError) {
|
|
167
|
+
// Probablemente ya tiene un fork
|
|
168
|
+
console.log("ℹ️ Ya tienes un fork de este repositorio")
|
|
169
|
+
}
|
|
170
|
+
} catch (repoError) {
|
|
171
|
+
console.log("⚠️ El repositorio de práctica aún no existe.")
|
|
172
|
+
console.log("")
|
|
173
|
+
console.log("Por ahora, practicaremos con el repositorio de Creta CLI:")
|
|
174
|
+
this.practiceRepo = 'icarusmx/creta'
|
|
175
|
+
this.repoUrl = `https://github.com/${this.practiceRepo}`
|
|
176
|
+
|
|
177
|
+
console.log("")
|
|
178
|
+
console.log(`Haciendo fork de: ${this.repoUrl}`)
|
|
179
|
+
console.log("")
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
execSync(`gh repo fork ${this.practiceRepo} --clone=false`, {
|
|
183
|
+
encoding: 'utf8',
|
|
184
|
+
stdio: 'inherit'
|
|
185
|
+
})
|
|
186
|
+
console.log("✅ Fork creado exitosamente")
|
|
187
|
+
} catch (forkError) {
|
|
188
|
+
console.log("ℹ️ Ya tienes un fork de este repositorio")
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.log("❌ Error al hacer fork:", error.message)
|
|
193
|
+
console.log("")
|
|
194
|
+
console.log("Puedes hacer fork manualmente en:")
|
|
195
|
+
console.log(`${this.repoUrl}`)
|
|
196
|
+
console.log("(Click en el botón 'Fork' en la esquina superior derecha)")
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
await this.waitForEnter("\nPresiona Enter para continuar al siguiente paso...")
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async step2_CloneRepo() {
|
|
203
|
+
console.clear()
|
|
204
|
+
console.log("Paso 2: Clonar tu Fork")
|
|
205
|
+
console.log("=" .repeat(50))
|
|
206
|
+
console.log("")
|
|
207
|
+
console.log("🤔 ¿Qué es clonar?")
|
|
208
|
+
console.log("")
|
|
209
|
+
console.log("Clonar es DESCARGAR una copia del repositorio a tu computadora.")
|
|
210
|
+
console.log("Ahora trabajarás en tu máquina local, no en GitHub.")
|
|
211
|
+
console.log("")
|
|
212
|
+
console.log("¿Por qué clonar tu fork y no el original?")
|
|
213
|
+
console.log(" • Tu fork está en tu cuenta, puedes hacer push a él")
|
|
214
|
+
console.log(" • El original no aceptaría tus cambios directos")
|
|
215
|
+
|
|
216
|
+
await this.waitForEnter("\nPresiona Enter para clonar...")
|
|
217
|
+
|
|
218
|
+
console.log("")
|
|
219
|
+
console.log("🔧 Ahora necesitamos clonar TU fork (no el original)")
|
|
220
|
+
console.log("")
|
|
221
|
+
|
|
222
|
+
// Obtener el username de GitHub
|
|
223
|
+
let username
|
|
224
|
+
try {
|
|
225
|
+
const authStatus = execSync('gh api user --jq .login', { encoding: 'utf8' }).trim()
|
|
226
|
+
username = authStatus
|
|
227
|
+
console.log(`Tu usuario de GitHub: ${username}`)
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.log("No pudimos obtener tu usuario automáticamente.")
|
|
230
|
+
username = await this.askQuestion("¿Cuál es tu usuario de GitHub? ")
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const forkUrl = `https://github.com/${username}/${this.practiceRepo.split('/')[1]}`
|
|
234
|
+
const projectName = this.practiceRepo.split('/')[1]
|
|
235
|
+
|
|
236
|
+
console.log("")
|
|
237
|
+
console.log(`Clonando: ${forkUrl}`)
|
|
238
|
+
console.log("")
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
// Verificar si ya existe el directorio
|
|
242
|
+
if (fs.existsSync(projectName)) {
|
|
243
|
+
console.log(`ℹ️ El directorio '${projectName}' ya existe.`)
|
|
244
|
+
const useExisting = await this.askQuestion("¿Quieres usar este directorio? (s/n): ")
|
|
245
|
+
|
|
246
|
+
if (useExisting.toLowerCase() === 's') {
|
|
247
|
+
this.projectDir = path.resolve(projectName)
|
|
248
|
+
console.log(`✅ Usando directorio existente: ${this.projectDir}`)
|
|
249
|
+
} else {
|
|
250
|
+
console.log("Por favor elimina o renombra el directorio y vuelve a intentar.")
|
|
251
|
+
process.exit(0)
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
console.log(`Ejecutando: git clone ${forkUrl}`)
|
|
255
|
+
execSync(`git clone ${forkUrl}`, { encoding: 'utf8', stdio: 'inherit' })
|
|
256
|
+
this.projectDir = path.resolve(projectName)
|
|
257
|
+
console.log(`✅ Repositorio clonado en: ${this.projectDir}`)
|
|
258
|
+
}
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.log("❌ Error al clonar:", error.message)
|
|
261
|
+
process.exit(1)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
await this.waitForEnter("\nPresiona Enter para continuar al siguiente paso...")
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async step3_CreateBranch() {
|
|
268
|
+
console.clear()
|
|
269
|
+
console.log("Paso 3: Crear una Rama (Branch)")
|
|
270
|
+
console.log("=" .repeat(50))
|
|
271
|
+
console.log("")
|
|
272
|
+
console.log("🤔 ¿Qué es una rama?")
|
|
273
|
+
console.log("")
|
|
274
|
+
console.log("Una rama es una LÍNEA DE DESARROLLO independiente.")
|
|
275
|
+
console.log("Es como trabajar en una copia paralela del código.")
|
|
276
|
+
console.log("")
|
|
277
|
+
console.log("¿Por qué crear una rama?")
|
|
278
|
+
console.log(" • No modificas la rama principal (main) directamente")
|
|
279
|
+
console.log(" • Puedes experimentar sin romper nada")
|
|
280
|
+
console.log(" • Facilita el code review")
|
|
281
|
+
console.log(" • Es la práctica estándar en equipos profesionales")
|
|
282
|
+
|
|
283
|
+
await this.waitForEnter("\nPresiona Enter para crear tu rama...")
|
|
284
|
+
|
|
285
|
+
console.log("")
|
|
286
|
+
console.log("💡 Reglas para nombres de ramas:")
|
|
287
|
+
console.log(" • Descriptivos y cortos")
|
|
288
|
+
console.log(" • En minúsculas, separados por guiones")
|
|
289
|
+
console.log(" • Ejemplos: fix-navbar, add-login, update-readme")
|
|
290
|
+
console.log("")
|
|
291
|
+
|
|
292
|
+
const defaultBranchName = "mi-primera-contribucion"
|
|
293
|
+
const branchName = await this.askQuestion(`Nombre de tu rama [${defaultBranchName}]: `) || defaultBranchName
|
|
294
|
+
|
|
295
|
+
console.log("")
|
|
296
|
+
console.log(`Ejecutando: git checkout -b ${branchName}`)
|
|
297
|
+
console.log("")
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
process.chdir(this.projectDir)
|
|
301
|
+
execSync(`git checkout -b ${branchName}`, { encoding: 'utf8', stdio: 'inherit' })
|
|
302
|
+
console.log(`✅ Rama '${branchName}' creada y seleccionada`)
|
|
303
|
+
} catch (error) {
|
|
304
|
+
console.log("❌ Error al crear rama:", error.message)
|
|
305
|
+
process.exit(1)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
await this.waitForEnter("\nPresiona Enter para continuar al siguiente paso...")
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async step4_MakeChanges() {
|
|
312
|
+
console.clear()
|
|
313
|
+
console.log("Paso 4: Hacer Cambios")
|
|
314
|
+
console.log("=" .repeat(50))
|
|
315
|
+
console.log("")
|
|
316
|
+
console.log("🤔 ¿Qué cambios haremos?")
|
|
317
|
+
console.log("")
|
|
318
|
+
console.log("Vamos a agregar tu nombre a un archivo de contribuidores.")
|
|
319
|
+
console.log("Este es un cambio simple y seguro para practicar.")
|
|
320
|
+
console.log("")
|
|
321
|
+
|
|
322
|
+
await this.waitForEnter("Presiona Enter para hacer el cambio...")
|
|
323
|
+
|
|
324
|
+
console.log("")
|
|
325
|
+
|
|
326
|
+
const contributorsFile = path.join(this.projectDir, 'CONTRIBUTORS.md')
|
|
327
|
+
|
|
328
|
+
// Crear archivo si no existe
|
|
329
|
+
if (!fs.existsSync(contributorsFile)) {
|
|
330
|
+
console.log("Creando archivo CONTRIBUTORS.md...")
|
|
331
|
+
fs.writeFileSync(contributorsFile, '# Contribuidores\n\nGracias a estas personas por contribuir al proyecto:\n\n')
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const name = await this.askQuestion("¿Cómo te llamas? ")
|
|
335
|
+
const date = new Date().toISOString().split('T')[0]
|
|
336
|
+
|
|
337
|
+
console.log("")
|
|
338
|
+
console.log("Agregando tu nombre al archivo...")
|
|
339
|
+
|
|
340
|
+
try {
|
|
341
|
+
const content = fs.readFileSync(contributorsFile, 'utf8')
|
|
342
|
+
const newContent = content + `- ${name} (${date})\n`
|
|
343
|
+
fs.writeFileSync(contributorsFile, newContent)
|
|
344
|
+
console.log("✅ Cambio realizado exitosamente")
|
|
345
|
+
console.log("")
|
|
346
|
+
console.log(`Tu nombre fue agregado a: ${contributorsFile}`)
|
|
347
|
+
} catch (error) {
|
|
348
|
+
console.log("❌ Error al modificar archivo:", error.message)
|
|
349
|
+
process.exit(1)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
console.log("")
|
|
353
|
+
console.log("🔍 Verificando cambios...")
|
|
354
|
+
console.log("")
|
|
355
|
+
console.log("Ejecutando: git status")
|
|
356
|
+
console.log("")
|
|
357
|
+
|
|
358
|
+
try {
|
|
359
|
+
execSync('git status', { encoding: 'utf8', stdio: 'inherit' })
|
|
360
|
+
} catch (error) {
|
|
361
|
+
// git status siempre funciona
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
await this.waitForEnter("\nPresiona Enter para continuar al siguiente paso...")
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async step5_CommitChanges() {
|
|
368
|
+
console.clear()
|
|
369
|
+
console.log("Paso 5: Hacer Commit de los Cambios")
|
|
370
|
+
console.log("=" .repeat(50))
|
|
371
|
+
console.log("")
|
|
372
|
+
console.log("🤔 ¿Qué es un commit?")
|
|
373
|
+
console.log("")
|
|
374
|
+
console.log("Un commit es un PUNTO DE GUARDADO en la historia del proyecto.")
|
|
375
|
+
console.log("Es como tomar una fotografía del estado actual del código.")
|
|
376
|
+
console.log("")
|
|
377
|
+
console.log("Cada commit tiene:")
|
|
378
|
+
console.log(" • Los cambios que hiciste")
|
|
379
|
+
console.log(" • Un mensaje describiendo QUÉ y POR QUÉ")
|
|
380
|
+
console.log(" • Tu nombre y la fecha")
|
|
381
|
+
|
|
382
|
+
await this.waitForEnter("\nPresiona Enter para hacer el commit...")
|
|
383
|
+
|
|
384
|
+
console.log("")
|
|
385
|
+
console.log("📝 Primero agregamos el archivo al staging area:")
|
|
386
|
+
console.log("Ejecutando: git add CONTRIBUTORS.md")
|
|
387
|
+
console.log("")
|
|
388
|
+
|
|
389
|
+
try {
|
|
390
|
+
execSync('git add CONTRIBUTORS.md', { encoding: 'utf8', stdio: 'inherit' })
|
|
391
|
+
console.log("✅ Archivo agregado al staging area")
|
|
392
|
+
} catch (error) {
|
|
393
|
+
console.log("❌ Error al agregar archivo:", error.message)
|
|
394
|
+
process.exit(1)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
console.log("")
|
|
398
|
+
console.log("💡 Ahora escribimos el mensaje del commit")
|
|
399
|
+
console.log("")
|
|
400
|
+
console.log("Reglas para buenos mensajes:")
|
|
401
|
+
console.log(" • Primera línea: resumen corto (50 caracteres)")
|
|
402
|
+
console.log(" • Usa imperativo: 'Agrega' no 'Agregué' ni 'Agregando'")
|
|
403
|
+
console.log(" • Sé específico: di QUÉ cambió y POR QUÉ")
|
|
404
|
+
console.log("")
|
|
405
|
+
|
|
406
|
+
const name = await this.askQuestion("¿Cómo te llamas? (para el mensaje del commit): ")
|
|
407
|
+
const commitMessage = `Agrega ${name} a la lista de contribuidores`
|
|
408
|
+
|
|
409
|
+
console.log("")
|
|
410
|
+
console.log(`Mensaje del commit: "${commitMessage}"`)
|
|
411
|
+
console.log("")
|
|
412
|
+
console.log(`Ejecutando: git commit -m "${commitMessage}"`)
|
|
413
|
+
console.log("")
|
|
414
|
+
|
|
415
|
+
try {
|
|
416
|
+
execSync(`git commit -m "${commitMessage}"`, { encoding: 'utf8', stdio: 'inherit' })
|
|
417
|
+
console.log("✅ Commit creado exitosamente")
|
|
418
|
+
} catch (error) {
|
|
419
|
+
console.log("❌ Error al crear commit:", error.message)
|
|
420
|
+
process.exit(1)
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
console.log("")
|
|
424
|
+
console.log("🎉 ¡Tu cambio ahora es parte de la historia del repositorio!")
|
|
425
|
+
console.log("")
|
|
426
|
+
console.log("Puedes verlo con: git log --oneline")
|
|
427
|
+
|
|
428
|
+
await this.waitForEnter("\nPresiona Enter para continuar al siguiente paso...")
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async step6_PushBranch() {
|
|
432
|
+
console.clear()
|
|
433
|
+
console.log("Paso 6: Subir los Cambios a GitHub (Push)")
|
|
434
|
+
console.log("=" .repeat(50))
|
|
435
|
+
console.log("")
|
|
436
|
+
console.log("🤔 ¿Qué es push?")
|
|
437
|
+
console.log("")
|
|
438
|
+
console.log("Push es SUBIR tus commits locales a GitHub.")
|
|
439
|
+
console.log("Hasta ahora todo estaba solo en tu computadora.")
|
|
440
|
+
console.log("")
|
|
441
|
+
console.log("¿Por qué hacer push?")
|
|
442
|
+
console.log(" • Respalda tu trabajo en la nube")
|
|
443
|
+
console.log(" • Otros pueden ver tus cambios")
|
|
444
|
+
console.log(" • Es necesario para crear la Pull Request")
|
|
445
|
+
|
|
446
|
+
await this.waitForEnter("\nPresiona Enter para hacer push...")
|
|
447
|
+
|
|
448
|
+
console.log("")
|
|
449
|
+
console.log("🚀 Subiendo tu rama a GitHub...")
|
|
450
|
+
console.log("")
|
|
451
|
+
|
|
452
|
+
// Obtener el nombre de la rama actual
|
|
453
|
+
let branchName
|
|
454
|
+
try {
|
|
455
|
+
branchName = execSync('git branch --show-current', { encoding: 'utf8' }).trim()
|
|
456
|
+
} catch (error) {
|
|
457
|
+
branchName = 'tu-rama'
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
console.log(`Ejecutando: git push origin ${branchName}`)
|
|
461
|
+
console.log("")
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
execSync(`git push -u origin ${branchName}`, { encoding: 'utf8', stdio: 'inherit' })
|
|
465
|
+
console.log("")
|
|
466
|
+
console.log("✅ Cambios subidos exitosamente a GitHub")
|
|
467
|
+
} catch (error) {
|
|
468
|
+
console.log("❌ Error al hacer push:", error.message)
|
|
469
|
+
console.log("")
|
|
470
|
+
console.log("Si el error es de autenticación, verifica que estés autenticado con gh.")
|
|
471
|
+
process.exit(1)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
console.log("")
|
|
475
|
+
console.log("🎉 ¡Tu rama ya está en GitHub!")
|
|
476
|
+
console.log("Ahora cualquiera puede ver tus cambios.")
|
|
477
|
+
|
|
478
|
+
await this.waitForEnter("\nPresiona Enter para continuar al siguiente paso...")
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async step7_CreatePR() {
|
|
482
|
+
console.clear()
|
|
483
|
+
console.log("Paso 7: Crear la Pull Request")
|
|
484
|
+
console.log("=" .repeat(50))
|
|
485
|
+
console.log("")
|
|
486
|
+
console.log("🤔 ¿Qué es una Pull Request (PR)?")
|
|
487
|
+
console.log("")
|
|
488
|
+
console.log("Una PR es una PROPUESTA de cambios al repositorio original.")
|
|
489
|
+
console.log("Es como decir: 'Mira los cambios que hice, ¿los aceptas?'")
|
|
490
|
+
console.log("")
|
|
491
|
+
console.log("¿Qué pasa después de crear una PR?")
|
|
492
|
+
console.log(" • Los mantenedores revisan tu código")
|
|
493
|
+
console.log(" • Pueden pedirte cambios")
|
|
494
|
+
console.log(" • Si todo está bien, la aceptan (merge)")
|
|
495
|
+
console.log(" • Tus cambios quedan en el proyecto original")
|
|
496
|
+
|
|
497
|
+
await this.waitForEnter("\nPresiona Enter para crear la PR...")
|
|
498
|
+
|
|
499
|
+
console.log("")
|
|
500
|
+
console.log("📝 Vamos a crear la PR con información descriptiva")
|
|
501
|
+
console.log("")
|
|
502
|
+
|
|
503
|
+
const prTitle = await this.askQuestion("Título de la PR [Agrega nuevo contribuidor]: ") || "Agrega nuevo contribuidor"
|
|
504
|
+
|
|
505
|
+
console.log("")
|
|
506
|
+
console.log("💡 El cuerpo de la PR debe explicar:")
|
|
507
|
+
console.log(" • QUÉ cambios hiciste")
|
|
508
|
+
console.log(" • POR QUÉ los hiciste")
|
|
509
|
+
console.log(" • CÓMO probaste que funcionan")
|
|
510
|
+
console.log("")
|
|
511
|
+
|
|
512
|
+
const prBody = `## Descripción
|
|
513
|
+
|
|
514
|
+
Agregué mi nombre a la lista de contribuidores como parte del tutorial de Creta.
|
|
515
|
+
|
|
516
|
+
## Checklist
|
|
517
|
+
|
|
518
|
+
- [x] El código sigue las convenciones del proyecto
|
|
519
|
+
- [x] He probado mis cambios localmente
|
|
520
|
+
- [x] Los cambios no rompen funcionalidad existente
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
🏛️ Creado con [Creta](https://github.com/icarusmx/creta) - Tutorial de Pull Requests`
|
|
525
|
+
|
|
526
|
+
console.log("")
|
|
527
|
+
console.log(`Ejecutando: gh pr create --title "${prTitle}" --body "..."`)
|
|
528
|
+
console.log("")
|
|
529
|
+
|
|
530
|
+
try {
|
|
531
|
+
execSync(`gh pr create --title "${prTitle}" --body "${prBody}"`, {
|
|
532
|
+
encoding: 'utf8',
|
|
533
|
+
stdio: 'inherit'
|
|
534
|
+
})
|
|
535
|
+
console.log("")
|
|
536
|
+
console.log("✅ Pull Request creada exitosamente")
|
|
537
|
+
} catch (error) {
|
|
538
|
+
console.log("❌ Error al crear PR:", error.message)
|
|
539
|
+
console.log("")
|
|
540
|
+
console.log("Puedes crear la PR manualmente en GitHub:")
|
|
541
|
+
console.log(`${this.repoUrl}/pulls`)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
await this.waitForEnter("\nPresiona Enter para ver la conclusión...")
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async conclusion() {
|
|
548
|
+
console.clear()
|
|
549
|
+
console.log("🎉 ¡Felicidades! Completaste el Tutorial")
|
|
550
|
+
console.log("=" .repeat(50))
|
|
551
|
+
console.log("")
|
|
552
|
+
console.log("📚 Lo que aprendiste:")
|
|
553
|
+
console.log("")
|
|
554
|
+
console.log("✅ Qué es un fork y cómo hacerlo")
|
|
555
|
+
console.log("✅ Cómo clonar un repositorio")
|
|
556
|
+
console.log("✅ Cómo crear y trabajar en ramas")
|
|
557
|
+
console.log("✅ Cómo hacer commits con buenos mensajes")
|
|
558
|
+
console.log("✅ Cómo subir cambios con push")
|
|
559
|
+
console.log("✅ Cómo crear una Pull Request profesional")
|
|
560
|
+
console.log("")
|
|
561
|
+
console.log("🚀 Ahora estás listo para:")
|
|
562
|
+
console.log("")
|
|
563
|
+
console.log("• Contribuir a proyectos open source")
|
|
564
|
+
console.log("• Trabajar en equipos de desarrollo")
|
|
565
|
+
console.log("• Seguir las mejores prácticas de Git/GitHub")
|
|
566
|
+
console.log("")
|
|
567
|
+
console.log("💡 Próximos pasos:")
|
|
568
|
+
console.log("")
|
|
569
|
+
console.log("1. Espera feedback en tu PR")
|
|
570
|
+
console.log("2. Practica haciendo más PRs")
|
|
571
|
+
console.log("3. Busca proyectos open source para contribuir")
|
|
572
|
+
console.log("")
|
|
573
|
+
console.log("📖 Recursos adicionales:")
|
|
574
|
+
console.log("")
|
|
575
|
+
console.log("• GitHub Docs: https://docs.github.com/pull-requests")
|
|
576
|
+
console.log("• Git Book: https://git-scm.com/book/es")
|
|
577
|
+
console.log("• First Contributions: https://firstcontributions.github.io")
|
|
578
|
+
|
|
579
|
+
await this.waitForEnter("\n✨ Presiona Enter para finalizar...")
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
async waitForEnter(message) {
|
|
583
|
+
return new Promise((resolve) => {
|
|
584
|
+
this.rl.question(message, () => {
|
|
585
|
+
console.log("")
|
|
586
|
+
resolve()
|
|
587
|
+
})
|
|
588
|
+
})
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
async askQuestion(question) {
|
|
592
|
+
return new Promise((resolve) => {
|
|
593
|
+
this.rl.question(question, (answer) => {
|
|
594
|
+
resolve(answer)
|
|
595
|
+
})
|
|
596
|
+
})
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Para usar el tutorial independientemente
|
|
601
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
602
|
+
const tutorial = new PullRequestTutorial()
|
|
603
|
+
await tutorial.start()
|
|
604
|
+
}
|