@edcalderon/versioning 1.4.2 → 1.4.3

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/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.4.2',
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.4.2',
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.4.2',
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.4.2',
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.4.2',
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.4.2',
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'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edcalderon/versioning",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "A comprehensive versioning and changelog management tool for monorepos",
5
5
  "main": "dist/index.js",
6
6
  "bin": {