autoforce 0.1.9 → 0.1.10

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +6 -3
  3. package/commands/modelA/tasks/start.json +2 -2
  4. package/commands/modelC/new/issue.json +41 -0
  5. package/commands/modelC/subtasks/checkout-branch.json +60 -0
  6. package/commands/modelC/subtasks/create-pull.json +20 -0
  7. package/commands/modelC/subtasks/pack.json +29 -0
  8. package/commands/modelC/subtasks/publish-branch.json +20 -0
  9. package/commands/modelC/tasks/cancel.json +6 -0
  10. package/commands/modelC/tasks/finish.json +41 -0
  11. package/commands/modelC/tasks/list.json +11 -0
  12. package/commands/modelC/tasks/publish.json +13 -0
  13. package/commands/modelC/tasks/start.json +51 -0
  14. package/commands/modelC/tasks/stop.json +32 -0
  15. package/commands/modelC/tasks/switch.json +53 -0
  16. package/commands/modelC/tasks/view.json +13 -0
  17. package/commands/models.json +18 -0
  18. package/lib/auto.js +2 -1
  19. package/lib/helpers/class.js +4 -3
  20. package/lib/helpers/context.d.ts +2 -0
  21. package/lib/helpers/context.js +16 -6
  22. package/lib/helpers/github-project-graphql.d.ts +9 -1
  23. package/lib/helpers/github-project-graphql.js +20 -10
  24. package/lib/helpers/gitlab-graphql.d.ts +2 -1
  25. package/lib/helpers/gitlab-graphql.js +7 -2
  26. package/lib/helpers/lwc.js +4 -3
  27. package/lib/helpers/metadata.js +2 -2
  28. package/lib/helpers/object.js +4 -3
  29. package/lib/helpers/taskFunctions.js +12 -3
  30. package/lib/helpers/tasks.js +1 -1
  31. package/lib/helpers/template.d.ts +2 -2
  32. package/lib/helpers/template.js +2 -4
  33. package/lib/helpers/util.d.ts +7 -1
  34. package/lib/helpers/util.js +48 -5
  35. package/package.json +1 -1
  36. package/templates/modelB/changelog.md +4 -0
  37. package/templates/modelB/openIssues.md +0 -0
  38. package/templates/models.json +13 -0
  39. package/templates/story.md +0 -32
  40. package/templates/usecase.md +0 -52
  41. /package/templates/{dictionary → modelA/dictionary}/class-all.md +0 -0
  42. /package/templates/{dictionary → modelA/dictionary}/class-diagrama.md +0 -0
  43. /package/templates/{dictionary → modelA/dictionary}/class-inner.md +0 -0
  44. /package/templates/{dictionary → modelA/dictionary}/class-metodos.md +0 -0
  45. /package/templates/{dictionary → modelA/dictionary}/class-public.md +0 -0
  46. /package/templates/{dictionary → modelA/dictionary}/class-referencias.md +0 -0
  47. /package/templates/{dictionary → modelA/dictionary}/class.md +0 -0
  48. /package/templates/{dictionary → modelA/dictionary}/classes.md +0 -0
  49. /package/templates/{dictionary → modelA/dictionary}/object.md +0 -0
  50. /package/templates/{dictionary → modelA/dictionary}/objects.md +0 -0
  51. /package/templates/{intro.md → modelA/intro.md} +0 -0
  52. /package/templates/{process.md → modelA/process.md} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
1
 
2
- Version 0.1.19
2
+ Version 0.1.9
3
3
  * Comando de new issue para crear un issue nuevo en el backlog
4
4
  * Comando de list para ver issues en backlog o ver los detalles de uno
package/README.md CHANGED
@@ -5,8 +5,11 @@ El proyecto esta en Beta todavia, recien fue migrado a Typescript y paso de ser
5
5
 
6
6
  ## Objetivo
7
7
 
8
- La motivacion de crear la herramienta fue facilitar y automatizar las tareas comunes que realizamos los desarrolladores, especialmente los que utilizacion Salesforce.
9
- A medida que pasa el tiempo tenemos cada vez mas herramientas diarias y especificas, pero las tareas en si son las mismas, queremos arrancar a desarrollar algo nuevo (start), terminar el desarrollo(finish), o bien dejarlo a un costado (stop), y posiblemente cancelar por completo alguno (cancel).
8
+ La motivacion de crear la herramienta fue facilitar y automatizar las tareas comunes que realizamos los desarrolladores, especialmente los que utilizamos Salesforce.
9
+
10
+ Me vi en la necesidad de tener una herramienta porque muchas veces me ganaba la ansiedad y queria hacer varios cambios juntos. Sentia que hacer varios stories, cada una con su branch, y todo el proceso era perder mucho tiempo. Pero cuando uno logra automatizar el repositorio queda mas prolijo y la trazabilidad tambien, y permite que otros desarrolladores puedan colaborar de forma mas simple.
11
+
12
+ En general cuando desarrollamos, repetimos mas o menos las mismas tareas. Arrancamos a desarrollar algo nuevo (start), terminamos ese desarrollo(finish), o bien dejarlo a un costado (stop), y posiblemente lo descartamos por completo (cancel). Dependiendo la tecnologia, el tipo de desarrollo, y que estrategia de branching, entre otras cosas mas, estas tareas podrian ser distintas.
10
13
 
11
14
  En este repo las tareas buscan automatizar o integrar el siguiente tipo gestiones:
12
15
 
@@ -30,7 +33,7 @@ En este repo las tareas buscan automatizar o integrar el siguiente tipo gestione
30
33
 
31
34
  - [Model B] "Desarrollo de Producto": 0%
32
35
 
33
- - [Custom] "Modelo configurado fuera de la herramienta"
36
+ - [Custom] "Modelo personalizado"
34
37
 
35
38
  2. Github Services
36
39
  - Github: Listo
@@ -29,7 +29,7 @@
29
29
  "function": "assignIssueToMe",
30
30
  "arguments": ["${newIssueNumber}"],
31
31
  "errorMessage": "No se pudo pudo asignar la branch (${newBranchName}) al issue. Por favor hagalo manualmente",
32
- "skipOnError": true
32
+ "onError": "skip"
33
33
  },
