@burgan-tech/vnext-workflow-cli 1.0.1 → 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.
@@ -2,187 +2,269 @@ const chalk = require('chalk');
2
2
  const ora = require('ora');
3
3
  const path = require('path');
4
4
  const config = require('../lib/config');
5
- const { discoverComponents } = require('../lib/discover');
6
- const { getInstanceId } = require('../lib/db');
7
- const { postWorkflow, activateWorkflow, reinitializeSystem } = require('../lib/api');
8
- const {
9
- getJsonMetadata,
10
- detectFlowFromPath,
11
- findAllJson
12
- } = require('../lib/workflow');
13
- const {
14
- processCsxFile,
15
- getGitChangedCsx,
16
- findAllCsx
17
- } = require('../lib/csx');
5
+ const { discoverComponents, findAllJsonFiles } = require('../lib/discover');
6
+ const { getDomain, getComponentTypes } = require('../lib/vnextConfig');
7
+ const { publishComponent, reinitializeSystem } = require('../lib/api');
8
+ const { getInstanceId, deleteWorkflow } = require('../lib/db');
9
+ const { getJsonMetadata, detectComponentType } = require('../lib/workflow');
10
+ const { processCsxFile, findAllCsx } = require('../lib/csx');
11
+
12
+ // Logging helpers
13
+ const LOG = {
14
+ separator: () => console.log(chalk.cyan('═'.repeat(60))),
15
+ subSeparator: () => console.log(chalk.cyan('─'.repeat(60))),
16
+ header: (text) => {
17
+ console.log();
18
+ LOG.separator();
19
+ console.log(chalk.cyan.bold(` ${text}`));
20
+ LOG.separator();
21
+ },
22
+ success: (text) => console.log(chalk.green(` ✓ ${text}`)),
23
+ error: (text) => console.log(chalk.red(` ✗ ${text}`)),
24
+ warning: (text) => console.log(chalk.yellow(` ⚠ ${text}`)),
25
+ info: (text) => console.log(chalk.dim(` ○ ${text}`)),
26
+ component: (type, name, status, detail = '') => {
27
+ const typeLabel = chalk.cyan(`[${type}]`);
28
+ const nameLabel = chalk.white(name);
29
+ if (status === 'success') {
30
+ console.log(` ${typeLabel} ${chalk.green('✓')} ${nameLabel} ${chalk.dim(detail)}`);
31
+ } else if (status === 'error') {
32
+ console.log(` ${typeLabel} ${chalk.red('✗')} ${nameLabel}`);
33
+ if (detail) console.log(chalk.red(` └─ ${detail}`));
34
+ } else if (status === 'skip') {
35
+ console.log(` ${typeLabel} ${chalk.dim('○')} ${nameLabel} ${chalk.dim(detail)}`);
36
+ }
37
+ }
38
+ };
18
39
 
