@brunoluizdesiqueira/bbuilder-cli 1.0.0 → 1.0.2
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/README.md +174 -21
- package/dist/cli/program.js +100 -11
- package/dist/config/validate.js +140 -0
- package/dist/diagnostics/doctor.js +122 -0
- package/dist/index.js +0 -0
- package/dist/ui/prompts.js +35 -0
- package/package.json +27 -3
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ CLI em Node.js/TypeScript que substitui o `build_local.bat` com interface intera
|
|
|
10
10
|
# Desenvolvimento local
|
|
11
11
|
npm install
|
|
12
12
|
npm run build
|
|
13
|
-
npm link # disponibiliza o comando '
|
|
13
|
+
npm link # disponibiliza o comando 'bbuilder' globalmente
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
```bash
|
|
@@ -23,6 +23,90 @@ npm install -g @brunoluizdesiqueira/bbuilder-cli
|
|
|
23
23
|
npm publish --access public
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## Publicação
|
|
27
|
+
|
|
28
|
+
### Publicação manual inicial
|
|
29
|
+
|
|
30
|
+
Use esse fluxo para a primeira publicação ou para publicar manualmente uma versão:
|
|
31
|
+
|
|
32
|
+
1. Faça login no npm:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm login
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
2. Valide o pacote localmente:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm run build
|
|
42
|
+
npm pack --dry-run
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
3. Publique:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm publish --access public
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Se a versão atual do `package.json` já tiver sido publicada, gere uma nova versão antes:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm version patch --no-git-tag-version
|
|
55
|
+
npm publish --access public
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Configurar publicação automática
|
|
59
|
+
|
|
60
|
+
Depois da primeira publicação manual, configure o npm para confiar no workflow do GitHub Actions.
|
|
61
|
+
|
|
62
|
+
No npm:
|
|
63
|
+
|
|
64
|
+
1. abra a página do pacote `@brunoluizdesiqueira/bbuilder-cli`
|
|
65
|
+
2. vá em `Settings`
|
|
66
|
+
3. abra `Trusted publishing`
|
|
67
|
+
4. adicione um publisher do tipo `GitHub Actions`
|
|
68
|
+
5. configure:
|
|
69
|
+
- repositório: `brunoluizdesiqueira/b-cli`
|
|
70
|
+
- workflow: `release.yml`
|
|
71
|
+
|
|
72
|
+
Na opção **Publishing access**, use:
|
|
73
|
+
|
|
74
|
+
- `Require two-factor authentication or a granular access token with bypass 2fa enabled`
|
|
75
|
+
|
|
76
|
+
Evite para esse fluxo:
|
|
77
|
+
|
|
78
|
+
- `Require two-factor authentication and disallow tokens`
|
|
79
|
+
|
|
80
|
+
### Publicação automática com Changesets
|
|
81
|
+
|
|
82
|
+
Depois do Trusted Publisher configurado, o fluxo recomendado fica assim:
|
|
83
|
+
|
|
84
|
+
1. criar uma changeset para cada mudança publicada:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm run changeset
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
2. fazer commit da changeset junto com o código
|
|
91
|
+
3. abrir PR e fazer merge na `main`
|
|
92
|
+
4. o workflow `Release` abre ou atualiza uma PR de release
|
|
93
|
+
5. ao mergear a PR de release, o npm é publicado automaticamente
|
|
94
|
+
|
|
95
|
+
Comandos locais úteis:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npm run changeset
|
|
99
|
+
npm run version-packages
|
|
100
|
+
npm run release
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## CI/CD
|
|
104
|
+
|
|
105
|
+
O repositório agora está preparado com GitHub Actions:
|
|
106
|
+
|
|
107
|
+
- `CI`: roda em `push` e `pull_request`, executando `npm ci`, `tsc`, `build` e `npm pack --dry-run`
|
|
108
|
+
- `Release`: usa `changesets` para abrir uma PR de release com bump de versão e changelog; quando essa PR entra na `main`, o pacote é publicado no npm
|
|
109
|
+
|
|
26
110
|
Ou use direto sem instalar globalmente:
|
|
27
111
|
```bash
|
|
28
112
|
npx ts-node src/index.ts build
|
|
@@ -34,35 +118,38 @@ npx ts-node src/index.ts build
|
|
|
34
118
|
|
|
35
119
|
### Modo interativo (sem argumentos)
|
|
36
120
|
```bash
|
|
37
|
-
|
|
121
|
+
bbuilder
|
|
38
122
|
```
|
|
39
123
|
Exibe menus para escolher: modo de build → projeto → versão.
|
|
40
124
|
|
|
41
125
|
### Comando `build` com flags opcionais
|
|
42
126
|
```bash
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
127
|
+
bbuilder build # interativo completo
|
|
128
|
+
bbuilder build --type DEBUG # escolhe projeto e versão interativamente
|
|
129
|
+
bbuilder build --type FAST --project faturamento\BimerFaturamento
|
|
130
|
+
bbuilder build --type RELEASE --project Bimer --version 11.3.1
|
|
47
131
|
```
|
|
48
132
|
|
|
49
133
|
### Atalhos diretos por modo
|
|
50
134
|
```bash
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
135
|
+
bbuilder fast # interativo para projeto/versão
|
|
136
|
+
bbuilder debug --project Bimer
|
|
137
|
+
bbuilder release --project Bimer --version 11.3.1
|
|
54
138
|
```
|
|
55
139
|
|
|
56
140
|
### Gerenciamento de projetos
|
|
57
141
|
```bash
|
|
58
|
-
|
|
59
|
-
|
|
142
|
+
bbuilder project list # lista projetos configurados
|
|
143
|
+
bbuilder project add # adiciona novo projeto (interativo)
|
|
144
|
+
bbuilder project remove # remove projeto (interativo ou por --name)
|
|
60
145
|
```
|
|
61
146
|
|
|
62
147
|
### Configuração do ambiente
|
|
63
148
|
```bash
|
|
64
|
-
|
|
65
|
-
|
|
149
|
+
bbuilder config init # assistente para criar bbuilder.config.json
|
|
150
|
+
bbuilder config show # exibe configuração atual
|
|
151
|
+
bbuilder config validate # valida a estrutura do arquivo de configuração
|
|
152
|
+
bbuilder doctor # diagnostica ambiente, config e paths
|
|
66
153
|
```
|
|
67
154
|
|
|
68
155
|
---
|
|
@@ -71,7 +158,7 @@ delphi config show # exibe configuração atual
|
|
|
71
158
|
|
|
72
159
|
Prioridade de resolução da configuração:
|
|
73
160
|
|
|
74
|
-
1. `
|
|
161
|
+
1. `bbuilder --config <caminho>`
|
|
75
162
|
2. Variável de ambiente `BBUILDER_CONFIG`
|
|
76
163
|
3. `bbuilder.config.json` no diretório atual
|
|
77
164
|
4. `bimer.config.json` no diretório atual, por compatibilidade
|
|
@@ -79,7 +166,7 @@ Prioridade de resolução da configuração:
|
|
|
79
166
|
|
|
80
167
|
No Windows, o arquivo global fica em `%APPDATA%\bbuilder-cli\bbuilder.config.json`.
|
|
81
168
|
|
|
82
|
-
Crie com `
|
|
169
|
+
Crie com `bbuilder config init`, ou manualmente:
|
|
83
170
|
|
|
84
171
|
```json
|
|
85
172
|
{
|
|
@@ -108,17 +195,57 @@ Crie com `delphi config init`, ou manualmente:
|
|
|
108
195
|
|
|
109
196
|
`projects` agora usa o formato `nome amigável: caminho real do projeto`, para a CLI exibir nomes humanizados sem perder a referência correta de compilação.
|
|
110
197
|
|
|
111
|
-
Se o arquivo não existir, os valores padrão acima são usados automaticamente. Ao rodar `
|
|
198
|
+
Se o arquivo não existir, os valores padrão acima são usados automaticamente. Ao rodar `bbuilder config init`, a CLI gera um `dependencyPaths` inicial com base nos diretórios informados.
|
|
199
|
+
|
|
200
|
+
### Como usar configs locais
|
|
201
|
+
|
|
202
|
+
O pacote é instalado normalmente, e a configuração é informada na execução, não na instalação.
|
|
203
|
+
|
|
204
|
+
Instalação global:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npm install -g @brunoluizdesiqueira/bbuilder-cli
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Usando um arquivo de config local explícito:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
bbuilder --config C:\configs\bbuilder.config.json build
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Usando variável de ambiente no Windows CMD:
|
|
217
|
+
|
|
218
|
+
```bat
|
|
219
|
+
set BBUILDER_CONFIG=C:\configs\bbuilder.config.json
|
|
220
|
+
bbuilder build
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Usando variável de ambiente no PowerShell:
|
|
224
|
+
|
|
225
|
+
```powershell
|
|
226
|
+
$env:BBUILDER_CONFIG="C:\configs\bbuilder.config.json"
|
|
227
|
+
bbuilder build
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Usando config local no diretório atual:
|
|
231
|
+
|
|
232
|
+
Se existir um `bbuilder.config.json` na pasta onde o comando é executado, a CLI usa esse arquivo automaticamente.
|
|
233
|
+
|
|
234
|
+
Para verificar qual arquivo está sendo usado:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
bbuilder config show
|
|
238
|
+
```
|
|
112
239
|
|
|
113
240
|
Exemplos:
|
|
114
241
|
|
|
115
242
|
```bash
|
|
116
|
-
|
|
243
|
+
bbuilder --config C:\configs\bbuilder.config.json build
|
|
117
244
|
```
|
|
118
245
|
|
|
119
246
|
```bash
|
|
120
247
|
set BBUILDER_CONFIG=C:\configs\bbuilder.config.json
|
|
121
|
-
|
|
248
|
+
bbuilder config show
|
|
122
249
|
```
|
|
123
250
|
|
|
124
251
|
---
|
|
@@ -134,7 +261,7 @@ Substitua o `tasks.json` atual por este (sem mais menus do VSCode, a CLI cuida d
|
|
|
134
261
|
{
|
|
135
262
|
"label": "Bimer: FAST + Run",
|
|
136
263
|
"type": "shell",
|
|
137
|
-
"command": "
|
|
264
|
+
"command": "bbuilder fast",
|
|
138
265
|
"group": "build",
|
|
139
266
|
"presentation": { "reveal": "always", "focus": true, "panel": "dedicated", "clear": true },
|
|
140
267
|
"problemMatcher": {
|
|
@@ -149,7 +276,7 @@ Substitua o `tasks.json` atual por este (sem mais menus do VSCode, a CLI cuida d
|
|
|
149
276
|
{
|
|
150
277
|
"label": "Bimer: DEBUG + Run",
|
|
151
278
|
"type": "shell",
|
|
152
|
-
"command": "
|
|
279
|
+
"command": "bbuilder debug",
|
|
153
280
|
"group": "build",
|
|
154
281
|
"presentation": { "reveal": "always", "focus": true, "panel": "dedicated", "clear": true },
|
|
155
282
|
"problemMatcher": {
|
|
@@ -164,7 +291,7 @@ Substitua o `tasks.json` atual por este (sem mais menus do VSCode, a CLI cuida d
|
|
|
164
291
|
{
|
|
165
292
|
"label": "Bimer: RELEASE",
|
|
166
293
|
"type": "shell",
|
|
167
|
-
"command": "
|
|
294
|
+
"command": "bbuilder release",
|
|
168
295
|
"group": "build",
|
|
169
296
|
"presentation": { "reveal": "always", "focus": true, "panel": "dedicated", "clear": true },
|
|
170
297
|
"problemMatcher": {
|
|
@@ -188,15 +315,41 @@ E nos keybindings, nada muda — os atalhos continuam os mesmos.
|
|
|
188
315
|
|
|
189
316
|
```
|
|
190
317
|
bbuilder-cli/
|
|
318
|
+
├── .changeset/
|
|
319
|
+
│ ├── config.json
|
|
320
|
+
│ └── *.md
|
|
321
|
+
├── .github/
|
|
322
|
+
│ └── workflows/
|
|
323
|
+
│ ├── ci.yml
|
|
324
|
+
│ └── release.yml
|
|
191
325
|
├── src/
|
|
192
326
|
│ ├── build/
|
|
327
|
+
│ │ ├── compiler.ts
|
|
328
|
+
│ │ ├── execute.ts
|
|
329
|
+
│ │ ├── project.ts
|
|
330
|
+
│ │ └── resources.ts
|
|
193
331
|
│ ├── cli/
|
|
332
|
+
│ │ └── program.ts
|
|
194
333
|
│ ├── config/
|
|
334
|
+
│ │ ├── config.ts
|
|
335
|
+
│ │ └── validate.ts
|
|
336
|
+
│ ├── diagnostics/
|
|
337
|
+
│ │ └── doctor.ts
|
|
195
338
|
│ ├── ui/
|
|
339
|
+
│ │ ├── output.ts
|
|
340
|
+
│ │ └── prompts.ts
|
|
196
341
|
│ ├── index.ts
|
|
197
342
|
│ └── types.ts
|
|
343
|
+
├── files/
|
|
344
|
+
│ ├── build_local.bat
|
|
345
|
+
│ ├── tasks.json
|
|
346
|
+
│ └── ...
|
|
347
|
+
├── bbuilder.config.json
|
|
198
348
|
├── package.json
|
|
349
|
+
├── package-lock.json
|
|
199
350
|
├── tsconfig.json
|
|
351
|
+
├── .gitignore
|
|
352
|
+
├── LICENSE
|
|
200
353
|
└── README.md
|
|
201
354
|
```
|
|
202
355
|
|
package/dist/cli/program.js
CHANGED
|
@@ -8,24 +8,97 @@ const commander_1 = require("commander");
|
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
9
|
const execute_1 = require("../build/execute");
|
|
10
10
|
const config_1 = require("../config/config");
|
|
11
|
+
const validate_1 = require("../config/validate");
|
|
12
|
+
const doctor_1 = require("../diagnostics/doctor");
|
|
11
13
|
const output_1 = require("../ui/output");
|
|
12
14
|
const prompts_1 = require("../ui/prompts");
|
|
15
|
+
const packageJson = require('../../package.json');
|
|
16
|
+
const HELP_EXAMPLES = {
|
|
17
|
+
root: [
|
|
18
|
+
'Exemplos:',
|
|
19
|
+
' bbuilder',
|
|
20
|
+
' bbuilder build --type DEBUG --project faturamento\\BimerFaturamento',
|
|
21
|
+
' bbuilder fast --project Bimer',
|
|
22
|
+
' bbuilder --config C:\\configs\\bbuilder.config.json doctor',
|
|
23
|
+
].join('\n'),
|
|
24
|
+
build: [
|
|
25
|
+
'Exemplos:',
|
|
26
|
+
' bbuilder build',
|
|
27
|
+
' bbuilder build --type RELEASE --project Bimer --version 11.3.1',
|
|
28
|
+
' bbuilder build --type FAST --project faturamento\\BimerFaturamento',
|
|
29
|
+
].join('\n'),
|
|
30
|
+
fast: [
|
|
31
|
+
'Exemplos:',
|
|
32
|
+
' bbuilder fast',
|
|
33
|
+
' bbuilder fast --project Bimer',
|
|
34
|
+
' bbuilder fast --project faturamento\\BimerFaturamento --version 11.3.1',
|
|
35
|
+
].join('\n'),
|
|
36
|
+
debug: [
|
|
37
|
+
'Exemplos:',
|
|
38
|
+
' bbuilder debug',
|
|
39
|
+
' bbuilder debug --project Bimer',
|
|
40
|
+
' bbuilder debug --project faturamento\\BimerFaturamento --version 11.3.1',
|
|
41
|
+
].join('\n'),
|
|
42
|
+
release: [
|
|
43
|
+
'Exemplos:',
|
|
44
|
+
' bbuilder release',
|
|
45
|
+
' bbuilder release --project Bimer',
|
|
46
|
+
' bbuilder release --project faturamento\\BimerFaturamento --version 11.3.1',
|
|
47
|
+
].join('\n'),
|
|
48
|
+
config: [
|
|
49
|
+
'Exemplos:',
|
|
50
|
+
' bbuilder config init',
|
|
51
|
+
' bbuilder config show',
|
|
52
|
+
' bbuilder config validate',
|
|
53
|
+
' bbuilder --config C:\\configs\\bbuilder.config.json config show',
|
|
54
|
+
].join('\n'),
|
|
55
|
+
configValidate: [
|
|
56
|
+
'Exemplos:',
|
|
57
|
+
' bbuilder config validate',
|
|
58
|
+
' bbuilder --config C:\\configs\\bbuilder.config.json config validate',
|
|
59
|
+
].join('\n'),
|
|
60
|
+
project: [
|
|
61
|
+
'Exemplos:',
|
|
62
|
+
' bbuilder project list',
|
|
63
|
+
' bbuilder project add',
|
|
64
|
+
' bbuilder project remove',
|
|
65
|
+
' bbuilder project remove --name Bimer',
|
|
66
|
+
].join('\n'),
|
|
67
|
+
projectRemove: [
|
|
68
|
+
'Exemplos:',
|
|
69
|
+
' bbuilder project remove',
|
|
70
|
+
' bbuilder project remove --name Bimer',
|
|
71
|
+
].join('\n'),
|
|
72
|
+
doctor: [
|
|
73
|
+
'Exemplos:',
|
|
74
|
+
' bbuilder doctor',
|
|
75
|
+
' bbuilder --config C:\\configs\\bbuilder.config.json doctor',
|
|
76
|
+
].join('\n'),
|
|
77
|
+
};
|
|
78
|
+
function attachHelpExamples(command, examples) {
|
|
79
|
+
command.on('--help', () => {
|
|
80
|
+
console.log('');
|
|
81
|
+
console.log(examples);
|
|
82
|
+
console.log('');
|
|
83
|
+
});
|
|
84
|
+
return command;
|
|
85
|
+
}
|
|
13
86
|
async function runCli(argv) {
|
|
14
87
|
const resolvedConfigPath = (0, config_1.resolveConfigPath)(argv);
|
|
15
88
|
const writableConfigPath = (0, config_1.getWritableConfigPath)(resolvedConfigPath);
|
|
16
89
|
const config = (0, config_1.loadConfig)(resolvedConfigPath);
|
|
17
90
|
const program = new commander_1.Command();
|
|
18
|
-
program
|
|
19
|
-
.name('
|
|
91
|
+
attachHelpExamples(program
|
|
92
|
+
.name('bbuilder')
|
|
20
93
|
.description('CLI de build local para projetos Delphi do Bimer')
|
|
21
|
-
.version(
|
|
22
|
-
.option('-c, --config <path>', `Caminho do arquivo de configuração (ou ${config_1.CONFIG_ENV_VAR})`);
|
|
23
|
-
program
|
|
94
|
+
.version(packageJson.version)
|
|
95
|
+
.option('-c, --config <path>', `Caminho do arquivo de configuração (ou ${config_1.CONFIG_ENV_VAR})`), HELP_EXAMPLES.root);
|
|
96
|
+
const buildCmd = attachHelpExamples(program
|
|
24
97
|
.command('build')
|
|
25
98
|
.description('Compila um projeto Delphi (interativo se flags omitidas)')
|
|
26
99
|
.option('-t, --type <FAST|DEBUG|RELEASE>', 'Modo de build')
|
|
27
100
|
.option('-p, --project <path>', 'Caminho do projeto (ex: faturamento\\BimerFaturamento)')
|
|
28
|
-
.option('-v, --version <version>', 'Versão a injetar (ex: 11.2.4)')
|
|
101
|
+
.option('-v, --version <version>', 'Versão a injetar (ex: 11.2.4)'), HELP_EXAMPLES.build)
|
|
29
102
|
.action(async (opts) => {
|
|
30
103
|
const buildType = opts.type?.toUpperCase();
|
|
31
104
|
if (buildType && !['FAST', 'DEBUG', 'RELEASE'].includes(buildType)) {
|
|
@@ -35,7 +108,7 @@ async function runCli(argv) {
|
|
|
35
108
|
await (0, execute_1.executeBuild)(resolved);
|
|
36
109
|
});
|
|
37
110
|
for (const type of ['fast', 'debug', 'release']) {
|
|
38
|
-
program
|
|
111
|
+
const shortcutCmd = program
|
|
39
112
|
.command(type)
|
|
40
113
|
.description(`Compila no modo ${type.toUpperCase()} (interativo para projeto/versão)`)
|
|
41
114
|
.option('-p, --project <path>', 'Caminho do projeto')
|
|
@@ -44,10 +117,11 @@ async function runCli(argv) {
|
|
|
44
117
|
const resolved = await (0, prompts_1.promptBuild)(config, type.toUpperCase(), opts.project, opts.version);
|
|
45
118
|
await (0, execute_1.executeBuild)(resolved);
|
|
46
119
|
});
|
|
120
|
+
attachHelpExamples(shortcutCmd, HELP_EXAMPLES[type]);
|
|
47
121
|
}
|
|
48
|
-
const configCmd = program
|
|
122
|
+
const configCmd = attachHelpExamples(program
|
|
49
123
|
.command('config')
|
|
50
|
-
.description('Gerencia a configuração do ambiente');
|
|
124
|
+
.description('Gerencia a configuração do ambiente'), HELP_EXAMPLES.config);
|
|
51
125
|
configCmd
|
|
52
126
|
.command('init')
|
|
53
127
|
.description('Configura o ambiente de forma interativa (cria bbuilder.config.json)')
|
|
@@ -67,9 +141,14 @@ async function runCli(argv) {
|
|
|
67
141
|
.join('\n'));
|
|
68
142
|
console.log('');
|
|
69
143
|
});
|
|
70
|
-
const
|
|
144
|
+
const configValidateCmd = configCmd
|
|
145
|
+
.command('validate')
|
|
146
|
+
.description('Valida a estrutura do arquivo de configuração')
|
|
147
|
+
.action(() => (0, validate_1.runConfigValidate)(resolvedConfigPath));
|
|
148
|
+
attachHelpExamples(configValidateCmd, HELP_EXAMPLES.configValidate);
|
|
149
|
+
const projectCmd = attachHelpExamples(program
|
|
71
150
|
.command('project')
|
|
72
|
-
.description('Gerencia a lista de projetos');
|
|
151
|
+
.description('Gerencia a lista de projetos'), HELP_EXAMPLES.project);
|
|
73
152
|
projectCmd
|
|
74
153
|
.command('add')
|
|
75
154
|
.description('Adiciona um novo projeto à lista')
|
|
@@ -86,6 +165,16 @@ async function runCli(argv) {
|
|
|
86
165
|
});
|
|
87
166
|
console.log('');
|
|
88
167
|
});
|
|
168
|
+
const projectRemoveCmd = projectCmd
|
|
169
|
+
.command('remove')
|
|
170
|
+
.description('Remove um projeto da lista')
|
|
171
|
+
.option('-n, --name <projectName>', 'Nome do projeto cadastrado')
|
|
172
|
+
.action((opts) => (0, prompts_1.runProjectRemove)(config, writableConfigPath, opts.name));
|
|
173
|
+
attachHelpExamples(projectRemoveCmd, HELP_EXAMPLES.projectRemove);
|
|
174
|
+
attachHelpExamples(program
|
|
175
|
+
.command('doctor')
|
|
176
|
+
.description('Diagnostica configuração, paths e binários do ambiente')
|
|
177
|
+
.action(() => (0, doctor_1.runDoctor)(config, resolvedConfigPath)), HELP_EXAMPLES.doctor);
|
|
89
178
|
if (argv.length <= 2) {
|
|
90
179
|
(0, output_1.banner)();
|
|
91
180
|
const resolved = await (0, prompts_1.promptBuild)(config);
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.validateConfigObject = validateConfigObject;
|
|
40
|
+
exports.runConfigValidate = runConfigValidate;
|
|
41
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
function isNonEmptyString(value) {
|
|
44
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
45
|
+
}
|
|
46
|
+
function validateProjects(projects) {
|
|
47
|
+
if (!projects || typeof projects !== 'object' || Array.isArray(projects)) {
|
|
48
|
+
return [{ field: 'projects', message: 'deve ser um objeto no formato nome => caminho' }];
|
|
49
|
+
}
|
|
50
|
+
const entries = Object.entries(projects);
|
|
51
|
+
if (entries.length === 0) {
|
|
52
|
+
return [{ field: 'projects', message: 'deve conter ao menos um projeto configurado' }];
|
|
53
|
+
}
|
|
54
|
+
const issues = [];
|
|
55
|
+
for (const [name, projectPath] of entries) {
|
|
56
|
+
if (!isNonEmptyString(name)) {
|
|
57
|
+
issues.push({ field: 'projects', message: 'contém uma chave de projeto inválida' });
|
|
58
|
+
}
|
|
59
|
+
if (!isNonEmptyString(projectPath)) {
|
|
60
|
+
issues.push({ field: `projects.${name}`, message: 'deve apontar para um caminho não vazio' });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return issues;
|
|
64
|
+
}
|
|
65
|
+
function validateConfigObject(raw) {
|
|
66
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
67
|
+
return [{ field: 'config', message: 'o arquivo deve conter um objeto JSON válido' }];
|
|
68
|
+
}
|
|
69
|
+
const config = raw;
|
|
70
|
+
const issues = [];
|
|
71
|
+
const requiredStringFields = [
|
|
72
|
+
'repoBase',
|
|
73
|
+
'delphiDir',
|
|
74
|
+
'envVersion',
|
|
75
|
+
'libRoot',
|
|
76
|
+
'libErp',
|
|
77
|
+
'libAlterdata',
|
|
78
|
+
];
|
|
79
|
+
for (const field of requiredStringFields) {
|
|
80
|
+
if (!isNonEmptyString(config[field])) {
|
|
81
|
+
issues.push({ field, message: 'deve ser uma string não vazia' });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!Array.isArray(config.dependencyPaths) || config.dependencyPaths.length === 0) {
|
|
85
|
+
issues.push({ field: 'dependencyPaths', message: 'deve ser um array com ao menos um path' });
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
config.dependencyPaths.forEach((depPath, index) => {
|
|
89
|
+
if (!isNonEmptyString(depPath)) {
|
|
90
|
+
issues.push({ field: `dependencyPaths[${index}]`, message: 'deve ser uma string não vazia' });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
issues.push(...validateProjects(config.projects));
|
|
95
|
+
return issues;
|
|
96
|
+
}
|
|
97
|
+
function runConfigValidate(configPath) {
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log(chalk_1.default.cyan(' Validação da Configuração'));
|
|
100
|
+
console.log(chalk_1.default.blue(' ─────────────────────────'));
|
|
101
|
+
console.log(chalk_1.default.gray(` Arquivo: ${configPath}`));
|
|
102
|
+
console.log('');
|
|
103
|
+
if (!fs.existsSync(configPath)) {
|
|
104
|
+
console.log(chalk_1.default.red(' FAIL Arquivo de configuração não encontrado.'));
|
|
105
|
+
console.log('');
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
let rawText;
|
|
110
|
+
try {
|
|
111
|
+
rawText = fs.readFileSync(configPath, 'utf-8');
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
console.log(chalk_1.default.red(` FAIL Não foi possível ler o arquivo: ${error instanceof Error ? error.message : String(error)}`));
|
|
115
|
+
console.log('');
|
|
116
|
+
process.exitCode = 1;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
let parsed;
|
|
120
|
+
try {
|
|
121
|
+
parsed = JSON.parse(rawText);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.log(chalk_1.default.red(` FAIL JSON inválido: ${error instanceof Error ? error.message : String(error)}`));
|
|
125
|
+
console.log('');
|
|
126
|
+
process.exitCode = 1;
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const issues = validateConfigObject(parsed);
|
|
130
|
+
if (issues.length === 0) {
|
|
131
|
+
console.log(chalk_1.default.green(' OK Estrutura da configuração está válida.'));
|
|
132
|
+
console.log('');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
issues.forEach(issue => {
|
|
136
|
+
console.log(chalk_1.default.red(` FAIL ${issue.field}: ${issue.message}`));
|
|
137
|
+
});
|
|
138
|
+
console.log('');
|
|
139
|
+
process.exitCode = 1;
|
|
140
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.runDoctor = runDoctor;
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
function checkPath(label, targetPath) {
|
|
44
|
+
return {
|
|
45
|
+
label,
|
|
46
|
+
ok: fs.existsSync(targetPath),
|
|
47
|
+
detail: targetPath,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function checkFile(label, targetPath) {
|
|
51
|
+
return {
|
|
52
|
+
label,
|
|
53
|
+
ok: fs.existsSync(targetPath) && fs.statSync(targetPath).isFile(),
|
|
54
|
+
detail: targetPath,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function printCheck(result) {
|
|
58
|
+
const status = result.ok ? chalk_1.default.green('OK') : chalk_1.default.red('FAIL');
|
|
59
|
+
console.log(` ${status.padEnd(6)} ${chalk_1.default.white(result.label)} ${chalk_1.default.gray(`→ ${result.detail}`)}`);
|
|
60
|
+
}
|
|
61
|
+
function runDoctor(config, resolvedConfigPath) {
|
|
62
|
+
const checks = [];
|
|
63
|
+
const cgrcPath = path.win32.join(config.delphiDir, 'bin', 'cgrc.exe');
|
|
64
|
+
const dcc64Path = path.win32.join(config.delphiDir, 'bin', 'dcc64.exe');
|
|
65
|
+
checks.push(checkFile('Arquivo de configuração em uso', resolvedConfigPath));
|
|
66
|
+
checks.push(checkPath('repoBase', config.repoBase));
|
|
67
|
+
checks.push(checkPath('delphiDir', config.delphiDir));
|
|
68
|
+
checks.push(checkPath('libRoot', config.libRoot));
|
|
69
|
+
checks.push(checkPath('libErp', config.libErp));
|
|
70
|
+
checks.push(checkPath('libAlterdata', config.libAlterdata));
|
|
71
|
+
checks.push(checkFile('cgrc.exe', cgrcPath));
|
|
72
|
+
checks.push(checkFile('dcc64.exe', dcc64Path));
|
|
73
|
+
const projectEntries = Object.entries(config.projects);
|
|
74
|
+
checks.push({
|
|
75
|
+
label: 'Projetos configurados',
|
|
76
|
+
ok: projectEntries.length > 0,
|
|
77
|
+
detail: `${projectEntries.length} projeto(s)`,
|
|
78
|
+
});
|
|
79
|
+
checks.push({
|
|
80
|
+
label: 'dependencyPaths configurados',
|
|
81
|
+
ok: Array.isArray(config.dependencyPaths) && config.dependencyPaths.length > 0,
|
|
82
|
+
detail: `${config.dependencyPaths.length} path(s)`,
|
|
83
|
+
});
|
|
84
|
+
console.log('');
|
|
85
|
+
console.log(chalk_1.default.cyan(' Diagnóstico do Ambiente'));
|
|
86
|
+
console.log(chalk_1.default.blue(' ───────────────────────'));
|
|
87
|
+
console.log(chalk_1.default.gray(` Config: ${resolvedConfigPath}`));
|
|
88
|
+
console.log('');
|
|
89
|
+
checks.forEach(printCheck);
|
|
90
|
+
if (projectEntries.length > 0) {
|
|
91
|
+
console.log('');
|
|
92
|
+
console.log(chalk_1.default.cyan(' Projetos'));
|
|
93
|
+
console.log(chalk_1.default.blue(' ────────'));
|
|
94
|
+
projectEntries.forEach(([name, projectPath]) => {
|
|
95
|
+
const fullPath = path.win32.join(config.repoBase, projectPath);
|
|
96
|
+
const dprojPath = `${fullPath}.dproj`;
|
|
97
|
+
const exists = fs.existsSync(dprojPath);
|
|
98
|
+
const status = exists ? chalk_1.default.green('OK') : chalk_1.default.red('FAIL');
|
|
99
|
+
console.log(` ${status.padEnd(6)} ${chalk_1.default.white(name)} ${chalk_1.default.gray(`→ ${dprojPath}`)}`);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (config.dependencyPaths.length > 0) {
|
|
103
|
+
console.log('');
|
|
104
|
+
console.log(chalk_1.default.cyan(' Dependências'));
|
|
105
|
+
console.log(chalk_1.default.blue(' ────────────'));
|
|
106
|
+
config.dependencyPaths.forEach(depPath => {
|
|
107
|
+
const exists = fs.existsSync(depPath);
|
|
108
|
+
const status = exists ? chalk_1.default.green('OK') : chalk_1.default.yellow('WARN');
|
|
109
|
+
console.log(` ${status.padEnd(6)} ${chalk_1.default.gray(depPath)}`);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const failed = checks.filter(check => !check.ok).length;
|
|
113
|
+
console.log('');
|
|
114
|
+
if (failed === 0) {
|
|
115
|
+
console.log(chalk_1.default.green(' Ambiente básico validado com sucesso.'));
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.log(chalk_1.default.yellow(` Diagnóstico concluído com ${failed} problema(s) principal(is).`));
|
|
119
|
+
process.exitCode = 1;
|
|
120
|
+
}
|
|
121
|
+
console.log('');
|
|
122
|
+
}
|
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/ui/prompts.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.promptBuild = promptBuild;
|
|
7
7
|
exports.runConfigInit = runConfigInit;
|
|
8
8
|
exports.runProjectAdd = runProjectAdd;
|
|
9
|
+
exports.runProjectRemove = runProjectRemove;
|
|
9
10
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
11
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
11
12
|
const config_1 = require("../config/config");
|
|
@@ -122,3 +123,37 @@ async function runProjectAdd(config, configPath) {
|
|
|
122
123
|
(0, config_1.saveConfig)(nextConfig, configPath);
|
|
123
124
|
console.log(chalk_1.default.green(`\n ✔ Projeto "${projectName}" adicionado!\n`));
|
|
124
125
|
}
|
|
126
|
+
async function runProjectRemove(config, configPath, cliProjectName) {
|
|
127
|
+
const projectEntries = Object.entries(config.projects);
|
|
128
|
+
if (projectEntries.length === 0) {
|
|
129
|
+
console.log(chalk_1.default.yellow('\n Não há projetos cadastrados para remover.\n'));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let projectName = cliProjectName;
|
|
133
|
+
if (!projectName) {
|
|
134
|
+
const answers = await inquirer_1.default.prompt([
|
|
135
|
+
{
|
|
136
|
+
type: 'list',
|
|
137
|
+
name: 'projectName',
|
|
138
|
+
message: 'Qual projeto deseja remover?',
|
|
139
|
+
choices: projectEntries.map(([name, projectPath]) => ({
|
|
140
|
+
name: `${name} (${projectPath})`,
|
|
141
|
+
value: name,
|
|
142
|
+
})),
|
|
143
|
+
},
|
|
144
|
+
]);
|
|
145
|
+
projectName = answers.projectName;
|
|
146
|
+
}
|
|
147
|
+
if (!projectName || !config.projects[projectName]) {
|
|
148
|
+
console.log(chalk_1.default.yellow(`\n Projeto "${projectName || ''}" não encontrado.\n`));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const nextProjects = { ...config.projects };
|
|
152
|
+
delete nextProjects[projectName];
|
|
153
|
+
const nextConfig = {
|
|
154
|
+
...config,
|
|
155
|
+
projects: nextProjects,
|
|
156
|
+
};
|
|
157
|
+
(0, config_1.saveConfig)(nextConfig, configPath);
|
|
158
|
+
console.log(chalk_1.default.green(`\n ✔ Projeto "${projectName}" removido!\n`));
|
|
159
|
+
}
|
package/package.json
CHANGED
|
@@ -1,19 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brunoluizdesiqueira/bbuilder-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "CLI de build local para projetos Delphi do Bimer",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/brunoluizdesiqueira/b-cli.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/brunoluizdesiqueira/b-cli#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/brunoluizdesiqueira/b-cli/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"cli",
|
|
16
|
+
"delphi",
|
|
17
|
+
"builder",
|
|
18
|
+
"bimer",
|
|
19
|
+
"typescript"
|
|
20
|
+
],
|
|
5
21
|
"files": [
|
|
6
22
|
"dist",
|
|
7
23
|
"README.md",
|
|
8
24
|
"LICENSE"
|
|
9
25
|
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"provenance": true
|
|
29
|
+
},
|
|
10
30
|
"bin": {
|
|
11
|
-
"
|
|
31
|
+
"bbuilder": "./dist/index.js"
|
|
12
32
|
},
|
|
13
33
|
"scripts": {
|
|
14
34
|
"build": "tsc",
|
|
15
35
|
"dev": "ts-node src/index.ts",
|
|
16
|
-
"prepack": "npm run build"
|
|
36
|
+
"prepack": "npm run build",
|
|
37
|
+
"changeset": "changeset",
|
|
38
|
+
"version-packages": "changeset version",
|
|
39
|
+
"release": "changeset publish"
|
|
17
40
|
},
|
|
18
41
|
"engines": {
|
|
19
42
|
"node": ">=18"
|
|
@@ -25,6 +48,7 @@
|
|
|
25
48
|
"inquirer": "^8.2.6"
|
|
26
49
|
},
|
|
27
50
|
"devDependencies": {
|
|
51
|
+
"@changesets/cli": "^2.30.0",
|
|
28
52
|
"@types/inquirer": "^8.2.10",
|
|
29
53
|
"@types/node": "^20.0.0",
|
|
30
54
|
"ts-node": "^10.9.2",
|