pypeline 1.0.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.
Files changed (43) hide show
  1. package/README.md +448 -0
  2. package/lib/commands/pypeline/build.d.ts +18 -0
  3. package/lib/commands/pypeline/build.js +86 -0
  4. package/lib/commands/pypeline/build.js.map +1 -0
  5. package/lib/commands/pypeline/deploy/training.d.ts +15 -0
  6. package/lib/commands/pypeline/deploy/training.js +62 -0
  7. package/lib/commands/pypeline/deploy/training.js.map +1 -0
  8. package/lib/commands/pypeline/package.d.ts +11 -0
  9. package/lib/commands/pypeline/package.js +27 -0
  10. package/lib/commands/pypeline/package.js.map +1 -0
  11. package/lib/commands/pypeline/prd.d.ts +16 -0
  12. package/lib/commands/pypeline/prd.js +78 -0
  13. package/lib/commands/pypeline/prd.js.map +1 -0
  14. package/lib/commands/pypeline/quickdeploy.d.ts +18 -0
  15. package/lib/commands/pypeline/quickdeploy.js +116 -0
  16. package/lib/commands/pypeline/quickdeploy.js.map +1 -0
  17. package/lib/commands/pypeline/run.d.ts +19 -0
  18. package/lib/commands/pypeline/run.js +161 -0
  19. package/lib/commands/pypeline/run.js.map +1 -0
  20. package/lib/commands/pypeline/training.d.ts +15 -0
  21. package/lib/commands/pypeline/training.js +67 -0
  22. package/lib/commands/pypeline/training.js.map +1 -0
  23. package/lib/commands/pypeline/validate/prd.d.ts +16 -0
  24. package/lib/commands/pypeline/validate/prd.js +78 -0
  25. package/lib/commands/pypeline/validate/prd.js.map +1 -0
  26. package/lib/config.d.ts +23 -0
  27. package/lib/config.js +72 -0
  28. package/lib/config.js.map +1 -0
  29. package/lib/fileUtils.d.ts +2 -0
  30. package/lib/fileUtils.js +78 -0
  31. package/lib/fileUtils.js.map +1 -0
  32. package/lib/index.d.ts +2 -0
  33. package/lib/index.js +2 -0
  34. package/lib/index.js.map +1 -0
  35. package/messages/pypeline.build.md +16 -0
  36. package/messages/pypeline.deploy.training.md +15 -0
  37. package/messages/pypeline.package.md +8 -0
  38. package/messages/pypeline.quickdeploy.md +22 -0
  39. package/messages/pypeline.run.md +26 -0
  40. package/messages/pypeline.validate.prd.md +15 -0
  41. package/oclif.lock +7808 -0
  42. package/oclif.manifest.json +544 -0
  43. package/package.json +163 -0
