@edcalderon/versioning 1.4.2 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/cli.js +53 -0
- package/dist/extension-manager.d.ts +18 -0
- package/dist/extension-manager.js +176 -0
- package/dist/extensions/cleanup-repo/index.js +1 -1
- package/dist/extensions/lifecycle-hooks/index.js +1 -1
- package/dist/extensions/npm-publish/index.js +1 -1
- package/dist/extensions/reentry-status/extension.js +1 -1
- package/dist/extensions/sample-extension/index.js +1 -1
- package/dist/extensions/secrets-check/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A comprehensive versioning and changelog management tool designed for monorepos
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## 📋 Latest Changes (v1.4.
|
|
11
|
+
## 📋 Latest Changes (v1.4.4)
|
|
12
12
|
|
|
13
13
|
**Extension Version Updates:**
|
|
14
14
|
- 🔄 Updated all extensions to v1.4.2 for consistency:
|
|
@@ -19,6 +19,15 @@ A comprehensive versioning and changelog management tool designed for monorepos
|
|
|
19
19
|
- `sample-extension`: 1.0.0 → 1.4.2
|
|
20
20
|
- `secrets-check`: 1.1.0 → 1.4.2
|
|
21
21
|
|
|
22
|
+
**From v1.4.3:**
|
|
23
|
+
- 📝 Added pre-commit linter to ensure README updates with version changes
|
|
24
|
+
- 🔧 Improved documentation maintenance workflow
|
|
25
|
+
|
|
26
|
+
**From v1.4.2:**
|
|
27
|
+
- 🔧 Added extension manager for centralized extension handling
|
|
28
|
+
- 📝 Added CHANGELOG files for all extensions
|
|
29
|
+
- 🔄 Updated CLI and sample extension with new features
|
|
30
|
+
|
|
22
31
|
**From v1.4.1:**
|
|
23
32
|
- 🐛 Fix pnpm audit vulnerabilities with override configuration
|
|
24
33
|
- 🔧 Improve error handling in StatusManager
|
package/dist/cli.js
CHANGED
|
@@ -41,6 +41,7 @@ const changelog_1 = require("./changelog");
|
|
|
41
41
|
const sync_1 = require("./sync");
|
|
42
42
|
const release_1 = require("./release");
|
|
43
43
|
const status_1 = require("./status");
|
|
44
|
+
const extension_manager_1 = require("./extension-manager");
|
|
44
45
|
const extensions_1 = require("./extensions");
|
|
45
46
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
46
47
|
const pkg = require('../package.json');
|
|
@@ -411,6 +412,58 @@ program
|
|
|
411
412
|
process.exit(1);
|
|
412
413
|
}
|
|
413
414
|
});
|
|
415
|
+
program
|
|
416
|
+
.command('extension')
|
|
417
|
+
.description('Manage extensions (list, bump, changelog)')
|
|
418
|
+
.argument('<action>', 'action to perform (list, bump, changelog)')
|
|
419
|
+
.argument('[extension]', 'extension name (required for bump and changelog)')
|
|
420
|
+
.option('-t, --type <type>', 'bump type for extension (patch, minor, major)', 'patch')
|
|
421
|
+
.option('-c, --config <file>', 'config file path', 'versioning.config.json')
|
|
422
|
+
.action(async (action, extension, options) => {
|
|
423
|
+
try {
|
|
424
|
+
const extensionManager = new extension_manager_1.ExtensionManager();
|
|
425
|
+
if (action === 'bump') {
|
|
426
|
+
if (!extension) {
|
|
427
|
+
console.error('❌ Extension name required for bump action');
|
|
428
|
+
process.exit(1);
|
|
429
|
+
}
|
|
430
|
+
const newVersion = await extensionManager.bumpExtensionVersion(extension, options.type);
|
|
431
|
+
console.log(`✅ Bumped ${extension} to ${newVersion}`);
|
|
432
|
+
}
|
|
433
|
+
else if (action === 'list') {
|
|
434
|
+
const extensions = await extensionManager.listExtensions();
|
|
435
|
+
console.log('📦 Available Extensions:');
|
|
436
|
+
extensions.forEach(ext => {
|
|
437
|
+
console.log(` • ${ext.name}@${ext.version} - ${ext.description}`);
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
else if (action === 'changelog') {
|
|
441
|
+
if (!extension) {
|
|
442
|
+
console.error('❌ Extension name required for changelog action');
|
|
443
|
+
process.exit(1);
|
|
444
|
+
}
|
|
445
|
+
const changelog = await extensionManager.getExtensionChangelog(extension);
|
|
446
|
+
if (changelog) {
|
|
447
|
+
console.log(`📝 Changelog for ${extension}:`);
|
|
448
|
+
console.log(changelog);
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
console.log(`❌ No changelog found for extension: ${extension}`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
console.log('Available actions: list, bump, changelog');
|
|
456
|
+
console.log('Usage:');
|
|
457
|
+
console.log(' versioning extension list');
|
|
458
|
+
console.log(' versioning extension bump <extension> --type patch');
|
|
459
|
+
console.log(' versioning extension changelog <extension>');
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
console.error('❌ Error:', error instanceof Error ? error.message : String(error));
|
|
464
|
+
process.exit(1);
|
|
465
|
+
}
|
|
466
|
+
});
|
|
414
467
|
async function loadConfig(configPath) {
|
|
415
468
|
if (!(await fs.pathExists(configPath))) {
|
|
416
469
|
throw new Error(`Config file not found: ${configPath}. Run 'versioning init' to create one.`);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ExtensionInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
version: string;
|
|
4
|
+
description: string;
|
|
5
|
+
path: string;
|
|
6
|
+
changelogPath?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class ExtensionManager {
|
|
9
|
+
private extensionsDir;
|
|
10
|
+
constructor(extensionsDir?: string);
|
|
11
|
+
listExtensions(): Promise<ExtensionInfo[]>;
|
|
12
|
+
bumpExtensionVersion(extensionName: string, bumpType: 'patch' | 'minor' | 'major'): Promise<string>;
|
|
13
|
+
private updateExtensionChangelog;
|
|
14
|
+
private getChangeType;
|
|
15
|
+
getExtensionChangelog(extensionName: string): Promise<string | null>;
|
|
16
|
+
createExtensionChangelog(extensionName: string): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=extension-manager.d.ts.map
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ExtensionManager = void 0;
|
|
37
|
+
const fs = __importStar(require("fs-extra"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const semver = __importStar(require("semver"));
|
|
40
|
+
class ExtensionManager {
|
|
41
|
+
constructor(extensionsDir) {
|
|
42
|
+
// In built version, __dirname is dist/, so go up one level to src/
|
|
43
|
+
const baseDir = path.dirname(__dirname);
|
|
44
|
+
this.extensionsDir = extensionsDir || path.join(baseDir, 'src', 'extensions');
|
|
45
|
+
}
|
|
46
|
+
async listExtensions() {
|
|
47
|
+
const extensions = [];
|
|
48
|
+
if (!(await fs.pathExists(this.extensionsDir))) {
|
|
49
|
+
return extensions;
|
|
50
|
+
}
|
|
51
|
+
const dirs = await fs.readdir(this.extensionsDir);
|
|
52
|
+
for (const dir of dirs) {
|
|
53
|
+
const extensionPath = path.join(this.extensionsDir, dir);
|
|
54
|
+
const stat = await fs.stat(extensionPath);
|
|
55
|
+
if (!stat.isDirectory())
|
|
56
|
+
continue;
|
|
57
|
+
const indexPath = path.join(extensionPath, 'index.ts');
|
|
58
|
+
if (!(await fs.pathExists(indexPath)))
|
|
59
|
+
continue;
|
|
60
|
+
const content = await fs.readFile(indexPath, 'utf-8');
|
|
61
|
+
const versionMatch = content.match(/version:\s*['"]([^'"]+)['"]/);
|
|
62
|
+
const descriptionMatch = content.match(/description:\s*['"]([^'"]+)['"]/);
|
|
63
|
+
if (versionMatch) {
|
|
64
|
+
const changelogPath = path.join(extensionPath, 'CHANGELOG.md');
|
|
65
|
+
const hasChangelog = await fs.pathExists(changelogPath);
|
|
66
|
+
extensions.push({
|
|
67
|
+
name: dir,
|
|
68
|
+
version: versionMatch[1],
|
|
69
|
+
description: descriptionMatch ? descriptionMatch[1] : 'No description',
|
|
70
|
+
path: extensionPath,
|
|
71
|
+
changelogPath: hasChangelog ? changelogPath : undefined
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return extensions;
|
|
76
|
+
}
|
|
77
|
+
async bumpExtensionVersion(extensionName, bumpType) {
|
|
78
|
+
const extensionPath = path.join(this.extensionsDir, extensionName, 'index.ts');
|
|
79
|
+
if (!(await fs.pathExists(extensionPath))) {
|
|
80
|
+
throw new Error(`Extension not found: ${extensionName}`);
|
|
81
|
+
}
|
|
82
|
+
const content = await fs.readFile(extensionPath, 'utf-8');
|
|
83
|
+
const versionMatch = content.match(/version:\s*['"]([^'"]+)['"]/);
|
|
84
|
+
if (!versionMatch) {
|
|
85
|
+
throw new Error(`Could not find version in ${extensionName}`);
|
|
86
|
+
}
|
|
87
|
+
const currentVersion = versionMatch[1];
|
|
88
|
+
const newVersion = semver.inc(currentVersion, bumpType);
|
|
89
|
+
if (!newVersion) {
|
|
90
|
+
throw new Error(`Invalid bump type: ${bumpType}`);
|
|
91
|
+
}
|
|
92
|
+
// Update version in index.ts
|
|
93
|
+
const updatedContent = content.replace(/version:\s*['"]([^'"]+)['"]/, `version: '${newVersion}'`);
|
|
94
|
+
await fs.writeFile(extensionPath, updatedContent);
|
|
95
|
+
// Update changelog if it exists
|
|
96
|
+
await this.updateExtensionChangelog(extensionName, currentVersion, newVersion, bumpType);
|
|
97
|
+
return newVersion;
|
|
98
|
+
}
|
|
99
|
+
async updateExtensionChangelog(extensionName, oldVersion, newVersion, bumpType) {
|
|
100
|
+
const changelogPath = path.join(this.extensionsDir, extensionName, 'CHANGELOG.md');
|
|
101
|
+
if (!(await fs.pathExists(changelogPath))) {
|
|
102
|
+
// Create changelog if it doesn't exist
|
|
103
|
+
const changelog = `# Changelog
|
|
104
|
+
|
|
105
|
+
All notable changes to this extension will be documented in this file.
|
|
106
|
+
|
|
107
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
108
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
109
|
+
|
|
110
|
+
## [${newVersion}] - ${new Date().toISOString().split('T')[0]}
|
|
111
|
+
|
|
112
|
+
### ${this.getChangeType(bumpType)}
|
|
113
|
+
- Version bump from ${oldVersion}
|
|
114
|
+
`;
|
|
115
|
+
await fs.writeFile(changelogPath, changelog);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Update existing changelog
|
|
119
|
+
const content = await fs.readFile(changelogPath, 'utf-8');
|
|
120
|
+
const today = new Date().toISOString().split('T')[0];
|
|
121
|
+
const newEntry = `\n## [${newVersion}] - ${today}\n\n### ${this.getChangeType(bumpType)}\n- Version bump from ${oldVersion}\n`;
|
|
122
|
+
// Find the first version entry and insert before it
|
|
123
|
+
const lines = content.split('\n');
|
|
124
|
+
const firstVersionIndex = lines.findIndex(line => line.match(/^## \[\d+\.\d+\.\d+\]/));
|
|
125
|
+
if (firstVersionIndex >= 0) {
|
|
126
|
+
lines.splice(firstVersionIndex, 0, newEntry.trim());
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
lines.push(newEntry.trim());
|
|
130
|
+
}
|
|
131
|
+
await fs.writeFile(changelogPath, lines.join('\n'));
|
|
132
|
+
}
|
|
133
|
+
getChangeType(bumpType) {
|
|
134
|
+
switch (bumpType) {
|
|
135
|
+
case 'major': return 'Breaking';
|
|
136
|
+
case 'minor': return 'Features';
|
|
137
|
+
case 'patch': return 'Fixes';
|
|
138
|
+
default: return 'Changes';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async getExtensionChangelog(extensionName) {
|
|
142
|
+
const changelogPath = path.join(this.extensionsDir, extensionName, 'CHANGELOG.md');
|
|
143
|
+
if (!(await fs.pathExists(changelogPath))) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
return await fs.readFile(changelogPath, 'utf-8');
|
|
147
|
+
}
|
|
148
|
+
async createExtensionChangelog(extensionName) {
|
|
149
|
+
const changelogPath = path.join(this.extensionsDir, extensionName, 'CHANGELOG.md');
|
|
150
|
+
if (await fs.pathExists(changelogPath)) {
|
|
151
|
+
throw new Error(`Changelog already exists for ${extensionName}`);
|
|
152
|
+
}
|
|
153
|
+
const extensionPath = path.join(this.extensionsDir, extensionName, 'index.ts');
|
|
154
|
+
if (!(await fs.pathExists(extensionPath))) {
|
|
155
|
+
throw new Error(`Extension not found: ${extensionName}`);
|
|
156
|
+
}
|
|
157
|
+
const content = await fs.readFile(extensionPath, 'utf-8');
|
|
158
|
+
const versionMatch = content.match(/version:\s*['"]([^'"]+)['"]/);
|
|
159
|
+
const version = versionMatch ? versionMatch[1] : '1.0.0';
|
|
160
|
+
const changelog = `# Changelog
|
|
161
|
+
|
|
162
|
+
All notable changes to this extension will be documented in this file.
|
|
163
|
+
|
|
164
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
165
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
166
|
+
|
|
167
|
+
## [${version}] - ${new Date().toISOString().split('T')[0]}
|
|
168
|
+
|
|
169
|
+
### Added
|
|
170
|
+
- Initial release
|
|
171
|
+
`;
|
|
172
|
+
await fs.writeFile(changelogPath, changelog);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.ExtensionManager = ExtensionManager;
|
|
176
|
+
//# sourceMappingURL=extension-manager.js.map
|
|
@@ -238,7 +238,7 @@ async function scanRootForCleanup(rootDir, config) {
|
|
|
238
238
|
const extension = {
|
|
239
239
|
name: CLEANUP_EXTENSION_NAME,
|
|
240
240
|
description: 'Config-driven repo root cleanup — keeps stray files out of root, configurable via versioning.config.json',
|
|
241
|
-
version: '1.
|
|
241
|
+
version: '1.1.0',
|
|
242
242
|
register: async (program, rootConfig) => {
|
|
243
243
|
const config = loadCleanupConfig(rootConfig);
|
|
244
244
|
const cleanupCmd = program
|
|
@@ -4,7 +4,7 @@ const commander_1 = require("commander");
|
|
|
4
4
|
const extension = {
|
|
5
5
|
name: 'lifecycle-hooks',
|
|
6
6
|
description: 'Extension demonstrating lifecycle hooks for versioning process',
|
|
7
|
-
version: '1.
|
|
7
|
+
version: '1.0.0',
|
|
8
8
|
hooks: {
|
|
9
9
|
preVersion: async (type, options) => {
|
|
10
10
|
console.log(`🔗 Pre-version hook: Preparing for ${type} release...`);
|
|
@@ -39,7 +39,7 @@ const path = __importStar(require("path"));
|
|
|
39
39
|
const extension = {
|
|
40
40
|
name: 'npm-publish',
|
|
41
41
|
description: 'Extension for NPM publishing with custom logic',
|
|
42
|
-
version: '1.
|
|
42
|
+
version: '1.0.0',
|
|
43
43
|
register: async (program, config) => {
|
|
44
44
|
// Add publish command
|
|
45
45
|
program
|
|
@@ -52,7 +52,7 @@ const git_context_1 = require("./git-context");
|
|
|
52
52
|
const extension = {
|
|
53
53
|
name: constants_1.REENTRY_EXTENSION_NAME,
|
|
54
54
|
description: 'Maintains canonical re-entry status and synchronizes to files, GitHub Issues, and Obsidian notes',
|
|
55
|
-
version: '1.
|
|
55
|
+
version: '1.2.0',
|
|
56
56
|
hooks: {
|
|
57
57
|
postVersion: async (type, version, options) => {
|
|
58
58
|
try {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const extension = {
|
|
4
4
|
name: 'sample-extension',
|
|
5
5
|
description: 'Sample extension demonstrating custom business logic',
|
|
6
|
-
version: '1.
|
|
6
|
+
version: '1.0.1',
|
|
7
7
|
register: async (program, config) => {
|
|
8
8
|
// Add a custom command
|
|
9
9
|
program
|
|
@@ -103,7 +103,7 @@ function checkContentForSecrets(content, patterns, allowlist, filename) {
|
|
|
103
103
|
const extension = {
|
|
104
104
|
name: 'secrets-check',
|
|
105
105
|
description: 'Checks for hardcoded secrets and private keys in staged files',
|
|
106
|
-
version: '1.
|
|
106
|
+
version: '1.1.0',
|
|
107
107
|
register: async (program, config) => {
|
|
108
108
|
// Try to get config from extensionConfig first, fallback to top-level secrets for backcompat
|
|
109
109
|
const extensionConfig = config.extensionConfig?.['secrets-check'];
|