UNPKG

@taizo-pro/github-discussions-cli

Version:

A powerful command-line tool for interacting with GitHub Discussions without opening a browser

169 lines 7.45 kB
import { Command } from 'commander'; import chalk from 'chalk'; import { GitHubClient, FileAuthManager, FileConfigManager } from '../../core/index.js'; import { EnhancedErrorHandler } from '../utils/enhanced-error-handler.js'; import { Spinner } from '../utils/spinner.js'; import { ProgressBar } from '../utils/progress.js'; export const statsCommand = new Command('stats') .description('Show repository discussion statistics') .argument('[repo]', 'Repository in owner/name format') .option('--detailed', 'Show detailed statistics') .action(async (repo, options) => { const spinner = new Spinner(); const context = { operation: 'analyze statistics', repository: repo }; try { const authManager = new FileAuthManager(); const configManager = new FileConfigManager(); spinner.start('Checking authentication...'); const token = await authManager.getToken(); if (!token) { spinner.fail('No GitHub token found'); console.error(chalk.red('Run "gh-discussions config" to set up authentication.')); process.exit(1); } spinner.succeed('Authentication verified'); const targetRepo = repo || (await configManager.getDefaultRepo()); if (!targetRepo) { console.error(chalk.red('No repository specified. Provide a repo argument or set a default repo.')); process.exit(1); } context.repository = targetRepo; spinner.start(`Analyzing discussions in ${targetRepo}...`); const client = new GitHubClient(token); // Get all discussions for analysis const discussions = await EnhancedErrorHandler.retryWithBackoff(() => client.listDiscussions(targetRepo, { first: 100, orderBy: { field: 'UPDATED_AT', direction: 'DESC' }, }), context); spinner.succeed('Analysis complete'); if (discussions.length === 0) { console.log(chalk.yellow('No discussions found to analyze.')); return; } // Calculate statistics const stats = calculateStats(discussions); // Display results displayStats(targetRepo, stats, options.detailed); if (options.detailed) { await displayDetailedStats(client, targetRepo, discussions); } } catch (error) { spinner.fail(); await EnhancedErrorHandler.handleError(error, context); } }); function calculateStats(discussions) { const stats = { total: discussions.length, totalComments: 0, averageComments: 0, categories: {}, authors: {}, topDiscussions: [], mostActive: [], recent: [], }; // Calculate totals and categorize discussions.forEach(discussion => { stats.totalComments += discussion.commentCount; // Category stats const category = discussion.category?.name || 'Uncategorized'; stats.categories[category] = (stats.categories[category] || 0) + 1; // Author stats const author = discussion.author.login; stats.authors[author] = (stats.authors[author] || 0) + 1; }); stats.averageComments = stats.total > 0 ? stats.totalComments / stats.total : 0; // Top discussions by comments stats.topDiscussions = discussions .filter(d => d.commentCount > 0) .sort((a, b) => b.commentCount - a.commentCount) .slice(0, 5); // Most active authors stats.mostActive = Object.entries(stats.authors) .sort(([, a], [, b]) => b - a) .slice(0, 5) .map(([author, count]) => ({ author, count })); // Recent discussions stats.recent = discussions .sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()) .slice(0, 5); return stats; } function displayStats(repo, stats, detailed) { console.log(); console.log(chalk.blue.bold(`📊 Discussion Statistics for ${repo}`)); console.log(chalk.blue('='.repeat(60))); console.log(); // Basic stats console.log(chalk.white.bold('📈 Overview')); console.log(` Total Discussions: ${chalk.green(stats.total)}`); console.log(` Total Comments: ${chalk.green(stats.totalComments)}`); console.log(` Average Comments per Discussion: ${chalk.green(stats.averageComments.toFixed(1))}`); console.log(); // Category breakdown if (Object.keys(stats.categories).length > 0) { console.log(chalk.white.bold('📁 Categories')); Object.entries(stats.categories) .sort(([, a], [, b]) => b - a) .forEach(([category, count]) => { const percentage = (count / stats.total * 100).toFixed(1); const bar = '█'.repeat(Math.max(1, Math.floor(count / stats.total * 20))); console.log(` ${category}: ${chalk.green(count)} (${percentage}%) ${chalk.gray(bar)}`); }); console.log(); } // Top contributors if (stats.mostActive.length > 0) { console.log(chalk.white.bold('👥 Most Active Contributors')); stats.mostActive.forEach(({ author, count }, index) => { const medal = index === 0 ? '🥇' : index === 1 ? '🥈' : index === 2 ? '🥉' : ' '; console.log(` ${medal} ${author}: ${chalk.green(count)} discussions`); }); console.log(); } // Top discussions if (stats.topDiscussions.length > 0) { console.log(chalk.white.bold('🔥 Most Commented Discussions')); stats.topDiscussions.forEach((discussion, index) => { const medal = index === 0 ? '🥇' : index === 1 ? '🥈' : index === 2 ? '🥉' : ' '; const title = discussion.title.length > 40 ? discussion.title.substring(0, 37) + '...' : discussion.title; console.log(` ${medal} ${title}`); console.log(` ${chalk.green(discussion.commentCount)} comments by ${chalk.gray(discussion.author.login)}`); }); console.log(); } } async function displayDetailedStats(client, repo, discussions) { console.log(chalk.white.bold('📋 Recent Activity')); const progress = new ProgressBar(); progress.start(Math.min(5, discussions.length)); for (let i = 0; i < Math.min(5, discussions.length); i++) { const discussion = discussions[i]; try { // Get detailed info for recent discussions const details = await client.getDiscussion(repo, discussion.id.split('/').pop() || '1'); const title = details.title.length > 50 ? details.title.substring(0, 47) + '...' : details.title; console.log(` • ${title}`); console.log(` ${chalk.gray('Author:')} ${details.author.login} ${chalk.gray('Comments:')} ${details.commentCount}`); console.log(` ${chalk.gray('Updated:')} ${new Date(details.updatedAt).toLocaleDateString()}`); if (details.comments.length > 0) { const lastComment = details.comments[details.comments.length - 1]; console.log(` ${chalk.gray('Last comment by:')} ${lastComment.author.login}`); } console.log(); progress.increment(); } catch (error) { progress.increment(); // Skip failed requests } } progress.stop(); } //# sourceMappingURL=stats.js.map