From 0fc9b9ac06fad8a4ebfbe199271dd9fc4bc4bba5 Mon Sep 17 00:00:00 2001 From: Nabil hassan mohamed ali <180658407+Nabilhassan12345@users.noreply.github.com> Date: Sat, 18 Oct 2025 16:38:44 +0300 Subject: [PATCH 1/2] feat: add examples directory with usage scripts - Add basic usage examples (evaluate-popular-repos, create-interactive, evaluate-with-token) - Add advanced examples (batch-evaluate, compare-repositories, export-results, check-org-repos) - Add integration examples (GitHub Actions, pre-commit hook, Slack integration) - Add sample data files and expected results - Add comprehensive README with usage instructions Closes #9 --- examples/README.md | 56 +++++++ examples/advanced/batch-evaluate.js | 112 +++++++++++++ examples/advanced/check-org-repos.js | 155 ++++++++++++++++++ examples/advanced/compare-repositories.js | 122 ++++++++++++++ examples/advanced/export-results.js | 139 ++++++++++++++++ examples/basic/create-repo-interactive.js | 72 ++++++++ examples/basic/evaluate-popular-repos.js | 53 ++++++ examples/basic/evaluate-with-token.js | 65 ++++++++ examples/data/expected-results.json | 48 ++++++ examples/data/sample-repos.json | 43 +++++ .../integrations/github-actions-example.yml | 41 +++++ examples/integrations/pre-commit-hook.js | 107 ++++++++++++ examples/integrations/slack-integration.js | 150 +++++++++++++++++ 13 files changed, 1163 insertions(+) create mode 100644 examples/README.md create mode 100755 examples/advanced/batch-evaluate.js create mode 100755 examples/advanced/check-org-repos.js create mode 100755 examples/advanced/compare-repositories.js create mode 100755 examples/advanced/export-results.js create mode 100755 examples/basic/create-repo-interactive.js create mode 100755 examples/basic/evaluate-popular-repos.js create mode 100755 examples/basic/evaluate-with-token.js create mode 100644 examples/data/expected-results.json create mode 100644 examples/data/sample-repos.json create mode 100644 examples/integrations/github-actions-example.yml create mode 100755 examples/integrations/pre-commit-hook.js create mode 100755 examples/integrations/slack-integration.js diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..d8dded6 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,56 @@ +# Examples Directory + +This directory contains practical examples of using RepoReady in various scenarios. + +## Getting Started + +1. Build RepoReady: `npm run build` +2. Set GitHub token: `export GITHUB_TOKEN=your_token_here` +3. Run examples: `node examples/basic/evaluate-popular-repos.js` + +## Directory Structure + +- `basic/` - Simple usage examples for beginners +- `advanced/` - Complex scenarios and batch operations +- `integrations/` - Integration with other tools and services +- `data/` - Sample data files and expected results + +## Requirements + +- Node.js 16+ +- Built RepoReady (`npm run build`) +- GitHub token (for API access) + +## Examples Overview + +### Basic Examples +- **evaluate-popular-repos.js** - Evaluate famous repositories +- **create-repo-interactive.js** - Interactive repository creation +- **evaluate-with-token.js** - Token usage best practices + +### Advanced Examples +- **batch-evaluate.js** - Evaluate multiple repos with export +- **compare-repositories.js** - Side-by-side repository comparison +- **export-results.js** - Export evaluation results to JSON/CSV +- **check-org-repos.js** - Evaluate all repos in an organization + +### Integration Examples +- **github-actions-example.yml** - CI/CD integration +- **pre-commit-hook.js** - Git hook integration +- **slack-integration.js** - Notifications integration + +## Benefits + +šŸ“š Provides practical learning materials +šŸš€ Helps users get started quickly +šŸ’” Demonstrates advanced use cases +šŸ”§ Shows integration possibilities +šŸ“Š Includes real-world scenarios +šŸŽÆ Reduces support burden with self-service examples + +## Integration with Documentation + +Link examples from main README.md +Reference examples in CLI help text +Include in getting started guides +Use in tutorials and blog posts diff --git a/examples/advanced/batch-evaluate.js b/examples/advanced/batch-evaluate.js new file mode 100755 index 0000000..b2900cd --- /dev/null +++ b/examples/advanced/batch-evaluate.js @@ -0,0 +1,112 @@ +#!/usr/bin/env node +// examples/advanced/batch-evaluate.js + +/** + * Example: Batch Repository Evaluation with Export + * + * Evaluates multiple repositories and exports results to JSON + */ + +const fs = require('fs').promises; +const path = require('path'); +const { exec } = require('child_process'); +const util = require('util'); + +const execPromise = util.promisify(exec); + +class BatchEvaluator { + constructor(githubToken) { + this.githubToken = githubToken; + this.results = []; + } + + async evaluateRepository(owner, repo) { + try { + console.log(`šŸ“Š Evaluating ${owner}/${repo}...`); + + const command = this.githubToken + ? `node ../../dist/index.js evaluate ${owner}/${repo} --token ${this.githubToken}` + : `node ../../dist/index.js evaluate ${owner}/${repo}`; + + const { stdout } = await execPromise(command); + + // Parse the output to extract score information + const scoreMatch = stdout.match(/Score: (\d+)%/); + const ratingMatch = stdout.match(/Rating: (\w+)/); + + const result = { + repository: `${owner}/${repo}`, + timestamp: new Date().toISOString(), + score: scoreMatch ? parseInt(scoreMatch[1]) : 0, + rating: ratingMatch ? ratingMatch[1] : 'Unknown', + rawOutput: stdout + }; + + this.results.push(result); + console.log(` Score: ${result.score}% (${result.rating})`); + + return result; + } catch (error) { + console.error(`āŒ Error evaluating ${owner}/${repo}:`, error.message); + return null; + } + } + + async evaluateBatch(repositories) { + for (const repo of repositories) { + const [owner, name] = repo.split('/'); + await this.evaluateRepository(owner, name); + + // Respect rate limits + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + + async exportResults(filename = 'evaluation-results.json') { + const outputPath = path.join(__dirname, '..', 'data', filename); + await fs.writeFile(outputPath, JSON.stringify(this.results, null, 2)); + console.log(`šŸ“„ Results exported to ${outputPath}`); + } + + generateSummary() { + if (this.results.length === 0) return; + + const avgScore = this.results.reduce((sum, r) => sum + r.score, 0) / this.results.length; + const ratingCounts = this.results.reduce((counts, r) => { + counts[r.rating] = (counts[r.rating] || 0) + 1; + return counts; + }, {}); + + console.log('\nšŸ“ˆ Batch Evaluation Summary'); + console.log(` Repositories evaluated: ${this.results.length}`); + console.log(` Average score: ${avgScore.toFixed(1)}%`); + console.log(` Rating distribution:`, ratingCounts); + } +} + +// Example usage +const exampleRepos = [ + 'OpenSource-Communities/RepoReady', + 'facebook/react', + 'microsoft/typescript' +]; + +async function main() { + const token = process.env.GITHUB_TOKEN; + if (!token) { + console.error('Please set GITHUB_TOKEN environment variable'); + process.exit(1); + } + + const batchEvaluator = new BatchEvaluator(token); + + await batchEvaluator.evaluateBatch(exampleRepos); + batchEvaluator.generateSummary(); + await batchEvaluator.exportResults(); +} + +if (require.main === module) { + main().catch(console.error); +} + +module.exports = { BatchEvaluator }; diff --git a/examples/advanced/check-org-repos.js b/examples/advanced/check-org-repos.js new file mode 100755 index 0000000..d21c8ae --- /dev/null +++ b/examples/advanced/check-org-repos.js @@ -0,0 +1,155 @@ +#!/usr/bin/env node +// examples/advanced/check-org-repos.js + +/** + * Example: Check Organization Repositories + * + * This script demonstrates how to evaluate all repositories + * in a GitHub organization for contributor readiness. + */ + +const { exec } = require('child_process'); +const util = require('util'); +const fs = require('fs').promises; +const path = require('path'); + +const execPromise = util.promisify(exec); + +class OrganizationEvaluator { + constructor(githubToken) { + this.githubToken = githubToken; + this.results = []; + } + + async getOrganizationRepos(orgName) { + try { + console.log(`šŸ” Fetching repositories for organization: ${orgName}`); + + // Use GitHub API to get organization repositories + const command = `curl -H "Authorization: token ${this.githubToken}" "https://api.github.com/orgs/${orgName}/repos?per_page=100"`; + const { stdout } = await execPromise(command); + + const repos = JSON.parse(stdout); + return repos.map(repo => `${repo.owner.login}/${repo.name}`); + } catch (error) { + console.error(`āŒ Error fetching organization repos:`, error.message); + return []; + } + } + + async evaluateRepository(owner, repo) { + try { + console.log(`šŸ“Š Evaluating ${owner}/${repo}...`); + + const command = this.githubToken + ? `node ../../dist/index.js evaluate ${owner}/${repo} --token ${this.githubToken}` + : `node ../../dist/index.js evaluate ${owner}/${repo}`; + + const { stdout } = await execPromise(command); + + // Parse the output to extract score information + const scoreMatch = stdout.match(/Score: (\d+)%/); + const ratingMatch = stdout.match(/Rating: (\w+)/); + + const result = { + repository: `${owner}/${repo}`, + score: scoreMatch ? parseInt(scoreMatch[1]) : 0, + rating: ratingMatch ? ratingMatch[1] : 'Unknown', + timestamp: new Date().toISOString() + }; + + this.results.push(result); + console.log(` Score: ${result.score}% (${result.rating})`); + + return result; + } catch (error) { + console.error(`āŒ Error evaluating ${owner}/${repo}:`, error.message); + return null; + } + } + + async evaluateOrganization(orgName) { + console.log(`šŸ¢ Evaluating Organization: ${orgName}\n`); + + const repositories = await this.getOrganizationRepos(orgName); + + if (repositories.length === 0) { + console.log('No repositories found for this organization'); + return; + } + + console.log(`Found ${repositories.length} repositories to evaluate\n`); + + for (const repo of repositories) { + const [owner, name] = repo.split('/'); + await this.evaluateRepository(owner, name); + + // Respect rate limits + await new Promise(resolve => setTimeout(resolve, 1000)); + } + + this.generateOrganizationReport(orgName); + await this.exportOrganizationResults(orgName); + } + + generateOrganizationReport(orgName) { + if (this.results.length === 0) return; + + console.log(`\nšŸ“Š Organization Report: ${orgName}`); + console.log('='.repeat(60)); + + const avgScore = this.results.reduce((sum, r) => sum + r.score, 0) / this.results.length; + const ratingCounts = this.results.reduce((counts, r) => { + counts[r.rating] = (counts[r.rating] || 0) + 1; + return counts; + }, {}); + + // Sort by score + const sortedResults = this.results.sort((a, b) => b.score - a.score); + + console.log(`Total Repositories: ${this.results.length}`); + console.log(`Average Score: ${avgScore.toFixed(1)}%`); + console.log(`Rating Distribution:`, ratingCounts); + + console.log('\nTop Performing Repositories:'); + sortedResults.slice(0, 5).forEach((result, index) => { + console.log(` ${index + 1}. ${result.repository} - ${result.score}% (${result.rating})`); + }); + + console.log('\nRepositories Needing Attention:'); + sortedResults.slice(-5).reverse().forEach((result, index) => { + console.log(` ${index + 1}. ${result.repository} - ${result.score}% (${result.rating})`); + }); + } + + async exportOrganizationResults(orgName) { + const outputPath = path.join(__dirname, '..', 'data', `${orgName}-evaluation.json`); + await fs.writeFile(outputPath, JSON.stringify(this.results, null, 2)); + console.log(`\nšŸ“„ Organization results exported to ${outputPath}`); + } +} + +// Example usage +async function main() { + const orgName = process.argv[2]; + const token = process.env.GITHUB_TOKEN; + + if (!orgName) { + console.error('Please provide organization name: node check-org-repos.js '); + process.exit(1); + } + + if (!token) { + console.error('Please set GITHUB_TOKEN environment variable'); + process.exit(1); + } + + const evaluator = new OrganizationEvaluator(token); + await evaluator.evaluateOrganization(orgName); +} + +if (require.main === module) { + main().catch(console.error); +} + +module.exports = { OrganizationEvaluator }; diff --git a/examples/advanced/compare-repositories.js b/examples/advanced/compare-repositories.js new file mode 100755 index 0000000..b0a3d15 --- /dev/null +++ b/examples/advanced/compare-repositories.js @@ -0,0 +1,122 @@ +#!/usr/bin/env node +// examples/advanced/compare-repositories.js + +/** + * Example: Compare Multiple Repositories + * + * This script evaluates multiple repositories and provides + * a side-by-side comparison of their scores. + */ + +const { exec } = require('child_process'); +const util = require('util'); +const execPromise = util.promisify(exec); + +class RepositoryComparator { + constructor(githubToken) { + this.githubToken = githubToken; + this.results = []; + } + + async evaluateRepository(owner, repo) { + try { + console.log(`šŸ“Š Evaluating ${owner}/${repo}...`); + + const command = this.githubToken + ? `node ../../dist/index.js evaluate ${owner}/${repo} --token ${this.githubToken}` + : `node ../../dist/index.js evaluate ${owner}/${repo}`; + + const { stdout } = await execPromise(command); + + // Parse the output to extract score information + const scoreMatch = stdout.match(/Score: (\d+)%/); + const ratingMatch = stdout.match(/Rating: (\w+)/); + + return { + repository: `${owner}/${repo}`, + score: scoreMatch ? parseInt(scoreMatch[1]) : 0, + rating: ratingMatch ? ratingMatch[1] : 'Unknown', + rawOutput: stdout + }; + } catch (error) { + console.error(`āŒ Error evaluating ${owner}/${repo}:`, error.message); + return null; + } + } + + async compareRepositories(repositories) { + console.log('šŸ”„ Comparing Repositories\n'); + + for (const repo of repositories) { + const [owner, name] = repo.split('/'); + const result = await this.evaluateRepository(owner, name); + if (result) { + this.results.push(result); + } + + // Respect rate limits + await new Promise(resolve => setTimeout(resolve, 1000)); + } + + this.displayComparison(); + } + + displayComparison() { + if (this.results.length === 0) { + console.log('No results to compare'); + return; + } + + console.log('\nšŸ“Š Repository Comparison Results\n'); + console.log('='.repeat(80)); + console.log('Repository'.padEnd(30) + 'Score'.padEnd(10) + 'Rating'.padEnd(15) + 'Status'); + console.log('='.repeat(80)); + + // Sort by score descending + const sortedResults = this.results.sort((a, b) => b.score - a.score); + + sortedResults.forEach((result, index) => { + const status = index === 0 ? 'šŸ„‡ Best' : index === 1 ? '🄈 2nd' : index === 2 ? 'šŸ„‰ 3rd' : ' '; + console.log( + result.repository.padEnd(30) + + `${result.score}%`.padEnd(10) + + result.rating.padEnd(15) + + status + ); + }); + + console.log('='.repeat(80)); + + // Show statistics + const avgScore = this.results.reduce((sum, r) => sum + r.score, 0) / this.results.length; + const bestRepo = sortedResults[0]; + const worstRepo = sortedResults[sortedResults.length - 1]; + + console.log(`\nšŸ“ˆ Statistics:`); + console.log(` Average Score: ${avgScore.toFixed(1)}%`); + console.log(` Best Repository: ${bestRepo.repository} (${bestRepo.score}%)`); + console.log(` Needs Most Work: ${worstRepo.repository} (${worstRepo.score}%)`); + } +} + +// Example usage +const repositoriesToCompare = [ + 'facebook/react', + 'microsoft/vscode', + 'nodejs/node', + 'tensorflow/tensorflow', + 'vuejs/vue' +]; + +async function main() { + const token = process.env.GITHUB_TOKEN; + const comparator = new RepositoryComparator(token); + + await comparator.compareRepositories(repositoriesToCompare); +} + +if (require.main === module) { + main().catch(console.error); +} + +module.exports = { RepositoryComparator }; diff --git a/examples/advanced/export-results.js b/examples/advanced/export-results.js new file mode 100755 index 0000000..dc73b97 --- /dev/null +++ b/examples/advanced/export-results.js @@ -0,0 +1,139 @@ +#!/usr/bin/env node +// examples/advanced/export-results.js + +/** + * Example: Export Evaluation Results + * + * This script demonstrates how to export evaluation results + * to various formats (JSON, CSV, Markdown). + */ + +const fs = require('fs').promises; +const path = require('path'); +const { exec } = require('child_process'); +const util = require('util'); + +const execPromise = util.promisify(exec); + +class ResultsExporter { + constructor(githubToken) { + this.githubToken = githubToken; + this.results = []; + } + + async evaluateRepository(owner, repo) { + try { + console.log(`šŸ“Š Evaluating ${owner}/${repo}...`); + + const command = this.githubToken + ? `node ../../dist/index.js evaluate ${owner}/${repo} --token ${this.githubToken}` + : `node ../../dist/index.js evaluate ${owner}/${repo}`; + + const { stdout } = await execPromise(command); + + // Parse the output to extract score information + const scoreMatch = stdout.match(/Score: (\d+)%/); + const ratingMatch = stdout.match(/Rating: (\w+)/); + + return { + repository: `${owner}/${repo}`, + score: scoreMatch ? parseInt(scoreMatch[1]) : 0, + rating: ratingMatch ? ratingMatch[1] : 'Unknown', + timestamp: new Date().toISOString(), + rawOutput: stdout + }; + } catch (error) { + console.error(`āŒ Error evaluating ${owner}/${repo}:`, error.message); + return null; + } + } + + async evaluateAndExport(repositories) { + console.log('šŸ”„ Evaluating repositories for export...\n'); + + for (const repo of repositories) { + const [owner, name] = repo.split('/'); + const result = await this.evaluateRepository(owner, name); + if (result) { + this.results.push(result); + } + + // Respect rate limits + await new Promise(resolve => setTimeout(resolve, 1000)); + } + + // Export to different formats + await this.exportToJSON(); + await this.exportToCSV(); + await this.exportToMarkdown(); + } + + async exportToJSON() { + const outputPath = path.join(__dirname, '..', 'data', 'results.json'); + await fs.writeFile(outputPath, JSON.stringify(this.results, null, 2)); + console.log(`šŸ“„ JSON results exported to ${outputPath}`); + } + + async exportToCSV() { + const csvHeader = 'Repository,Score,Rating,Timestamp\n'; + const csvRows = this.results.map(r => + `"${r.repository}",${r.score},"${r.rating}","${r.timestamp}"` + ).join('\n'); + + const outputPath = path.join(__dirname, '..', 'data', 'results.csv'); + await fs.writeFile(outputPath, csvHeader + csvRows); + console.log(`šŸ“„ CSV results exported to ${outputPath}`); + } + + async exportToMarkdown() { + const mdContent = `# Repository Evaluation Results + +Generated on: ${new Date().toISOString()} + +## Summary + +| Repository | Score | Rating | Timestamp | +|------------|-------|--------|-----------| +${this.results.map(r => `| ${r.repository} | ${r.score}% | ${r.rating} | ${r.timestamp} |`).join('\n')} + +## Detailed Results + +${this.results.map(r => `### ${r.repository} + +**Score:** ${r.score}% +**Rating:** ${r.rating} +**Evaluated:** ${r.timestamp} + +\`\`\` +${r.rawOutput} +\`\`\` + +---`).join('\n\n')} +`; + + const outputPath = path.join(__dirname, '..', 'data', 'results.md'); + await fs.writeFile(outputPath, mdContent); + console.log(`šŸ“„ Markdown results exported to ${outputPath}`); + } +} + +// Example usage +const repositories = [ + 'facebook/react', + 'microsoft/vscode', + 'nodejs/node' +]; + +async function main() { + const token = process.env.GITHUB_TOKEN; + const exporter = new ResultsExporter(token); + + await exporter.evaluateAndExport(repositories); + console.log('\nāœ… All exports completed!'); +} + +if (require.main === module) { + main().catch(console.error); +} + +module.exports = { ResultsExporter }; diff --git a/examples/basic/create-repo-interactive.js b/examples/basic/create-repo-interactive.js new file mode 100755 index 0000000..d316c8f --- /dev/null +++ b/examples/basic/create-repo-interactive.js @@ -0,0 +1,72 @@ +#!/usr/bin/env node +// examples/basic/create-repo-interactive.js + +/** + * Example: Interactive Repository Creation + * + * This script demonstrates how to create a new repository + * using RepoReady with interactive prompts. + */ + +const { exec } = require('child_process'); +const util = require('util'); +const readline = require('readline'); + +const execPromise = util.promisify(exec); + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); + +function askQuestion(question) { + return new Promise((resolve) => { + rl.question(question, resolve); + }); +} + +async function createRepositoryInteractive() { + console.log('šŸš€ Interactive Repository Creation with RepoReady\n'); + + try { + // Check if GitHub token is available + if (!process.env.GITHUB_TOKEN) { + console.log('āš ļø GITHUB_TOKEN environment variable not set.'); + const token = await askQuestion('Enter your GitHub token: '); + process.env.GITHUB_TOKEN = token; + } + + const name = await askQuestion('Repository name: '); + const description = await askQuestion('Repository description: '); + const isPrivate = await askQuestion('Private repository? (y/N): '); + + const privateFlag = isPrivate.toLowerCase() === 'y' ? '--private' : ''; + + console.log('\nšŸ“¦ Creating repository...\n'); + + // Use the built RepoReady CLI + const command = `node ../../dist/index.js create --token ${process.env.GITHUB_TOKEN} --name "${name}" --description "${description}" ${privateFlag}`; + + const { stdout } = await execPromise(command); + console.log(stdout); + + console.log('\nāœ… Repository created successfully!'); + console.log('Next steps:'); + console.log('1. Clone your repository'); + console.log('2. Add your code'); + console.log('3. Push to GitHub'); + console.log('4. Run: rr evaluate /'); + + } catch (error) { + console.error('āŒ Error creating repository:', error.message); + } finally { + rl.close(); + } +} + +// Run if called directly +if (require.main === module) { + createRepositoryInteractive(); +} + +module.exports = { createRepositoryInteractive }; diff --git a/examples/basic/evaluate-popular-repos.js b/examples/basic/evaluate-popular-repos.js new file mode 100755 index 0000000..b2cb222 --- /dev/null +++ b/examples/basic/evaluate-popular-repos.js @@ -0,0 +1,53 @@ +#!/usr/bin/env node +// examples/basic/evaluate-popular-repos.js + +/** + * Example: Evaluate Popular Open Source Repositories + * + * This script demonstrates how to use RepoReady to evaluate + * several well-known open source repositories and compare their scores. + */ + +const { exec } = require('child_process'); +const util = require('util'); +const execPromise = util.promisify(exec); + +const popularRepos = [ + 'facebook/react', + 'microsoft/vscode', + 'nodejs/node', + 'tensorflow/tensorflow', + 'vuejs/vue' +]; + +async function evaluateRepos() { + console.log('šŸš€ Evaluating Popular Open Source Repositories\n'); + console.log('This may take a moment due to API rate limits...\n'); + + for (const repo of popularRepos) { + try { + console.log(`šŸ“Š Evaluating ${repo}...`); + + // Use the built RepoReady CLI + const { stdout } = await execPromise(`node ../../dist/index.js evaluate ${repo}`); + + console.log(stdout); + console.log('─'.repeat(50)); + + // Small delay to respect rate limits + await new Promise(resolve => setTimeout(resolve, 1000)); + + } catch (error) { + console.error(`āŒ Error evaluating ${repo}:`, error.message); + } + } +} + +// Run if called directly +if (require.main === module) { + evaluateRepos() + .then(() => console.log('āœ… Evaluation complete!')) + .catch(console.error); +} + +module.exports = { evaluateRepos, popularRepos }; diff --git a/examples/basic/evaluate-with-token.js b/examples/basic/evaluate-with-token.js new file mode 100755 index 0000000..6bc0bf1 --- /dev/null +++ b/examples/basic/evaluate-with-token.js @@ -0,0 +1,65 @@ +#!/usr/bin/env node +// examples/basic/evaluate-with-token.js + +/** + * Example: Using GitHub Tokens with RepoReady + * + * This script demonstrates best practices for using GitHub tokens + * to avoid rate limits and access private repositories. + */ + +const { exec } = require('child_process'); +const util = require('util'); +const execPromise = util.promisify(exec); + +async function evaluateWithToken() { + console.log('šŸ”‘ GitHub Token Usage Example\n'); + + // Check for token + if (!process.env.GITHUB_TOKEN) { + console.log('āŒ GITHUB_TOKEN environment variable not set.'); + console.log('Set it with: export GITHUB_TOKEN=your_token_here'); + console.log('Get a token at: https://github.com/settings/tokens'); + process.exit(1); + } + + console.log('āœ… GitHub token found'); + console.log('This allows for higher rate limits and access to private repos\n'); + + const repositories = [ + 'microsoft/vscode', + 'facebook/react', + 'nodejs/node' + ]; + + for (const repo of repositories) { + try { + console.log(`šŸ“Š Evaluating ${repo} with token...`); + + // Use token flag for better rate limits + const { stdout } = await execPromise(`node ../../dist/index.js evaluate ${repo} --token ${process.env.GITHUB_TOKEN}`); + + console.log(stdout); + console.log('─'.repeat(50)); + + // Shorter delay since we have a token + await new Promise(resolve => setTimeout(resolve, 500)); + + } catch (error) { + console.error(`āŒ Error evaluating ${repo}:`, error.message); + } + } + + console.log('\nšŸ’” Token Benefits:'); + console.log('- Higher rate limits (5000 requests/hour vs 60)'); + console.log('- Access to private repositories'); + console.log('- Better error messages'); + console.log('- Faster evaluation process'); +} + +// Run if called directly +if (require.main === module) { + evaluateWithToken(); +} + +module.exports = { evaluateWithToken }; diff --git a/examples/data/expected-results.json b/examples/data/expected-results.json new file mode 100644 index 0000000..3ef376c --- /dev/null +++ b/examples/data/expected-results.json @@ -0,0 +1,48 @@ +{ + "sampleResults": [ + { + "repository": "facebook/react", + "score": 95, + "rating": "Excellent", + "timestamp": "2024-01-15T10:30:00.000Z", + "expectedFeatures": [ + "README.md", + "CONTRIBUTING.md", + "LICENSE", + "Issue templates", + "Good first issues", + "Code of conduct" + ] + }, + { + "repository": "microsoft/vscode", + "score": 92, + "rating": "Excellent", + "timestamp": "2024-01-15T10:31:00.000Z", + "expectedFeatures": [ + "README.md", + "CONTRIBUTING.md", + "LICENSE", + "Issue templates", + "Good first issues" + ] + } + ], + "scoringCriteria": { + "README.md": 20, + "CONTRIBUTING.md": 15, + "LICENSE": 10, + "Issue templates": 15, + "Pull request template": 10, + "Good first issues": 15, + "Help wanted issues": 10, + "Code of conduct": 5 + }, + "ratingThresholds": { + "Excellent": 90, + "Good": 75, + "Fair": 60, + "Needs Work": 40, + "Not Ready": 0 + } +} diff --git a/examples/data/sample-repos.json b/examples/data/sample-repos.json new file mode 100644 index 0000000..4bbd258 --- /dev/null +++ b/examples/data/sample-repos.json @@ -0,0 +1,43 @@ +{ + "popularRepositories": [ + "facebook/react", + "microsoft/vscode", + "nodejs/node", + "tensorflow/tensorflow", + "vuejs/vue", + "angular/angular", + "microsoft/typescript", + "golang/go", + "rust-lang/rust", + "kubernetes/kubernetes" + ], + "testRepositories": [ + "OpenSource-Communities/RepoReady", + "facebook/react", + "microsoft/typescript", + "nodejs/node", + "tensorflow/tensorflow" + ], + "categories": { + "frontend": [ + "facebook/react", + "vuejs/vue", + "angular/angular" + ], + "backend": [ + "nodejs/node", + "golang/go", + "rust-lang/rust" + ], + "tools": [ + "microsoft/vscode", + "microsoft/typescript" + ], + "ai": [ + "tensorflow/tensorflow" + ], + "infrastructure": [ + "kubernetes/kubernetes" + ] + } +} diff --git a/examples/integrations/github-actions-example.yml b/examples/integrations/github-actions-example.yml new file mode 100644 index 0000000..2538a9b --- /dev/null +++ b/examples/integrations/github-actions-example.yml @@ -0,0 +1,41 @@ +# examples/integrations/github-actions-example.yml + +# Example GitHub Actions workflow using RepoReady +name: Repository Health Check + +on: + schedule: + # Run weekly on Sundays at 6 AM UTC + - cron: '0 6 * * 0' + workflow_dispatch: # Allow manual triggering + +jobs: + evaluate-repos: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Install RepoReady + run: npm install -g repoready + + - name: Evaluate repository + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "## Repository Health Report" >> $GITHUB_STEP_SUMMARY + rr evaluate ${{ github.repository }} >> $GITHUB_STEP_SUMMARY + + - name: Evaluate competitor repositories + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "## Competitor Analysis" >> $GITHUB_STEP_SUMMARY + rr evaluate microsoft/vscode >> $GITHUB_STEP_SUMMARY + rr evaluate facebook/react >> $GITHUB_STEP_SUMMARY diff --git a/examples/integrations/pre-commit-hook.js b/examples/integrations/pre-commit-hook.js new file mode 100755 index 0000000..bd635e9 --- /dev/null +++ b/examples/integrations/pre-commit-hook.js @@ -0,0 +1,107 @@ +#!/usr/bin/env node +// examples/integrations/pre-commit-hook.js + +/** + * Example: Pre-commit Hook Integration + * + * This script can be used as a pre-commit hook to evaluate + * repository health before allowing commits. + */ + +const { exec } = require('child_process'); +const util = require('util'); +const fs = require('fs').promises; +const path = require('path'); + +const execPromise = util.promisify(exec); + +class PreCommitEvaluator { + constructor() { + this.minimumScore = 60; // Minimum score required to allow commit + } + + async getRepositoryInfo() { + try { + // Get current repository info from git + const { stdout: remoteUrl } = await execPromise('git config --get remote.origin.url'); + const { stdout: branch } = await execPromise('git branch --show-current'); + + // Parse GitHub URL to get owner/repo + const match = remoteUrl.match(/github\.com[:/]([^/]+)\/([^/]+)\.git$/); + if (!match) { + throw new Error('Not a GitHub repository'); + } + + return { + owner: match[1], + repo: match[2].replace('.git', ''), + branch + }; + } catch (error) { + throw new Error('Could not determine repository information'); + } + } + + async evaluateRepository(owner, repo) { + try { + console.log(`šŸ“Š Evaluating ${owner}/${repo}...`); + + const command = `node ../../dist/index.js evaluate ${owner}/${repo}`; + const { stdout } = await execPromise(command); + + // Parse score from output + const scoreMatch = stdout.match(/Score: (\d+)%/); + return scoreMatch ? parseInt(scoreMatch[1]) : 0; + } catch (error) { + console.error(`āŒ Error evaluating repository:`, error.message); + return 0; + } + } + + async checkRepositoryHealth() { + try { + console.log('šŸ” Pre-commit Repository Health Check\n'); + + const repoInfo = await this.getRepositoryInfo(); + console.log(`Repository: ${repoInfo.owner}/${repoInfo.repo}`); + console.log(`Branch: ${repoInfo.branch}\n`); + + const score = await this.evaluateRepository(repoInfo.owner, repoInfo.repo); + + console.log(`\nšŸ“Š Repository Score: ${score}%`); + console.log(`Minimum Required: ${this.minimumScore}%`); + + if (score >= this.minimumScore) { + console.log('āœ… Repository health check passed! Proceeding with commit...'); + return true; + } else { + console.log('āŒ Repository health check failed!'); + console.log('Please improve your repository before committing:'); + console.log('- Add a README.md'); + console.log('- Add a CONTRIBUTING.md'); + console.log('- Add a LICENSE file'); + console.log('- Add issue templates'); + console.log('- Add good first issues'); + return false; + } + } catch (error) { + console.error('āŒ Pre-commit check failed:', error.message); + return false; + } + } +} + +async function main() { + const evaluator = new PreCommitEvaluator(); + const passed = await evaluator.checkRepositoryHealth(); + + if (!passed) { + process.exit(1); + } +} + +if (require.main === module) { + main().catch(console.error); +} + +module.exports = { PreCommitEvaluator }; diff --git a/examples/integrations/slack-integration.js b/examples/integrations/slack-integration.js new file mode 100755 index 0000000..4fcfd42 --- /dev/null +++ b/examples/integrations/slack-integration.js @@ -0,0 +1,150 @@ +#!/usr/bin/env node +// examples/integrations/slack-integration.js + +/** + * Example: Slack Integration + * + * This script evaluates repositories and sends results to Slack + * using webhooks or the Slack API. + */ + +const { exec } = require('child_process'); +const util = require('util'); +const https = require('https'); + +const execPromise = util.promisify(exec); + +class SlackReporter { + constructor(webhookUrl, githubToken) { + this.webhookUrl = webhookUrl; + this.githubToken = githubToken; + } + + async evaluateRepository(owner, repo) { + try { + console.log(`šŸ“Š Evaluating ${owner}/${repo}...`); + + const command = this.githubToken + ? `node ../../dist/index.js evaluate ${owner}/${repo} --token ${this.githubToken}` + : `node ../../dist/index.js evaluate ${owner}/${repo}`; + + const { stdout } = await execPromise(command); + + // Parse the output to extract score information + const scoreMatch = stdout.match(/Score: (\d+)%/); + const ratingMatch = stdout.match(/Rating: (\w+)/); + + return { + repository: `${owner}/${repo}`, + score: scoreMatch ? parseInt(scoreMatch[1]) : 0, + rating: ratingMatch ? ratingMatch[1] : 'Unknown', + rawOutput: stdout + }; + } catch (error) { + console.error(`āŒ Error evaluating ${owner}/${repo}:`, error.message); + return null; + } + } + + async sendToSlack(message) { + return new Promise((resolve, reject) => { + const data = JSON.stringify({ text: message }); + + const options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': data.length + } + }; + + const req = https.request(this.webhookUrl, options, (res) => { + if (res.statusCode === 200) { + resolve(); + } else { + reject(new Error(`Slack API error: ${res.statusCode}`)); + } + }); + + req.on('error', reject); + req.write(data); + req.end(); + }); + } + + formatSlackMessage(results) { + const emoji = { + 'Excellent': '🟢', + 'Good': '🟔', + 'Fair': '🟠', + 'Needs Work': 'šŸ”“', + 'Not Ready': '⚫' + }; + + let message = `*šŸ“Š Repository Health Report*\n\n`; + + results.forEach(result => { + const statusEmoji = emoji[result.rating] || 'ā“'; + message += `${statusEmoji} *${result.repository}*: ${result.score}% (${result.rating})\n`; + }); + + const avgScore = results.reduce((sum, r) => sum + r.score, 0) / results.length; + message += `\n*Average Score:* ${avgScore.toFixed(1)}%`; + + return message; + } + + async evaluateAndReport(repositories) { + console.log('šŸ”„ Evaluating repositories for Slack report...\n'); + + const results = []; + + for (const repo of repositories) { + const [owner, name] = repo.split('/'); + const result = await this.evaluateRepository(owner, name); + if (result) { + results.push(result); + } + + // Respect rate limits + await new Promise(resolve => setTimeout(resolve, 1000)); + } + + if (results.length > 0) { + const message = this.formatSlackMessage(results); + + try { + await this.sendToSlack(message); + console.log('āœ… Results sent to Slack successfully!'); + } catch (error) { + console.error('āŒ Failed to send to Slack:', error.message); + } + } + } +} + +// Example usage +const repositories = [ + 'facebook/react', + 'microsoft/vscode', + 'nodejs/node' +]; + +async function main() { + const webhookUrl = process.env.SLACK_WEBHOOK_URL; + const githubToken = process.env.GITHUB_TOKEN; + + if (!webhookUrl) { + console.error('Please set SLACK_WEBHOOK_URL environment variable'); + process.exit(1); + } + + const reporter = new SlackReporter(webhookUrl, githubToken); + await reporter.evaluateAndReport(repositories); +} + +if (require.main === module) { + main().catch(console.error); +} + +module.exports = { SlackReporter }; From 42c6d67b5ffb676e12f72322e4d39faa505a94b1 Mon Sep 17 00:00:00 2001 From: Nabil hassan mohamed ali <180658407+Nabilhassan12345@users.noreply.github.com> Date: Sat, 18 Oct 2025 16:50:32 +0300 Subject: [PATCH 2/2] feat: add examples directory with usage scripts - Add basic usage examples (evaluate-popular-repos, create-interactive, evaluate-with-token) - Add advanced examples (batch-evaluate, compare-repositories, export-results, check-org-repos) - Add integration examples (GitHub Actions, pre-commit hook, Slack integration) - Add sample data files and expected results - Add comprehensive README with usage instructions Closes #9