autoforce 0.1.22 → 0.1.24

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/.autoforce.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.22",
2
+ "version": "0.1.23",
3
3
  "backlogColumn": "Todo",
4
4
  "gitServices": "github",
5
5
  "gitModel": "githubflow",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Versiones
2
2
 
3
+ 0.1.23
4
+ ## Version 0.1.23
5
+ - Fecha:
6
+ - Paquete: [Descargar](https://www.npmjs.com/package/autoforce/v/0.1.23)
7
+ - Cambios:
8
+ * Bugfixing para la suit de test autoforce-test
9
+
10
+ ## Version 0.1.22
11
+ - Fecha:
12
+ - Paquete: [Descargar](https://www.npmjs.com/package/autoforce/v/0.1.22)
13
+ - Cambios:
14
+ * [publish] que cierre el milestone de la version
15
+ - https://github.com/sebastianclaros/autoforce/issues/35
16
+
3
17
  ## Version 0.1.20
4
18
  - Fecha:
5
19
  - Paquete: [Descargar](https://www.npmjs.com/package/autoforce/v/0.1.20)
package/README.md CHANGED
@@ -35,19 +35,32 @@ En cada una de ellas buscamos automatizar o integrar las siguientes gestiones:
35
35
  - Calidad de codigo (PMD)
36
36
  - Uso de IA ( OpenAI, )
37
37
 
38
+ ## Tipos de Modelos
39
+
40
+ Al principio habia pensando en una lista de modelos, ejemplo paquetes de appexchange y otro para proyectos sobre salesforce.
41
+
42
+ Pero al final vi que los modelos son combinaciones de acuerdo a las siguientes variables:
43
+ - Branching strategy: En este sentido, el start y finish van a hacer task distintas, si quiero un gitflow o main
44
+ - Tipo de desarrollo: Si estoy desarrollando paquetes o usango scratch en el start voy a buscar que me arme un ambiente nuevo
45
+ - Tipo de Projecto: Si el projecto maneja milestones como releases, cambian o se agregan mas preguntas en algunos steps
46
+ - Modelo de documentacion: La documentacion estaria muy relacionada con el tipo de desarrollo, pero quedo como una variable aparte por orden.
47
+
48
+
38
49
  ## Roadmap Status
39
50
 
40
- 1. Modelos
41
- - [Model A] "Procesos de Negocio en Clientes de Salesforce": 70%
51
+ 1. Implementaciones
52
+ - "Procesos de Negocio en Clientes de Salesforce": 70%
42
53
  Salesforce: Scratchs con Tracking y deploys usando sf cli
43
54
  Documentacion: Markdowns de Procesos con Github pages
44
- Gestion de Proyecto: Github Project
45
- Source Control: Github
55
+ Gestion de Proyecto: Project con milestones
46
56
  Branching Strategy: Github workflow
47
57
 
48
- - [Model B] "Desarrollo de Producto": 0%
58
+ - "Desarrollo de Producto": 30%
59
+ Salesforce: Scratchs con Tracking y deploys con second generation package
60
+ Documentacion: Markdowns de Procesos con Github pages
61
+ Gestion de Proyecto: Project con milestones
62
+ Branching Strategy: Gitflow workflow
49
63
 
50
- - [Custom] "Modelo personalizado"
51
64
 
52
65
  2. Github Services
53
66
  - Github: Listo
@@ -72,9 +85,17 @@ En cada una de ellas buscamos automatizar o integrar las siguientes gestiones:
72
85
  - Documentation: 0%
73
86
 
74
87
 
88
+ ## Repositorio de Ejemplo
89
+ En el siguiente [repositorio](https://github.com/sebastianclaros/autoforce-test) tomamos como ejemplo un proyecto de Salesforce.
90
+ En la carpeta scripts/test hay una serie de comandos (all.sh), que hace de forma autamtizada lo siguiente:
91
+
92
+ * Hace un upgrade de autoforce
93
+ * Crea un Milestone representando un release nuevo
94
+ * Crea 3 issues dentro de ese Milestone
75
95
 
76
96
 
77
- ## Usos
97
+ ## Uso
98
+
78
99
  Una vez instalado se puede crear scripts a medida o bien ejecutar
79
100
 
80
101
  ```
@@ -102,7 +123,8 @@ https://github.com/sebastianclaros/autoforce-test
102
123
  La guia del readme sirve de ejemplo.
103
124
 
104
125
 
105
- ## Testear una version
126
+
127
+ ## Testear una version en forma local
106
128
 
107
129
  Para hacer un testeo local se puede generar una version nueva
108
130
 
package/lib/auto.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import type { ConfigArguments } from "./types/auto.js";
2
- export default function main(): Promise<void>;
2
+ export default function main(): Promise<true | undefined>;
3
3
  export declare function getConfigFromArgs(processArgs: string[]): ConfigArguments;
package/lib/auto.js CHANGED
@@ -27,23 +27,22 @@ export default async function main() {
27
27
  try {
28
28
  const config = getConfigFromArgs(process.argv.slice(2));
29
29
  const taskCommandKeys = Object.keys(taskCommand);
30
- if (taskCommandKeys.includes(config.command)) {
31
- const tasks = getTasks(config.subfolder);
32
- const taskName = await askForTaskName(config.taskName, tasks);
33
- if (taskName) {
34
- const task = tasks[taskName];
35
- context.options = config.arguments && task.arguments ? { ...config.options, ...createObject(task.arguments, config.arguments) } : config.options;
36
- // Valida los json de task y subtask
37
- if (validateTask(task)) {
38
- await taskCommand[config.command](task, context.options);
39
- }
40
- else {
41
- logError('Verifique que los json de task y subtask esten validos');
42
- }
43
- }
44
- }
45
- else {
30
+ if (!taskCommandKeys.includes(config.command)) {
46
31
  await proxyCommand[config.command](config.taskName, config.options);
32
+ return true;
33
+ }
34
+ const tasks = getTasks(config.subfolder);
35
+ const taskName = await askForTaskName(config.taskName, tasks);
36
+ if (taskName) {
37
+ const task = tasks[taskName];
38
+ context.options = config.arguments && task.arguments ? { ...config.options, ...createObject(task.arguments, config.arguments) } : config.options;
39
+ // Valida los json de task y subtask
40
+ if (validateTask(task)) {
41
+ await taskCommand[config.command](task, context.options);
42
+ }
43
+ else {
44
+ logError('Verifique que los json de task y subtask esten validos');
45
+ }
47
46
  }
48
47
  }
49
48
  catch (error) {
@@ -23,6 +23,7 @@ declare class Context implements IObjectRecord {
23
23
  devModel: string | undefined;
24
24
  gitModel: string | undefined;
25
25
  docModel: string | undefined;
26
+ errorMessage: string;
26
27
  projectModel: string | undefined;
27
28
  gitServices: GitServices;
28
29
  isGitApi: boolean;
@@ -69,7 +70,8 @@ declare class Context implements IObjectRecord {
69
70
  loadProjectApi(): void;
70
71
  loadGitApi(): void;
71
72
  loadPackage(): void;
72
- loadConfig(): Promise<boolean>;
73
+ createConfig(): Promise<boolean | undefined>;
74
+ loadConfig(): true | undefined;
73
75
  init(): void;
74
76
  get targetOrg(): string;
75
77
  get existBranchScratch(): boolean;
@@ -30,7 +30,7 @@ const filterProcesses = (fullPath) => fullPath.endsWith(".md"); // && !fullPath.
30
30
  const ISSUES_TYPES = [{ value: 'feature', title: 'feature' }, { value: 'bug', title: 'bug' }, { value: 'documentation', title: 'documentation' }, { value: 'automation', title: 'automation' }];
31
31
  function searchInFolderHierarchy(element, parentFolder) {
32
32
  if (fs.existsSync(`${parentFolder}/${element}`)) {
33
- return `${parentFolder}/${element}`;
33
+ return parentFolder;
34
34
  }
35
35
  else {
36
36
  const lastIndex = parentFolder.lastIndexOf('/');
@@ -46,9 +46,10 @@ function searchInFolderHierarchy(element, parentFolder) {
46
46
  function getDataFromPackage() {
47
47
  const data = {};
48
48
  try {
49
- const filename = searchInFolderHierarchy("package.json", process.cwd());
50
- if (!filename) {
51
- throw new Error("No se encontro el package.json en " + process.cwd());
49
+ const PROJECT_FOLDER = searchInFolderHierarchy('package.json', process.cwd() || '.');
50
+ const filename = `${PROJECT_FOLDER}/package.json`;
51
+ if (!fs.existsSync(filename)) {
52
+ throw new Error("No se encontro el package.json en " + PROJECT_FOLDER);
52
53
  }
53
54
  const content = fs.readFileSync(filename, "utf8");
54
55
  const packageJson = JSON.parse(content);
@@ -89,6 +90,7 @@ class Context {
89
90
  devModel; // Default Model de commands
90
91
  gitModel;
91
92
  docModel;
93
+ errorMessage = '';
92
94
  projectModel;
93
95
  gitServices = GitServices.None;
94
96
  isGitApi = false;
@@ -234,7 +236,7 @@ class Context {
234
236
  this.repositoryOwner = data.repositoryOwner;
235
237
  this.repositoryRepo = data.repositoryRepo;
236
238
  }
237
- async loadConfig() {
239
+ async createConfig() {
238
240
  if (!fs.existsSync(CONFIG_FILE)) {
239
241
  logWarning('Bienvenido! La herramienta Autoforce necesita un primer paso de configuracion antes de usarla.');
240
242
  logWarning('- Podes usar el asistente ejecutando npx autoforce config');
@@ -252,19 +254,24 @@ class Context {
252
254
  }
253
255
  return false;
254
256
  }
255
- const content = fs.readFileSync(CONFIG_FILE, "utf8");
256
- try {
257
- const config = JSON.parse(content);
258
- for (const key in config) {
259
- this.set(key, config[key]);
257
+ }
258
+ loadConfig() {
259
+ if (fs.existsSync(CONFIG_FILE)) {
260
+ const content = fs.readFileSync(CONFIG_FILE, "utf8");
261
+ try {
262
+ const config = JSON.parse(content);
263
+ for (const key in config) {
264
+ this.set(key, config[key]);
265
+ }
260
266
  }
267
+ catch {
268
+ throw new Error(`Verifique que el ${CONFIG_FILE} sea json valido`);
269
+ }
270
+ return true;
261
271
  }
262
- catch {
263
- throw new Error(`Verifique que el ${CONFIG_FILE} sea json valido`);
264
- }
265
- return true;
266
272
  }
267
273
  init() {
274
+ this.createConfig();
268
275
  this.loadProjectApi();
269
276
  this.loadGitApi();
270
277
  //
@@ -447,6 +454,12 @@ class Context {
447
454
  return this.newBranchName;
448
455
  }
449
456
  async askFornewIssueNumber() {
457
+ if (this.options.issue && this.projectApi) {
458
+ const issues = await this.projectApi.searchIssues(this.options.issue);
459
+ if (issues.length === 1) {
460
+ return `${issues[0].number}`;
461
+ }
462
+ }
450
463
  const answer = await prompts([
451
464
  {
452
465
  type: "text",
@@ -49,6 +49,7 @@ export declare class GitHubProjectApi extends GitHubApi implements IProjectApi {
49
49
  id: string;
50
50
  title: string;
51
51
  }[]>;
52
+ searchIssues(title: string): Promise<IIssueObject[]>;
52
53
  getIssuesWithFilter(filterBy: string): Promise<{
53
54
  id: string;
54
55
  title: string;
@@ -213,6 +213,21 @@ export class GitHubProjectApi extends GitHubApi {
213
213
  async getIssues() {
214
214
  return await this.getIssuesWithFilter(`{ states: OPEN }`);
215
215
  }
216
+ async searchIssues(title) {
217
+ const query = `query getIssues() {
218
+ search(query: "repo:${this.repoVar.owner}/${this.repoVar.repo} in:title ${title}", type: ISSUE, first: 10) {
219
+ nodes {
220
+ ... on Issue {
221
+ id
222
+ number
223
+ title
224
+ }
225
+ }
226
+ }
227
+ }`;
228
+ const { search } = await this.graphqlAuth(query, this.repoVar);
229
+ return search.nodes;
230
+ }
216
231
  async getIssuesWithFilter(filterBy) {
217
232
  const query = `
218
233
  query getIssues($owner:String!, $repo: String!) {
@@ -24,6 +24,7 @@ export declare class GitLabApi implements IGitApi, IProjectApi {
24
24
  state: string;
25
25
  url: string;
26
26
  }>;
27
+ searchIssues(title: string): Promise<IIssueObject[]>;
27
28
  updateMilestone(title: string, state?: string, description?: string, dueOn?: string): Promise<{
28
29
  id: string;
29
30
  title: string;
@@ -35,6 +35,10 @@ export class GitLabApi {
35
35
  console.log(title, state, description, dueOn);
36
36
  return { id: '', title: '', state: '', url: '' };
37
37
  }
38
+ async searchIssues(title) {
39
+ console.log(title);
40
+ return [];
41
+ }
38
42
  async updateMilestone(title, state = 'open', description, dueOn) {
39
43
  console.log(title, state, description, dueOn);
40
44
  return { id: '', title: '', state: '', url: '' };
@@ -316,7 +316,6 @@ export const taskFunctions = {
316
316
  if (context.projectApi === undefined || context.gitApi === undefined) {
317
317
  return false;
318
318
  }
319
- console.log(title, state, description, dueOn);
320
319
  const result = await context.gitApi.updateMilestone(title, state, description, dueOn);
321
320
  return result?.id ? true : false;
322
321
  },
@@ -376,14 +375,21 @@ export const taskFunctions = {
376
375
  },
377
376
  async validateIssue(issueNumber, states) {
378
377
  if (context.projectApi === undefined) {
378
+ context.errorMessage = 'context.projectApi esta undefined';
379
379
  return false;
380
380
  }
381
381
  const issue = await context.projectApi.getIssue(issueNumber);
382
382
  if (!issue.state) {
383
+ context.errorMessage = 'El state del issue es undefined';
383
384
  return false;
384
385
  }
385
386
  const arrayStates = states.toLocaleLowerCase().replace(' ', '').split(',');
386
- return arrayStates.includes(issue.state.toLocaleLowerCase().replace(' ', ''));
387
+ const validate = arrayStates.includes(issue.state.toLocaleLowerCase().replace(' ', ''));
388
+ if (!validate) {
389
+ context.errorMessage = `El state del issue es "${issue.state}", mientras deberia ser ${states}`;
390
+ return false;
391
+ }
392
+ return true;
387
393
  },
388
394
  async validaNoseaBranchActual(newBranchName) {
389
395
  return getBranchName() !== newBranchName;
@@ -1,6 +1,7 @@
1
1
  import { Choice } from "prompts";
2
2
  import { AnyValue, CommandOptions } from "../types/auto.js";
3
3
  export declare const WORKING_FOLDER: string;
4
+ export declare const PROJECT_FOLDER: string;
4
5
  export declare const CONFIG_FILE: string;
5
6
  export declare const DICTIONARY_FOLDER: string;
6
7
  export declare const filterJson: (fullPath: string) => boolean;
@@ -3,9 +3,10 @@ import { fileURLToPath } from 'url';
3
3
  import prompts from "prompts";
4
4
  import context, { ProjectServices, GitServices } from "./context.js";
5
5
  import { logInfo, logWarning } from "./color.js";
6
- const MODELS_FOLDER = searchInFolderHierarchy('models', fileURLToPath(import.meta.url));
6
+ const MODELS_FOLDER = searchInFolderHierarchy('models', fileURLToPath(import.meta.url)) + '/models';
7
7
  export const WORKING_FOLDER = process.env.INIT_CWD || ".";
8
- export const CONFIG_FILE = searchInFolderHierarchy('.autoforce.json', WORKING_FOLDER);
8
+ export const PROJECT_FOLDER = searchInFolderHierarchy('package.json', WORKING_FOLDER);
9
+ export const CONFIG_FILE = PROJECT_FOLDER + '/.autoforce.json';
9
10
  export const DICTIONARY_FOLDER = process.cwd() + "/docs"; // context.dictionaryFolder;
10
11
  export const filterJson = (fullPath) => fullPath.endsWith(".json");
11
12
  export const filterDirectory = (fullPath) => fs.lstatSync(fullPath).isDirectory();
@@ -259,7 +260,7 @@ export function addNewItems(baseArray, newArray) {
259
260
  }
260
261
  export function searchInFolderHierarchy(element, parentFolder) {
261
262
  if (fs.existsSync(`${parentFolder}/${element}`)) {
262
- return `${parentFolder}/${element}`;
263
+ return parentFolder;
263
264
  }
264
265
  else {
265
266
  const lastIndex = parentFolder.lastIndexOf('/');
@@ -8,8 +8,8 @@
8
8
  "steps": [
9
9
  { "name": "Actualiza la version", "function": "storeConfig", "arguments": ["version", "${newVersion}"] },
10
10
  { "name": "Paquetiza", "subtask": "pack" },
11
+ { "name": "Salida para el Changelog.md", "task": "list", "arguments": {"filter": "milestone", "template": "changelog", "milestone": "v${newVersion}"} },
11
12
  { "name": "Publica", "command": "yarn publish ", "arguments": {"--new-version": "${newVersion}"} },
12
- { "name": "Salida para el Changelog.md", "task": "list", "arguments": {"filter": "milestone", "template": "changelog", "milestone": "${newVersion}"} },
13
13
  { "name": "Actualiza el milestone", "function": "updateMilestone", "arguments": ["v${newVersion}", "closed"] }
14
14
  ]
15
15
  }
@@ -7,9 +7,9 @@
7
7
  {
8
8
  "name": "validate issue",
9
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"
10
+ "arguments": ["${newIssueNumber}", "Todo"],
11
+ "description": "Valida que Issue este en la Columna Todo",
12
+ "errorMessage": "Por favor verifique que el issue ${newIssueNumber} este en la columna Todo. \n ${errorMessage}"
13
13
  },
14
14
  {
15
15
  "name": "check Issue type based on Labels",
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.22",
5
+ "version": "0.1.24",
6
6
  "keywords": [
7
7
  "Salesforce",
8
8
  "Automation",