@mks2508/better-logger 5.0.0 → 5.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/dist/chunks/{Logger-Cbi1f10o.js → Logger-CKqzXDh3.js} +2 -2
- package/dist/chunks/{Logger-Cbi1f10o.js.map → Logger-CKqzXDh3.js.map} +1 -1
- package/dist/chunks/{Logger-BZ7B7OXE.js → Logger-D_vuKP4l.js} +2 -2
- package/dist/chunks/{Logger-BZ7B7OXE.js.map → Logger-D_vuKP4l.js.map} +1 -1
- package/dist/chunks/cli-module-B-njrTWb.js +2 -0
- package/dist/chunks/cli-module-B-njrTWb.js.map +1 -0
- package/dist/chunks/{cli-module-ClIJmaT8.js → cli-module-Cx7qotPY.js} +16 -9
- package/dist/chunks/cli-module-Cx7qotPY.js.map +1 -0
- package/dist/cli.cjs +1 -1
- package/dist/cli.js +1 -1
- package/dist/exports.cjs +1 -1
- package/dist/exports.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +3 -3
- package/dist/styling.cjs +1 -1
- package/dist/styling.js +2 -2
- package/dist/terminal/formatter.d.ts.map +1 -1
- package/package.json +5 -1
- package/.claude/settings.local.json +0 -48
- package/.github/workflows/ci-quality.yml +0 -357
- package/.github/workflows/docs-demo.yml +0 -119
- package/.github/workflows/releases-core.yml +0 -512
- package/.github/workflows/releases-full.yml +0 -582
- package/.github/workflows-backup/ci.yml +0 -221
- package/.github/workflows-backup/nightly.yml +0 -196
- package/.github/workflows-backup/release-optimized.yml +0 -373
- package/.github/workflows-backup/release.yml +0 -269
- package/.release-notes-0.2.0.md +0 -129
- package/.yamllint +0 -28
- package/CHANGELOG.json +0 -1076
- package/CHANGELOG.md +0 -209
- package/CLAUDE.md +0 -217
- package/bun.lock +0 -333
- package/demo.html +0 -847
- package/dist/chunks/cli-module-CadqgZ1Z.js +0 -2
- package/dist/chunks/cli-module-CadqgZ1Z.js.map +0 -1
- package/dist/chunks/cli-module-ClIJmaT8.js.map +0 -1
- package/docs/API.md +0 -918
- package/docs/CORE.md +0 -264
- package/docs/DEVELOPMENT.md +0 -731
- package/docs/EXPORTS.md +0 -467
- package/docs/PACKAGES.md +0 -244
- package/docs/STYLING.md +0 -405
- package/docs/_config.yml +0 -36
- package/docs/index.md +0 -179
- package/examples/README.md +0 -208
- package/examples/basic-logging.js +0 -75
- package/examples/data-export.js +0 -234
- package/examples/package.json +0 -16
- package/examples/performance-timing.js +0 -170
- package/examples/simplified-api.js +0 -124
- package/examples/styling-themes.js +0 -207
- package/index.html +0 -358
- package/packages/core/package.json +0 -57
- package/packages/exports/package.json +0 -41
- package/packages/nodejs-opentui/README.md +0 -232
- package/packages/nodejs-opentui/package.json +0 -72
- package/packages/nodejs-opentui/src/LogRenderer.ts +0 -171
- package/packages/nodejs-opentui/src/OpenTUILogHandler.ts +0 -178
- package/packages/nodejs-opentui/src/components/LogBadge.tsx +0 -131
- package/packages/nodejs-opentui/src/index.ts +0 -133
- package/packages/nodejs-opentui/src/types.ts +0 -158
- package/packages/nodejs-opentui/tsconfig.json +0 -20
- package/packages/styling/package.json +0 -41
- package/playground/demo-all.ts +0 -95
- package/playground/demo-box.ts +0 -85
- package/playground/demo-levels.ts +0 -56
- package/playground/demo-real-world.ts +0 -98
- package/playground/demo-spinner.ts +0 -77
- package/playground/demo-steps.ts +0 -72
- package/playground/demo-table.ts +0 -83
- package/project-utils/README.md +0 -172
- package/project-utils/auto-release-gemini.ts +0 -1193
- package/project-utils/auto-release-ui.ts +0 -1329
- package/project-utils/commit-generator.ts +0 -1385
- package/project-utils/commit-ui.ts +0 -264
- package/project-utils/git-utils.ts +0 -199
- package/project-utils/github-release-manager.ts +0 -466
- package/project-utils/project-config.ts +0 -260
- package/project-utils/prompt-templates.js +0 -345
- package/project-utils/prompt-templates.ts +0 -422
- package/project-utils/version-manager.ts +0 -1078
- package/public/vite.svg +0 -1
- package/src/Logger.ts +0 -1858
- package/src/ScopedLogger.ts +0 -256
- package/src/cli/CommandProcessor.ts +0 -248
- package/src/cli/commands/ConfigCommand.ts +0 -93
- package/src/cli/commands/ExportCommand.ts +0 -276
- package/src/cli/commands/HistoryCommand.ts +0 -117
- package/src/cli/commands/StatusCommand.ts +0 -112
- package/src/cli/commands/ThemeCommand.ts +0 -88
- package/src/cli/help.ts +0 -127
- package/src/cli/index.ts +0 -71
- package/src/cli-module.ts +0 -21
- package/src/cli-primitives/box.ts +0 -86
- package/src/cli-primitives/cli-table.ts +0 -62
- package/src/cli-primitives/divider.ts +0 -17
- package/src/cli-primitives/header.ts +0 -18
- package/src/cli-primitives/index.ts +0 -13
- package/src/cli-primitives/server-fallback.ts +0 -54
- package/src/cli-primitives/spinner.ts +0 -133
- package/src/cli-primitives/step.ts +0 -22
- package/src/constants.ts +0 -313
- package/src/core.ts +0 -397
- package/src/example.ts +0 -210
- package/src/exports-module.ts +0 -311
- package/src/handlers/AnalyticsLogHandler.ts +0 -22
- package/src/handlers/ExportLogHandler.ts +0 -610
- package/src/handlers/FileLogHandler.ts +0 -169
- package/src/handlers/RemoteLogHandler.ts +0 -42
- package/src/handlers/index.ts +0 -8
- package/src/hooks/HookManager.ts +0 -177
- package/src/hooks/index.ts +0 -1
- package/src/index.ts +0 -395
- package/src/main.ts +0 -196
- package/src/serializers/SerializerRegistry.ts +0 -173
- package/src/serializers/index.ts +0 -1
- package/src/style.css +0 -96
- package/src/styling/LogStyleBuilder.ts +0 -355
- package/src/styling/SemanticStyles.ts +0 -380
- package/src/styling/SmartPresets.ts +0 -288
- package/src/styling/StyleBuilder.ts +0 -319
- package/src/styling/StyleCache.ts +0 -131
- package/src/styling/banners.ts +0 -168
- package/src/styling/index.ts +0 -27
- package/src/styling/themes.ts +0 -235
- package/src/styling-module.ts +0 -244
- package/src/terminal/color-converter.ts +0 -315
- package/src/terminal/formatter.ts +0 -236
- package/src/terminal/terminal-renderer.ts +0 -342
- package/src/transports/ConsoleTransport.ts +0 -28
- package/src/transports/FileTransport.ts +0 -53
- package/src/transports/HttpTransport.ts +0 -56
- package/src/transports/TransportManager.ts +0 -130
- package/src/transports/index.ts +0 -4
- package/src/types/core.ts +0 -417
- package/src/types/handlers.ts +0 -95
- package/src/types/hooks.ts +0 -45
- package/src/types/index.ts +0 -83
- package/src/types/serializers.ts +0 -30
- package/src/types/transports.ts +0 -52
- package/src/typescript.svg +0 -1
- package/src/utils/adapter.ts +0 -291
- package/src/utils/ansi-colors.ts +0 -333
- package/src/utils/environment-detector.ts +0 -170
- package/src/utils/environment.ts +0 -94
- package/src/utils/formatting.ts +0 -332
- package/src/utils/index.ts +0 -33
- package/src/utils/opentui-detection.ts +0 -138
- package/src/utils/output.ts +0 -227
- package/src/utils/stackTrace.ts +0 -144
- package/src/utils/timestamps.ts +0 -80
- package/src/vite-env.d.ts +0 -1
- package/src/writers/BufferWriter.ts +0 -157
- package/src/writers/index.ts +0 -6
- package/test-core-browser.html +0 -237
- package/test-core-node.js +0 -63
- package/tests/test-conflict-resolution.ts +0 -391
- package/tests/validate-workflows.sh +0 -131
- package/tests/yaml-autofix.sh +0 -146
- package/tsconfig.json +0 -50
- package/vite.config.ts +0 -256
|
@@ -1,1078 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Version Manager para Better Logger
|
|
5
|
-
* Analiza commits, extrae changelog, asigna versiones y actualiza archivos
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
9
|
-
import { join } from 'path';
|
|
10
|
-
|
|
11
|
-
interface ChangelogEntry {
|
|
12
|
-
type: 'feature' | 'fix' | 'improvement' | 'breaking';
|
|
13
|
-
title: string;
|
|
14
|
-
description: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface Version {
|
|
18
|
-
version: string;
|
|
19
|
-
date: string;
|
|
20
|
-
type: 'initial' | 'major' | 'minor' | 'patch';
|
|
21
|
-
title: string;
|
|
22
|
-
changes: ChangelogEntry[];
|
|
23
|
-
technical_notes: string;
|
|
24
|
-
breaking_changes: string[];
|
|
25
|
-
commit_hash: string;
|
|
26
|
-
prefix?: string; // pre-alpha, alpha, beta, rc, o undefined para stable
|
|
27
|
-
affected_modules?: string[]; // Módulos afectados en esta versión
|
|
28
|
-
module_versions?: Record<string, string>; // Versiones específicas de cada módulo
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface ChangelogData {
|
|
32
|
-
current_version: string;
|
|
33
|
-
versions: Version[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface CommitInfo {
|
|
37
|
-
hash: string;
|
|
38
|
-
date: string;
|
|
39
|
-
title: string;
|
|
40
|
-
description: string;
|
|
41
|
-
technical_section?: string;
|
|
42
|
-
changelog_section?: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
class VersionManager {
|
|
46
|
-
private projectRoot: string;
|
|
47
|
-
private changelogPath: string;
|
|
48
|
-
private packageJsonPath: string;
|
|
49
|
-
private modulePackagePaths: Record<string, string>;
|
|
50
|
-
|
|
51
|
-
constructor() {
|
|
52
|
-
this.projectRoot = process.cwd();
|
|
53
|
-
this.changelogPath = join(this.projectRoot, 'CHANGELOG.json');
|
|
54
|
-
this.packageJsonPath = join(this.projectRoot, 'package.json');
|
|
55
|
-
this.modulePackagePaths = {
|
|
56
|
-
'core': join(this.projectRoot, 'packages/core/package.json'),
|
|
57
|
-
'styling': join(this.projectRoot, 'packages/styling/package.json'),
|
|
58
|
-
'exports': join(this.projectRoot, 'packages/exports/package.json')
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Ejecuta comando git y devuelve resultado
|
|
64
|
-
*/
|
|
65
|
-
private async gitCommand(args: string[]): Promise<string> {
|
|
66
|
-
const { spawn } = await import('child_process');
|
|
67
|
-
|
|
68
|
-
return new Promise((resolve, reject) => {
|
|
69
|
-
const proc = spawn('git', args, {
|
|
70
|
-
cwd: this.projectRoot,
|
|
71
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
let stdout = '';
|
|
75
|
-
let stderr = '';
|
|
76
|
-
|
|
77
|
-
proc.stdout?.on('data', (data) => {
|
|
78
|
-
stdout += data.toString();
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
proc.stderr?.on('data', (data) => {
|
|
82
|
-
stderr += data.toString();
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
proc.on('exit', (code) => {
|
|
86
|
-
if (code !== 0) {
|
|
87
|
-
reject(new Error(`Git error: ${stderr || 'Git command failed'}`));
|
|
88
|
-
} else {
|
|
89
|
-
resolve(stdout.trim());
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
proc.on('error', (error) => {
|
|
94
|
-
reject(error);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Obtiene todos los commits desde un hash específico
|
|
101
|
-
*/
|
|
102
|
-
private async getCommitsSince(sinceHash?: string): Promise<CommitInfo[]> {
|
|
103
|
-
const args = ['log', '--pretty=format:%H|%ci|%s', '--reverse'];
|
|
104
|
-
if (sinceHash) {
|
|
105
|
-
args.push(`${sinceHash}..HEAD`);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const output = await this.gitCommand(args);
|
|
109
|
-
if (!output) return [];
|
|
110
|
-
|
|
111
|
-
const commits: CommitInfo[] = [];
|
|
112
|
-
|
|
113
|
-
for (const line of output.split('\n')) {
|
|
114
|
-
const [hash, date, title] = line.split('|');
|
|
115
|
-
if (!hash) continue;
|
|
116
|
-
|
|
117
|
-
// Obtener el mensaje completo del commit
|
|
118
|
-
try {
|
|
119
|
-
const fullMessage = await this.gitCommand(['log', '-1', '--pretty=format:%B', hash]);
|
|
120
|
-
const sections = this.parseCommitMessage(fullMessage);
|
|
121
|
-
|
|
122
|
-
commits.push({
|
|
123
|
-
hash,
|
|
124
|
-
date: new Date(date).toISOString().split('T')[0],
|
|
125
|
-
title,
|
|
126
|
-
description: fullMessage,
|
|
127
|
-
technical_section: sections.technical,
|
|
128
|
-
changelog_section: sections.changelog
|
|
129
|
-
});
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.warn(`⚠️ No se pudo obtener mensaje completo para commit ${hash}: ${error}`);
|
|
132
|
-
commits.push({
|
|
133
|
-
hash,
|
|
134
|
-
date: new Date(date).toISOString().split('T')[0],
|
|
135
|
-
title,
|
|
136
|
-
description: title
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return commits;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Extrae secciones <technical> y <changelog> de un mensaje de commit
|
|
146
|
-
*/
|
|
147
|
-
private parseCommitMessage(message: string): { technical?: string; changelog?: string } {
|
|
148
|
-
const technicalMatch = message.match(/<technical>([\s\S]*?)<\/technical>/);
|
|
149
|
-
const changelogMatch = message.match(/<changelog>([\s\S]*?)<\/changelog>/);
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
technical: technicalMatch?.[1]?.trim(),
|
|
153
|
-
changelog: changelogMatch?.[1]?.trim()
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Convierte sección de changelog en entradas estructuradas
|
|
159
|
-
*/
|
|
160
|
-
private parseChangelogSection(changelog: string): ChangelogEntry[] {
|
|
161
|
-
if (!changelog) return [];
|
|
162
|
-
|
|
163
|
-
const entries: ChangelogEntry[] = [];
|
|
164
|
-
const lines = changelog.split('\n').map(line => line.trim()).filter(line => line);
|
|
165
|
-
|
|
166
|
-
let currentSection = '';
|
|
167
|
-
let currentEntries: string[] = [];
|
|
168
|
-
|
|
169
|
-
for (const line of lines) {
|
|
170
|
-
if (line.startsWith('##')) {
|
|
171
|
-
// Procesar sección anterior
|
|
172
|
-
if (currentSection && currentEntries.length > 0) {
|
|
173
|
-
entries.push(...this.processSectionEntries(currentSection, currentEntries));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Nueva sección
|
|
177
|
-
currentSection = line.replace(/^##\s*/, '').toLowerCase();
|
|
178
|
-
currentEntries = [];
|
|
179
|
-
} else if (line.startsWith('-')) {
|
|
180
|
-
currentEntries.push(line.replace(/^-\s*/, ''));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Procesar última sección
|
|
185
|
-
if (currentSection && currentEntries.length > 0) {
|
|
186
|
-
entries.push(...this.processSectionEntries(currentSection, currentEntries));
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return entries;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Procesa entradas de una sección específica del changelog
|
|
194
|
-
*/
|
|
195
|
-
private processSectionEntries(section: string, entries: string[]): ChangelogEntry[] {
|
|
196
|
-
let type: ChangelogEntry['type'] = 'improvement';
|
|
197
|
-
|
|
198
|
-
if (section.includes('fix') || section.includes('🐛')) {
|
|
199
|
-
type = 'fix';
|
|
200
|
-
} else if (section.includes('feature') || section.includes('✨')) {
|
|
201
|
-
type = 'feature';
|
|
202
|
-
} else if (section.includes('breaking')) {
|
|
203
|
-
type = 'breaking';
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return entries.map(entry => ({
|
|
207
|
-
type,
|
|
208
|
-
title: entry.split('.')[0] || entry,
|
|
209
|
-
description: entry
|
|
210
|
-
}));
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Determina el tipo de versión basado en los cambios
|
|
215
|
-
*/
|
|
216
|
-
private determineVersionType(commits: CommitInfo[]): Version['type'] {
|
|
217
|
-
const hasBreaking = commits.some(c =>
|
|
218
|
-
c.changelog_section?.includes('breaking') ||
|
|
219
|
-
c.title.toLowerCase().includes('breaking')
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
if (hasBreaking) return 'major';
|
|
223
|
-
|
|
224
|
-
const hasFeature = commits.some(c =>
|
|
225
|
-
c.title.startsWith('feat(') ||
|
|
226
|
-
c.changelog_section?.includes('✨') ||
|
|
227
|
-
c.changelog_section?.toLowerCase().includes('feature')
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
if (hasFeature) return 'minor';
|
|
231
|
-
|
|
232
|
-
return 'patch';
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Incrementa versión según el tipo, considerando prefijos
|
|
237
|
-
*/
|
|
238
|
-
private incrementVersion(
|
|
239
|
-
currentVersion: string,
|
|
240
|
-
type: Version['type'],
|
|
241
|
-
targetPrefix?: string,
|
|
242
|
-
overrideType?: Version['type']
|
|
243
|
-
): string {
|
|
244
|
-
// Extraer prefix y versión base
|
|
245
|
-
const { prefix, baseVersion } = this.parseVersionString(currentVersion);
|
|
246
|
-
const [major, minor, patch] = baseVersion.split('.').map(Number);
|
|
247
|
-
|
|
248
|
-
// Si se especifica un targetPrefix, usarlo; si no, mantener el actual
|
|
249
|
-
const newPrefix = targetPrefix !== undefined ? targetPrefix : prefix;
|
|
250
|
-
|
|
251
|
-
// Si se especifica un override del tipo, usarlo
|
|
252
|
-
const actualType = overrideType || type;
|
|
253
|
-
|
|
254
|
-
let newBaseVersion: string;
|
|
255
|
-
switch (actualType) {
|
|
256
|
-
case 'major':
|
|
257
|
-
newBaseVersion = `${major + 1}.0.0`;
|
|
258
|
-
break;
|
|
259
|
-
case 'minor':
|
|
260
|
-
newBaseVersion = `${major}.${minor + 1}.0`;
|
|
261
|
-
break;
|
|
262
|
-
case 'patch':
|
|
263
|
-
newBaseVersion = `${major}.${minor}.${patch + 1}`;
|
|
264
|
-
break;
|
|
265
|
-
default:
|
|
266
|
-
newBaseVersion = baseVersion;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Determinar incremento de prerelease
|
|
270
|
-
const prereleaseIncrement = this.calculatePrereleaseIncrement(
|
|
271
|
-
currentVersion,
|
|
272
|
-
newPrefix,
|
|
273
|
-
newBaseVersion,
|
|
274
|
-
actualType
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
return this.buildVersionString(newPrefix, newBaseVersion, prereleaseIncrement);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Calcula el incremento de prerelease apropiado
|
|
282
|
-
*/
|
|
283
|
-
private calculatePrereleaseIncrement(
|
|
284
|
-
currentVersion: string,
|
|
285
|
-
targetPrefix?: string,
|
|
286
|
-
newBaseVersion?: string,
|
|
287
|
-
versionType?: Version['type']
|
|
288
|
-
): number {
|
|
289
|
-
const { prefix: currentPrefix, baseVersion: currentBaseVersion, prereleaseIncrement } = this.parseVersionString(currentVersion);
|
|
290
|
-
|
|
291
|
-
// Si cambiamos de prefijo o de versión base, resetear a 1
|
|
292
|
-
if (targetPrefix !== currentPrefix || newBaseVersion !== currentBaseVersion) {
|
|
293
|
-
return 1;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Si mantenemos el mismo prefijo y versión base, incrementar
|
|
297
|
-
return (prereleaseIncrement || 0) + 1;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Parsea una versión con posible prefijo (soporta formatos legacy y semver)
|
|
302
|
-
*/
|
|
303
|
-
private parseVersionString(version: string): { prefix?: string; baseVersion: string; prereleaseIncrement?: number } {
|
|
304
|
-
// Formato semver: X.Y.Z-prefix.N (ej: 0.6.0-alpha.1)
|
|
305
|
-
const semverMatch = version.match(/^(\d+\.\d+\.\d+)-(pre-alpha|alpha|beta|rc)\.(\d+)$/);
|
|
306
|
-
if (semverMatch) {
|
|
307
|
-
return {
|
|
308
|
-
baseVersion: semverMatch[1],
|
|
309
|
-
prefix: semverMatch[2],
|
|
310
|
-
prereleaseIncrement: parseInt(semverMatch[3])
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Formato legacy: prefix-X.Y.Z (ej: alpha-0.6.0) - para compatibilidad temporal
|
|
315
|
-
const legacyMatch = version.match(/^(pre-alpha-|alpha-|beta-|rc-)?(.+)$/);
|
|
316
|
-
if (legacyMatch) {
|
|
317
|
-
return {
|
|
318
|
-
prefix: legacyMatch[1]?.replace(/-$/, ''), // Remover el guión final
|
|
319
|
-
baseVersion: legacyMatch[2],
|
|
320
|
-
prereleaseIncrement: 1 // Default para conversión
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
return { baseVersion: version };
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Construye una versión con prefijo en formato semver compatible con NPM
|
|
329
|
-
*/
|
|
330
|
-
private buildVersionString(prefix?: string, baseVersion?: string, prereleaseIncrement?: number): string {
|
|
331
|
-
if (!baseVersion) return '1.0.0';
|
|
332
|
-
if (!prefix) return baseVersion; // Sin prefijo = estable
|
|
333
|
-
|
|
334
|
-
// Formato semver: baseVersion-prefix.increment (ej: 0.6.0-alpha.1)
|
|
335
|
-
const increment = prereleaseIncrement || 1;
|
|
336
|
-
return `${baseVersion}-${prefix}.${increment}`;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Valida que la transición de prefijo sea lógica
|
|
341
|
-
*/
|
|
342
|
-
private validatePrefixTransition(currentVersion: string, targetPrefix?: string): void {
|
|
343
|
-
const { prefix: currentPrefix } = this.parseVersionString(currentVersion);
|
|
344
|
-
|
|
345
|
-
// Definir orden de prefijos (undefined = stable)
|
|
346
|
-
const prefixOrder = ['pre-alpha', 'alpha', 'beta', 'rc', undefined];
|
|
347
|
-
const currentIndex = prefixOrder.indexOf(currentPrefix);
|
|
348
|
-
const targetIndex = prefixOrder.indexOf(targetPrefix);
|
|
349
|
-
|
|
350
|
-
// Permitir cualquier transición, pero advertir sobre regresiones
|
|
351
|
-
if (currentIndex !== -1 && targetIndex !== -1 && targetIndex < currentIndex) {
|
|
352
|
-
console.warn(`⚠️ Advertencia: Transición de prefijo regresiva ${currentPrefix || 'stable'} → ${targetPrefix || 'stable'}`);
|
|
353
|
-
console.warn(' Esto podría confundir a los usuarios sobre el estado de estabilidad.');
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Validar prefijos válidos
|
|
357
|
-
const validPrefixes = ['pre-alpha', 'alpha', 'beta', 'rc'];
|
|
358
|
-
if (targetPrefix && !validPrefixes.includes(targetPrefix)) {
|
|
359
|
-
throw new Error(`❌ Prefijo inválido: ${targetPrefix}. Válidos: ${validPrefixes.join(', ')}, o sin prefijo para stable`);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Carga datos actuales del changelog
|
|
365
|
-
*/
|
|
366
|
-
private loadChangelogData(): ChangelogData {
|
|
367
|
-
if (existsSync(this.changelogPath)) {
|
|
368
|
-
try {
|
|
369
|
-
const content = readFileSync(this.changelogPath, 'utf-8');
|
|
370
|
-
return JSON.parse(content);
|
|
371
|
-
} catch (error) {
|
|
372
|
-
console.warn('⚠️ Error leyendo changelog.json, creando nuevo');
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return {
|
|
377
|
-
current_version: '0.1.0',
|
|
378
|
-
versions: []
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Obtiene el último commit versionado
|
|
384
|
-
*/
|
|
385
|
-
private getLastVersionedCommit(data: ChangelogData): string | undefined {
|
|
386
|
-
const sortedVersions = [...data.versions].sort((a, b) =>
|
|
387
|
-
new Date(b.date).getTime() - new Date(a.date).getTime()
|
|
388
|
-
);
|
|
389
|
-
|
|
390
|
-
return sortedVersions[0]?.commit_hash;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* Analiza commits y genera nueva versión
|
|
395
|
-
*/
|
|
396
|
-
async analyzeAndVersion(options: {
|
|
397
|
-
type?: Version['type'];
|
|
398
|
-
prefix?: string;
|
|
399
|
-
} = {}): Promise<void> {
|
|
400
|
-
console.log('🚀 Iniciando análisis de versionado...\n');
|
|
401
|
-
|
|
402
|
-
try {
|
|
403
|
-
// Cargar datos existentes
|
|
404
|
-
const changelogData = this.loadChangelogData();
|
|
405
|
-
console.log(`📋 Versión actual: ${changelogData.current_version}`);
|
|
406
|
-
|
|
407
|
-
// Obtener último commit versionado
|
|
408
|
-
const lastVersionedCommit = this.getLastVersionedCommit(changelogData);
|
|
409
|
-
console.log(`🔍 Último commit versionado: ${lastVersionedCommit || 'ninguno'}`);
|
|
410
|
-
|
|
411
|
-
// Obtener commits nuevos
|
|
412
|
-
const newCommits = await this.getCommitsSince(lastVersionedCommit);
|
|
413
|
-
console.log(`📝 Encontrados ${newCommits.length} commits nuevos`);
|
|
414
|
-
|
|
415
|
-
if (newCommits.length === 0) {
|
|
416
|
-
console.log('✅ No hay commits nuevos para versionar');
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Mostrar commits que se van a versionar
|
|
421
|
-
console.log('\n📋 Commits que se incluirán en la nueva versión:');
|
|
422
|
-
newCommits.forEach(commit => {
|
|
423
|
-
console.log(` • ${commit.hash.slice(0, 7)} - ${commit.title}`);
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
// Determinar tipo de versión
|
|
427
|
-
const detectedVersionType = this.determineVersionType(newCommits);
|
|
428
|
-
const finalVersionType = options.type || detectedVersionType;
|
|
429
|
-
|
|
430
|
-
// Si se especifica un prefix, validarlo
|
|
431
|
-
if (options.prefix !== undefined) {
|
|
432
|
-
this.validatePrefixTransition(changelogData.current_version, options.prefix);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
const newVersion = this.incrementVersion(
|
|
436
|
-
changelogData.current_version,
|
|
437
|
-
detectedVersionType,
|
|
438
|
-
options.prefix,
|
|
439
|
-
finalVersionType
|
|
440
|
-
);
|
|
441
|
-
|
|
442
|
-
console.log(`\n🏷️ Nueva versión: ${changelogData.current_version} → ${newVersion}`);
|
|
443
|
-
console.log(`📊 Tipo detectado: ${detectedVersionType}${options.type ? ` → Forzado: ${options.type}` : ''}`);
|
|
444
|
-
if (options.prefix !== undefined) {
|
|
445
|
-
const { prefix: currentPrefix } = this.parseVersionString(changelogData.current_version);
|
|
446
|
-
console.log(`🏷️ Prefix: ${currentPrefix || 'stable'} → ${options.prefix || 'stable'}`);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// Procesar cambios
|
|
450
|
-
const allChanges: ChangelogEntry[] = [];
|
|
451
|
-
let technicalNotes = '';
|
|
452
|
-
|
|
453
|
-
for (const commit of newCommits) {
|
|
454
|
-
if (commit.changelog_section) {
|
|
455
|
-
const changes = this.parseChangelogSection(commit.changelog_section);
|
|
456
|
-
allChanges.push(...changes);
|
|
457
|
-
} else {
|
|
458
|
-
// Generar entrada básica desde el título del commit
|
|
459
|
-
let type: ChangelogEntry['type'] = 'improvement';
|
|
460
|
-
if (commit.title.startsWith('feat(')) type = 'feature';
|
|
461
|
-
else if (commit.title.startsWith('fix(')) type = 'fix';
|
|
462
|
-
|
|
463
|
-
allChanges.push({
|
|
464
|
-
type,
|
|
465
|
-
title: commit.title.replace(/^(feat|fix|refactor)\([^)]+\)\s*-\s*/, ''),
|
|
466
|
-
description: commit.title
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
if (commit.technical_section) {
|
|
471
|
-
technicalNotes += `\n${commit.technical_section}`;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Crear nueva versión
|
|
476
|
-
const { prefix } = this.parseVersionString(newVersion);
|
|
477
|
-
const newVersionEntry: Version = {
|
|
478
|
-
version: newVersion,
|
|
479
|
-
date: new Date().toISOString().split('T')[0],
|
|
480
|
-
type: finalVersionType,
|
|
481
|
-
title: this.generateVersionTitle(allChanges, finalVersionType, prefix),
|
|
482
|
-
changes: allChanges,
|
|
483
|
-
technical_notes: technicalNotes.trim(),
|
|
484
|
-
breaking_changes: allChanges
|
|
485
|
-
.filter(c => c.type === 'breaking')
|
|
486
|
-
.map(c => c.description),
|
|
487
|
-
commit_hash: newCommits[newCommits.length - 1].hash,
|
|
488
|
-
prefix
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
// Actualizar datos
|
|
492
|
-
changelogData.current_version = newVersion;
|
|
493
|
-
changelogData.versions.unshift(newVersionEntry); // Agregar al principio
|
|
494
|
-
|
|
495
|
-
// Guardar changelog actualizado
|
|
496
|
-
writeFileSync(this.changelogPath, JSON.stringify(changelogData, null, 2));
|
|
497
|
-
console.log(`💾 Changelog actualizado: ${this.changelogPath}`);
|
|
498
|
-
|
|
499
|
-
// Detectar módulos afectados y actualizar archivos de configuración
|
|
500
|
-
const affectedModules = await this.detectAffectedModules();
|
|
501
|
-
await this.updateAllVersionFiles(newVersion, affectedModules);
|
|
502
|
-
|
|
503
|
-
console.log(`\n✅ Versionado completado exitosamente!`);
|
|
504
|
-
console.log(`📦 Nueva versión: ${newVersion}`);
|
|
505
|
-
console.log(`📋 Cambios incluidos: ${allChanges.length}`);
|
|
506
|
-
console.log(`📝 Commits procesados: ${newCommits.length}`);
|
|
507
|
-
|
|
508
|
-
// Sugerir creación de release si hay archivos de distribución disponibles
|
|
509
|
-
const distDir = join(this.projectRoot, 'dist');
|
|
510
|
-
if (existsSync(distDir)) {
|
|
511
|
-
console.log(`\n💡 Archivos de distribución detectados en ${distDir}`);
|
|
512
|
-
console.log(`🚀 Para crear release en GitHub ejecuta:`);
|
|
513
|
-
console.log(` npm run release:github`);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
} catch (error) {
|
|
517
|
-
console.error('❌ Error durante el versionado:', error);
|
|
518
|
-
throw error;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
/**
|
|
523
|
-
* Genera título descriptivo para la versión
|
|
524
|
-
*/
|
|
525
|
-
private generateVersionTitle(changes: ChangelogEntry[], type: Version['type'], prefix?: string): string {
|
|
526
|
-
const features = changes.filter(c => c.type === 'feature');
|
|
527
|
-
const fixes = changes.filter(c => c.type === 'fix');
|
|
528
|
-
const improvements = changes.filter(c => c.type === 'improvement');
|
|
529
|
-
|
|
530
|
-
// Prefijo para el título
|
|
531
|
-
const prefixLabel = prefix ?
|
|
532
|
-
`Versión ${prefix.charAt(0).toUpperCase() + prefix.slice(1)} - ` : '';
|
|
533
|
-
|
|
534
|
-
if (type === 'major') {
|
|
535
|
-
return `${prefixLabel}Actualización mayor con cambios significativos`;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (features.length > 0) {
|
|
539
|
-
const mainFeature = features[0].title;
|
|
540
|
-
if (features.length === 1) {
|
|
541
|
-
return `${prefixLabel}Nueva funcionalidad: ${mainFeature}`;
|
|
542
|
-
}
|
|
543
|
-
return `${prefixLabel}Nuevas funcionalidades incluyendo ${mainFeature} y ${features.length - 1} más`;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
if (fixes.length > 0) {
|
|
547
|
-
if (fixes.length === 1) {
|
|
548
|
-
return `${prefixLabel}Corrección: ${fixes[0].title}`;
|
|
549
|
-
}
|
|
550
|
-
return `${prefixLabel}Correcciones y mejoras (${fixes.length} fixes, ${improvements.length} mejoras)`;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
return `${prefixLabel}Mejoras y optimizaciones`;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
/**
|
|
557
|
-
* Actualiza versión en todos los archivos de configuración
|
|
558
|
-
*/
|
|
559
|
-
private async updateAllVersionFiles(version: string, affectedModules?: string[]): Promise<void> {
|
|
560
|
-
console.log(`🔄 Sincronizando versión ${version} en todos los archivos...`);
|
|
561
|
-
|
|
562
|
-
// Actualizar package.json principal y modulares
|
|
563
|
-
await this.updatePackageVersion(version, affectedModules);
|
|
564
|
-
|
|
565
|
-
// No hay archivos adicionales que actualizar para Better Logger
|
|
566
|
-
|
|
567
|
-
// Better Logger no requiere sincronización OTA
|
|
568
|
-
|
|
569
|
-
console.log(`✅ Todas las versiones sincronizadas en ${version}`);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* Detecta qué módulos han sido afectados basado en archivos cambiados
|
|
574
|
-
*/
|
|
575
|
-
private async detectAffectedModules(): Promise<string[]> {
|
|
576
|
-
try {
|
|
577
|
-
const changedFiles = await this.gitCommand(['diff', '--name-only', 'HEAD~1']);
|
|
578
|
-
const affectedModules = new Set<string>();
|
|
579
|
-
|
|
580
|
-
for (const file of changedFiles.split('\n').filter(f => f.trim())) {
|
|
581
|
-
// Detectar por patterns de archivos
|
|
582
|
-
if (file.includes('core') || file.includes('Logger.ts') || file.includes('constants.ts')) {
|
|
583
|
-
affectedModules.add('core');
|
|
584
|
-
}
|
|
585
|
-
if (file.includes('styling') || file.includes('Style')) {
|
|
586
|
-
affectedModules.add('styling');
|
|
587
|
-
}
|
|
588
|
-
if (file.includes('exports') || file.includes('Handler')) {
|
|
589
|
-
affectedModules.add('exports');
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// Si no se puede determinar, afectar todos los módulos
|
|
594
|
-
const result = Array.from(affectedModules);
|
|
595
|
-
if (result.length === 0) {
|
|
596
|
-
console.log(`⚠️ No se pudo determinar módulos afectados, usando todos`);
|
|
597
|
-
return ['core', 'styling', 'exports'];
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
console.log(`📋 Módulos afectados detectados: ${result.join(', ')}`);
|
|
601
|
-
return result;
|
|
602
|
-
} catch (error) {
|
|
603
|
-
console.warn(`⚠️ Error detectando módulos afectados:`, error);
|
|
604
|
-
return ['core', 'styling', 'exports']; // fallback
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
/**
|
|
609
|
-
* Actualiza versión en package.json principal y modulares
|
|
610
|
-
*/
|
|
611
|
-
private async updatePackageVersion(version: string, modules?: string[]): Promise<void> {
|
|
612
|
-
// Actualizar package.json principal
|
|
613
|
-
const packageJson = JSON.parse(readFileSync(this.packageJsonPath, 'utf-8'));
|
|
614
|
-
packageJson.version = version;
|
|
615
|
-
writeFileSync(this.packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
|
616
|
-
console.log(`📦 Actualizado package.json → ${version}`);
|
|
617
|
-
|
|
618
|
-
// Actualizar package.json de módulos afectados
|
|
619
|
-
if (modules && modules.length > 0) {
|
|
620
|
-
for (const moduleName of modules) {
|
|
621
|
-
const modulePath = this.modulePackagePaths[moduleName];
|
|
622
|
-
if (modulePath && existsSync(modulePath)) {
|
|
623
|
-
const modulePackageJson = JSON.parse(readFileSync(modulePath, 'utf-8'));
|
|
624
|
-
modulePackageJson.version = version;
|
|
625
|
-
|
|
626
|
-
// Actualizar peerDependencies si existen
|
|
627
|
-
if (modulePackageJson.peerDependencies) {
|
|
628
|
-
Object.keys(modulePackageJson.peerDependencies).forEach(dep => {
|
|
629
|
-
if (dep.startsWith('@mks2508/better-logger')) {
|
|
630
|
-
modulePackageJson.peerDependencies[dep] = `^${version}`;
|
|
631
|
-
}
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
writeFileSync(modulePath, JSON.stringify(modulePackageJson, null, 2) + '\n');
|
|
636
|
-
console.log(`📦 Actualizado ${moduleName}/package.json → ${version}`);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
/**
|
|
643
|
-
* Actualiza versión en tauri.conf.json
|
|
644
|
-
* Tauri requiere versionado semántico estricto (sin prefijos)
|
|
645
|
-
*/
|
|
646
|
-
private async updateTauriVersion(version: string): Promise<void> {
|
|
647
|
-
const tauriConfig = JSON.parse(readFileSync(this.tauriConfigPath, 'utf-8'));
|
|
648
|
-
|
|
649
|
-
// Extraer solo la versión base para Tauri (sin prefijos)
|
|
650
|
-
const { baseVersion } = this.parseVersionString(version);
|
|
651
|
-
tauriConfig.version = baseVersion;
|
|
652
|
-
|
|
653
|
-
writeFileSync(this.tauriConfigPath, JSON.stringify(tauriConfig, null, 2) + '\n');
|
|
654
|
-
console.log(`🦀 Actualizado tauri.conf.json → ${baseVersion} (sin prefijo para semver)`);
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
/**
|
|
658
|
-
* Actualiza versión en Cargo.toml
|
|
659
|
-
* Cargo también requiere versionado semántico estricto (sin prefijos)
|
|
660
|
-
*/
|
|
661
|
-
private async updateCargoVersion(version: string): Promise<void> {
|
|
662
|
-
const cargoContent = readFileSync(this.cargoTomlPath, 'utf-8');
|
|
663
|
-
|
|
664
|
-
// Extraer solo la versión base para Cargo (sin prefijos)
|
|
665
|
-
const { baseVersion } = this.parseVersionString(version);
|
|
666
|
-
const updatedContent = cargoContent.replace(
|
|
667
|
-
/^version\s*=\s*"[^"]*"/m,
|
|
668
|
-
`version = "${baseVersion}"`
|
|
669
|
-
);
|
|
670
|
-
|
|
671
|
-
writeFileSync(this.cargoTomlPath, updatedContent);
|
|
672
|
-
console.log(`🦀 Actualizado Cargo.toml → ${baseVersion} (sin prefijo para semver)`);
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
/**
|
|
676
|
-
* Sincroniza la nueva versión con el sistema OTA
|
|
677
|
-
* Actualiza versions.json y mapea prefijos a canales OTA
|
|
678
|
-
*/
|
|
679
|
-
private async syncWithOTASystem(version: string): Promise<void> {
|
|
680
|
-
const versionsPath = join(this.projectRoot, 'versions.json');
|
|
681
|
-
|
|
682
|
-
try {
|
|
683
|
-
// Extraer información de la versión
|
|
684
|
-
const { prefix, baseVersion } = this.parseVersionString(version);
|
|
685
|
-
|
|
686
|
-
// Mapear prefix a canal OTA
|
|
687
|
-
let targetChannel = 'stable';
|
|
688
|
-
if (prefix === 'alpha' || prefix === 'beta') {
|
|
689
|
-
targetChannel = 'beta';
|
|
690
|
-
} else if (prefix === 'pre-alpha' || prefix === 'rc') {
|
|
691
|
-
targetChannel = 'dev';
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
if (!existsSync(versionsPath)) {
|
|
695
|
-
console.log('⚠️ versions.json no existe, creando estructura inicial...');
|
|
696
|
-
await this.createInitialVersionsFile(baseVersion, targetChannel);
|
|
697
|
-
return;
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
// Leer versions.json actual
|
|
701
|
-
const versionsData = JSON.parse(readFileSync(versionsPath, 'utf-8'));
|
|
702
|
-
const currentDate = new Date().toISOString();
|
|
703
|
-
const buildNumber = currentDate.replace(/[-:.TZ]/g, '').slice(0, 12);
|
|
704
|
-
|
|
705
|
-
// Actualizar versiones principales
|
|
706
|
-
versionsData.frontend.version = baseVersion;
|
|
707
|
-
versionsData.frontend.build = buildNumber;
|
|
708
|
-
versionsData.frontend.lastUpdated = currentDate;
|
|
709
|
-
|
|
710
|
-
versionsData.backend.version = baseVersion;
|
|
711
|
-
versionsData.backend.build = buildNumber;
|
|
712
|
-
versionsData.backend.lastUpdated = currentDate;
|
|
713
|
-
|
|
714
|
-
// Actualizar canal OTA correspondiente
|
|
715
|
-
versionsData.updateChannels[targetChannel].frontend = version;
|
|
716
|
-
versionsData.updateChannels[targetChannel].backend = version;
|
|
717
|
-
|
|
718
|
-
// Agregar entrada de changelog OTA
|
|
719
|
-
const changelogEntry = {
|
|
720
|
-
version: baseVersion,
|
|
721
|
-
date: new Date().toISOString().split('T')[0],
|
|
722
|
-
changes: [`Actualización automática desde version-manager (${version})`]
|
|
723
|
-
};
|
|
724
|
-
|
|
725
|
-
// Agregar al inicio del changelog (más reciente primero)
|
|
726
|
-
if (!versionsData.frontend.changelog.find((entry: any) => entry.version === baseVersion)) {
|
|
727
|
-
versionsData.frontend.changelog.unshift(changelogEntry);
|
|
728
|
-
versionsData.backend.changelog.unshift(changelogEntry);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
// Actualizar matriz de compatibilidad
|
|
732
|
-
const compatibilityEntry = versionsData.compatibility.matrix.find((entry: any) =>
|
|
733
|
-
entry.backend === baseVersion
|
|
734
|
-
);
|
|
735
|
-
|
|
736
|
-
if (!compatibilityEntry) {
|
|
737
|
-
versionsData.compatibility.matrix.unshift({
|
|
738
|
-
backend: baseVersion,
|
|
739
|
-
frontend: [baseVersion]
|
|
740
|
-
});
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
// Guardar versions.json actualizado
|
|
744
|
-
writeFileSync(versionsPath, JSON.stringify(versionsData, null, 2));
|
|
745
|
-
console.log(`🔄 Sistema OTA sincronizado → ${baseVersion} (canal: ${targetChannel})`);
|
|
746
|
-
|
|
747
|
-
} catch (error) {
|
|
748
|
-
console.warn(`⚠️ Error sincronizando sistema OTA: ${error}`);
|
|
749
|
-
console.warn('El versionado principal continuará sin sincronización OTA');
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
/**
|
|
754
|
-
* Crea archivo versions.json inicial cuando no existe
|
|
755
|
-
*/
|
|
756
|
-
private async createInitialVersionsFile(version: string, channel: string): Promise<void> {
|
|
757
|
-
const currentDate = new Date().toISOString();
|
|
758
|
-
const buildNumber = currentDate.replace(/[-:.TZ]/g, '').slice(0, 12);
|
|
759
|
-
|
|
760
|
-
const initialVersions = {
|
|
761
|
-
frontend: {
|
|
762
|
-
version,
|
|
763
|
-
build: buildNumber,
|
|
764
|
-
lastUpdated: currentDate,
|
|
765
|
-
changelog: [{
|
|
766
|
-
version,
|
|
767
|
-
date: new Date().toISOString().split('T')[0],
|
|
768
|
-
changes: ['Inicialización automática del sistema OTA']
|
|
769
|
-
}]
|
|
770
|
-
},
|
|
771
|
-
backend: {
|
|
772
|
-
version,
|
|
773
|
-
build: buildNumber,
|
|
774
|
-
lastUpdated: currentDate,
|
|
775
|
-
minimumFrontend: version,
|
|
776
|
-
changelog: [{
|
|
777
|
-
version,
|
|
778
|
-
date: new Date().toISOString().split('T')[0],
|
|
779
|
-
changes: ['Inicialización automática del sistema OTA']
|
|
780
|
-
}]
|
|
781
|
-
},
|
|
782
|
-
compatibility: {
|
|
783
|
-
matrix: [{
|
|
784
|
-
backend: version,
|
|
785
|
-
frontend: [version]
|
|
786
|
-
}]
|
|
787
|
-
},
|
|
788
|
-
updateChannels: {
|
|
789
|
-
stable: { frontend: version, backend: version },
|
|
790
|
-
beta: { frontend: version, backend: version },
|
|
791
|
-
dev: { frontend: version, backend: version }
|
|
792
|
-
}
|
|
793
|
-
};
|
|
794
|
-
|
|
795
|
-
const versionsPath = join(this.projectRoot, 'versions.json');
|
|
796
|
-
writeFileSync(versionsPath, JSON.stringify(initialVersions, null, 2));
|
|
797
|
-
console.log(`🆕 Archivo versions.json creado con versión inicial: ${version}`);
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
/**
|
|
801
|
-
* Sincroniza todos los archivos de configuración con la versión actual del changelog
|
|
802
|
-
*/
|
|
803
|
-
async syncVersionFiles(): Promise<void> {
|
|
804
|
-
console.log('🔄 Sincronizando archivos de configuración con versión actual...\n');
|
|
805
|
-
|
|
806
|
-
try {
|
|
807
|
-
// Cargar datos del changelog
|
|
808
|
-
const changelogData = this.loadChangelogData();
|
|
809
|
-
const currentVersion = changelogData.current_version;
|
|
810
|
-
|
|
811
|
-
console.log(`📋 Versión actual en changelog: ${currentVersion}`);
|
|
812
|
-
|
|
813
|
-
// Actualizar todos los archivos de configuración
|
|
814
|
-
await this.updateAllVersionFiles(currentVersion);
|
|
815
|
-
|
|
816
|
-
console.log(`\n✅ Sincronización completada exitosamente!`);
|
|
817
|
-
console.log(`📦 Todos los archivos actualizados a: ${currentVersion}`);
|
|
818
|
-
|
|
819
|
-
} catch (error) {
|
|
820
|
-
console.error('❌ Error durante la sincronización:', error);
|
|
821
|
-
throw error;
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
/**
|
|
826
|
-
* Procesa todos los commits existentes (para inicialización)
|
|
827
|
-
*/
|
|
828
|
-
async initializeFromHistory(): Promise<void> {
|
|
829
|
-
console.log('🔄 Inicializando changelog desde historial completo...\n');
|
|
830
|
-
|
|
831
|
-
try {
|
|
832
|
-
// Obtener TODOS los commits
|
|
833
|
-
const allCommits = await this.getCommitsSince();
|
|
834
|
-
console.log(`📝 Encontrados ${allCommits.length} commits totales en el historial`);
|
|
835
|
-
|
|
836
|
-
if (allCommits.length === 0) {
|
|
837
|
-
console.log('✅ No hay commits para procesar');
|
|
838
|
-
return;
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
// Agrupar commits por tipo y fecha para crear versiones lógicas
|
|
842
|
-
const versionGroups = this.groupCommitsIntoVersions(allCommits);
|
|
843
|
-
console.log(`📊 Agrupados en ${versionGroups.length} versiones lógicas`);
|
|
844
|
-
|
|
845
|
-
const changelogData: ChangelogData = {
|
|
846
|
-
current_version: '0.1.0',
|
|
847
|
-
versions: []
|
|
848
|
-
};
|
|
849
|
-
|
|
850
|
-
// Procesar cada grupo como una versión
|
|
851
|
-
for (let i = 0; i < versionGroups.length; i++) {
|
|
852
|
-
const group = versionGroups[i];
|
|
853
|
-
const versionNumber = this.generateVersionNumber(i, versionGroups.length);
|
|
854
|
-
|
|
855
|
-
const allChanges: ChangelogEntry[] = [];
|
|
856
|
-
let technicalNotes = '';
|
|
857
|
-
|
|
858
|
-
for (const commit of group.commits) {
|
|
859
|
-
if (commit.changelog_section) {
|
|
860
|
-
const changes = this.parseChangelogSection(commit.changelog_section);
|
|
861
|
-
allChanges.push(...changes);
|
|
862
|
-
} else {
|
|
863
|
-
let type: ChangelogEntry['type'] = 'improvement';
|
|
864
|
-
if (commit.title.startsWith('feat(')) type = 'feature';
|
|
865
|
-
else if (commit.title.startsWith('fix(')) type = 'fix';
|
|
866
|
-
|
|
867
|
-
allChanges.push({
|
|
868
|
-
type,
|
|
869
|
-
title: commit.title.replace(/^(feat|fix|refactor)\([^)]+\)\s*-\s*/, ''),
|
|
870
|
-
description: commit.title
|
|
871
|
-
});
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
if (commit.technical_section) {
|
|
875
|
-
technicalNotes += `\n${commit.technical_section}`;
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
const version: Version = {
|
|
880
|
-
version: versionNumber,
|
|
881
|
-
date: group.date,
|
|
882
|
-
type: group.type,
|
|
883
|
-
title: group.title,
|
|
884
|
-
changes: allChanges,
|
|
885
|
-
technical_notes: technicalNotes.trim(),
|
|
886
|
-
breaking_changes: allChanges
|
|
887
|
-
.filter(c => c.type === 'breaking')
|
|
888
|
-
.map(c => c.description),
|
|
889
|
-
commit_hash: group.commits[group.commits.length - 1].hash
|
|
890
|
-
};
|
|
891
|
-
|
|
892
|
-
changelogData.versions.push(version);
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
// La versión más reciente es la actual
|
|
896
|
-
if (changelogData.versions.length > 0) {
|
|
897
|
-
changelogData.current_version = changelogData.versions[0].version;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
// Guardar changelog
|
|
901
|
-
writeFileSync(this.changelogPath, JSON.stringify(changelogData, null, 2));
|
|
902
|
-
console.log(`💾 Changelog inicializado: ${this.changelogPath}`);
|
|
903
|
-
|
|
904
|
-
// Actualizar archivos de configuración
|
|
905
|
-
await this.updateAllVersionFiles(changelogData.current_version);
|
|
906
|
-
|
|
907
|
-
console.log(`\n✅ Inicialización completada!`);
|
|
908
|
-
console.log(`📦 Versión actual: ${changelogData.current_version}`);
|
|
909
|
-
console.log(`📋 Versiones creadas: ${changelogData.versions.length}`);
|
|
910
|
-
|
|
911
|
-
} catch (error) {
|
|
912
|
-
console.error('❌ Error durante la inicialización:', error);
|
|
913
|
-
throw error;
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
/**
|
|
918
|
-
* Agrupa commits en versiones lógicas
|
|
919
|
-
*/
|
|
920
|
-
private groupCommitsIntoVersions(commits: CommitInfo[]): Array<{
|
|
921
|
-
commits: CommitInfo[];
|
|
922
|
-
date: string;
|
|
923
|
-
type: Version['type'];
|
|
924
|
-
title: string;
|
|
925
|
-
}> {
|
|
926
|
-
const groups: Array<{
|
|
927
|
-
commits: CommitInfo[];
|
|
928
|
-
date: string;
|
|
929
|
-
type: Version['type'];
|
|
930
|
-
title: string;
|
|
931
|
-
}> = [];
|
|
932
|
-
|
|
933
|
-
// Agrupar por fechas similares y tipos de commits
|
|
934
|
-
let currentGroup: CommitInfo[] = [];
|
|
935
|
-
let currentDate = '';
|
|
936
|
-
|
|
937
|
-
for (let i = 0; i < commits.length; i++) {
|
|
938
|
-
const commit = commits[i];
|
|
939
|
-
|
|
940
|
-
// Si es primer commit o fecha muy diferente, crear nuevo grupo
|
|
941
|
-
if (!currentDate || this.daysDifference(currentDate, commit.date) > 7 || currentGroup.length >= 10) {
|
|
942
|
-
if (currentGroup.length > 0) {
|
|
943
|
-
groups.push({
|
|
944
|
-
commits: [...currentGroup],
|
|
945
|
-
date: currentDate,
|
|
946
|
-
type: this.determineVersionType(currentGroup),
|
|
947
|
-
title: this.generateGroupTitle(currentGroup)
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
|
-
currentGroup = [commit];
|
|
951
|
-
currentDate = commit.date;
|
|
952
|
-
} else {
|
|
953
|
-
currentGroup.push(commit);
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
// Agregar último grupo
|
|
958
|
-
if (currentGroup.length > 0) {
|
|
959
|
-
groups.push({
|
|
960
|
-
commits: currentGroup,
|
|
961
|
-
date: currentDate,
|
|
962
|
-
type: this.determineVersionType(currentGroup),
|
|
963
|
-
title: this.generateGroupTitle(currentGroup)
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
return groups.reverse(); // Más recientes primero
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
/**
|
|
971
|
-
* Calcula diferencia en días entre fechas
|
|
972
|
-
*/
|
|
973
|
-
private daysDifference(date1: string, date2: string): number {
|
|
974
|
-
const d1 = new Date(date1).getTime();
|
|
975
|
-
const d2 = new Date(date2).getTime();
|
|
976
|
-
return Math.abs((d2 - d1) / (1000 * 60 * 60 * 24));
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
/**
|
|
980
|
-
* Genera título para un grupo de commits
|
|
981
|
-
*/
|
|
982
|
-
private generateGroupTitle(commits: CommitInfo[]): string {
|
|
983
|
-
const features = commits.filter(c => c.title.startsWith('feat('));
|
|
984
|
-
const fixes = commits.filter(c => c.title.startsWith('fix('));
|
|
985
|
-
|
|
986
|
-
if (features.length > 0) {
|
|
987
|
-
return `Nuevas funcionalidades y mejoras`;
|
|
988
|
-
}
|
|
989
|
-
if (fixes.length > 0) {
|
|
990
|
-
return `Correcciones y optimizaciones`;
|
|
991
|
-
}
|
|
992
|
-
return `Mejoras del sistema`;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
/**
|
|
996
|
-
* Genera número de versión para inicialización
|
|
997
|
-
*/
|
|
998
|
-
private generateVersionNumber(index: number, total: number): string {
|
|
999
|
-
if (total === 1) return '1.0.0';
|
|
1000
|
-
|
|
1001
|
-
if (index === 0) return '1.0.0'; // Versión más reciente
|
|
1002
|
-
if (index < 3) return `0.${9 - index}.0`; // Versiones recientes
|
|
1003
|
-
|
|
1004
|
-
// Versiones más antiguas
|
|
1005
|
-
const patchVersion = Math.max(1, total - index);
|
|
1006
|
-
return `0.1.${patchVersion}`;
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
// Ejecutar script
|
|
1011
|
-
if (import.meta.main) {
|
|
1012
|
-
const manager = new VersionManager();
|
|
1013
|
-
|
|
1014
|
-
const args = process.argv.slice(2);
|
|
1015
|
-
const isInit = args.includes('--init') || args.includes('-i');
|
|
1016
|
-
const isSync = args.includes('--sync') || args.includes('-s');
|
|
1017
|
-
const autoApprove = args.includes('--auto-approve');
|
|
1018
|
-
const noSync = args.includes('--no-sync');
|
|
1019
|
-
const quiet = args.includes('--quiet');
|
|
1020
|
-
|
|
1021
|
-
// Parsear parámetros adicionales
|
|
1022
|
-
const typeIndex = args.indexOf('--type');
|
|
1023
|
-
const type = typeIndex > -1 && args[typeIndex + 1] ? args[typeIndex + 1] as Version['type'] : undefined;
|
|
1024
|
-
|
|
1025
|
-
const prefixIndex = args.indexOf('--prefix');
|
|
1026
|
-
const prefix = prefixIndex > -1 ? (args[prefixIndex + 1] || '') : undefined;
|
|
1027
|
-
|
|
1028
|
-
// Validar tipo si se especifica
|
|
1029
|
-
if (type && !['major', 'minor', 'patch'].includes(type)) {
|
|
1030
|
-
console.error(`❌ Tipo de versión inválido: ${type}. Válidos: major, minor, patch`);
|
|
1031
|
-
process.exit(1);
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
// Mostrar ayuda
|
|
1035
|
-
if (args.includes('--help') || args.includes('-h')) {
|
|
1036
|
-
console.log(`
|
|
1037
|
-
🚀 Version Manager para Better Logger
|
|
1038
|
-
|
|
1039
|
-
Uso:
|
|
1040
|
-
node project-utils/version-manager.ts [opciones]
|
|
1041
|
-
|
|
1042
|
-
Opciones:
|
|
1043
|
-
--init, -i Inicializar desde historial completo
|
|
1044
|
-
--sync, -s Sincronizar archivos de configuración
|
|
1045
|
-
--auto-approve Ejecución automática sin confirmaciones
|
|
1046
|
-
--no-sync No sincronizar archivos de configuración
|
|
1047
|
-
--quiet Ejecución silenciosa (solo errores y resultados)
|
|
1048
|
-
--type <tipo> Forzar tipo de versión (major|minor|patch)
|
|
1049
|
-
--prefix <prefijo> Cambiar prefijo (pre-alpha|alpha|beta|rc|'' para stable)
|
|
1050
|
-
--help, -h Mostrar esta ayuda
|
|
1051
|
-
|
|
1052
|
-
Ejemplos:
|
|
1053
|
-
node project-utils/version-manager.ts # Análisis automático
|
|
1054
|
-
node project-utils/version-manager.ts --auto-approve # Ejecución silenciosa
|
|
1055
|
-
node project-utils/version-manager.ts --type minor --auto-approve
|
|
1056
|
-
node project-utils/version-manager.ts --prefix beta --auto-approve
|
|
1057
|
-
node project-utils/version-manager.ts --sync --auto-approve
|
|
1058
|
-
node project-utils/version-manager.ts --quiet --auto-approve # Para workflows
|
|
1059
|
-
`);
|
|
1060
|
-
process.exit(0);
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
try {
|
|
1064
|
-
if (isInit) {
|
|
1065
|
-
await manager.initializeFromHistory();
|
|
1066
|
-
} else if (isSync) {
|
|
1067
|
-
await manager.syncVersionFiles();
|
|
1068
|
-
} else {
|
|
1069
|
-
await manager.analyzeAndVersion({
|
|
1070
|
-
type,
|
|
1071
|
-
prefix: prefix === '' ? undefined : prefix
|
|
1072
|
-
});
|
|
1073
|
-
}
|
|
1074
|
-
} catch (error) {
|
|
1075
|
-
console.error('❌ Error:', error);
|
|
1076
|
-
process.exit(1);
|
|
1077
|
-
}
|
|
1078
|
-
}
|