19
40
  async function syncCommand() {
20
- console.log(chalk.cyan.bold('\n🔄 Sistem Sync - Eksik Olanları Ekle\n'));
41
+ LOG.header('SYSTEM SYNC - Add Missing Components');
21
42
 
22
43
  const projectRoot = config.get('PROJECT_ROOT');
23
44
  const autoDiscover = config.get('AUTO_DISCOVER');
24
45
 
25
46
  if (!autoDiscover) {
26
- console.log(chalk.yellow('⚠️ AUTO_DISCOVER kapalı. Açmak için:'));
47
+ LOG.warning('AUTO_DISCOVER is disabled. To enable:');
27
48
  console.log(chalk.dim(' workflow config set AUTO_DISCOVER true\n'));
28
49
  return;
29
50
  }
30
51
 
52
+ // Get domain from vnext.config.json
53
+ let domain;
54
+ try {
55
+ domain = getDomain(projectRoot);
56
+ } catch (error) {
57
+ LOG.error(`Failed to read vnext.config.json: ${error.message}`);
58
+ return;
59
+ }
60
+
31
61
  // DB Config
62
+ const useDockerValue = config.get('USE_DOCKER');
32
63
  const dbConfig = {
33
64
  host: config.get('DB_HOST'),
34
65
  port: config.get('DB_PORT'),
35
66
  database: config.get('DB_NAME'),
36
67
  user: config.get('DB_USER'),
37
68
  password: config.get('DB_PASSWORD'),
38
- useDocker: config.get('USE_DOCKER'),
69
+ useDocker: useDockerValue === true || useDockerValue === 'true',
39
70
  dockerContainer: config.get('DOCKER_POSTGRES_CONTAINER')
40
71
  };
41
72
 
42
73
  // API Config
43
74
  const apiConfig = {
44
75
  baseUrl: config.get('API_BASE_URL'),
45
- version: config.get('API_VERSION')
76
+ version: config.get('API_VERSION'),
77
+ domain: domain
46
78
  };
47
79
 
48
- // Klasörleri bul
49
- const discoverSpinner = ora('Klasörler taranıyor...').start();
50
- const discovered = await discoverComponents(projectRoot);
51
- discoverSpinner.succeed(chalk.green('Klasörler bulundu'));
80
+ console.log(chalk.dim(` Domain: ${domain}`));
81
+ console.log(chalk.dim(` API: ${apiConfig.baseUrl}`));
82
+ console.log();
83
+
84
+ // Discover folders
85
+ const discoverSpinner = ora('Scanning folders...').start();
86
+ let discovered;
87
+ try {
88
+ discovered = await discoverComponents(projectRoot);
89
+ discoverSpinner.succeed(chalk.green('Folders discovered'));
90
+ } catch (error) {
91
+ discoverSpinner.fail(chalk.red(`Folder scan error: ${error.message}`));
92
+ return;
93
+ }
94
+
95
+ // FIRST: Update all CSX files
96
+ const csxSpinner = ora('Finding CSX files...').start();
97
+ let csxFiles;
98
+ try {
99
+ csxFiles = await findAllCsx(projectRoot);
100
+ csxSpinner.succeed(chalk.green(`${csxFiles.length} CSX files found`));
101
+ } catch (error) {
102
+ csxSpinner.warn(chalk.yellow(`CSX scan error: ${error.message}`));
103
+ csxFiles = [];
104
+ }
52
105
 
53
- // ÖNCELİKLE: Tüm CSX dosyalarını güncelle
54
- const csxSpinner = ora('Tüm CSX dosyaları bulunuyor...').start();
55
- const csxFiles = await findAllCsx(projectRoot);
56
- csxSpinner.succeed(chalk.green(`${csxFiles.length} CSX dosyası bulundu`));
106
+ // Update CSX files
107
+ const csxResults = { success: 0, failed: 0, errors: [] };
57
108
 
58
- // CSX dosyalarını güncelle
59
109
  if (csxFiles.length > 0) {
60
- console.log(chalk.blue('\n📝 CSX dosyaları JSON\'lara yazılıyor...\n'));
110
+ console.log(chalk.blue('\n Writing CSX files to JSONs...\n'));
61
111
 
62
- let csxSuccessCount = 0;
63
112
  for (const csxFile of csxFiles) {
64
113
  const fileName = path.basename(csxFile);
65
- const csxFileSpinner = ora(`Base64 encode: ${fileName}`).start();
66
114
 
67
115
  try {
68
116
  const result = await processCsxFile(csxFile, projectRoot);
69
117
 
70
118
  if (result.success) {
71
- csxFileSpinner.succeed(chalk.green(`✓ ${fileName} ${result.updatedCount} JSON`));
72
- csxSuccessCount++;
119
+ LOG.component('CSX', fileName, 'success', `→ ${result.updatedJsonCount} JSON, ${result.totalUpdates} refs`);
120
+ csxResults.success++;
73
121
  } else {
74
- csxFileSpinner.warn(chalk.yellow(`○ ${fileName} ${result.message}`));
122
+ LOG.component('CSX', fileName, 'skip', result.message);
75
123
  }
76
124
  } catch (error) {
77
- csxFileSpinner.fail(chalk.red(`✗ ${fileName} ${error.message}`));
125
+ LOG.component('CSX', fileName, 'error', error.message);
126
+ csxResults.failed++;
127
+ csxResults.errors.push({ file: fileName, error: error.message });
78
128
  }
79
129
  }
80
-
81
- if (csxSuccessCount > 0) {
82
- console.log(chalk.green(`\n✓ ${csxSuccessCount} CSX dosyası güncellendi\n`));
83
- }
84
130
  }
85
131
 
86
- // Tüm JSON dosyalarını bul
87
- const findSpinner = ora('JSON dosyaları bulunuyor...').start();
88
- const allJsons = await findAllJson(discovered);
89
- findSpinner.succeed(chalk.green(`${allJsons.length} JSON dosyası bulundu`));
132
+ // Find all JSON files
133
+ const findSpinner = ora('Finding JSON files...').start();
134
+ let allJsonFiles;
135
+ try {
136
+ allJsonFiles = await findAllJsonFiles(discovered);
137
+ findSpinner.succeed(chalk.green(`${allJsonFiles.length} JSON files found`));
138
+ } catch (error) {
139
+ findSpinner.fail(chalk.red(`JSON scan error: ${error.message}`));
140
+ return;
141
+ }
90
142
 
91
- // Her dosyayı kontrol et
92
- let addedCount = 0;
93
- let skippedCount = 0;
94
- let failedCount = 0;
143
+ // Group by component type
144
+ const componentStats = {};
145
+ const errors = [];
95
146
 
96
- console.log();
97
- for (const jsonFile of allJsons) {
98
- const fileName = require('path').basename(jsonFile);
99
- const spinner = ora(`Kontrol ediliyor: ${fileName}`).start();
147
+ console.log(chalk.blue('\n Publishing components...\n'));
148
+
149
+ for (const jsonInfo of allJsonFiles) {
150
+ const { path: jsonPath, type, fileName } = jsonInfo;
151
+
152
+ // Initialize stats
153
+ if (!componentStats[type]) {
154
+ componentStats[type] = { success: 0, failed: 0, skipped: 0, existing: 0 };
155
+ }
100
156
 
101
157
  try {
102
- const metadata = await getJsonMetadata(jsonFile);
158
+ const metadata = await getJsonMetadata(jsonPath);
103
159
 
104
160
  if (!metadata.key || !metadata.version) {
105
- spinner.warn(chalk.yellow(`○ ${fileName} key/version yok`));
106
- skippedCount++;
161
+ LOG.component(type, fileName, 'skip', 'no key/version');
162
+ componentStats[type].skipped++;
107
163
  continue;
108
164
  }
109
165
 
110
- const flow = metadata.flow || detectFlowFromPath(jsonFile);
166
+ // Detect flow type
167
+ const flow = metadata.flow || detectComponentType(jsonPath, projectRoot);
111
168
 
112
- // DB'de var mı?
169
+ // Check if exists in DB
113
170
  const existingId = await getInstanceId(dbConfig, flow, metadata.key, metadata.version);
114
171
 
115
172
  if (existingId) {
116
- spinner.info(chalk.dim(`○ ${fileName} zaten var`));
117
- skippedCount++;
173
+ // Already exists, skip
174
+ LOG.component(type, fileName, 'skip', 'already exists');
175
+ componentStats[type].existing++;
176
+ continue;
177
+ }
178
+
179
+ // Not in DB, publish to API
180
+ const result = await publishComponent(apiConfig.baseUrl, metadata.data);
181
+
182
+ if (result.success) {
183
+ LOG.component(type, fileName, 'success', '→ published');
184
+ componentStats[type].success++;
118
185
  } else {
119
- // Yok, ekle
120
- const postResult = await postWorkflow(
121
- apiConfig.baseUrl,
122
- apiConfig.version,
123
- flow,
124
- metadata.data
125
- );
126
-
127
- const newId = postResult.id || postResult.Id;
128
-
129
- // Aktif et
130
- await activateWorkflow(
131
- apiConfig.baseUrl,
132
- apiConfig.version,
133
- flow,
134
- newId,
135
- metadata.version
136
- );
137
-
138
- spinner.succeed(chalk.green(`✓ ${fileName} → eklendi`));
139
- addedCount++;
186
+ LOG.component(type, fileName, 'error', result.error);
187
+ componentStats[type].failed++;
188
+ errors.push({ type, file: fileName, error: result.error });
140
189
  }
141
190
  } catch (error) {
142
- let errorMsg = error.message;
143
- if (error.response?.data) {
144
- if (typeof error.response.data === 'string') {
145
- errorMsg = error.response.data;
146
- } else if (error.response.data.message) {
147
- errorMsg = error.response.data.message;
148
- } else {
149
- errorMsg = JSON.stringify(error.response.data);
150
- }
151
- }
152
- spinner.fail(chalk.red(`✗ ${fileName} → ${errorMsg}`));
153
- failedCount++;
191
+ const errorMsg = error.message || 'Unknown error';
192
+ LOG.component(type, fileName, 'error', errorMsg);
193
+ componentStats[type].failed++;
194
+ errors.push({ type, file: fileName, error: errorMsg });
154
195
  }
155
196
  }
156
197
 
157
198
  // Re-initialize
158
- if (addedCount > 0) {
199
+ const totalSuccess = Object.values(componentStats).reduce((sum, s) => sum + s.success, 0);
200
+
201
+ if (totalSuccess > 0) {
159
202
  console.log();
160
- const reinitSpinner = ora('Sistem yeniden başlatılıyor...').start();
203
+ const reinitSpinner = ora('Re-initializing system...').start();
161
204
  const reinitSuccess = await reinitializeSystem(apiConfig.baseUrl, apiConfig.version);
162
205
 
163
206
  if (reinitSuccess) {
164
- reinitSpinner.succeed(chalk.green(' Sistem yenilendi'));
207
+ reinitSpinner.succeed(chalk.green('System re-initialized'));
165
208
  } else {
166
- reinitSpinner.warn(chalk.yellow(' Sistem yenilenemedi'));
209
+ reinitSpinner.warn(chalk.yellow('System re-initialization failed'));
167
210
  }
168
211
  }
169
212
 
170
- // Özet
171
- console.log();
172
- console.log(chalk.cyan('═'.repeat(50)));
173
- console.log(chalk.white(`Toplam: ${allJsons.length} dosya`));
174
- console.log(chalk.green(`✓ Eklendi: ${addedCount}`));
175
- console.log(chalk.dim(`○ Zaten var: ${skippedCount}`));
176
- if (failedCount > 0) {
177
- console.log(chalk.red(`✗ Başarısız: ${failedCount}`));
213
+ // SUMMARY REPORT
214
+ LOG.header('SYNC SUMMARY');
215
+
216
+ // Component statistics
217
+ console.log(chalk.white.bold('\n Component Publish Results:\n'));
218
+
219
+ const componentTypes = getComponentTypes(projectRoot);
220
+ for (const [type, folderName] of Object.entries(componentTypes)) {
221
+ const stats = componentStats[type];
222
+ if (stats) {
223
+ const successLabel = stats.success > 0 ? chalk.green(`${stats.success} added`) : '';
224
+ const existingLabel = stats.existing > 0 ? chalk.dim(`${stats.existing} existing`) : '';
225
+ const failedLabel = stats.failed > 0 ? chalk.red(`${stats.failed} failed`) : '';
226
+ const skippedLabel = stats.skipped > 0 ? chalk.dim(`${stats.skipped} skipped`) : '';
227
+
228
+ const parts = [successLabel, existingLabel, failedLabel, skippedLabel].filter(Boolean);
229
+ console.log(` ${chalk.cyan(type.padEnd(12))} : ${parts.join(', ') || chalk.dim('0')}`);
230
+ }
178
231
  }
179
- console.log(chalk.cyan('═'.repeat(50)));
180
- console.log();
181
232
 
182
- if (addedCount === 0 && failedCount === 0) {
183
- console.log(chalk.green.bold('✓ Sistem güncel - Tüm kayıtlar mevcut\n'));
184
- } else if (addedCount > 0) {
185
- console.log(chalk.green.bold(' Sync tamamlandı\n'));
233
+ // CSX summary
234
+ if (csxFiles.length > 0) {
235
+ console.log();
236
+ const csxSuccessLabel = csxResults.success > 0 ? chalk.green(`${csxResults.success} success`) : chalk.dim('0 success');
237
+ const csxFailedLabel = csxResults.failed > 0 ? chalk.red(`, ${csxResults.failed} failed`) : '';
238
+ console.log(` ${chalk.cyan('CSX'.padEnd(12))} : ${csxSuccessLabel}${csxFailedLabel}`);
239
+ }
240
+
241
+ // Errors
242
+ if (errors.length > 0 || csxResults.errors.length > 0) {
243
+ console.log();
244
+ LOG.subSeparator();
245
+ console.log(chalk.red.bold('\n ERRORS:\n'));
246
+
247
+ for (const err of errors) {
248
+ console.log(chalk.red(` [${err.type}] ${err.file}`));
249
+ console.log(chalk.dim(` └─ ${err.error}`));
250
+ }
251
+
252
+ for (const err of csxResults.errors) {
253
+ console.log(chalk.red(` [CSX] ${err.file}`));
254
+ console.log(chalk.dim(` └─ ${err.error}`));
255
+ }
256
+ }
257
+
258
+ LOG.separator();
259
+
260
+ const totalFailed = Object.values(componentStats).reduce((sum, s) => sum + s.failed, 0) + csxResults.failed;
261
+
262
+ if (totalSuccess === 0 && totalFailed === 0) {
263
+ console.log(chalk.green.bold('\n ✓ System up to date - All records exist\n'));
264
+ } else if (totalFailed === 0) {
265
+ console.log(chalk.green.bold('\n ✓ Sync completed\n'));
266
+ } else {
267
+ console.log(chalk.yellow.bold(`\n ⚠ Sync completed (${totalFailed} errors)\n`));
186
268
  }
187
269
  }
188
270