package/README.md ADDED
@@ -0,0 +1,448 @@
1
+ # pypeline — SF CLI Plugin
2
+
3
+ Pipeline DevOps Salesforce completo como plugin nativo do `sf` CLI. Orquestra build, geração de package.xml, validação em PRD e quick deploy a partir de um repositório git.
4
+
5
+ ---
6
+
7
+ ## Índice
8
+
9
+ - [Pré-requisitos](#pré-requisitos)
10
+ - [Instalação](#instalação)
11
+ - [Configuração inicial](#configuração-inicial)
12
+ - [Como buildar o plugin](#como-buildar-o-plugin)
13
+ - [Comandos disponíveis](#comandos-disponíveis)
14
+ - [Fluxo completo de uso](#fluxo-completo-de-uso)
15
+ - [Testes](#testes)
16
+ - [Estrutura do projeto](#estrutura-do-projeto)
17
+ - [Solução de problemas](#solução-de-problemas)
18
+
19
+ ---
20
+
21
+ ## Pré-requisitos
22
+
23
+ Antes de começar, certifique-se de ter instalado:
24
+
25
+ - **Node.js** >= 18.0.0
26
+ - **Yarn** (recomendado) ou npm
27
+ - **Salesforce CLI** (`sf`) >= 2.x — instale com `npm install -g @salesforce/cli`
28
+ - **Git** configurado no PATH
29
+ - **Python 3** (apenas se você ainda usar os scripts `.py` originais em paralelo)
30
+
31
+ Verifique as versões:
32
+
33
+ ```bash
34
+ node --version # deve ser >= 18
35
+ sf --version # deve ser >= 2
36
+ git --version
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Instalação
42
+
43
+ ### Opção 1 — Link local (desenvolvimento)
44
+
45
+ É o modo recomendado enquanto você está desenvolvendo o plugin:
46
+
47
+ ```bash
48
+ # 1. Entre na pasta do plugin
49
+ cd pypeline
50
+
51
+ # 2. Instale as dependências
52
+ yarn install
53
+
54
+ # 3. Compile o TypeScript
55
+ yarn build
56
+
57
+ # 4. Linke o plugin no sf CLI local
58
+ sf plugins link .
59
+ ```
60
+
61
+ Após o link, o plugin fica disponível globalmente no seu `sf`:
62
+
63
+ ```bash
64
+ sf pypeline --help
65
+ ```
66
+
67
+ Para atualizar o plugin após alterar código, recompile e o link já pega automaticamente:
68
+
69
+ ```bash
70
+ yarn build
71
+ ```
72
+
73
+ ### Opção 2 — Instalação a partir de um diretório (sem publicar no npm)
74
+
75
+ ```bash
76
+ sf plugins install /caminho/absoluto/para/pypeline
77
+ ```
78
+
79
+ ### Opção 3 — Publicar no npm e instalar
80
+
81
+ ```bash
82
+ # Dentro da pasta do plugin
83
+ npm publish
84
+
85
+ # Em qualquer máquina
86
+ sf plugins install pypeline
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Configuração inicial
92
+
93
+ Antes de usar o pipeline, você precisa de dois arquivos na pasta `workspace_bash`:
94
+
95
+ ### 1. `baseline.txt`
96
+
97
+ Contém o hash do commit git que serve como ponto de partida do diff. O pipeline copia apenas os arquivos alterados **a partir desse commit**.
98
+
99
+ ```bash
100
+ # Criar com o hash atual (ponto zero)
101
+ git rev-parse HEAD > baseline.txt
102
+
103
+ # Ou com um commit específico
104
+ echo "abc1234def5678..." > baseline.txt
105
+ ```
106
+
107
+ ### 2. Autenticação das orgs no sf CLI
108
+
109
+ O pipeline usa dois aliases de org por padrão:
110
+
111
+ | Alias | Finalidade |
112
+ |-------|-----------|
113
+ | `devops` | Org de produção (PRD) |
114
+ | `treino` | Org de treinamento |
115
+
116
+ Autentique cada uma:
117
+
118
+ ```bash
119
+ sf org login web --alias devops
120
+ sf org login web --alias treino
121
+ ```
122
+
123
+ Para usar aliases diferentes, passe as flags `--prd-org` e `--training-org` nos comandos.
124
+
125
+ ---
126
+
127
+ ## Como buildar o plugin
128
+
129
+ O projeto usa **TypeScript** compilado via `tsc` com **wireit** para cache incremental.
130
+
131
+ ```bash
132
+ # Build completo (compila + lint)
133
+ yarn build
134
+
135
+ # Apenas compilar TypeScript (mais rápido, sem lint)
136
+ yarn compile
137
+
138
+ # Limpar os artefatos de build
139
+ yarn clean
140
+
141
+ # Limpar tudo (incluindo node_modules)
142
+ yarn clean-all
143
+ ```
144
+
145
+ Os arquivos compilados ficam em `lib/` — é o que o sf CLI carrega em produção.
146
+
147
+ > **Atenção:** nunca edite arquivos em `lib/` diretamente. Sempre edite em `src/` e recompile.
148
+
149
+ ---
150
+
151
+ ## Comandos disponíveis
152
+
153
+ ### `sf pypeline run` — Pipeline completo
154
+
155
+ Executa todas as 4 etapas em sequência. O deploy em Training roda em paralelo ao validate PRD. Em caso de falha em qualquer etapa, faz rollback automático do `baseline.txt`.
156
+
157
+ ```bash
158
+ # Execução padrão
159
+ sf pypeline run
160
+
161
+ # Com branch customizada
162
+ sf pypeline run --branch release-v5.0.0
163
+
164
+ # Pulando o deploy em Training
165
+ sf pypeline run --skip-training
166
+
167
+ # Com orgs customizadas
168
+ sf pypeline run --prd-org minha-producao --training-org minha-homolog
169
+
170
+ # Simulando o build sem copiar arquivos
171
+ sf pypeline run --dry-run
172
+ ```
173
+
174
+ **Flags disponíveis:**
175
+
176
+ | Flag | Padrão | Descrição |
177
+ |------|--------|-----------|
178
+ | `--branch, -b` | valor em `config.ts` | Branch git para checkout no build |
179
+ | `--skip-training` | `false` | Pula o deploy em Training |
180
+ | `--dry-run` | `false` | Simula o build sem tocar em arquivos |
181
+ | `--prd-org` | `devops` | Alias da org de produção |
182
+ | `--training-org` | `treino` | Alias da org de treinamento |
183
+
184
+ ---
185
+
186
+ ### `sf pypeline build` — Etapa 1
187
+
188
+ Faz checkout da branch, git pull, calcula o diff desde o baseline e copia os arquivos alterados para a pasta `build_deploy/`.
189
+
190
+ ```bash
191
+ sf pypeline build
192
+ sf pypeline build --branch release-v5.0.0
193
+ sf pypeline build --dry-run
194
+ ```
195
+
196
+ Arquivos gerados após a execução:
197
+
198
+ ```
199
+ workspace_bash/
200
+ ├── build_deploy/ ← pasta com os arquivos do deploy
201
+ ├── commitlist.txt ← lista de commits desde o baseline
202
+ ├── lista_arquivos_adicionados.txt
203
+ ├── lista_arquivos_modificados.txt
204
+ ├── lista_arquivos_deletados.txt
205
+ └── lista_arquivos_naodeletados.txt
206
+ ```
207
+
208
+ ---
209
+
210
+ ### `sf pypeline package` — Etapa 2
211
+
212
+ Gera o `package.xml` a partir da pasta de build usando `sf project generate manifest`.
213
+
214
+ ```bash
215
+ sf pypeline package
216
+ ```
217
+
218
+ ---
219
+
220
+ ### `sf pypeline deploy training` — Etapa 3
221
+
222
+ Deploy na org de treinamento com `RunLocalTests`. Grava output em `deploy_training_output.log`.
223
+
224
+ ```bash
225
+ sf pypeline deploy training
226
+ sf pypeline deploy training --target-org minha-org-treino
227
+ sf pypeline deploy training --wait 120
228
+ ```
229
+
230
+ | Flag | Padrão | Descrição |
231
+ |------|--------|-----------|
232
+ | `--target-org, -o` | `treino` | Alias da org de treinamento |
233
+ | `--wait, -w` | `240` | Minutos de espera pelo resultado |
234
+
235
+ ---
236
+
237
+ ### `sf pypeline validate prd` — Etapa 4
238
+
239
+ Valida o deploy em produção (sem efetivá-lo). Extrai o Job ID do output e salva em `prd_job_id.txt`. Grava output em `deploy_prd_output.log`.
240
+
241
+ ```bash
242
+ sf pypeline validate prd
243
+ sf pypeline validate prd --target-org minha-producao
244
+ ```
245
+
246
+ | Flag | Padrão | Descrição |
247
+ |------|--------|-----------|
248
+ | `--target-org, -o` | `devops` | Alias da org de produção |
249
+ | `--wait, -w` | `240` | Minutos de espera pela validação |
250
+
251
+ ---
252
+
253
+ ### `sf pypeline quickdeploy` — Quick deploy
254
+
255
+ Executa o quick deploy em produção usando o Job ID salvo. O Job ID expira **10 horas** após o validate. Remove `prd_job_id.txt` após sucesso para evitar reuso.
256
+
257
+ ```bash
258
+ # Lê o Job ID de prd_job_id.txt automaticamente
259
+ sf pypeline quickdeploy
260
+
261
+ # Passando o Job ID diretamente (sem precisar do arquivo)
262
+ sf pypeline quickdeploy --job-id 0Af000000000001AAA
263
+
264
+ # Sem confirmação interativa (para CI/CD)
265
+ sf pypeline quickdeploy --no-prompt
266
+ ```
267
+
268
+ | Flag | Padrão | Descrição |
269
+ |------|--------|-----------|
270
+ | `--target-org, -o` | `devops` | Alias da org de produção |
271
+ | `--job-id, -j` | lê do arquivo | Job ID da validação |
272
+ | `--wait, -w` | `240` | Minutos de espera |
273
+ | `--no-prompt` | `false` | Pula a confirmação interativa |
274
+
275
+ ---
276
+
277
+ ## Fluxo completo de uso
278
+
279
+ ### Fluxo padrão (recomendado)
280
+
281
+ ```bash
282
+ # 1. Execute o pipeline completo
283
+ sf pypeline run
284
+
285
+ # 2. Quando o pipeline terminar com sucesso, o Job ID fica salvo.
286
+ # Execute o quick deploy (feito pelo time de PRD):
287
+ sf pypeline quickdeploy
288
+ ```
289
+
290
+ ### Fluxo manual (etapa por etapa)
291
+
292
+ Útil para depurar ou reexecutar apenas uma etapa:
293
+
294
+ ```bash
295
+ # Etapa 1: build
296
+ sf pypeline build
297
+
298
+ # Etapa 2: gerar package.xml
299
+ sf pypeline package
300
+
301
+ # Etapa 3: deploy em Training (em background, se quiser)
302
+ sf pypeline deploy training &
303
+
304
+ # Etapa 4: validar em PRD (síncrono)
305
+ sf pypeline validate prd
306
+
307
+ # Após validação bem-sucedida:
308
+ sf pypeline quickdeploy
309
+ ```
310
+
311
+ ### Fluxo com rollback
312
+
313
+ Se qualquer etapa do `sf pypeline run` falhar, o `baseline.txt` é restaurado automaticamente para o valor anterior. Nenhuma alteração é promovida.
314
+
315
+ Você pode verificar o motivo da falha nos logs:
316
+
317
+ ```bash
318
+ cat deploy_prd_output.log
319
+ cat deploy_training_output.log
320
+ ```
321
+
322
+ ---
323
+
324
+ ## Testes
325
+
326
+ ### Instalar dependências de teste
327
+
328
+ As dependências de teste (mocha, sinon, chai, nyc) já estão no `package.json`. Basta instalar:
329
+
330
+ ```bash
331
+ yarn install
332
+ ```
333
+
334
+ ### Rodar os unit tests
335
+
336
+ Rápidos, sem necessidade de org ou internet. Testam toda a lógica do plugin com mocks.
337
+
338
+ ```bash
339
+ # Rodar unit tests
340
+ yarn test:only
341
+
342
+ # Rodar com relatório de cobertura (exige >= 90%)
343
+ yarn test:coverage
344
+ ```
345
+
346
+ O relatório de cobertura é gerado em `coverage/lcov-report/index.html`.
347
+
348
+ ### Rodar todos os testes (unit + lint + type-check)
349
+
350
+ ```bash
351
+ yarn test
352
+ ```
353
+
354
+ ### Rodar os NUT tests (integração com org real)
355
+
356
+ Os NUT tests rodam o plugin de verdade contra uma org Salesforce. São lentos e opcionais.
357
+
358
+ ```bash
359
+ # NUTs básicos (build + package — não tocam em nenhuma org)
360
+ NUT_ORG_ALIAS=treino yarn test:nuts
361
+
362
+ # Habilitar o validate prd no NUT (cuidado: roda contra a org real)
363
+ RUN_VALIDATE_NUT=1 NUT_ORG_ALIAS=treino yarn test:nuts
364
+
365
+ # Habilitar o quick deploy no NUT (só roda se prd_job_id.txt existir)
366
+ RUN_QUICKDEPLOY_NUT=1 NUT_ORG_ALIAS=treino yarn test:nuts
367
+ ```
368
+
369
+ > **Atenção:** nunca sete `RUN_VALIDATE_NUT` ou `RUN_QUICKDEPLOY_NUT` em pipelines de CI/CD automáticos sem revisão, pois esses testes fazem operações reais em orgs Salesforce.
370
+
371
+ ### Estrutura dos testes
372
+
373
+ ```
374
+ test/
375
+ ├── helpers.ts ← stubs reutilizáveis (fs, spawn, git)
376
+ ├── unit/
377
+ │ ├── config.test.ts ← readFileTrimmed, gitDiffFiles...
378
+ │ ├── fileUtils.test.ts ← cleanFilename, copyFile
379
+ │ └── commands/pypeline/
380
+ │ ├── build.test.ts
381
+ │ ├── package.test.ts
382
+ │ ├── quickdeploy.test.ts
383
+ │ ├── run.test.ts ← rollback, paralelismo, flags
384
+ │ ├── deploy/training.test.ts
385
+ │ └── validate/prd.test.ts ← extração do Job ID
386
+ └── nuts/
387
+ └── pypeline.nut.ts ← testes contra org real
388
+ ```
389
+
390
+ ---
391
+
392
+ ## Estrutura do projeto
393
+
394
+ ```
395
+ pypeline/
396
+ ├── src/
397
+ │ ├── config.ts ← caminhos, constantes, utilitários git/fs
398
+ │ ├── fileUtils.ts ← lógica de cópia de arquivos Salesforce
399
+ │ └── commands/pypeline/
400
+ │ ├── run.ts ← sf pypeline run
401
+ │ ├── build.ts ← sf pypeline build
402
+ │ ├── package.ts ← sf pypeline package
403
+ │ ├── quickdeploy.ts ← sf pypeline quickdeploy
404
+ │ ├── deploy/
405
+ │ │ └── training.ts ← sf pypeline deploy training
406
+ │ └── validate/
407
+ │ └── prd.ts ← sf pypeline validate prd
408
+ ├── messages/
409
+ │ ├── pypeline.run.md
410
+ │ ├── pypeline.build.md
411
+ │ ├── pypeline.package.md
412
+ │ ├── pypeline.quickdeploy.md
413
+ │ ├── pypeline.deploy.training.md
414
+ │ └── pypeline.validate.prd.md
415
+ ├── test/
416
+ │ ├── helpers.ts
417
+ │ ├── unit/
418
+ │ └── nuts/
419
+ ├── lib/ ← compilado pelo tsc (não editar)
420
+ ├── .mocharc.json ← configuração do runner de testes
421
+ ├── .nycrc ← configuração de cobertura (mínimo 90%)
422
+ ├── package.json
423
+ └── tsconfig.json
424
+ ```
425
+
426
+ ---
427
+
428
+ ## Solução de problemas
429
+
430
+ **`sf: command not found` ao linkar o plugin**
431
+
432
+ Verifique se o sf CLI está instalado globalmente: `npm install -g @salesforce/cli`
433
+
434
+ **`Pasta raiz 'workspace_bash' não encontrada`**
435
+
436
+ O `config.ts` sobe na árvore de diretórios procurando uma pasta chamada `workspace_bash`. Certifique-se de que o plugin está dentro dessa estrutura ou ajuste o `marker` em `src/config.ts`.
437
+
438
+ **`baseline.txt não encontrado`**
439
+
440
+ Crie o arquivo com `git rev-parse HEAD > baseline.txt` na raiz de `workspace_bash`.
441
+
442
+ **Job ID não encontrado após o validate**
443
+
444
+ O Job ID é extraído por regex do output do `sf project deploy validate`. Se o formato do output mudar em versões futuras do sf CLI, ajuste o pattern `0Af[0-9A-Za-z]{15}` em `src/commands/pypeline/validate/prd.ts`.
445
+
446
+ **Cobertura abaixo de 90%**
447
+
448
+ Rode `yarn test:coverage` para ver o relatório detalhado e identificar quais linhas não estão cobertas. O limite mínimo está configurado em `.nycrc`.
@@ -0,0 +1,18 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ export type PypelineBuildResult = {
3
+ commitHash: string;
4
+ novoBaseline: string;
5
+ added: string[];
6
+ modified: string[];
7
+ deleted: string[];
8
+ };
9
+ export default class PypelineBuild extends SfCommand<PypelineBuildResult> {
10
+ static readonly summary: string;
11
+ static readonly description: string;
12
+ static readonly examples: string[];
13
+ static readonly flags: {
14
+ branch: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
15
+ 'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ };
17
+ run(): Promise<PypelineBuildResult>;
18
+ }
@@ -0,0 +1,86 @@
1
+ import { execSync, spawnSync } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
5
+ import { Messages } from '@salesforce/core';
6
+ import { BASELINE_FILE, BRANCH, BUILD_DIR, PROJECT_DIR, PROJECT_NAME, SCRIPT_DIR, fileExists, readFileTrimmed, writeFile, gitDiffFiles, } from '../../config.js';
7
+ import { copyFile } from '../../fileUtils.js';
8
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
9
+ const messages = Messages.loadMessages('pypeline', 'pypeline.build');
10
+ export default class PypelineBuild extends SfCommand {
11
+ static summary = messages.getMessage('summary');
12
+ static description = messages.getMessage('description');
13
+ static examples = messages.getMessages('examples');
14
+ static flags = {
15
+ branch: Flags.string({
16
+ char: 'b',
17
+ summary: messages.getMessage('flags.branch.summary'),
18
+ default: BRANCH,
19
+ }),
20
+ 'dry-run': Flags.boolean({
21
+ summary: messages.getMessage('flags.dry-run.summary'),
22
+ default: false,
23
+ }),
24
+ };
25
+ async run() {
26
+ const { flags } = await this.parse(PypelineBuild);
27
+ const branch = flags['branch'];
28
+ const dryRun = flags['dry-run'];
29
+ this.log(`SCRIPT_DIR : ${SCRIPT_DIR}`);
30
+ this.log(`PROJECT_DIR : ${PROJECT_DIR()}`);
31
+ if (!dryRun) {
32
+ const gen = spawnSync('sf', ['project', 'generate', '--name', PROJECT_NAME, '--output-dir', PROJECT_DIR()], {
33
+ encoding: 'utf8',
34
+ stdio: 'inherit',
35
+ });
36
+ if (gen.status !== 0)
37
+ this.error('Falha ao gerar estrutura do projeto sf.');
38
+ }
39
+ if (!fileExists(BASELINE_FILE()))
40
+ this.error('baseline.txt não encontrado!');
41
+ const commitHash = readFileTrimmed(BASELINE_FILE());
42
+ this.log(`Baseline : ${commitHash}`);
43
+ if (!dryRun) {
44
+ for (const cmd of [
45
+ ['git', 'checkout', branch ?? BRANCH],
46
+ ['git', 'fetch'],
47
+ ['git', 'pull'],
48
+ ]) {
49
+ const r = spawnSync(cmd[0], cmd.slice(1), { stdio: 'inherit' });
50
+ if (r.status !== 0)
51
+ this.error(`Falha ao executar: ${cmd.join(' ')}`);
52
+ }
53
+ }
54
+ const commits = execSync(`git rev-list ${commitHash}..HEAD --oneline`, { encoding: 'utf8' });
55
+ writeFile(path.join(PROJECT_DIR(), 'commitlist.txt'), commits);
56
+ if (fs.existsSync(BUILD_DIR()))
57
+ fs.rmSync(BUILD_DIR(), { recursive: true, force: true });
58
+ fs.mkdirSync(BUILD_DIR(), { recursive: true });
59
+ const diff = gitDiffFiles(commitHash);
60
+ writeFile(path.join(PROJECT_DIR(), 'lista_arquivos_naodeletados.txt'), diff.notDeleted.join('\n'));
61
+ writeFile(path.join(PROJECT_DIR(), 'lista_arquivos_deletados.txt'), diff.deleted.join('\n'));
62
+ writeFile(path.join(PROJECT_DIR(), 'lista_arquivos_adicionados.txt'), diff.added.join('\n'));
63
+ writeFile(path.join(PROJECT_DIR(), 'lista_arquivos_modificados.txt'), diff.modified.join('\n'));
64
+ this.log('Arquivos modificados ou adicionados:');
65
+ for (const file of diff.notDeleted) {
66
+ this.log(` Arquivo a ser avaliado: ${file}`);
67
+ if (!dryRun) {
68
+ try {
69
+ copyFile(file, BUILD_DIR());
70
+ }
71
+ catch (err) {
72
+ this.warn(`Erro ao copiar '${file}': ${err.message}`);
73
+ }
74
+ }
75
+ }
76
+ const novoBaseline = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
77
+ this.log(`[INFO] Novo baseline calculado: ${novoBaseline}`);
78
+ this.log('[INFO] baseline.txt será atualizado pelo comando run após validate PRD.');
79
+ process.env['NOVO_BASELINE'] = novoBaseline;
80
+ const branchInfo = execSync('git branch', { encoding: 'utf8' });
81
+ this.log(`Branches:\n${branchInfo}`);
82
+ this.log(`Build project criado em ${BUILD_DIR()}.`);
83
+ return { commitHash, novoBaseline, added: diff.added, modified: diff.modified, deleted: diff.deleted };
84
+ }
85
+ }
86
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/pypeline/build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ export type PypelineDeployTrainingResult = {
3
+ success: boolean;
4
+ logPath: string;
5
+ };
6
+ export default class PypelineDeployTraining extends SfCommand<PypelineDeployTrainingResult> {
7
+ static readonly summary: string;
8
+ static readonly description: string;
9
+ static readonly examples: string[];
10
+ static readonly flags: {
11
+ 'target-org': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
12
+ wait: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
13
+ };
14
+ run(): Promise<PypelineDeployTrainingResult>;
15
+ }
@@ -0,0 +1,62 @@
1
+ import { spawn } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
4
+ import { Messages } from '@salesforce/core';
5
+ import { LOG_TRAINING, SOURCE_DIR, unlinkIfExists } from '../../../config.js';
6
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
+ const messages = Messages.loadMessages('pypeline', 'pypeline.deploy.training');
8
+ export default class PypelineDeployTraining extends SfCommand {
9
+ static summary = messages.getMessage('summary');
10
+ static description = messages.getMessage('description');
11
+ static examples = messages.getMessages('examples');
12
+ static flags = {
13
+ 'target-org': Flags.string({
14
+ summary: messages.getMessage('flags.target-org.summary'),
15
+ default: 'treino',
16
+ }),
17
+ wait: Flags.integer({
18
+ char: 'w',
19
+ summary: messages.getMessage('flags.wait.summary'),
20
+ default: 240,
21
+ }),
22
+ };
23
+ async run() {
24
+ const { flags } = await this.parse(PypelineDeployTraining);
25
+ const logPath = LOG_TRAINING();
26
+ const sourceDir = SOURCE_DIR();
27
+ unlinkIfExists(logPath);
28
+ this.log('Iniciando deploy em Training...');
29
+ const cmd = [
30
+ 'project', 'deploy', 'start',
31
+ '--source-dir', sourceDir,
32
+ '--target-org', flags['target-org'] ?? 'treino',
33
+ '--test-level', 'RunLocalTests',
34
+ '-w', String(flags['wait'] ?? 240),
35
+ '--ignore-conflicts',
36
+ '--verbose',
37
+ ];
38
+ const exitCode = await new Promise((resolve) => {
39
+ const proc = spawn('sf', cmd, { stdio: ['inherit', 'pipe', 'pipe'] });
40
+ const log = fs.createWriteStream(logPath, { flags: 'a' });
41
+ if (proc.stdout)
42
+ proc.stdout.on('data', (chunk) => {
43
+ const text = chunk.toString();
44
+ process.stdout.write(text);
45
+ log.write(text);
46
+ });
47
+ if (proc.stderr)
48
+ proc.stderr.on('data', (chunk) => {
49
+ const text = chunk.toString();
50
+ process.stderr.write(text);
51
+ log.write(text);
52
+ });
53
+ proc.on('close', (code) => { log.close(); resolve(code ?? 1); });
54
+ });
55
+ if (exitCode !== 0) {
56
+ this.error(`Deploy em Training falhou com exit code ${exitCode}.`);
57
+ }
58
+ this.log('Deploy em Training concluído com sucesso.');
59
+ return { success: true, logPath };
60
+ }
61
+ }
62
+ //# sourceMappingURL=training.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"training.js","sourceRoot":"","sources":["../../../../src/commands/pypeline/deploy/training.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ export type PypelinePackageResult = {
3
+ success: boolean;
4
+ buildDir: string;
5
+ };
6
+ export default class PypelinePackage extends SfCommand<PypelinePackageResult> {
7
+ static readonly summary: string;
8
+ static readonly description: string;
9
+ static readonly examples: string[];
10
+ run(): Promise<PypelinePackageResult>;
11
+ }
@@ -0,0 +1,27 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { SfCommand } from '@salesforce/sf-plugins-core';
3
+ import { Messages } from '@salesforce/core';
4
+ import { BUILD_DIR } from '../../config.js';
5
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
6
+ const messages = Messages.loadMessages('pypeline', 'pypeline.package');
7
+ export default class PypelinePackage extends SfCommand {
8
+ static summary = messages.getMessage('summary');
9
+ static description = messages.getMessage('description');
10
+ static examples = messages.getMessages('examples');
11
+ async run() {
12
+ const buildDir = BUILD_DIR();
13
+ this.log('Gerando package.xml...');
14
+ const exitCode = await new Promise((resolve) => {
15
+ const proc = spawn('sf', ['project', 'generate', 'manifest', '--source-dir', buildDir], {
16
+ stdio: 'inherit',
17
+ });
18
+ proc.on('close', (code) => resolve(code ?? 1));
19
+ });
20
+ if (exitCode !== 0) {
21
+ this.error('Falha ao gerar package.xml.');
22
+ }
23
+ this.log('package.xml gerado com sucesso.');
24
+ return { success: true, buildDir };
25
+ }
26
+ }
27
+ //# sourceMappingURL=package.js.map