@icarusmx/creta 1.2.0 → 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 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'
@@ -621,7 +622,8 @@ async function startMainMenuInteractive() {
621
622
 
622
623
  const options = [
623
624
  { id: 1, title: "Aprender conceptos", description: "Explora los enunciados fundamentales" },
624
- { id: 2, title: "Construir proyectos", description: "Crea tu portafolio personal" }
625
+ { id: 2, title: "Construir proyectos", description: "Crea tu portafolio personal" },
626
+ { id: 3, title: "Crea una pull-request", description: "Aprende el flujo de contribución con Git" }
625
627
  ]
626
628
 
627
629
  let selectedIndex = 0
@@ -692,6 +694,8 @@ Salgamos de este laberinto 🏛️
692
694
  startEnunciadosSelector().then(resolve)
693
695
  } else if (selectedOption.id === 2) {
694
696
  startProyectosSelector().then(resolve)
697
+ } else if (selectedOption.id === 3) {
698
+ startPullRequestTutorial().then(resolve)
695
699
  }
696
700
  return
697
701
  }
@@ -727,9 +731,10 @@ async function startMainMenuFallback() {
727
731
  console.log("")
728
732
  console.log("1. Aprender conceptos - Explora los enunciados fundamentales")
729
733
  console.log("2. Construir proyectos - Crea tu portafolio personal")
734
+ console.log("3. Crea una pull-request - Aprende el flujo de contribución con Git")
730
735
  console.log("")
731
736
 
732
- const respuesta = await askQuestion("Elige una opción (1-2) o 'q' para salir: ")
737
+ const respuesta = await askQuestion("Elige una opción (1-3) o 'q' para salir: ")
733
738
 
734
739
  if (respuesta.toLowerCase() === 'q') {
735
740
  console.log("Hecho con <3 por icarus.mx")
@@ -745,8 +750,11 @@ async function startMainMenuFallback() {
745
750
  } else if (opcionSeleccionada === 2) {
746
751
  rl.close()
747
752
  await startProyectosSelector()
753
+ } else if (opcionSeleccionada === 3) {
754
+ rl.close()
755
+ await startPullRequestTutorial()
748
756
  } else {
749
- console.log("❌ Opción no válida. Elige 1 o 2.")
757
+ console.log("❌ Opción no válida. Elige 1, 2 o 3.")
750
758
  rl.close()
751
759
  }
752
760
 
@@ -1405,3 +1413,30 @@ async function startProyectosSelectorFallback() {
1405
1413
  process.exit(1)
1406
1414
  }
1407
1415
  }
1416
+
1417
+ async function startPullRequestTutorial() {
1418
+ try {
1419
+ const tutorial = new PullRequestTutorial()
1420
+ await tutorial.start()
1421
+
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.")
1427
+
1428
+ const rl = createInterface({
1429
+ input: process.stdin,
1430
+ output: process.stdout
1431
+ })
1432
+
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
+ }
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icarusmx/creta",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Salgamos de este laberinto.",
5
5
  "type": "module",
6
6
  "bin": {