34
34
  {
35
35
  "name": "Pone la branch en el issue",
@@ -39,7 +39,7 @@
39
39
  "issueNumber": "${newIssueNumber}"
40
40
  },
41
41
  "errorMessage": "No se pudo asignar la branch ${newBranchName} al issue ${newIssueNumber}. Hagalo manualmente",
42
- "skipOnError": true
42
+ "onError": "skip"
43
43
  },
44
44
  {
45
45
  "name": "Asocia la branch con el remote",
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "issue",
3
+ "guards": ["isGitApi"],
4
+ "arguments": {
5
+ "title": { "required": true },
6
+ "label": {
7
+ "type": "select",
8
+ "choices": [
9
+ {
10
+ "title": "Automation",
11
+ "value": "automation",
12
+ "description": "Test cases de automatizacion o cualquier cambio dentro de la automatizacion del pipeline"
13
+ },
14
+ {
15
+ "title": "Bugfix",
16
+ "value": "bug",
17
+ "description": "Correxion de codigo, no hay incremento funcional"
18
+ },
19
+ {
20
+ "title": "Documentation",
21
+ "value": "documentation",
22
+ "description": "Cambios en la documentacion"
23
+ },
24
+ {
25
+ "title": "Feature",
26
+ "value": "feature",
27
+ "description": "Nuevas funcionalidades"
28
+ }
29
+ ]
30
+ },
31
+ "body": { "required": false }
32
+ },
33
+ "description": "Comando para crear un requerimiento nuevo",
34
+ "steps": [
35
+ {
36
+ "name": "Crear un issue nuevo",
37
+ "function": "createIssue",
38
+ "arguments": ["${title}", "${label}", "${body}"]
39
+ }
40
+ ]
41
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "checkout-branch",
3
+ "guards": ["isGitApi"],
4
+ "arguments": ["newBranchName"],
5
+ "description": "Comando para cambiar de branch y baja cualquier cambio que este en la remote branch o en main",
6
+ "steps": [
7
+ {
8
+ "name": "valida que no sea la branch actual",
9
+ "function": "validaNoseaBranchActual",
10
+ "arguments": ["${newBranchName}"],
11
+ "description": "Valida que no sea la branch actual",
12
+ "errorMessage": "Ya esta parado sobre la branch ${newBranchName}"
13
+ },
14
+ {
15
+ "name": "chequea si hay cambios sin commit",
16
+ "function": "checkCommitPending",
17
+ "description": "Chequea si hay algo sin commitear",
18
+ "errorMessage": "Tiene modificaciones pendientes:\n ${salida}",
19
+ "onError": "commitChanges"
20
+ },
21
+ {
22
+ "name": "baja cambios en remote y en main",
23
+ "command": "git",
24
+ "arguments": ["fetch"],
25
+ "description": "Baja de remote",
26
+ "errorMessage": "No se pudo actualizar la branch, intente manualmente con git fetch"
27
+ },
28
+ {
29
+ "criteria": { "field": "existNewBranch", "value": true },
30
+ "name": "cambia de branch",
31
+ "command": "git",
32
+ "arguments": ["checkout", "${newBranchName}"],
33
+ "description": "Cambia de branch",
34
+ "errorMessage": "No se pudo mover al branch ${newBranchName}. Hagalo manualmente ${command}"
35
+ },
36
+ {
37
+ "criteria": { "field": "existNewBranch", "value": true },
38
+ "name": "baja de la remote branch",
39
+ "command": "git",
40
+ "arguments": ["pull", "--set-upstream", "origin ${newBranchName}"],
41
+ "description": "Trae contenido de branch remota",
42
+ "errorMessage": "No se pudo traer de la remote branch ${newBranchName}. Hagalo manualmente ${command}"
43
+ },
44
+ {
45
+ "criteria": { "field": "existNewBranch", "value": true },
46
+ "name": "merge de main",
47
+ "command": "git",
48
+ "arguments": ["merge main"],
49
+ "description": "Trae cualquier cambio en main",
50
+ "errorMessage": "No se pudo actualizar la branch con main, intente manualmente con git merge main"
51
+ },
52
+ {
53
+ "criteria": { "field": "existNewBranch", "value": false },
54
+ "name": "crea de branch",
55
+ "function": "createBranch",
56
+ "description": "Crea la nueva branch ${newBranchName}",
57
+ "errorMessage": "No se pudo crear la branch ${newBranchName}. Hagalo manualmente ${command}"
58
+ }
59
+ ]
60
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "create-pull",
3
+ "guards": ["isGitApi"],
4
+ "description": "Comando para crear el pull request de la branch",
5
+ "steps": [
6
+ {
7
+ "name": "chequea si hay cambios sin commit",
8
+ "function": "checkCommitPending",
9
+ "description": "Chequea si hay algo sin commitear",
10
+ "errorMessage": "Tiene modificaciones pendientes:\n ${salida}",
11
+ "onError": "commitChanges"
12
+ },
13
+ {
14
+ "name": "publica la branch",
15
+ "function": "publishBranch",
16
+ "description": "Publicha la branch en Remote",
17
+ "errorMessage": "No se pudo publicar la branch"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "pack",
3
+ "description": "Comando para crear el package localmente",
4
+ "steps": [
5
+ {
6
+ "name": "Borra el paquete",
7
+ "command": "rm autoforce*.tgz",
8
+ "onError": "skip"
9
+ },
10
+ {
11
+ "name": "Borra los archivos en Lib",
12
+ "command": "rm -rf ./lib/",
13
+ "onError": "skip"
14
+ },
15
+ {
16
+ "name": "Compila el typescript",
17
+ "command": "tsc --project tsconfig.build.json"
18
+ },
19
+ {
20
+ "name": "Arma el paquete",
21
+ "command": "yarn pack"
22
+ },
23
+ {
24
+ "name": "Renombra paquete",
25
+ "command": "mv autoforce*.tgz autoforce.tgz"
26
+ }
27
+ ]
28
+ }
29
+
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "publish-branch",
3
+ "guards": ["isGitApi"],
4
+ "description": "Comando para publicar la branch en Remote",
5
+ "steps": [
6
+ {
7
+ "name": "chequea si hay cambios sin commit",
8
+ "function": "checkCommitPending",
9
+ "description": "Chequea si hay algo sin commitear",
10
+ "errorMessage": "Tiene modificaciones pendientes:\n ${salida}",
11
+ "onError": "commitChanges"
12
+ },
13
+ {
14
+ "name": "publica la branch",
15
+ "function": "publishBranch",
16
+ "description": "Publicha la branch en Remote",
17
+ "errorMessage": "No se pudo publicar la branch"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "cancel",
3
+ "guards": ["isGitApi"],
4
+ "description": "Comando para cancelar un requerimiento",
5
+ "steps": [{ "name": "Cancela el issue", "function": "cancelIssue" }]
6
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "finish",
3
+ "guards": ["isGitApi"],
4
+ "description": "Comando para teminar un requerimiento. Automatiza las acciones cuando se termino el desarrollo de un requerimiento",
5
+ "steps": [
6
+ {
7
+ "criteria": { "field": "isDevelopment", "value": true },
8
+ "subtask": "validate-scratch"
9
+ },
10
+ {
11
+ "name": "chequea si hay cambios sin commit",
12
+ "function": "checkCommitPending",
13
+ "description": "Chequea si hay algo sin commitear:\n ${salida}",
14
+ "errorMessage": "Tiene modificaciones pendientes",
15
+ "onError": "commitChanges"
16
+ },
17
+ {
18
+ "criteria": { "field": "isDevelopment", "value": true },
19
+ "subtask": "update-documentation"
20
+ },
21
+ {
22
+ "criteria": { "field": "isDevelopment", "value": true },
23
+ "subtask": "validate-code"
24
+ },
25
+ {
26
+ "name": "publica la branch",
27
+ "subtask": "publish-branch",
28
+ "description": "Publica la branch en Remote",
29
+ "errorMessage": "No se pudo publicar la branch"
30
+ },
31
+ {
32
+ "name": "crea el pull request",
33
+ "subtask": "create-pull",
34
+ "description": "Crea el pull request"
35
+ },
36
+ {
37
+ "criteria": { "field": "isDevelopment", "value": true },
38
+ "subtask": "drop-scratch"
39
+ }
40
+ ]
41
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "list",
3
+ "guards": ["isGitApi"],
4
+ "description": "Comando para ver en detalle el requerimiento",
5
+ "steps": [
6
+ {
7
+ "name": "Ver los issues del Backlog",
8
+ "function": "listIssues"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "publish",
3
+ "guards": ["$NPM_TOKEN"],
4
+ "arguments": {
5
+ "newVersion": { "required": true }
6
+ },
7
+ "description": "Comando para publicar un requerimiento al ambiente",
8
+ "steps": [
9
+ { "name": "Paquetiza", "subtask": "pack" },
10
+ { "name": "Actualiza la version", "function": "storeConfig", "arguments": ["version", "${newVersion}"] },
11
+ { "name": "Publica", "command": "yarn publish ", "arguments": {"--new-version": "${newVersion}"} }
12
+ ]
13
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "start",
3
+ "guards": ["isGitApi"],
4
+ "arguments": ["newIssueNumber"],
5
+ "description": "Comando para iniciar un requerimiento. Automatiza las acciones cuando se arranca un requerimiento nuevo",
6
+ "steps": [
7
+ {
8
+ "name": "validate issue",
9
+ "function": "validateIssue",
10
+ "arguments": ["${newIssueNumber}", "Ready,Backlog"],
11
+ "description": "Valida que Issue este en la Columna Ready o Backlog",
12
+ "errorMessage": "Por favor verifique que el issue ${newIssueNumber} este en la columna Ready o Backlog"
13
+ },
14
+ {
15
+ "name": "check Issue type based on Labels",
16
+ "function": "checkIssueType",
17
+ "arguments": ["${newIssueNumber}"],
18
+ "description": "Verifica si el issueType es de Desarrollo o No segun los labels (no desa son automation, documentation)"
19
+ },
20
+ { "subtask": "checkout-branch", "arguments": ["${newBranchName}"] },
21
+ {
22
+ "name": "Mueve el issue a In Progress",
23
+ "function": "moveIssue",
24
+ "arguments": ["${newIssueNumber}", "In Progress"],
25
+ "errorMessage": "No se pudo mover el issue a inprogress, hagalo manualmente"
26
+ },
27
+ {
28
+ "name": "Me Asigna el issue",
29
+ "function": "assignIssueToMe",
30
+ "arguments": ["${newIssueNumber}"],
31
+ "errorMessage": "No se pudo pudo asignar la branch (${newBranchName}) al issue. Por favor hagalo manualmente",
32
+ "onError": "skip"
33
+ },
34
+ {
35
+ "name": "Pone la branch en el issue",
36
+ "function": "assignBranchToIssue",
37
+ "arguments": {
38
+ "newBranchName": "${newBranchName}",
39
+ "issueNumber": "${newIssueNumber}"
40
+ },
41
+ "errorMessage": "No se pudo asignar la branch ${newBranchName} al issue ${newIssueNumber}. Hagalo manualmente",
42
+ "onError": "skip"
43
+ },
44
+ {
45
+ "name": "Asocia la branch con el remote",
46
+ "command": "git push -u origin",
47
+ "arguments": ["${newBranchName}"],
48
+ "errorMessage": "No se pudo asociar la branch ${newBranchNamed} al remote. verifique con git branch -vv "
49
+ }
50
+ ]
51
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "stop",
3
+ "guards": ["isGitApi"],
4
+ "description": "Comando para dejar a un lado un requerimiento",
5
+ "steps": [
6
+ {
7
+ "criteria": { "field": "isDevelopment", "value": true },
8
+ "subtask": "validate-scratch"
9
+ },
10
+ {
11
+ "criteria": { "field": "isDevelopment", "value": true },
12
+ "subtask": "update-documentation"
13
+ },
14
+ {
15
+ "name": "chequea si hay cambios sin commit",
16
+ "function": "checkCommitPending",
17
+ "description": "Chequea si hay algo sin commitear:\n ${salida}",
18
+ "errorMessage": "Tiene modificaciones pendientes",
19
+ "onError": "commitChanges"
20
+ },
21
+ {
22
+ "name": "publica la branch",
23
+ "subtask": "publish-branch",
24
+ "description": "Publica la branch en Remote",
25
+ "errorMessage": "No se pudo publicar la branch"
26
+ },
27
+ {
28
+ "criteria": { "field": "isDevelopment", "value": true },
29
+ "subtask": "drop-scratch"
30
+ }
31
+ ]
32
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "switch",
3
+ "guards": ["isGitApi"],
4
+ "arguments": ["newIssueNumber"],
5
+ "description": "Comando para cambiar el requerimiento a desarrollar",
6
+ "steps": [
7
+ {
8
+ "name": "validate issue",
9
+ "function": "validateIssue",
10
+ "arguments": ["${newIssueNumber}", "In Progress"],
11
+ "description": "Valida que Issue este en la Columna In Progress",
12
+ "errorMessage": "Por favor verifique que el issue ${newIssueNumber} este en la columna In Progress"
13
+ },
14
+ {
15
+ "name": "check Issue type based on Labels",
16
+ "function": "checkIssueType",
17
+ "arguments": ["${newIssueNumber}"],
18
+ "description": "Verifica si el issueType es de Desarrollo o No segun los labels (no desa son automation, documentation)"
19
+ },
20
+ {
21
+ "name": "Se fija que este parado en ${newBranchName}",
22
+ "function": "validaNoseaBranchActual",
23
+ "arguments": ["${newBranchName}"],
24
+ "description": "Valida que no sea la branch actual",
25
+ "errorMessage": "Ya esta parado sobre la branch ${newBranchName}"
26
+ },
27
+ {
28
+ "criteria": { "field": "isDevelopment", "value": true },
29
+ "subtask": "update-documentation"
30
+ },
31
+ {
32
+ "criteria": { "field": "isDevelopment", "value": true },
33
+ "subtask": "validate-scratch"
34
+ },
35
+ { "subtask": "checkout-branch", "arguments": ["${newBranchName}"] },
36
+ {
37
+ "criteria": { "field": "isNewDevelopment", "value": true },
38
+ "name": "switch scratch",
39
+ "command": "sf force config set target-org",
40
+ "arguments": { "--target-org": "${newBranchName}" },
41
+ "description": "Cambia la scratch",
42
+ "errorMessage": "No se pudo mover al scratch ${newBranchName}. Hagalo manualmente ${command}"
43
+ },
44
+ {
45
+ "criteria": { "field": "isNewDevelopment", "value": true },
46
+ "name": "deploy scratch localmente",
47
+ "command": "sf project deploy start",
48
+ "arguments": { "--target-org": "${newBranchName}" },
49
+ "description": "Deploy por si hubo cambios en main",
50
+ "errorMessage": "No se pudo mover al scratch ${newBranchName}. Hagalo manualmente ${command}"
51
+ }
52
+ ]
53
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "view",
3
+ "guards": ["isGitApi"],
4
+ "arguments": ["issueNumber"],
5
+ "description": "Comando para ver en detalle el requerimiento",
6
+ "steps": [
7
+ {
8
+ "name": "Ver datos del issue",
9
+ "function": "viewIssue",
10
+ "arguments": ["${issueNumber}"]
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,18 @@
1
+ [
2
+ {
3
+ "title": "Continious Delivery con Scratch Orgs",
4
+ "value": "modelA",
5
+ "description": "Github workflow pensado en soluciones para Clientes finales"
6
+ },
7
+ {
8
+ "title": "Second Generation Packages con Scratch Orgs",
9
+ "value": "modelB",
10
+ "description": "Gitflow workflow pensado para ISV"
11
+ },
12
+ {
13
+ "title": "Paquetes de NPM",
14
+ "value": "modelC",
15
+ "description": "Para herramientas complementarias como autoforce"
16
+ }
17
+ ]
18
+
package/lib/auto.js CHANGED
@@ -12,6 +12,7 @@ import { createObject, validateTask, getTasks, helpTask, runTask, getTaskFolder
12
12
  import { logError } from "./helpers/color.js";
13
13
  import prompts from "prompts";
14
14
  import { createConfigurationFile } from "./helpers/util.js";
15
+ import context from "./helpers/context.js";
15
16
  const proxyCommand = {
16
17
  'version': showVersion,
17
18
  'config': createConfigurationFile
@@ -24,7 +25,7 @@ const taskCommand = {
24
25
  };
25
26
  function showVersion() {
26
27
  return __awaiter(this, void 0, void 0, function* () {
27
- console.log('AutoForce v0.1.4');
28
+ console.log('AutoForce v' + context.version);
28
29
  return true;
29
30
  });
30
31
  }
@@ -9,8 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import sf from "./connect.js";
11
11
  import templateGenerator from "./template.js";
12
- const templateEngine = templateGenerator("dictionary", "md");
13
- import { sortByName, getNamesByExtension, verFecha, splitFilename, DICTIONARY_FOLDER, TEMPLATES_FOLDER } from "./util.js";
12
+ import { DICTIONARY_FOLDER, TEMPLATE_MODEL_FOLDER } from "./util.js";
13
+ const templateEngine = templateGenerator(`${TEMPLATE_MODEL_FOLDER}/dictionary`, "md");
14
+ import { sortByName, getNamesByExtension, verFecha, splitFilename } from "./util.js";
14
15
  function getMetadata(clases) {
15
16
  return __awaiter(this, void 0, void 0, function* () {
16
17
  try {
@@ -189,7 +190,7 @@ function executeClasses(items, filename, folder) {
189
190
  classLink
190
191
  }
191
192
  });
192
- templateEngine.save(filename, TEMPLATES_FOLDER + "/" + folder);
193
+ templateEngine.save(filename, +"/" + folder);
193
194
  });
194
195
  }
195
196
  const classModule = {
@@ -15,9 +15,11 @@ export declare enum ProjectServices {
15
15
  declare class Context implements IObjectRecord {
16
16
  [s: string]: AnyValue | undefined;
17
17
  model: string;
18
+ modelTemplates: string;
18
19
  gitServices: GitServices;
19
20
  isGitApi: boolean;
20
21
  gitApi: IGitApi | undefined;
22
+ version: string | undefined;
21
23
  projectServices: ProjectServices;
22
24
  isProjectApi: boolean;
23
25
  projectApi: IProjectApi | undefined;
@@ -33,7 +33,8 @@ const filterProcesses = (fullPath) => fullPath.endsWith(".md"); // && !fullPath.
33
33
  const ISSUES_TYPES = [{ value: 'feature', title: 'feature' }, { value: 'bug', title: 'bug' }, { value: 'documentation', title: 'documentation' }, { value: 'automation', title: 'automation' }];
34
34
  class Context {
35
35
  constructor() {
36
- this.model = 'modelA'; // Default Model
36
+ this.model = 'modelA'; // Default Model de commands
37
+ this.modelTemplates = 'modelA'; // Default Model de templates
37
38
  this.gitServices = GitServices.None;
38
39
  this.isGitApi = false;
39
40
  this.projectServices = ProjectServices.None;
@@ -242,9 +243,17 @@ class Context {
242
243
  validate(guards) {
243
244
  return __awaiter(this, void 0, void 0, function* () {
244
245
  for (const guard of guards) {
245
- const value = yield this.get(guard);
246
- if (!value) {
247
- throw new Error(`No se encontro la variable ${guard} en el contexto. Ejecute yarn auto config o lea el index.md para mas informacion.`);
246
+ // Chequeo de variables de entorno
247
+ if (guard[0] === '$') {
248
+ if (!process.env[guard.substring(1)]) {
249
+ throw new Error(`La variable de entorno ${guard} no esta configurada.`);
250
+ }
251
+ }
252
+ else {
253
+ const value = yield this.get(guard);
254
+ if (!value) {
255
+ throw new Error(`No se encontro la variable ${guard} en el contexto. Ejecute yarn auto config o lea el index.md para mas informacion.`);
256
+ }
248
257
  }
249
258
  }
250
259
  });
@@ -450,7 +459,7 @@ class Context {
450
459
  }
451
460
  setObject(obj) {
452
461
  for (const field in obj) {
453
- Object.defineProperty(this, field, obj[field]);
462
+ Object.defineProperty(this, field, { value: obj[field], writable: true });
454
463
  }
455
464
  }
456
465
  set(key, value) {
@@ -509,10 +518,11 @@ class Context {
509
518
  }
510
519
  }
511
520
  const context = new Context();
521
+ context.loadConfig();
512
522
  let initialized = false;
513
523
  export function initializeContext() {
514
524
  try {
515
- if (!initialized) {
525
+ if (initialized === false) {
516
526
  context.init();
517
527
  initialized = true;
518
528
  }
@@ -3,7 +3,7 @@ export declare class GitHubProjectApi extends GitHubApi implements IProjectApi {
3
3
  projectNumber: number;
4
4
  constructor(token: string, owner: string, repo: string, projectNumber: number);
5
5
  getColumnValueMap(): Promise<Record<string, string>>;
6
- createIssue(title: string, state?: string, label?: string, milestone?: string, body?: string): Promise<number>;
6
+ createIssue(title: string, state?: string, label?: string, body?: string, milestone?: string): Promise<number>;
7
7
  getIssueState(issueNumber: string): Promise<string>;
8
8
  getIssueName(title: string): string;
9
9
  getIssueObject(issueNumber: string): Promise<IIssueObject>;
@@ -11,6 +11,14 @@ export declare class GitHubProjectApi extends GitHubApi implements IProjectApi {
11
11
  id: string;
12
12
  title: string;
13
13
  }[]>;
14
+ getIssuesByMilestone(milestone: string): Promise<{
15
+ id: string;
16
+ title: string;
17
+ }[]>;
18
+ getIssuesWithFilter(filterBy: string): Promise<{
19
+ id: string;
20
+ title: string;
21
+ }[]>;
14
22
  moveIssue(issueNumber: string, state: string): Promise<boolean>;
15
23
  assignIssueToMe(issueNumber: string): Promise<boolean>;
16
24
  }
@@ -42,7 +42,7 @@ export class GitHubProjectApi extends GitHubApi {
42
42
  return mapValues;
43
43
  });
44
44
  }
45
- createIssue(title, state, label, milestone, body) {
45
+ createIssue(title, state, label, body, milestone) {
46
46
  var _a;
47
47
  return __awaiter(this, void 0, void 0, function* () {
48
48
  const user = yield this.getUser();
@@ -145,19 +145,29 @@ export class GitHubProjectApi extends GitHubApi {
145
145
  });
146
146
  }
147
147
  getIssues() {
148
+ return __awaiter(this, void 0, void 0, function* () {
149
+ return yield this.getIssuesWithFilter(`{ states: OPEN }`);
150
+ });
151
+ }
152
+ getIssuesByMilestone(milestone) {
153
+ return __awaiter(this, void 0, void 0, function* () {
154
+ return yield this.getIssuesWithFilter(`{ milestone: ${milestone} }`);
155
+ });
156
+ }
157
+ getIssuesWithFilter(filterBy) {
148
158
  return __awaiter(this, void 0, void 0, function* () {
149
159
  const query = `
150
- query getIssue($owner:String!, $repo: String!) {
151
- repository(owner: $owner, name: $repo) {
152
- issues(last: 10) {
153
- nodes {
154
- title
155
- id
160
+ query getIssues($owner:String!, $repo: String!) {
161
+ repository(owner: $owner, name: $repo) {
162
+ issues(last: 10, filterBy: ${filterBy} ) {
163
+ nodes {
164
+ title
165
+ id
166
+ }
167
+ }
156
168
  }
157
169
  }
158
- }
159
- }
160
- `;
170
+ `;
161
171
  const { repository } = yield this.graphqlAuth(query, this.repoVar);
162
172
  return repository.issues.nodes;
163
173
  });
@@ -10,7 +10,8 @@ export declare class GitLabApi implements IGitApi, IProjectApi {
10
10
  constructor(token: string, owner: string, repo: string, projectNumber?: number);
11
11
  getIssueObject(issueNumber: string): Promise<{}>;
12
12
  getIssues(): Promise<never[]>;
13
- createIssue(title: string, state?: string, label?: string, milestone?: string, body?: string): Promise<number>;
13
+ getIssuesByMilestone(milestone: string): Promise<never[]>;
14
+ createIssue(title: string, state?: string, label?: string, body?: string, milestone?: string): Promise<number>;
14
15
  moveIssue(issueNumber: string, state: string): Promise<boolean>;
15
16
  assignIssueToMe(issueNumber: string): Promise<boolean>;
16
17
  getUser(): Promise<{
@@ -27,9 +27,14 @@ export class GitLabApi {
27
27
  return [];
28
28
  });
29
29
  }
30
- createIssue(title, state, label, milestone, body) {
30
+ getIssuesByMilestone(milestone) {
31
31
  return __awaiter(this, void 0, void 0, function* () {
32
- console.log(title, label, milestone, body);
32
+ return [];
33
+ });
34
+ }
35
+ createIssue(title, state, label, body, milestone) {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ console.log(title, state, label, body, milestone);
33
38
  return 1;
34
39
  });
35
40
  }
@@ -9,8 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import sf from "./connect.js";
11
11
  import templateGenerator from "./template.js";
12
- const templateEngine = templateGenerator("dictionary", "md");
13
- import { sortByName, splitFilename, DICTIONARY_FOLDER, TEMPLATES_FOLDER } from "./util.js";
12
+ import { DICTIONARY_FOLDER, TEMPLATE_MODEL_FOLDER } from "./util.js";
13
+ const templateEngine = templateGenerator(`${TEMPLATE_MODEL_FOLDER}/dictionary`, "md");
14
+ import { sortByName, splitFilename } from "./util.js";
14
15
  function getMetadata(lwc) {
15
16
  return __awaiter(this, void 0, void 0, function* () {
16
17
  try {
@@ -59,7 +60,7 @@ function executeLwc(items, filename, folder) {
59
60
  templateEngine.render(lwcContext, {
60
61
  helpers: {}
61
62
  });
62
- templateEngine.save(filename, TEMPLATES_FOLDER + "/" + folder);
63
+ templateEngine.save(filename, TEMPLATE_MODEL_FOLDER + "/" + folder);
63
64
  });
64
65
  }
65
66
  const lwcModule = {
@@ -10,7 +10,7 @@ const helpers = {
10
10
  export default helpers;
11
11
  /*
12
12
  import context from "./context.js";
13
- import { TEMPLATES_FOLDER } from "./util.js";
13
+ import { TEMPLATE_MODEL_FOLDER } from "./util.js";
14
14
  import type { DocumentationModule, IProcessInfo, IMetadataNode, IMetadataComponentNode } from "../types/auto.js";
15
15
  function getMetadataFromContext(components: string[]) {
16
16
  return getMetadataArray(context.getProcessMetadata(), components);
@@ -66,7 +66,7 @@ function getMetadataArray(metadata: IProcessInfo[], props: string[]) {
66
66
  return items;
67
67
  };
68
68
 
69
- return getItemsFromTree({ folder: TEMPLATES_FOLDER, childs: metadata });
69
+ return getItemsFromTree({ folder: TEMPLATE_MODEL_FOLDER, childs: metadata });
70
70
  }
71
71
 
72
72
  export async function execute() {
@@ -9,8 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import sf from "./connect.js";
11
11
  import templateGenerator from "./template.js";
12
- const templateEngine = templateGenerator("dictionary", "md");
13
- import { sortByLabel, DICTIONARY_FOLDER, TEMPLATES_FOLDER, } from "./util.js";
12
+ import { DICTIONARY_FOLDER, TEMPLATE_MODEL_FOLDER } from "./util.js";
13
+ const templateEngine = templateGenerator(`${TEMPLATE_MODEL_FOLDER}/dictionary`, "md");
14
+ import { sortByLabel } from "./util.js";
14
15
  function getMetadata(objetos) {
15
16
  return __awaiter(this, void 0, void 0, function* () {
16
17
  try {
@@ -123,7 +124,7 @@ function executeObjects(items, filename, folder) {
123
124
  templateEngine.render(objectContext, {
124
125
  helpers: { isManaged, isMetadataFormula, attributesFormula }
125
126
  });
126
- templateEngine.save(filename, TEMPLATES_FOLDER + "/" + folder);
127
+ templateEngine.save(filename, TEMPLATE_MODEL_FOLDER + "/" + folder);
127
128
  });
128
129
  }
129
130
  const objectModule = {
@@ -9,11 +9,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { execSync } from "child_process";
11
11
  import context from "./context.js";
12
- import { logError } from "./color.js";
12
+ import { logError, logInfo } from "./color.js";
13
13
  import metadata from './metadata.js';
14
14
  import prompts from "prompts";
15
15
  import templateGenerator from "./template.js";
16
16
  import { getColored } from "./color.js";
17
+ import { storeConfig } from "./util.js";
17
18
  function createTemplate(templateFolder, templateExtension, template, filename, folder, context) {
18
19
  if (!template || !filename || !templateFolder || !templateExtension) {
19
20
  return;
@@ -219,6 +220,14 @@ function getFilesChanged() {
219
220
  return files;
220
221
  }
221
222
  export const taskFunctions = {
223
+ skip() {
224
+ logInfo('Error omitido por configuracion del step');
225
+ return true;
226
+ },
227
+ storeConfig(variable, value) {
228
+ storeConfig(variable, value);
229
+ return true;
230
+ },
222
231
  docProcess() {
223
232
  return __awaiter(this, void 0, void 0, function* () {
224
233
  if (!context.process) {
@@ -312,12 +321,12 @@ export const taskFunctions = {
312
321
  console.log('Not implemented');
313
322
  return false;
314
323
  },
315
- createIssue(title, label) {
324
+ createIssue(title, label, body) {
316
325
  return __awaiter(this, void 0, void 0, function* () {
317
326
  if (context.projectApi === undefined) {
318
327
  return false;
319
328
  }
320
- const issueNumber = yield context.projectApi.createIssue(title, context.backlogColumn, label);
329
+ const issueNumber = yield context.projectApi.createIssue(title, context.backlogColumn, label, body);
321
330
  if (issueNumber) {
322
331
  console.log(`Se creo el issue ${issueNumber}`);
323
332
  return true;
@@ -178,7 +178,7 @@ function runStep(step, tabs) {
178
178
  }
179
179
  else if (typeof step.subtask === 'string') {
180
180
  const subtask = getTask(step.subtask, SUBTASKS_FOLDER);
181
- let stepContext = context.mergeArgs(step.arguments);
181
+ let stepContext = step.arguments ? context.mergeArgs(step.arguments) : {};
182
182
  if (Array.isArray(stepContext)) {
183
183
  stepContext = createObject(subtask.arguments, stepContext);
184
184
  }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="handlebars" />
2
- declare class TemplateEngine<T> {
2
+ declare class TemplateEngine {
3
3
  _template: HandlebarsTemplateDelegate | undefined;
4
4
  _rendered: string | undefined;
5
5
  _extension: string;
@@ -10,5 +10,5 @@ declare class TemplateEngine<T> {
10
10
  render(context: object, options?: RuntimeOptions): void;
11
11
  save(filename: string, folder: string, options?: SaveTemplateOptions): void;
12
12
  }
13
- declare const _default: (source: string, extension: string) => TemplateEngine<unknown>;
13
+ declare const _default: (source: string, extension: string) => TemplateEngine;
14
14
  export default _default;
@@ -1,9 +1,7 @@
1
1
  import fs from "fs";
2
2
  import Handlebars from "handlebars";
3
3
  import { merge } from "./merge.js";
4
- import { fileURLToPath } from 'url';
5
- import { getFiles, searchInFolderHierarchy } from "./util.js";
6
- const TEMPLATE_ROOT_FOLDER = searchInFolderHierarchy('templates', fileURLToPath(import.meta.url));
4
+ import { getFiles } from "./util.js";
7
5
  function isObjectEmpty(objectName) {
8
6
  return (objectName &&
9
7
  Object.keys(objectName).length === 0 &&
@@ -26,7 +24,7 @@ function openTemplate(sourceFolder, templateName, extension) {
26
24
  }
27
25
  class TemplateEngine {
28
26
  constructor(source, extension) {
29
- this._sourceFolder = `${TEMPLATE_ROOT_FOLDER}/${source}`;
27
+ this._sourceFolder = source;
30
28
  if (!fs.existsSync(this._sourceFolder)) {
31
29
  throw new Error(`La carpeta source ${this._sourceFolder} no existe!`);
32
30
  }
@@ -1,7 +1,10 @@
1
+ import prompts from "prompts";
2
+ import { AnyValue } from "../types/auto.js";
3
+ export declare const CONFIG_FILE: string;
1
4
  export declare const TEMPLATES_FOLDER: string;
5
+ export declare const TEMPLATE_MODEL_FOLDER: string;
2
6
  export declare const DICTIONARY_FOLDER: string;
3
7
  export declare const WORKING_FOLDER: string;
4
- export declare const CONFIG_FILE: string;
5
8
  export declare const filterJson: (fullPath: string) => boolean;
6
9
  export declare const filterDirectory: (fullPath: string) => boolean;
7
10
  export declare const filterFiles: (fullPath: string) => boolean;
@@ -18,6 +21,8 @@ export declare function titlesToChoices(list: string[], titleToValue?: (title: s
18
21
  }[];
19
22
  export declare function getDataFromPackage(): Record<string, string>;
20
23
  export declare function createConfigurationFile(): Promise<boolean>;
24
+ export declare function getConfig(variable: string, defaultValue: AnyValue): any;
25
+ export declare function storeConfig(variable: string, value: AnyValue): void;
21
26
  export declare function sortByName(objA: {
22
27
  Name: string;
23
28
  }, objB: {
@@ -44,3 +49,4 @@ export declare function searchInFolderHierarchy(element: string, parentFolder: s
44
49
  export declare function getFiles(source: string, filter?: (file: string) => boolean, recursive?: boolean, ignoreList?: string[]): string[];
45
50
  export declare function convertNameToKey(name: string): string;
46
51
  export declare function convertKeyToName(key: string): string;
52
+ export declare function readJsonSync(filename: string): prompts.Choice[];
@@ -13,10 +13,11 @@ import prompts from "prompts";
13
13
  import { ProjectServices, GitServices } from "./context.js";
14
14
  import { logInfo, logWarning } from "./color.js";
15
15
  const COMMAND_FOLDER = searchInFolderHierarchy('commands', fileURLToPath(import.meta.url));
16
+ export const CONFIG_FILE = process.cwd() + '/.autoforce.json';
16
17
  export const TEMPLATES_FOLDER = searchInFolderHierarchy('templates', fileURLToPath(import.meta.url));
17
- export const DICTIONARY_FOLDER = TEMPLATES_FOLDER + "/diccionarios";
18
+ export const TEMPLATE_MODEL_FOLDER = TEMPLATES_FOLDER + '/' + getConfig('modelTemplates', 'modelA');
19
+ export const DICTIONARY_FOLDER = TEMPLATE_MODEL_FOLDER + "/diccionarios";
18
20
  export const WORKING_FOLDER = process.env.INIT_CWD || ".";
19
- export const CONFIG_FILE = process.cwd() + '/.autoforce.json';
20
21
  export const filterJson = (fullPath) => fullPath.endsWith(".json");
21
22
  export const filterDirectory = (fullPath) => fs.lstatSync(fullPath).isDirectory();
22
23
  export const filterFiles = (fullPath) => !fs.lstatSync(fullPath).isDirectory();
@@ -92,7 +93,7 @@ export function createConfigurationFile() {
92
93
  if (gitServices.git === GitServices.GitLab && !process.env.GITLAB_TOKEN) {
93
94
  logWarning('A fin de que la herramienta funcione debe configurar una variable de entorno GITLAB_TOKEN');
94
95
  }
95
- const models = valuesToChoices(getFiles(COMMAND_FOLDER, filterDirectory));
96
+ const models = readJsonSync(`${COMMAND_FOLDER}/models.json`);
96
97
  const automationModel = yield prompts([{
97
98
  type: "select",
98
99
  name: "model",
@@ -124,7 +125,7 @@ export function createConfigurationFile() {
124
125
  const backlogColumn = yield prompts([{
125
126
  type: "text",
126
127
  name: "backlogColumn",
127
- initial: 'Backlog',
128
+ initial: 'Todo',
128
129
  message: "Nombre de la columna donde se crean nuevos issues"
129
130
  }]);
130
131
  optionals['backlogColumn'] = backlogColumn.backlogColumn;
@@ -135,8 +136,16 @@ export function createConfigurationFile() {
135
136
  name: "projectId",
136
137
  message: "Id del proyecto"
137
138
  }]);
139
+ // Modelo de Dcumentacion
140
+ const modelsTemplates = readJsonSync(`${TEMPLATES_FOLDER}/models.json`);
141
+ const modelTemplates = yield prompts([{
142
+ type: "select",
143
+ name: "model",
144
+ message: "Elija un modelo de documentacion",
145
+ choices: modelsTemplates
146
+ }]);
138
147
  // console.log('Genera documentacion');
139
- const config = Object.assign({ model: automationModel.model, gitServices: gitServices.git, projectServices: projectServices.project, projectId: projectId.projectId }, optionals);
148
+ const config = Object.assign({ model: automationModel.model, modelTemplates: modelTemplates.model, gitServices: gitServices.git, projectServices: projectServices.project, projectId: projectId.projectId }, optionals);
140
149
  try {
141
150
  fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
142
151
  }
@@ -146,6 +155,35 @@ export function createConfigurationFile() {
146
155
  return true;
147
156
  });
148
157
  }
158
+ export function getConfig(variable, defaultValue) {
159
+ if (fs.existsSync(CONFIG_FILE)) {
160
+ const content = fs.readFileSync(CONFIG_FILE, "utf8");
161
+ try {
162
+ const config = JSON.parse(content);
163
+ if (config[variable]) {
164
+ return config[variable];
165
+ }
166
+ }
167
+ catch (_a) {
168
+ return defaultValue;
169
+ }
170
+ }
171
+ return defaultValue;
172
+ }
173
+ export function storeConfig(variable, value) {
174
+ let config = {};
175
+ if (fs.existsSync(CONFIG_FILE)) {
176
+ const content = fs.readFileSync(CONFIG_FILE, "utf8");
177
+ try {
178
+ config = JSON.parse(content);
179
+ }
180
+ catch (_a) {
181
+ throw new Error(`Verifique que el ${CONFIG_FILE} sea json valido`);
182
+ }
183
+ }
184
+ config[variable] = value;
185
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
186
+ }
149
187
  export function sortByName(objA, objB) {
150
188
  return objA.Name > objB.Name ? 1 : objA.Name < objB.Name ? -1 : 0;
151
189
  }
@@ -239,3 +277,8 @@ export function convertKeyToName(key) {
239
277
  .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
240
278
  .join(' ');
241
279
  }
280
+ export function readJsonSync(filename) {
281
+ const content = fs.readFileSync(filename, "utf8");
282
+ const data = JSON.parse(content);
283
+ return data;
284
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "autoforce",
3
3
  "homepage": "https://sebastianclaros.github.io/autoforce",
4
4
  "private": false,
5
- "version": "0.1.9",
5
+ "version": "0.1.10",
6
6
  "keywords": [
7
7
  "Salesforce",
8
8
  "Automation",
@@ -0,0 +1,4 @@
1
+
2
+ {{#each issues}}
3
+ * {{title}}
4
+ {{/each}}
File without changes
@@ -0,0 +1,13 @@
1
+ [
2
+ {
3
+ "title": "Procesos de Negocio en Salesforce",
4
+ "value": "modelA",
5
+ "description": "Documenta Clases, Objetos y LWC a traves de procesos de negocios. Se basa en docusaurus"0
6
+ },
7
+ {
8
+ "title": "Proyecto simple en Github Docs",
9
+ "value": "modelB",
10
+ "description": "Github pages con changelog, readme y carpeta docs de Markdowns"
11
+ }
12
+ ]
13
+
@@ -1,32 +0,0 @@
1
- ---
2
- sidebar_position: 1
3
- tags: [{ { rol } }]
4
- ---
5
-
6
- # {{titulo}}
7
-
8
- - Modulo: [{{modulo}}](/{{modulo}})
9
- - Roles: [{{rol}}](/tags/{{rol}})
10
-
11
- ## Descripcion:
12
-
13
- ## Escenarios
14
-
15
- 1.
16
-
17
- <!-- START autogenerated-objects -->
18
- <!-- END autogenerated-objects -->
19
-
20
- <!-- START autogenerated-classes -->
21
- <!-- END autogenerated-classes -->
22
-
23
- <!-- START autogenerated-usecase -->
24
-
25
- :::tip
26
- Para refrescar metadata:
27
-
28
- ```bash
29
- {{command}}
30
- ```
31
-
32
- <!-- END autogenerated-usecase -->
@@ -1,52 +0,0 @@
1
- ---
2
- sidebar_position: 1
3
- tags: [{ { actor } }]
4
- ---
5
-
6
- # {{titulo}}
7
-
8
- - Modulo: [{{modulo}}](/{{modulo}})
9
- - Roles: [{{actor}}](/tags/{{actor}})
10
- - Alcance:
11
- - Proposito:
12
-
13
- ## Descripcion:
14
-
15
- - Suposiciones:
16
- - Cuando:
17
- - Precondiciones:
18
- - Postcondiciones:
19
-
20
- ## Flujo Principal
21
-
22
- _Pasos: _
23
-
24
- 1.
25
-
26
- ## Flujos Alternativos
27
-
28
- _Pasos: _
29
-
30
- 1.
31
-
32
- ## Use cases relacionados
33
-
34
- | Nombre | Descripcion |
35
- | ------ | ----------- |
36
-
37
- <!-- START autogenerated-objects -->
38
- <!-- END autogenerated-objects -->
39
-
40
- <!-- START autogenerated-classes -->
41
- <!-- END autogenerated-classes -->
42
-
43
- <!-- START autogenerated-usecase -->
44
-
45
- :::tip
46
- Para refrescar metadata:
47
-
48
- ```bash
49
- {{command}}
50
- ```
51
-
52
- <!-- END autogenerated-usecase -->
File without changes
File without changes