@contentstack/cli-utilities 1.14.2 ā 1.15.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.
- package/lib/config-handler.d.ts +24 -2
- package/lib/config-handler.js +25 -1
- package/lib/constants/logging.d.ts +1 -0
- package/lib/constants/logging.js +4 -3
- package/lib/helpers.d.ts +1 -0
- package/lib/helpers.js +11 -3
- package/lib/index.d.ts +1 -0
- package/lib/index.js +8 -1
- package/lib/interfaces/index.d.ts +50 -1
- package/lib/logger/cli-error-handler.js +1 -2
- package/lib/logger/log.js +1 -1
- package/lib/logger/logger.js +37 -17
- package/lib/progress-summary/cli-progress-manager.d.ts +121 -0
- package/lib/progress-summary/cli-progress-manager.js +530 -0
- package/lib/progress-summary/index.d.ts +4 -0
- package/lib/progress-summary/index.js +13 -0
- package/lib/progress-summary/progress-strategy.d.ts +25 -0
- package/lib/progress-summary/progress-strategy.js +54 -0
- package/lib/progress-summary/summary-manager.d.ts +24 -0
- package/lib/progress-summary/summary-manager.js +181 -0
- package/package.json +1 -1
package/lib/config-handler.d.ts
CHANGED
|
@@ -1,8 +1,30 @@
|
|
|
1
1
|
import Conf from 'conf';
|
|
2
|
+
declare class Config {
|
|
3
|
+
private config;
|
|
4
|
+
private inMemoryStore;
|
|
5
|
+
private isPrepackMode;
|
|
6
|
+
constructor();
|
|
7
|
+
init(): Conf<Record<string, unknown>>;
|
|
8
|
+
importOldConfig(): void;
|
|
9
|
+
setOldConfigStoreData(data: any, _path?: string): void;
|
|
10
|
+
isConfigFileValid(configPath: string): boolean;
|
|
11
|
+
safeDeleteConfigIfInvalid(configFilePath: string): void;
|
|
12
|
+
removeOldConfigStoreFile(): void;
|
|
13
|
+
private getOldConfig;
|
|
14
|
+
private fallbackInit;
|
|
15
|
+
private getObfuscationKey;
|
|
16
|
+
private getConfigDataAndUnlinkConfigFile;
|
|
17
|
+
private getEncryptedConfig;
|
|
18
|
+
private getDecryptedConfig;
|
|
19
|
+
get(key: any): string | any;
|
|
20
|
+
set(key: any, value: any): this | Conf<Record<string, unknown>>;
|
|
21
|
+
delete(key: any): this | Conf<Record<string, unknown>>;
|
|
22
|
+
clear(): void;
|
|
23
|
+
}
|
|
2
24
|
declare const lazyConfig: {
|
|
3
25
|
get(key: string): any;
|
|
4
|
-
set(key: string, value: any): Conf<Record<string, unknown>>;
|
|
5
|
-
delete(key: string): Conf<Record<string, unknown>>;
|
|
26
|
+
set(key: string, value: any): Config | Conf<Record<string, unknown>>;
|
|
27
|
+
delete(key: string): Config | Conf<Record<string, unknown>>;
|
|
6
28
|
clear(): void;
|
|
7
29
|
};
|
|
8
30
|
export default lazyConfig;
|
package/lib/config-handler.js
CHANGED
|
@@ -22,10 +22,19 @@ const oldConfigPath = path.join(oldConfigDirectory, pathPrefix);
|
|
|
22
22
|
const cwd = process.env.CS_CLI_CONFIG_PATH;
|
|
23
23
|
class Config {
|
|
24
24
|
constructor() {
|
|
25
|
+
this.inMemoryStore = new Map();
|
|
26
|
+
this.isPrepackMode = process.env.NODE_ENV === 'PREPACK_MODE';
|
|
25
27
|
this.init();
|
|
26
|
-
this.
|
|
28
|
+
if (!this.isPrepackMode) {
|
|
29
|
+
this.importOldConfig();
|
|
30
|
+
}
|
|
27
31
|
}
|
|
28
32
|
init() {
|
|
33
|
+
// Skip file-based config during prepack to prevent race conditions
|
|
34
|
+
if (this.isPrepackMode) {
|
|
35
|
+
// Initialize with empty in-memory store for prepack
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
29
38
|
return ENCRYPT_CONF === true ? this.getEncryptedConfig() : this.getDecryptedConfig();
|
|
30
39
|
}
|
|
31
40
|
importOldConfig() {
|
|
@@ -189,20 +198,35 @@ class Config {
|
|
|
189
198
|
}
|
|
190
199
|
get(key) {
|
|
191
200
|
var _a;
|
|
201
|
+
if (this.isPrepackMode) {
|
|
202
|
+
return this.inMemoryStore.get(key);
|
|
203
|
+
}
|
|
192
204
|
return (_a = this.config) === null || _a === void 0 ? void 0 : _a.get(key);
|
|
193
205
|
}
|
|
194
206
|
set(key, value) {
|
|
195
207
|
var _a;
|
|
208
|
+
if (this.isPrepackMode) {
|
|
209
|
+
this.inMemoryStore.set(key, value);
|
|
210
|
+
return this;
|
|
211
|
+
}
|
|
196
212
|
(_a = this.config) === null || _a === void 0 ? void 0 : _a.set(key, value);
|
|
197
213
|
return this.config;
|
|
198
214
|
}
|
|
199
215
|
delete(key) {
|
|
200
216
|
var _a;
|
|
217
|
+
if (this.isPrepackMode) {
|
|
218
|
+
this.inMemoryStore.delete(key);
|
|
219
|
+
return this;
|
|
220
|
+
}
|
|
201
221
|
(_a = this.config) === null || _a === void 0 ? void 0 : _a.delete(key);
|
|
202
222
|
return this.config;
|
|
203
223
|
}
|
|
204
224
|
clear() {
|
|
205
225
|
var _a;
|
|
226
|
+
if (this.isPrepackMode) {
|
|
227
|
+
this.inMemoryStore.clear();
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
206
230
|
(_a = this.config) === null || _a === void 0 ? void 0 : _a.clear();
|
|
207
231
|
}
|
|
208
232
|
}
|
package/lib/constants/logging.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.levelColors = exports.logLevels = void 0;
|
|
3
|
+
exports.PROGRESS_SUPPORTED_MODULES = exports.levelColors = exports.logLevels = void 0;
|
|
4
4
|
exports.logLevels = {
|
|
5
5
|
error: 0,
|
|
6
6
|
warn: 1,
|
|
7
7
|
info: 2,
|
|
8
8
|
success: 2,
|
|
9
9
|
debug: 3,
|
|
10
|
-
verbose: 4
|
|
10
|
+
verbose: 4,
|
|
11
11
|
};
|
|
12
12
|
// 2. Create color mappings (for console only)
|
|
13
13
|
exports.levelColors = {
|
|
@@ -15,5 +15,6 @@ exports.levelColors = {
|
|
|
15
15
|
warn: 'yellow',
|
|
16
16
|
success: 'green',
|
|
17
17
|
info: 'white',
|
|
18
|
-
debug: 'blue'
|
|
18
|
+
debug: 'blue',
|
|
19
19
|
};
|
|
20
|
+
exports.PROGRESS_SUPPORTED_MODULES = ['export', 'import'];
|
package/lib/helpers.d.ts
CHANGED
package/lib/helpers.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.redactObject = exports.formatError = exports.validateRegex = exports.validateFileName = exports.validateUids = exports.sanitizePath = exports.escapeRegExp = exports.validatePath = exports.createDeveloperHubUrl = exports.isManagementTokenValid = exports.getBranchFromAlias = exports.doesBranchExist = exports.isAuthenticated = void 0;
|
|
3
|
+
exports.clearProgressModuleSetting = exports.redactObject = exports.formatError = exports.validateRegex = exports.validateFileName = exports.validateUids = exports.sanitizePath = exports.escapeRegExp = exports.validatePath = exports.createDeveloperHubUrl = exports.isManagementTokenValid = exports.getBranchFromAlias = exports.doesBranchExist = exports.isAuthenticated = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const recheck_1 = require("recheck");
|
|
6
6
|
const traverse_1 = tslib_1.__importDefault(require("traverse"));
|
|
@@ -185,8 +185,8 @@ const formatError = function (error) {
|
|
|
185
185
|
// If message is in JSON format, parse it to extract the actual message string
|
|
186
186
|
try {
|
|
187
187
|
const parsedMessage = JSON.parse(message);
|
|
188
|
-
if (typeof parsedMessage === 'object') {
|
|
189
|
-
message = (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.message) || message;
|
|
188
|
+
if (typeof parsedMessage === 'object' && parsedMessage !== null) {
|
|
189
|
+
message = (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.message) || (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.errorMessage) || (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.error) || message;
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
catch (e) {
|
|
@@ -238,3 +238,11 @@ const sensitiveKeys = [
|
|
|
238
238
|
/management[-._]?token/i,
|
|
239
239
|
/delivery[-._]?token/i,
|
|
240
240
|
];
|
|
241
|
+
function clearProgressModuleSetting() {
|
|
242
|
+
const logConfig = _1.configHandler.get('log') || {};
|
|
243
|
+
if (logConfig === null || logConfig === void 0 ? void 0 : logConfig.progressSupportedModule) {
|
|
244
|
+
delete logConfig.progressSupportedModule;
|
|
245
|
+
_1.configHandler.set('log', logConfig);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
exports.clearProgressModuleSetting = clearProgressModuleSetting;
|
package/lib/index.d.ts
CHANGED
|
@@ -25,3 +25,4 @@ export { default as TablePrompt } from './inquirer-table-prompt';
|
|
|
25
25
|
export { Logger };
|
|
26
26
|
export { default as authenticationHandler } from './authentication-handler';
|
|
27
27
|
export { v2Logger as log, cliErrorHandler, handleAndLogError, getLogPath } from './logger/log';
|
|
28
|
+
export { CLIProgressManager, SummaryManager, PrimaryProcessStrategy, ProgressStrategyRegistry, CustomProgressStrategy, DefaultProgressStrategy } from './progress-summary';
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.log = exports.authenticationHandler = exports.Logger = exports.TablePrompt = exports.execute = exports.ux = exports.flush = exports.settings = exports.toConfiguredId = exports.toStandardizedId = exports.run = exports.Plugin = exports.Parser = exports.Interfaces = exports.HelpBase = exports.Help = exports.loadHelpClass = exports.Flags = exports.Errors = exports.Config = exports.CommandHelp = exports.Args = exports.marketplaceSDKInitiator = exports.MarketplaceSDKInitiator = exports.marketplaceSDKClient = exports.CLITable = exports.Command = exports.flags = exports.args = exports.NodeCrypto = exports.printFlagDeprecation = exports.managementSDKInitiator = exports.managementSDKClient = exports.configHandler = exports.authHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.LoggerService = void 0;
|
|
3
|
+
exports.DefaultProgressStrategy = exports.CustomProgressStrategy = exports.ProgressStrategyRegistry = exports.PrimaryProcessStrategy = exports.SummaryManager = exports.CLIProgressManager = exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.log = exports.authenticationHandler = exports.Logger = exports.TablePrompt = exports.execute = exports.ux = exports.flush = exports.settings = exports.toConfiguredId = exports.toStandardizedId = exports.run = exports.Plugin = exports.Parser = exports.Interfaces = exports.HelpBase = exports.Help = exports.loadHelpClass = exports.Flags = exports.Errors = exports.Config = exports.CommandHelp = exports.Args = exports.marketplaceSDKInitiator = exports.MarketplaceSDKInitiator = exports.marketplaceSDKClient = exports.CLITable = exports.Command = exports.flags = exports.args = exports.NodeCrypto = exports.printFlagDeprecation = exports.managementSDKInitiator = exports.managementSDKClient = exports.configHandler = exports.authHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.LoggerService = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const logger_1 = tslib_1.__importDefault(require("./logger"));
|
|
6
6
|
exports.Logger = logger_1.default;
|
|
@@ -69,3 +69,10 @@ Object.defineProperty(exports, "log", { enumerable: true, get: function () { ret
|
|
|
69
69
|
Object.defineProperty(exports, "cliErrorHandler", { enumerable: true, get: function () { return log_1.cliErrorHandler; } });
|
|
70
70
|
Object.defineProperty(exports, "handleAndLogError", { enumerable: true, get: function () { return log_1.handleAndLogError; } });
|
|
71
71
|
Object.defineProperty(exports, "getLogPath", { enumerable: true, get: function () { return log_1.getLogPath; } });
|
|
72
|
+
var progress_summary_1 = require("./progress-summary");
|
|
73
|
+
Object.defineProperty(exports, "CLIProgressManager", { enumerable: true, get: function () { return progress_summary_1.CLIProgressManager; } });
|
|
74
|
+
Object.defineProperty(exports, "SummaryManager", { enumerable: true, get: function () { return progress_summary_1.SummaryManager; } });
|
|
75
|
+
Object.defineProperty(exports, "PrimaryProcessStrategy", { enumerable: true, get: function () { return progress_summary_1.PrimaryProcessStrategy; } });
|
|
76
|
+
Object.defineProperty(exports, "ProgressStrategyRegistry", { enumerable: true, get: function () { return progress_summary_1.ProgressStrategyRegistry; } });
|
|
77
|
+
Object.defineProperty(exports, "CustomProgressStrategy", { enumerable: true, get: function () { return progress_summary_1.CustomProgressStrategy; } });
|
|
78
|
+
Object.defineProperty(exports, "DefaultProgressStrategy", { enumerable: true, get: function () { return progress_summary_1.DefaultProgressStrategy; } });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { logLevels } from
|
|
1
|
+
import { logLevels } from '../constants/logging';
|
|
2
|
+
import ProgressBar from 'cli-progress';
|
|
2
3
|
export interface IPromptOptions {
|
|
3
4
|
prompt?: string;
|
|
4
5
|
type?: 'normal' | 'mask' | 'hide' | 'single';
|
|
@@ -101,3 +102,51 @@ export interface ErrorContextBase {
|
|
|
101
102
|
export type ErrorContext = ErrorContextBase & {
|
|
102
103
|
[key: string]: unknown;
|
|
103
104
|
};
|
|
105
|
+
export interface Failure {
|
|
106
|
+
item: string;
|
|
107
|
+
error: string | null;
|
|
108
|
+
process?: string;
|
|
109
|
+
}
|
|
110
|
+
export interface ProcessProgress {
|
|
111
|
+
name: string;
|
|
112
|
+
total: number;
|
|
113
|
+
current: number;
|
|
114
|
+
status: 'pending' | 'active' | 'completed' | 'failed';
|
|
115
|
+
successCount: number;
|
|
116
|
+
failureCount: number;
|
|
117
|
+
failures: Failure[];
|
|
118
|
+
progressBar?: ProgressBar.SingleBar;
|
|
119
|
+
}
|
|
120
|
+
export interface ProgressManagerOptions {
|
|
121
|
+
showConsoleLogs?: boolean;
|
|
122
|
+
total?: number;
|
|
123
|
+
moduleName?: string;
|
|
124
|
+
enableNestedProgress?: boolean;
|
|
125
|
+
}
|
|
126
|
+
export interface ModuleResult {
|
|
127
|
+
name: string;
|
|
128
|
+
status: 'pending' | 'running' | 'completed' | 'failed';
|
|
129
|
+
startTime?: number;
|
|
130
|
+
endTime?: number;
|
|
131
|
+
totalItems: number;
|
|
132
|
+
successCount: number;
|
|
133
|
+
failureCount: number;
|
|
134
|
+
failures: Array<{
|
|
135
|
+
item: string;
|
|
136
|
+
error: string;
|
|
137
|
+
}>;
|
|
138
|
+
processes?: Array<{
|
|
139
|
+
processName: string;
|
|
140
|
+
[key: string]: any;
|
|
141
|
+
}>;
|
|
142
|
+
}
|
|
143
|
+
export interface SummaryOptions {
|
|
144
|
+
operationName: string;
|
|
145
|
+
context?: any;
|
|
146
|
+
branchName?: string;
|
|
147
|
+
}
|
|
148
|
+
export interface ProgressResult {
|
|
149
|
+
total: number;
|
|
150
|
+
success: number;
|
|
151
|
+
failures: number;
|
|
152
|
+
}
|
|
@@ -114,8 +114,7 @@ class CLIErrorHandler {
|
|
|
114
114
|
if (typeof error === 'object') {
|
|
115
115
|
try {
|
|
116
116
|
const errorObj = error;
|
|
117
|
-
const
|
|
118
|
-
const normalizedError = new Error(message);
|
|
117
|
+
const normalizedError = new Error('Error occurred');
|
|
119
118
|
// Only copy essential properties
|
|
120
119
|
const essentialProps = [
|
|
121
120
|
'code',
|
package/lib/logger/log.js
CHANGED
|
@@ -13,7 +13,7 @@ function createLoggerInstance() {
|
|
|
13
13
|
var _a;
|
|
14
14
|
const logConfig = __1.configHandler.get('log');
|
|
15
15
|
const logLevel = (logConfig === null || logConfig === void 0 ? void 0 : logConfig.level) || 'info';
|
|
16
|
-
const showConsoleLogs = (_a = logConfig === null || logConfig === void 0 ? void 0 : logConfig
|
|
16
|
+
const showConsoleLogs = (_a = logConfig === null || logConfig === void 0 ? void 0 : logConfig.showConsoleLogs) !== null && _a !== void 0 ? _a : false;
|
|
17
17
|
const config = {
|
|
18
18
|
basePath: getLogPath(),
|
|
19
19
|
logLevel: logLevel,
|
package/lib/logger/logger.js
CHANGED
|
@@ -6,6 +6,7 @@ const full_1 = require("klona/full");
|
|
|
6
6
|
const path_1 = require("path");
|
|
7
7
|
const winston = tslib_1.__importStar(require("winston"));
|
|
8
8
|
const logging_1 = require("../constants/logging");
|
|
9
|
+
const __1 = require("..");
|
|
9
10
|
class Logger {
|
|
10
11
|
constructor(config) {
|
|
11
12
|
this.consoleSensitiveKeys = [
|
|
@@ -43,26 +44,45 @@ class Logger {
|
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
46
|
createLogger(level, filePath) {
|
|
47
|
+
var _a;
|
|
48
|
+
const transports = [
|
|
49
|
+
new winston.transports.File(Object.assign(Object.assign({}, this.loggerOptions), { filename: `${filePath}/${level}.log`, format: winston.format.combine(winston.format.timestamp(), winston.format.printf((info) => {
|
|
50
|
+
// Apply minimal redaction for files (debugging info preserved)
|
|
51
|
+
const redactedInfo = this.redact(info, false);
|
|
52
|
+
return JSON.stringify(redactedInfo);
|
|
53
|
+
})) })),
|
|
54
|
+
];
|
|
55
|
+
// Determine console logging based on configuration
|
|
56
|
+
let showConsoleLogs = true;
|
|
57
|
+
if (__1.configHandler && typeof __1.configHandler.get === 'function') {
|
|
58
|
+
const logConfig = __1.configHandler.get('log') || {};
|
|
59
|
+
const currentModule = logConfig.progressSupportedModule;
|
|
60
|
+
const hasProgressSupport = currentModule && logging_1.PROGRESS_SUPPORTED_MODULES.includes(currentModule);
|
|
61
|
+
if (hasProgressSupport) {
|
|
62
|
+
// Plugin has progress bars - respect user's showConsoleLogs setting
|
|
63
|
+
showConsoleLogs = (_a = logConfig.showConsoleLogs) !== null && _a !== void 0 ? _a : true;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// Plugin doesn't have progress support - always show console logs
|
|
67
|
+
showConsoleLogs = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (showConsoleLogs) {
|
|
71
|
+
transports.push(new winston.transports.Console({
|
|
72
|
+
format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf((info) => {
|
|
73
|
+
// Apply full redaction for console (user-facing)
|
|
74
|
+
const redactedInfo = this.redact(info, true);
|
|
75
|
+
const colorizer = winston.format.colorize();
|
|
76
|
+
const levelText = redactedInfo.level.toUpperCase();
|
|
77
|
+
const { timestamp, message } = redactedInfo;
|
|
78
|
+
return colorizer.colorize(redactedInfo.level, `[${timestamp}] ${levelText}: ${message}`);
|
|
79
|
+
})),
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
46
82
|
return winston.createLogger({
|
|
47
83
|
levels: logging_1.logLevels,
|
|
48
84
|
level,
|
|
49
|
-
transports
|
|
50
|
-
new winston.transports.File(Object.assign(Object.assign({}, this.loggerOptions), { filename: `${filePath}/${level}.log`, format: winston.format.combine(winston.format.timestamp(), winston.format.printf((info) => {
|
|
51
|
-
// Apply minimal redaction for files (debugging info preserved)
|
|
52
|
-
const redactedInfo = this.redact(info, false);
|
|
53
|
-
return JSON.stringify(redactedInfo);
|
|
54
|
-
})) })),
|
|
55
|
-
new winston.transports.Console({
|
|
56
|
-
format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf((info) => {
|
|
57
|
-
// Apply full redaction for console (user-facing)
|
|
58
|
-
const redactedInfo = this.redact(info, true);
|
|
59
|
-
const colorizer = winston.format.colorize();
|
|
60
|
-
const levelText = redactedInfo.level.toUpperCase();
|
|
61
|
-
const { timestamp, message } = redactedInfo;
|
|
62
|
-
return colorizer.colorize(redactedInfo.level, `[${timestamp}] ${levelText}: ${message}`);
|
|
63
|
-
})),
|
|
64
|
-
}),
|
|
65
|
-
],
|
|
85
|
+
transports,
|
|
66
86
|
});
|
|
67
87
|
}
|
|
68
88
|
isSensitiveKey(keyStr, consoleMode = false) {
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import SummaryManager from './summary-manager';
|
|
2
|
+
import { ProgressManagerOptions } from '../interfaces';
|
|
3
|
+
interface ProgressCallback {
|
|
4
|
+
onModuleStart?: (moduleName: string) => void;
|
|
5
|
+
onModuleComplete?: (moduleName: string, success: boolean, error?: string) => void;
|
|
6
|
+
onProgress?: (moduleName: string, success: boolean, itemName: string, error?: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export default class CLIProgressManager {
|
|
9
|
+
private static globalSummary;
|
|
10
|
+
private showConsoleLogs;
|
|
11
|
+
private total;
|
|
12
|
+
private moduleName;
|
|
13
|
+
private enableNestedProgress;
|
|
14
|
+
private successCount;
|
|
15
|
+
private failureCount;
|
|
16
|
+
private failures;
|
|
17
|
+
private spinner;
|
|
18
|
+
private progressBar;
|
|
19
|
+
private processes;
|
|
20
|
+
private multiBar;
|
|
21
|
+
private currentProcess;
|
|
22
|
+
private callbacks;
|
|
23
|
+
private branchName;
|
|
24
|
+
constructor({ showConsoleLogs, total, moduleName, enableNestedProgress, }?: ProgressManagerOptions);
|
|
25
|
+
/**
|
|
26
|
+
* Initialize global summary manager for the entire operation
|
|
27
|
+
*/
|
|
28
|
+
static initializeGlobalSummary(operationName: string, branchName: string, headerTitle?: string): SummaryManager;
|
|
29
|
+
/**
|
|
30
|
+
* Display operation header with branch information
|
|
31
|
+
*/
|
|
32
|
+
static displayOperationHeader(branchName: string, headerTitle?: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Print the final summary for all modules using strategies
|
|
35
|
+
*/
|
|
36
|
+
static printGlobalSummary(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Apply strategy-based corrections to module data
|
|
39
|
+
*/
|
|
40
|
+
private static applyStrategyCorrections;
|
|
41
|
+
/**
|
|
42
|
+
* Clear global summary (for cleanup)
|
|
43
|
+
*/
|
|
44
|
+
static clearGlobalSummary(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Create a simple progress manager (no nested processes)
|
|
47
|
+
*/
|
|
48
|
+
static createSimple(moduleName: string, total?: number, showConsoleLogs?: boolean): CLIProgressManager;
|
|
49
|
+
/**
|
|
50
|
+
* Create a nested progress manager (with sub-processes)
|
|
51
|
+
*/
|
|
52
|
+
static createNested(moduleName: string, showConsoleLogs?: boolean): CLIProgressManager;
|
|
53
|
+
/**
|
|
54
|
+
* Show a loading spinner before initializing progress
|
|
55
|
+
*/
|
|
56
|
+
static withLoadingSpinner<T>(message: string, asyncOperation: () => Promise<T>): Promise<T>;
|
|
57
|
+
private setupGlobalSummaryIntegration;
|
|
58
|
+
/**
|
|
59
|
+
* Register process data with summary manager for strategy calculations
|
|
60
|
+
*/
|
|
61
|
+
private registerProcessDataWithSummary;
|
|
62
|
+
/**
|
|
63
|
+
* Set callbacks for external integration
|
|
64
|
+
*/
|
|
65
|
+
setCallbacks(callbacks: ProgressCallback): void;
|
|
66
|
+
/**
|
|
67
|
+
* Convert module name from UPPERCASE to PascalCase
|
|
68
|
+
*/
|
|
69
|
+
private formatModuleName;
|
|
70
|
+
/**
|
|
71
|
+
* Format process name with smart truncation (modules should use short names)
|
|
72
|
+
*/
|
|
73
|
+
private formatProcessName;
|
|
74
|
+
/**
|
|
75
|
+
* Format percentage for consistent alignment (always 3 characters)
|
|
76
|
+
*/
|
|
77
|
+
private formatPercentage;
|
|
78
|
+
private initializeProgress;
|
|
79
|
+
/**
|
|
80
|
+
* Add a new process to track (for nested progress)
|
|
81
|
+
*/
|
|
82
|
+
addProcess(processName: string, total: number): this;
|
|
83
|
+
/**
|
|
84
|
+
* Update the total for a specific process (for dynamic totals after API calls)
|
|
85
|
+
*/
|
|
86
|
+
updateProcessTotal(processName: string, newTotal: number): this;
|
|
87
|
+
/**
|
|
88
|
+
* Start a specific process
|
|
89
|
+
*/
|
|
90
|
+
startProcess(processName: string): this;
|
|
91
|
+
/**
|
|
92
|
+
* Complete a specific process
|
|
93
|
+
*/
|
|
94
|
+
completeProcess(processName: string, success?: boolean): this;
|
|
95
|
+
/**
|
|
96
|
+
* Update status message
|
|
97
|
+
*/
|
|
98
|
+
updateStatus(message: string, processName?: string): this;
|
|
99
|
+
/**
|
|
100
|
+
* Update progress
|
|
101
|
+
*/
|
|
102
|
+
tick(success?: boolean, itemName?: string, errorMessage?: string | null, processName?: string): this;
|
|
103
|
+
/**
|
|
104
|
+
* Complete the entire module
|
|
105
|
+
*/
|
|
106
|
+
complete(success?: boolean, error?: string): this;
|
|
107
|
+
/**
|
|
108
|
+
* Log message (respects showConsoleLogs mode)
|
|
109
|
+
*/
|
|
110
|
+
log(msg: string): void;
|
|
111
|
+
/**
|
|
112
|
+
* Stop all progress indicators
|
|
113
|
+
*/
|
|
114
|
+
stop(): void;
|
|
115
|
+
private printSummary;
|
|
116
|
+
/**
|
|
117
|
+
* Get the current failure count
|
|
118
|
+
*/
|
|
119
|
+
getFailureCount(): number;
|
|
120
|
+
}
|
|
121
|
+
export {};
|
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
5
|
+
const ora_1 = tslib_1.__importDefault(require("ora"));
|
|
6
|
+
const cli_progress_1 = tslib_1.__importDefault(require("cli-progress"));
|
|
7
|
+
const summary_manager_1 = tslib_1.__importDefault(require("./summary-manager"));
|
|
8
|
+
const __1 = require("..");
|
|
9
|
+
const progress_strategy_1 = require("./progress-strategy");
|
|
10
|
+
class CLIProgressManager {
|
|
11
|
+
constructor({ showConsoleLogs = false, total = 0, moduleName = 'Module', enableNestedProgress = false, } = {}) {
|
|
12
|
+
this.showConsoleLogs = showConsoleLogs;
|
|
13
|
+
this.total = total;
|
|
14
|
+
this.moduleName = moduleName;
|
|
15
|
+
this.enableNestedProgress = enableNestedProgress;
|
|
16
|
+
this.successCount = 0;
|
|
17
|
+
this.failureCount = 0;
|
|
18
|
+
this.failures = [];
|
|
19
|
+
this.spinner = null;
|
|
20
|
+
this.progressBar = null;
|
|
21
|
+
this.processes = new Map();
|
|
22
|
+
this.multiBar = null;
|
|
23
|
+
this.currentProcess = null;
|
|
24
|
+
this.callbacks = {};
|
|
25
|
+
this.branchName = '';
|
|
26
|
+
this.initializeProgress();
|
|
27
|
+
this.setupGlobalSummaryIntegration();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Initialize global summary manager for the entire operation
|
|
31
|
+
*/
|
|
32
|
+
static initializeGlobalSummary(operationName, branchName, headerTitle) {
|
|
33
|
+
var _a;
|
|
34
|
+
CLIProgressManager.globalSummary = new summary_manager_1.default({ operationName, context: { branchName } });
|
|
35
|
+
// Only show header if console logs are disabled (progress UI mode)
|
|
36
|
+
if (!((_a = __1.configHandler.get('log')) === null || _a === void 0 ? void 0 : _a.showConsoleLogs)) {
|
|
37
|
+
CLIProgressManager.displayOperationHeader(branchName, headerTitle);
|
|
38
|
+
}
|
|
39
|
+
return CLIProgressManager.globalSummary;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Display operation header with branch information
|
|
43
|
+
*/
|
|
44
|
+
static displayOperationHeader(branchName, headerTitle) {
|
|
45
|
+
if (!headerTitle)
|
|
46
|
+
return;
|
|
47
|
+
const safeBranchName = branchName || 'main';
|
|
48
|
+
const branchInfo = headerTitle || `${safeBranchName === null || safeBranchName === void 0 ? void 0 : safeBranchName.toUpperCase()} CONTENT`;
|
|
49
|
+
console.log('\n' + chalk_1.default.bold('='.repeat(80)));
|
|
50
|
+
if (branchInfo) {
|
|
51
|
+
console.log(chalk_1.default.bold.white(` ${branchInfo}`));
|
|
52
|
+
}
|
|
53
|
+
console.log(chalk_1.default.bold('='.repeat(80)) + '\n');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Print the final summary for all modules using strategies
|
|
57
|
+
*/
|
|
58
|
+
static printGlobalSummary() {
|
|
59
|
+
if (!CLIProgressManager.globalSummary) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Apply strategy-based corrections before printing
|
|
63
|
+
CLIProgressManager.applyStrategyCorrections();
|
|
64
|
+
// Print the final summary
|
|
65
|
+
CLIProgressManager.globalSummary.printFinalSummary();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Apply strategy-based corrections to module data
|
|
69
|
+
*/
|
|
70
|
+
static applyStrategyCorrections() {
|
|
71
|
+
if (!CLIProgressManager.globalSummary)
|
|
72
|
+
return;
|
|
73
|
+
const modules = Array.from(CLIProgressManager.globalSummary.getModules().values());
|
|
74
|
+
modules.forEach((module) => {
|
|
75
|
+
// Check if this module has a registered strategy
|
|
76
|
+
if (progress_strategy_1.ProgressStrategyRegistry.has(module.name)) {
|
|
77
|
+
const strategy = progress_strategy_1.ProgressStrategyRegistry.get(module.name);
|
|
78
|
+
// Create a processes map from module data if available
|
|
79
|
+
const processesMap = new Map();
|
|
80
|
+
// If module has process data, populate the map
|
|
81
|
+
if (module.processes && Array.isArray(module.processes)) {
|
|
82
|
+
module.processes.forEach((processData) => {
|
|
83
|
+
if (processData.processName) {
|
|
84
|
+
processesMap.set(processData.processName, processData);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// Calculate corrected progress using strategy
|
|
89
|
+
const correctedResult = strategy.calculate(processesMap);
|
|
90
|
+
if (correctedResult) {
|
|
91
|
+
// Update module with corrected counts
|
|
92
|
+
module.totalItems = correctedResult.total;
|
|
93
|
+
module.successCount = correctedResult.success;
|
|
94
|
+
module.failureCount = correctedResult.failures;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Clear global summary (for cleanup)
|
|
101
|
+
*/
|
|
102
|
+
static clearGlobalSummary() {
|
|
103
|
+
CLIProgressManager.globalSummary = null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Create a simple progress manager (no nested processes)
|
|
107
|
+
*/
|
|
108
|
+
static createSimple(moduleName, total, showConsoleLogs = false) {
|
|
109
|
+
return new CLIProgressManager({
|
|
110
|
+
moduleName: moduleName.toUpperCase(),
|
|
111
|
+
total: total || 0,
|
|
112
|
+
showConsoleLogs,
|
|
113
|
+
enableNestedProgress: false,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Create a nested progress manager (with sub-processes)
|
|
118
|
+
*/
|
|
119
|
+
static createNested(moduleName, showConsoleLogs = false) {
|
|
120
|
+
return new CLIProgressManager({
|
|
121
|
+
moduleName: moduleName.toUpperCase(),
|
|
122
|
+
total: 0,
|
|
123
|
+
showConsoleLogs,
|
|
124
|
+
enableNestedProgress: true,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Show a loading spinner before initializing progress
|
|
129
|
+
*/
|
|
130
|
+
static async withLoadingSpinner(message, asyncOperation) {
|
|
131
|
+
const spinner = (0, ora_1.default)(message).start();
|
|
132
|
+
try {
|
|
133
|
+
const result = await asyncOperation();
|
|
134
|
+
spinner.stop();
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
spinner.stop();
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
setupGlobalSummaryIntegration() {
|
|
143
|
+
var _a, _b;
|
|
144
|
+
// Auto-register with global summary if it exists
|
|
145
|
+
if (CLIProgressManager.globalSummary) {
|
|
146
|
+
this.setCallbacks({
|
|
147
|
+
onModuleStart: (name) => {
|
|
148
|
+
var _a, _b;
|
|
149
|
+
(_a = CLIProgressManager.globalSummary) === null || _a === void 0 ? void 0 : _a.registerModule(name, this.total);
|
|
150
|
+
(_b = CLIProgressManager.globalSummary) === null || _b === void 0 ? void 0 : _b.startModule(name);
|
|
151
|
+
},
|
|
152
|
+
onModuleComplete: (name, success, error) => {
|
|
153
|
+
var _a;
|
|
154
|
+
// Register process data with summary manager before completing
|
|
155
|
+
this.registerProcessDataWithSummary(name);
|
|
156
|
+
(_a = CLIProgressManager.globalSummary) === null || _a === void 0 ? void 0 : _a.completeModule(name, success, error);
|
|
157
|
+
},
|
|
158
|
+
onProgress: (name, success, itemName, error) => {
|
|
159
|
+
var _a;
|
|
160
|
+
(_a = CLIProgressManager.globalSummary) === null || _a === void 0 ? void 0 : _a.updateModuleProgress(name, success, itemName, error);
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
// Trigger module start
|
|
164
|
+
(_b = (_a = this.callbacks).onModuleStart) === null || _b === void 0 ? void 0 : _b.call(_a, this.moduleName);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Register process data with summary manager for strategy calculations
|
|
169
|
+
*/
|
|
170
|
+
registerProcessDataWithSummary(moduleName) {
|
|
171
|
+
if (!CLIProgressManager.globalSummary)
|
|
172
|
+
return;
|
|
173
|
+
// Register each process with the summary manager
|
|
174
|
+
this.processes.forEach((processData, processName) => {
|
|
175
|
+
var _a;
|
|
176
|
+
(_a = CLIProgressManager.globalSummary) === null || _a === void 0 ? void 0 : _a.registerProcessData(moduleName, processName, {
|
|
177
|
+
processName,
|
|
178
|
+
total: processData.total,
|
|
179
|
+
current: processData.current,
|
|
180
|
+
successCount: processData.successCount,
|
|
181
|
+
failureCount: processData.failureCount,
|
|
182
|
+
status: processData.status,
|
|
183
|
+
failures: processData.failures,
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Set callbacks for external integration
|
|
189
|
+
*/
|
|
190
|
+
setCallbacks(callbacks) {
|
|
191
|
+
this.callbacks = Object.assign(Object.assign({}, this.callbacks), callbacks);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Convert module name from UPPERCASE to PascalCase
|
|
195
|
+
*/
|
|
196
|
+
formatModuleName(name) {
|
|
197
|
+
return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Format process name with smart truncation (modules should use short names)
|
|
201
|
+
*/
|
|
202
|
+
formatProcessName(processName) {
|
|
203
|
+
const cleaned = processName.trim();
|
|
204
|
+
if (cleaned.length <= 20) {
|
|
205
|
+
return cleaned;
|
|
206
|
+
}
|
|
207
|
+
return cleaned.length <= 20 ? cleaned : cleaned.substring(0, 20) + '...';
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Format percentage for consistent alignment (always 3 characters)
|
|
211
|
+
*/
|
|
212
|
+
formatPercentage(percentage) {
|
|
213
|
+
if (percentage === 100) {
|
|
214
|
+
return '100';
|
|
215
|
+
}
|
|
216
|
+
else if (percentage >= 10) {
|
|
217
|
+
return ` ${percentage}`;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
return ` ${percentage}`;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
initializeProgress() {
|
|
224
|
+
if (this.showConsoleLogs) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (this.enableNestedProgress) {
|
|
228
|
+
// Initialize multi-bar for nested progress tracking
|
|
229
|
+
this.multiBar = new cli_progress_1.default.MultiBar({
|
|
230
|
+
clearOnComplete: false,
|
|
231
|
+
hideCursor: true,
|
|
232
|
+
format: ' {label} |' + chalk_1.default.cyan('{bar}') + '| {percentage}% | {value}/{total} | {status}',
|
|
233
|
+
barCompleteChar: '\u2588',
|
|
234
|
+
barIncompleteChar: '\u2591',
|
|
235
|
+
}, cli_progress_1.default.Presets.shades_classic);
|
|
236
|
+
if (!this.showConsoleLogs) {
|
|
237
|
+
console.log(chalk_1.default.bold.cyan(`\n${this.moduleName}:`));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else if (this.total > 0) {
|
|
241
|
+
if (!this.showConsoleLogs) {
|
|
242
|
+
console.log(chalk_1.default.bold.cyan(`\n${this.moduleName}:`));
|
|
243
|
+
}
|
|
244
|
+
this.progressBar = new cli_progress_1.default.SingleBar({
|
|
245
|
+
format: ' {label} |' + chalk_1.default.cyan('{bar}') + '| {percentage}% | {value}/{total} | {status}',
|
|
246
|
+
barCompleteChar: '\u2588',
|
|
247
|
+
barIncompleteChar: '\u2591',
|
|
248
|
+
hideCursor: true,
|
|
249
|
+
});
|
|
250
|
+
const formattedName = this.formatModuleName(this.moduleName);
|
|
251
|
+
const displayName = formattedName.length > 20 ? formattedName.substring(0, 17) + '...' : formattedName;
|
|
252
|
+
this.progressBar.start(this.total, 0, {
|
|
253
|
+
label: chalk_1.default.gray(` āā ${displayName}`.padEnd(25)),
|
|
254
|
+
status: chalk_1.default.gray('Starting...'),
|
|
255
|
+
percentage: ' 0',
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
this.spinner = (0, ora_1.default)(`${chalk_1.default.bold(this.moduleName)}: Processing...`).start();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Add a new process to track (for nested progress)
|
|
264
|
+
*/
|
|
265
|
+
addProcess(processName, total) {
|
|
266
|
+
if (!this.enableNestedProgress || !this.multiBar)
|
|
267
|
+
return this;
|
|
268
|
+
const process = {
|
|
269
|
+
name: processName,
|
|
270
|
+
total,
|
|
271
|
+
current: 0,
|
|
272
|
+
status: 'pending',
|
|
273
|
+
successCount: 0,
|
|
274
|
+
failureCount: 0,
|
|
275
|
+
failures: [],
|
|
276
|
+
};
|
|
277
|
+
if (!this.showConsoleLogs) {
|
|
278
|
+
const displayName = this.formatProcessName(processName);
|
|
279
|
+
const indentedLabel = ` āā ${displayName}`.padEnd(25);
|
|
280
|
+
process.progressBar = this.multiBar.create(total, 0, {
|
|
281
|
+
label: chalk_1.default.gray(indentedLabel),
|
|
282
|
+
status: chalk_1.default.gray('Pending'),
|
|
283
|
+
percentage: ' 0',
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
this.processes.set(processName, process);
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Update the total for a specific process (for dynamic totals after API calls)
|
|
291
|
+
*/
|
|
292
|
+
updateProcessTotal(processName, newTotal) {
|
|
293
|
+
if (!this.enableNestedProgress)
|
|
294
|
+
return this;
|
|
295
|
+
const process = this.processes.get(processName);
|
|
296
|
+
if (process) {
|
|
297
|
+
process.total = newTotal;
|
|
298
|
+
if (process.progressBar && !this.showConsoleLogs) {
|
|
299
|
+
// Update the progress bar with the new total
|
|
300
|
+
process.progressBar.setTotal(newTotal);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return this;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Start a specific process
|
|
307
|
+
*/
|
|
308
|
+
startProcess(processName) {
|
|
309
|
+
if (!this.enableNestedProgress)
|
|
310
|
+
return this;
|
|
311
|
+
const process = this.processes.get(processName);
|
|
312
|
+
if (process) {
|
|
313
|
+
process.status = 'active';
|
|
314
|
+
if (!this.showConsoleLogs && process.progressBar) {
|
|
315
|
+
const displayName = this.formatProcessName(processName);
|
|
316
|
+
const indentedLabel = ` āā ${displayName}`.padEnd(25);
|
|
317
|
+
process.progressBar.update(0, {
|
|
318
|
+
label: chalk_1.default.yellow(indentedLabel),
|
|
319
|
+
status: chalk_1.default.yellow('Processing'),
|
|
320
|
+
percentage: ' 0',
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
this.currentProcess = processName;
|
|
324
|
+
}
|
|
325
|
+
return this;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Complete a specific process
|
|
329
|
+
*/
|
|
330
|
+
completeProcess(processName, success = true) {
|
|
331
|
+
if (!this.enableNestedProgress)
|
|
332
|
+
return this;
|
|
333
|
+
const process = this.processes.get(processName);
|
|
334
|
+
if (process) {
|
|
335
|
+
process.status = success ? 'completed' : 'failed';
|
|
336
|
+
if (!this.showConsoleLogs && process.progressBar) {
|
|
337
|
+
const percentage = Math.round((process.current / process.total) * 100);
|
|
338
|
+
const formattedPercentage = this.formatPercentage(percentage);
|
|
339
|
+
const statusText = success
|
|
340
|
+
? chalk_1.default.green(`ā Complete (${process.successCount}/${process.current})`)
|
|
341
|
+
: chalk_1.default.red(`ā Failed (${process.successCount}/${process.current})`);
|
|
342
|
+
const displayName = this.formatProcessName(processName);
|
|
343
|
+
const indentedLabel = ` āā ${displayName}`.padEnd(25);
|
|
344
|
+
process.progressBar.update(process.total, {
|
|
345
|
+
label: success ? chalk_1.default.green(indentedLabel) : chalk_1.default.red(indentedLabel),
|
|
346
|
+
status: statusText,
|
|
347
|
+
percentage: formattedPercentage,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return this;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Update status message
|
|
355
|
+
*/
|
|
356
|
+
updateStatus(message, processName) {
|
|
357
|
+
if (!this.showConsoleLogs) {
|
|
358
|
+
if (this.enableNestedProgress && processName) {
|
|
359
|
+
const process = this.processes.get(processName);
|
|
360
|
+
if (process && process.progressBar) {
|
|
361
|
+
const percentage = Math.round((process.current / process.total) * 100);
|
|
362
|
+
const formattedPercentage = this.formatPercentage(percentage);
|
|
363
|
+
const displayName = this.formatProcessName(processName);
|
|
364
|
+
const indentedLabel = ` āā ${displayName}`.padEnd(25);
|
|
365
|
+
process.progressBar.update(process.current, {
|
|
366
|
+
label: chalk_1.default.yellow(indentedLabel),
|
|
367
|
+
status: chalk_1.default.yellow(message),
|
|
368
|
+
percentage: formattedPercentage,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else if (this.progressBar) {
|
|
373
|
+
const percentage = Math.round(this.progressBar.getProgress() * 100);
|
|
374
|
+
const formattedPercentage = this.formatPercentage(percentage);
|
|
375
|
+
const formattedName = this.formatModuleName(this.moduleName);
|
|
376
|
+
const displayName = formattedName.length > 20 ? formattedName.substring(0, 17) + '...' : formattedName;
|
|
377
|
+
this.progressBar.update(this.progressBar.getProgress() * this.total, {
|
|
378
|
+
label: chalk_1.default.yellow(` āā ${displayName}`.padEnd(25)),
|
|
379
|
+
status: chalk_1.default.yellow(message),
|
|
380
|
+
percentage: formattedPercentage,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
else if (this.spinner) {
|
|
384
|
+
this.spinner.text = `${chalk_1.default.bold(this.moduleName)}: ${message}`;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return this;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Update progress
|
|
391
|
+
*/
|
|
392
|
+
tick(success = true, itemName = '', errorMessage = null, processName) {
|
|
393
|
+
var _a, _b;
|
|
394
|
+
const targetProcess = processName || this.currentProcess;
|
|
395
|
+
if (success) {
|
|
396
|
+
this.successCount++;
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
this.failureCount++;
|
|
400
|
+
this.failures.push({
|
|
401
|
+
item: itemName,
|
|
402
|
+
error: errorMessage,
|
|
403
|
+
process: targetProcess || undefined,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
// Trigger callback
|
|
407
|
+
(_b = (_a = this.callbacks).onProgress) === null || _b === void 0 ? void 0 : _b.call(_a, this.moduleName, success, itemName, errorMessage || undefined);
|
|
408
|
+
// Update nested progress if enabled and console logs are disabled
|
|
409
|
+
if (this.enableNestedProgress && targetProcess) {
|
|
410
|
+
const process = this.processes.get(targetProcess);
|
|
411
|
+
if (process) {
|
|
412
|
+
process.current++;
|
|
413
|
+
if (success) {
|
|
414
|
+
process.successCount++;
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
process.failureCount++;
|
|
418
|
+
process.failures.push({ item: itemName, error: errorMessage });
|
|
419
|
+
}
|
|
420
|
+
// Only update progress bar if console logs are disabled
|
|
421
|
+
if (!this.showConsoleLogs && process.progressBar) {
|
|
422
|
+
const percentage = Math.round((process.current / process.total) * 100);
|
|
423
|
+
const formattedPercentage = this.formatPercentage(percentage);
|
|
424
|
+
const statusText = `${process.successCount}ā ${process.failureCount}ā`;
|
|
425
|
+
const displayName = this.formatProcessName(targetProcess);
|
|
426
|
+
const indentedLabel = ` āā ${displayName}`.padEnd(25);
|
|
427
|
+
process.progressBar.increment(1, {
|
|
428
|
+
label: chalk_1.default.cyan(indentedLabel),
|
|
429
|
+
status: chalk_1.default.cyan(statusText),
|
|
430
|
+
percentage: formattedPercentage,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
// Update single progress bar or spinner only if console logs are disabled
|
|
437
|
+
if (!this.showConsoleLogs) {
|
|
438
|
+
if (this.progressBar) {
|
|
439
|
+
const percentage = Math.round(((this.successCount + this.failureCount) / this.total) * 100);
|
|
440
|
+
const formattedPercentage = this.formatPercentage(percentage);
|
|
441
|
+
const totalProcessed = this.successCount + this.failureCount;
|
|
442
|
+
// Show completion status when finished, otherwise show running count
|
|
443
|
+
const statusText = totalProcessed >= this.total
|
|
444
|
+
? this.failureCount === 0
|
|
445
|
+
? chalk_1.default.green(`ā Complete (${this.successCount}/${totalProcessed})`)
|
|
446
|
+
: chalk_1.default.yellow(`ā Complete (${this.successCount}/${totalProcessed})`)
|
|
447
|
+
: chalk_1.default.cyan(`${this.successCount}ā ${this.failureCount}ā`);
|
|
448
|
+
const labelColor = totalProcessed >= this.total ? (this.failureCount === 0 ? chalk_1.default.green : chalk_1.default.yellow) : chalk_1.default.cyan;
|
|
449
|
+
const formattedName = this.formatModuleName(this.moduleName);
|
|
450
|
+
const displayName = formattedName.length > 20 ? formattedName.substring(0, 17) + '...' : formattedName;
|
|
451
|
+
this.progressBar.increment(1, {
|
|
452
|
+
label: labelColor(` āā ${displayName}`.padEnd(25)),
|
|
453
|
+
status: statusText,
|
|
454
|
+
percentage: formattedPercentage,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
else if (this.spinner) {
|
|
458
|
+
const total = this.successCount + this.failureCount;
|
|
459
|
+
this.spinner.text = `${chalk_1.default.bold(this.moduleName)}: ${total} items (${this.successCount}ā ${this.failureCount}ā)`;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return this;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Complete the entire module
|
|
467
|
+
*/
|
|
468
|
+
complete(success = true, error) {
|
|
469
|
+
var _a, _b;
|
|
470
|
+
this.stop();
|
|
471
|
+
(_b = (_a = this.callbacks).onModuleComplete) === null || _b === void 0 ? void 0 : _b.call(_a, this.moduleName, success, error);
|
|
472
|
+
return this;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Log message (respects showConsoleLogs mode)
|
|
476
|
+
*/
|
|
477
|
+
log(msg) {
|
|
478
|
+
if (this.showConsoleLogs) {
|
|
479
|
+
console.log(msg);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Stop all progress indicators
|
|
484
|
+
*/
|
|
485
|
+
stop() {
|
|
486
|
+
// Only stop progress bars if they were initialized (console logs disabled)
|
|
487
|
+
if (!this.showConsoleLogs) {
|
|
488
|
+
if (this.multiBar) {
|
|
489
|
+
this.multiBar.stop();
|
|
490
|
+
}
|
|
491
|
+
if (this.progressBar) {
|
|
492
|
+
this.progressBar.stop();
|
|
493
|
+
}
|
|
494
|
+
if (this.spinner) {
|
|
495
|
+
this.spinner.stop();
|
|
496
|
+
}
|
|
497
|
+
this.printSummary();
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
printSummary() {
|
|
501
|
+
if (!this.enableNestedProgress) {
|
|
502
|
+
// Simple summary for single progress
|
|
503
|
+
this.log('\n' + chalk_1.default.bold(`${this.moduleName} Summary:`));
|
|
504
|
+
this.log(`ā Success: ${chalk_1.default.green(this.successCount)}`);
|
|
505
|
+
this.log(`ā Failures: ${chalk_1.default.red(this.failureCount)}`);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
// Detailed summary for nested progress
|
|
509
|
+
this.log('\n' + chalk_1.default.bold(`${this.moduleName} Detailed Summary:`));
|
|
510
|
+
for (const [processName, process] of this.processes) {
|
|
511
|
+
const status = process.status === 'completed'
|
|
512
|
+
? 'ā'
|
|
513
|
+
: process.status === 'failed'
|
|
514
|
+
? 'ā'
|
|
515
|
+
: process.status === 'active'
|
|
516
|
+
? 'ā'
|
|
517
|
+
: 'ā';
|
|
518
|
+
this.log(` ${status} ${processName}: ${process.successCount}ā ${process.failureCount}ā (${process.current}/${process.total})`);
|
|
519
|
+
}
|
|
520
|
+
this.log(`\nOverall: ${this.successCount}ā ${this.failureCount}ā`);
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Get the current failure count
|
|
524
|
+
*/
|
|
525
|
+
getFailureCount() {
|
|
526
|
+
return this.failureCount;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
exports.default = CLIProgressManager;
|
|
530
|
+
CLIProgressManager.globalSummary = null;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import SummaryManager from './summary-manager';
|
|
2
|
+
import CLIProgressManager from './cli-progress-manager';
|
|
3
|
+
import { PrimaryProcessStrategy, CustomProgressStrategy, ProgressStrategyRegistry, DefaultProgressStrategy } from './progress-strategy';
|
|
4
|
+
export { SummaryManager, CLIProgressManager, PrimaryProcessStrategy, CustomProgressStrategy, ProgressStrategyRegistry, DefaultProgressStrategy, };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultProgressStrategy = exports.ProgressStrategyRegistry = exports.CustomProgressStrategy = exports.PrimaryProcessStrategy = exports.CLIProgressManager = exports.SummaryManager = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const summary_manager_1 = tslib_1.__importDefault(require("./summary-manager"));
|
|
6
|
+
exports.SummaryManager = summary_manager_1.default;
|
|
7
|
+
const cli_progress_manager_1 = tslib_1.__importDefault(require("./cli-progress-manager"));
|
|
8
|
+
exports.CLIProgressManager = cli_progress_manager_1.default;
|
|
9
|
+
const progress_strategy_1 = require("./progress-strategy");
|
|
10
|
+
Object.defineProperty(exports, "PrimaryProcessStrategy", { enumerable: true, get: function () { return progress_strategy_1.PrimaryProcessStrategy; } });
|
|
11
|
+
Object.defineProperty(exports, "CustomProgressStrategy", { enumerable: true, get: function () { return progress_strategy_1.CustomProgressStrategy; } });
|
|
12
|
+
Object.defineProperty(exports, "ProgressStrategyRegistry", { enumerable: true, get: function () { return progress_strategy_1.ProgressStrategyRegistry; } });
|
|
13
|
+
Object.defineProperty(exports, "DefaultProgressStrategy", { enumerable: true, get: function () { return progress_strategy_1.DefaultProgressStrategy; } });
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ProcessProgress, ProgressResult } from '../interfaces';
|
|
2
|
+
export interface ProgressCalculationStrategy {
|
|
3
|
+
calculate(processes: Map<string, ProcessProgress>): ProgressResult | null;
|
|
4
|
+
}
|
|
5
|
+
export declare class DefaultProgressStrategy implements ProgressCalculationStrategy {
|
|
6
|
+
calculate(): ProgressResult | null;
|
|
7
|
+
}
|
|
8
|
+
export declare class PrimaryProcessStrategy implements ProgressCalculationStrategy {
|
|
9
|
+
private primaryProcessName;
|
|
10
|
+
constructor(primaryProcessName: string);
|
|
11
|
+
calculate(processes: Map<string, ProcessProgress>): ProgressResult | null;
|
|
12
|
+
}
|
|
13
|
+
export declare class CustomProgressStrategy implements ProgressCalculationStrategy {
|
|
14
|
+
private calculator;
|
|
15
|
+
constructor(calculator: (processes: Map<string, ProcessProgress>) => ProgressResult | null);
|
|
16
|
+
calculate(processes: Map<string, ProcessProgress>): ProgressResult | null;
|
|
17
|
+
}
|
|
18
|
+
export declare class ProgressStrategyRegistry {
|
|
19
|
+
private static strategies;
|
|
20
|
+
static register(moduleName: string, strategy: ProgressCalculationStrategy): void;
|
|
21
|
+
static get(moduleName: string): ProgressCalculationStrategy;
|
|
22
|
+
static clear(): void;
|
|
23
|
+
static has(moduleName: string): boolean;
|
|
24
|
+
static getAllRegistered(): string[];
|
|
25
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProgressStrategyRegistry = exports.CustomProgressStrategy = exports.PrimaryProcessStrategy = exports.DefaultProgressStrategy = void 0;
|
|
4
|
+
class DefaultProgressStrategy {
|
|
5
|
+
calculate() {
|
|
6
|
+
return null; // Use default aggregated counting
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
exports.DefaultProgressStrategy = DefaultProgressStrategy;
|
|
10
|
+
class PrimaryProcessStrategy {
|
|
11
|
+
constructor(primaryProcessName) {
|
|
12
|
+
this.primaryProcessName = primaryProcessName;
|
|
13
|
+
}
|
|
14
|
+
calculate(processes) {
|
|
15
|
+
const primaryProcess = processes.get(this.primaryProcessName);
|
|
16
|
+
if (!primaryProcess)
|
|
17
|
+
return null;
|
|
18
|
+
return {
|
|
19
|
+
total: primaryProcess.total,
|
|
20
|
+
success: primaryProcess.successCount,
|
|
21
|
+
failures: primaryProcess.failureCount
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.PrimaryProcessStrategy = PrimaryProcessStrategy;
|
|
26
|
+
class CustomProgressStrategy {
|
|
27
|
+
constructor(calculator) {
|
|
28
|
+
this.calculator = calculator;
|
|
29
|
+
}
|
|
30
|
+
calculate(processes) {
|
|
31
|
+
return this.calculator(processes);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.CustomProgressStrategy = CustomProgressStrategy;
|
|
35
|
+
// Registry
|
|
36
|
+
class ProgressStrategyRegistry {
|
|
37
|
+
static register(moduleName, strategy) {
|
|
38
|
+
this.strategies.set(moduleName.toUpperCase(), strategy);
|
|
39
|
+
}
|
|
40
|
+
static get(moduleName) {
|
|
41
|
+
return this.strategies.get(moduleName.toUpperCase()) || new DefaultProgressStrategy();
|
|
42
|
+
}
|
|
43
|
+
static clear() {
|
|
44
|
+
this.strategies.clear();
|
|
45
|
+
}
|
|
46
|
+
static has(moduleName) {
|
|
47
|
+
return this.strategies.has(moduleName.toUpperCase());
|
|
48
|
+
}
|
|
49
|
+
static getAllRegistered() {
|
|
50
|
+
return Array.from(this.strategies.keys());
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.ProgressStrategyRegistry = ProgressStrategyRegistry;
|
|
54
|
+
ProgressStrategyRegistry.strategies = new Map();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ModuleResult, SummaryOptions } from '../interfaces/index';
|
|
2
|
+
export default class SummaryManager {
|
|
3
|
+
private modules;
|
|
4
|
+
private operationName;
|
|
5
|
+
private context;
|
|
6
|
+
private operationStartTime;
|
|
7
|
+
private branchName;
|
|
8
|
+
constructor({ operationName, context }: SummaryOptions);
|
|
9
|
+
getModules(): Map<string, ModuleResult>;
|
|
10
|
+
registerModule(moduleName: string, totalItems?: number): void;
|
|
11
|
+
startModule(moduleName: string): void;
|
|
12
|
+
completeModule(moduleName: string, success?: boolean, error?: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Register process data for strategy calculations
|
|
15
|
+
*/
|
|
16
|
+
registerProcessData(moduleName: string, processName: string, processData: any): void;
|
|
17
|
+
updateModuleProgress(moduleName: string, success: boolean, itemName: string, error?: string): void;
|
|
18
|
+
printFinalSummary(): void;
|
|
19
|
+
private printFailureSummaryWithLogReference;
|
|
20
|
+
private getStatusIcon;
|
|
21
|
+
private formatDuration;
|
|
22
|
+
private calculateSuccessRate;
|
|
23
|
+
private formatSuccessRate;
|
|
24
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
5
|
+
class SummaryManager {
|
|
6
|
+
constructor({ operationName, context }) {
|
|
7
|
+
this.modules = new Map();
|
|
8
|
+
this.operationName = operationName;
|
|
9
|
+
this.context = context;
|
|
10
|
+
this.operationStartTime = Date.now();
|
|
11
|
+
this.branchName = context.branchName || '';
|
|
12
|
+
}
|
|
13
|
+
getModules() {
|
|
14
|
+
return this.modules;
|
|
15
|
+
}
|
|
16
|
+
registerModule(moduleName, totalItems = 0) {
|
|
17
|
+
this.modules.set(moduleName, {
|
|
18
|
+
name: moduleName,
|
|
19
|
+
status: 'pending',
|
|
20
|
+
totalItems,
|
|
21
|
+
successCount: 0,
|
|
22
|
+
failureCount: 0,
|
|
23
|
+
failures: [],
|
|
24
|
+
processes: [],
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
startModule(moduleName) {
|
|
28
|
+
const module = this.modules.get(moduleName);
|
|
29
|
+
if (module) {
|
|
30
|
+
module.status = 'running';
|
|
31
|
+
module.startTime = Date.now();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
completeModule(moduleName, success = true, error) {
|
|
35
|
+
const module = this.modules.get(moduleName);
|
|
36
|
+
if (module) {
|
|
37
|
+
module.status = success ? 'completed' : 'failed';
|
|
38
|
+
module.endTime = Date.now();
|
|
39
|
+
if (!success && error) {
|
|
40
|
+
module.failures.push({ item: 'module', error });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Register process data for strategy calculations
|
|
46
|
+
*/
|
|
47
|
+
registerProcessData(moduleName, processName, processData) {
|
|
48
|
+
const module = this.modules.get(moduleName);
|
|
49
|
+
if (module) {
|
|
50
|
+
if (!module.processes) {
|
|
51
|
+
module.processes = [];
|
|
52
|
+
}
|
|
53
|
+
const existingIndex = module.processes.findIndex((p) => p.processName === processName);
|
|
54
|
+
if (existingIndex >= 0) {
|
|
55
|
+
module.processes[existingIndex] = Object.assign({ processName }, processData);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
module.processes.push(Object.assign({ processName }, processData));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
updateModuleProgress(moduleName, success, itemName, error) {
|
|
63
|
+
const module = this.modules.get(moduleName);
|
|
64
|
+
if (module) {
|
|
65
|
+
if (success) {
|
|
66
|
+
module.successCount++;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
module.failureCount++;
|
|
70
|
+
if (error) {
|
|
71
|
+
module.failures.push({ item: itemName, error });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
printFinalSummary() {
|
|
77
|
+
const operationEndTime = Date.now();
|
|
78
|
+
const totalDuration = operationEndTime - this.operationStartTime;
|
|
79
|
+
// Overall Statistics
|
|
80
|
+
const totalModules = this.modules.size;
|
|
81
|
+
const completedModules = Array.from(this.modules.values()).filter((m) => m.status === 'completed').length;
|
|
82
|
+
const failedModules = Array.from(this.modules.values()).filter((m) => m.status === 'failed').length;
|
|
83
|
+
const totalItems = Array.from(this.modules.values()).reduce((sum, m) => sum + m.successCount + m.failureCount, 0);
|
|
84
|
+
const totalSuccess = Array.from(this.modules.values()).reduce((sum, m) => sum + m.successCount, 0);
|
|
85
|
+
const totalFailures = Array.from(this.modules.values()).reduce((sum, m) => sum + m.failureCount, 0);
|
|
86
|
+
console.log('\n' + chalk_1.default.bold('='.repeat(80)));
|
|
87
|
+
console.log('\n' + chalk_1.default.bold('Overall Statistics:'));
|
|
88
|
+
console.log(` Total ${this.operationName} Time: ${chalk_1.default.cyan(this.formatDuration(totalDuration))}`);
|
|
89
|
+
console.log(` Modules Processed: ${chalk_1.default.cyan(completedModules)}/${chalk_1.default.cyan(totalModules)}`);
|
|
90
|
+
console.log(` Items Processed: ${chalk_1.default.green(totalSuccess)} success, ${chalk_1.default.red(totalFailures)} failed of ${chalk_1.default.cyan(totalItems)} total`);
|
|
91
|
+
console.log(` Success Rate: ${chalk_1.default.cyan(this.calculateSuccessRate(totalSuccess, totalItems))}%`);
|
|
92
|
+
// Module Details
|
|
93
|
+
console.log('\n' + chalk_1.default.bold('Module Details:'));
|
|
94
|
+
console.log(chalk_1.default.gray('-'.repeat(80)));
|
|
95
|
+
Array.from(this.modules.values()).forEach((module) => {
|
|
96
|
+
const status = this.getStatusIcon(module.status);
|
|
97
|
+
const totalCount = module.successCount + module.failureCount;
|
|
98
|
+
const duration = module.endTime && module.startTime ? this.formatDuration(module.endTime - module.startTime) : 'N/A';
|
|
99
|
+
const successRate = this.calculateSuccessRate(module.successCount, totalCount);
|
|
100
|
+
console.log(`${status} ${module.name.padEnd(20)} | ` +
|
|
101
|
+
`${String(module.successCount).padStart(4)}/${String(totalCount).padStart(4)} items | ` +
|
|
102
|
+
`${this.formatSuccessRate(successRate).padStart(6)} | ` +
|
|
103
|
+
`${duration.padStart(8)}`);
|
|
104
|
+
});
|
|
105
|
+
// Final Status
|
|
106
|
+
console.log('\n' + chalk_1.default.bold('Final Status:'));
|
|
107
|
+
if (failedModules === 0) {
|
|
108
|
+
console.log(chalk_1.default.bold.green(`š ${this.operationName} completed successfully!`));
|
|
109
|
+
}
|
|
110
|
+
else if (completedModules > 0) {
|
|
111
|
+
console.log(chalk_1.default.bold.yellow(`ā ļø ${this.operationName} completed with ${failedModules} failed modules`));
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.log(chalk_1.default.bold.red(`ā ${this.operationName} failed`));
|
|
115
|
+
}
|
|
116
|
+
console.log(chalk_1.default.bold('='.repeat(80)));
|
|
117
|
+
console.log(chalk_1.default.bold('='.repeat(80)));
|
|
118
|
+
// Simple failure summary with log reference
|
|
119
|
+
this.printFailureSummaryWithLogReference();
|
|
120
|
+
}
|
|
121
|
+
printFailureSummaryWithLogReference() {
|
|
122
|
+
const modulesWithFailures = Array.from(this.modules.values()).filter((m) => m.failures.length > 0);
|
|
123
|
+
if (modulesWithFailures.length === 0)
|
|
124
|
+
return;
|
|
125
|
+
const totalFailures = modulesWithFailures.reduce((sum, m) => sum + m.failures.length, 0);
|
|
126
|
+
console.log('\n' + chalk_1.default.bold.red('Failure Summary:'));
|
|
127
|
+
console.log(chalk_1.default.red('-'.repeat(50)));
|
|
128
|
+
modulesWithFailures.forEach((module) => {
|
|
129
|
+
console.log(`${chalk_1.default.bold.red('ā')} ${chalk_1.default.bold(module.name)}: ${chalk_1.default.red(module.failures.length)} failures`);
|
|
130
|
+
// Show just first 2-3 failures briefly
|
|
131
|
+
const preview = module.failures.slice(0, 2);
|
|
132
|
+
preview.forEach((failure) => {
|
|
133
|
+
console.log(` ⢠${chalk_1.default.gray(failure.item)}`);
|
|
134
|
+
});
|
|
135
|
+
if (module.failures.length > 2) {
|
|
136
|
+
console.log(` ${chalk_1.default.gray(`... and ${module.failures.length - 2} more`)}`);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
console.log(chalk_1.default.blue('\nš For detailed error information, check the log files:'));
|
|
140
|
+
//console.log(chalk.blue(` ${getLogPath()}`));
|
|
141
|
+
console.log(chalk_1.default.gray(' Recent errors are logged with full context and stack traces.'));
|
|
142
|
+
}
|
|
143
|
+
getStatusIcon(status) {
|
|
144
|
+
switch (status) {
|
|
145
|
+
case 'completed':
|
|
146
|
+
return chalk_1.default.green('ā');
|
|
147
|
+
case 'failed':
|
|
148
|
+
return chalk_1.default.red('ā');
|
|
149
|
+
case 'running':
|
|
150
|
+
return chalk_1.default.yellow('ā');
|
|
151
|
+
case 'pending':
|
|
152
|
+
return chalk_1.default.gray('ā');
|
|
153
|
+
default:
|
|
154
|
+
return chalk_1.default.gray('?');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
formatDuration(ms) {
|
|
158
|
+
if (ms < 1000)
|
|
159
|
+
return `${ms}ms`;
|
|
160
|
+
if (ms < 60000)
|
|
161
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
162
|
+
return `${(ms / 60000).toFixed(1)}m`;
|
|
163
|
+
}
|
|
164
|
+
calculateSuccessRate(success, total) {
|
|
165
|
+
if (total === 0)
|
|
166
|
+
return '0';
|
|
167
|
+
return ((success / total) * 100).toFixed(1);
|
|
168
|
+
}
|
|
169
|
+
formatSuccessRate(rate) {
|
|
170
|
+
if (rate === '100.0') {
|
|
171
|
+
return '100%';
|
|
172
|
+
}
|
|
173
|
+
else if (parseFloat(rate) >= 10) {
|
|
174
|
+
return `${rate}%`;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
return ` ${rate}%`;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
exports.default = SummaryManager;
|