{"id":30277135,"url":"https://github.com/mona-actions/gh-repo-stats-plus","last_synced_at":"2026-04-02T17:08:06.234Z","repository":{"id":281864710,"uuid":"943920277","full_name":"mona-actions/gh-repo-stats-plus","owner":"mona-actions","description":"TypeScript version of repo-stats to collect statistics from GitHub repositories","archived":false,"fork":false,"pushed_at":"2026-03-26T17:46:50.000Z","size":778,"stargazers_count":8,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-26T20:35:59.303Z","etag":null,"topics":["gh-extension","github-api","migrations","repo-stats"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mona-actions.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-06T13:40:11.000Z","updated_at":"2026-03-26T17:46:24.000Z","dependencies_parsed_at":"2026-01-06T11:00:31.225Z","dependency_job_id":null,"html_url":"https://github.com/mona-actions/gh-repo-stats-plus","commit_stats":null,"previous_names":["scottluskcis/repo-stats-ts","mona-actions/gh-repo-stats-plus"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/mona-actions/gh-repo-stats-plus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mona-actions%2Fgh-repo-stats-plus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mona-actions%2Fgh-repo-stats-plus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mona-actions%2Fgh-repo-stats-plus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mona-actions%2Fgh-repo-stats-plus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mona-actions","download_url":"https://codeload.github.com/mona-actions/gh-repo-stats-plus/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mona-actions%2Fgh-repo-stats-plus/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31311193,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gh-extension","github-api","migrations","repo-stats"],"created_at":"2025-08-16T11:14:00.378Z","updated_at":"2026-04-02T17:08:06.228Z","avatar_url":"https://github.com/mona-actions.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gh-repo-stats-plus\n\nA GitHub CLI extension for gathering comprehensive repository statistics from GitHub organizations. This TypeScript implementation builds upon the solid foundation of [mona-actions/gh-repo-stats](https://github.com/mona-actions/gh-repo-stats), adding modern features and performance improvements for enterprise-scale repository analysis.\n\n## 🚀 Quick Start\n\n1. **Install the extension**:\n\n   ```bash\n   gh extension install mona-actions/gh-repo-stats-plus\n   ```\n\n2. **Authenticate with GitHub**:\n\n   ```bash\n   gh auth login\n   ```\n\n3. **Collect repository statistics**:\n\n   ```bash\n   gh repo-stats-plus repo-stats --org-name my-org\n   ```\n\nThe tool will generate a CSV file with comprehensive repository statistics in the `./output/` directory (or a custom directory you specify).\n\n## Key Features\n\nThis TypeScript rewrite offers several advantages:\n\n1. **Octokit SDK Integration**: Built on GitHub's official Octokit.js SDK, providing:\n   - Token renewal\n   - Built-in retries\n   - Rate limit handling\n   - Pagination\n   - GraphQL and REST API support\n\n2. **Streaming Processing with Async Generators**: Writes results incrementally as they're processed rather than collecting everything up front, resulting in better memory management and reliability.\n\n3. **State Persistence with Multi-Organization Support**: Saves processing state to organization-specific files (e.g., `last_known_state_\u003corg\u003e.json`) after each successful repository, storing the current cursor position and processed repositories. Each organization maintains its own isolated state, allowing sequential or parallel processing of multiple organizations without conflicts.\n\n4. **Resume Capability**: Can resume operations from the last saved state in case of interruptions or failures.\n\n5. **Smart Duplicate Avoidance**: Skips already processed repositories when resuming to prevent duplicates and save processing time.\n\n6. **Advanced Retry Logic**: Implements exponential backoff strategy for retries to gracefully handle rate limits and transient errors.\n\n7. **Enhanced Debugging**: Easier to debug and maintain with modern TypeScript development tools like VS Code.\n\n8. **Comprehensive Logging**: Detailed logs stored in log files for later review and troubleshooting.\n\n9. **Missing Repositories Detection**: Dedicated command to identify repositories that might have been missed during processing.\n\n10. **Configurable Output Directory**: Control where output files and state files are saved with the `--output-dir` option (defaults to `./output/`) for organized file management.\n\n11. **Project Stats Tracking**: Counts unique ProjectsV2 linked to repositories via issues and directly, based on [jcantosz/Count-repo-projects](https://github.com/jcantosz/Count-repo-projects).\n\n12. **Batch Processing**: Split large organizations into parallel batches using `--batch-size` and `--batch-index`, ideal for GitHub Actions matrix strategies. Includes a `combine-stats` command to merge batch results. See the [Batch Processing Guide](docs/batch-processing.md).\n\n13. **CSV Post-Processing**: Transform and standardize CSV data using configurable rules for pattern matching, value replacement, and indicator column generation. Based on [jcantosz/generate-repo-report/post-process](https://github.com/jcantosz/generate-repo-report/tree/main/post-process). See the [Post-Process Command Reference](docs/commands/post-process.md).\n\n14. **Rows-to-Columns Pivot**: Convert rows from an additional CSV (e.g., migration audit data) into new columns in a base CSV by matching rows and pivoting values. Based on [jcantosz/generate-repo-report/rows-to-columns](https://github.com/jcantosz/generate-repo-report/tree/main/rows-to-columns). See the [Rows-to-Columns Command Reference](docs/commands/rows-to-columns.md).\n\n## Technical Implementation\n\nThe extension is built using modern TypeScript patterns with:\n\n- **Async Generators** for streaming large datasets\n- **Retry Logic** with exponential backoff\n- **Rate Limit Handling** via GitHub Octokit SDK\n- **State Persistence** for resumable operations\n- **Comprehensive Logging** with Winston\n- **Type Safety** throughout the codebase\n- **On-demand Building** for clean installation without pre-built artifacts\n\n## Documentation\n\n| Guide                                               | Description                                   |\n| --------------------------------------------------- | --------------------------------------------- |\n| [Installation](docs/installation.md)                | Prerequisites and installation methods        |\n| [Usage Guide](docs/usage.md)                        | Authentication and usage examples             |\n| [Commands](docs/commands.md)                        | Complete command reference                    |\n| [LFS Sizing](docs/lfs-sizing.md)                    | Git LFS storage analysis per repo             |\n| [Development](docs/development.md)                  | Setup and development workflow                |\n| [Batch Processing](docs/batch-processing.md)        | Parallel batch processing with GitHub Actions |\n| [Post-Processing](docs/commands/post-process.md)    | CSV transformation with configurable rules    |\n| [Rows-to-Columns](docs/commands/rows-to-columns.md) | Pivot additional CSV rows into columns        |\n\n## Common Usage Examples\n\n### Basic Organization Analysis\n\n```bash\n# Generate repository statistics (output saved to ./output/ directory)\ngh repo-stats-plus repo-stats --org-name my-org\n```\n\n### Multiple Organizations\n\nProcess multiple organizations from a single file:\n\n```bash\n# Create an org list file (one org per line)\ncat \u003e orgs.txt \u003c\u003c EOF\nOrg1\nOrg2\nOrg3\nEOF\n\n# Process all organizations with a single command\ngh repo-stats-plus repo-stats --org-list orgs.txt\n\n# Add delays between organizations (default: 5 seconds)\ngh repo-stats-plus repo-stats --org-list orgs.txt --delay-between-orgs 10\n\n# Continue processing other orgs if one fails\ngh repo-stats-plus repo-stats --org-list orgs.txt --continue-on-error\n\n# Combine options\ngh repo-stats-plus repo-stats \\\n  --org-list orgs.txt \\\n  --delay-between-orgs 10 \\\n  --continue-on-error \\\n  --output-dir ./reports\n```\n\n\u003e [!NOTE]\n\u003e Organizations are processed strictly sequentially. This design choice is intentional to respect GitHub API rate limits and provide predictable resource usage. For large organization lists, consider the configurable delay between organizations and the estimated processing time logged at startup.\n\nOr process organizations individually:\n\n```bash\n# Process multiple organizations sequentially (each maintains its own state)\ngh repo-stats-plus repo-stats --org-name org1\ngh repo-stats-plus repo-stats --org-name org2\ngh repo-stats-plus repo-stats --org-name org3\n\n# Use custom output directory (state files are stored here too)\ngh repo-stats-plus repo-stats --org-name my-org --output-dir ./reports\n\n# Clean up state file after successful completion\ngh repo-stats-plus repo-stats --org-name my-org --clean-state\n```\n\n### Custom Output Directory\n\n```bash\n# Save output files to a custom directory\ngh repo-stats-plus repo-stats --org-name my-org --output-dir /path/to/my/reports\n\n# Use relative path from current directory\ngh repo-stats-plus repo-stats --org-name my-org --output-dir reports\n```\n\n### Resume Long-Running Collection\n\n```bash\ngh repo-stats-plus repo-stats --org-name my-org --resume-from-last-save\n```\n\n### High-Volume Processing with GitHub App\n\n```bash\ngh repo-stats-plus repo-stats \\\n  --org-name my-org \\\n  --app-id 12345 \\\n  --private-key-file app.pem \\\n  --app-installation-id 67890 \\\n  --output-dir /path/to/reports\n```\n\n### Find and Process Missing Data\n\n```bash\n# Check for missing repositories (looks for CSV in ./output/ by default)\ngh repo-stats-plus missing-repos --org-name my-org --file results.csv\n\n# Use custom output directory for missing repos check\ngh repo-stats-plus missing-repos \\\n  --org-name my-org \\\n  --file results.csv \\\n  --output-dir /path/to/reports\n\n# Auto-process missing repositories\ngh repo-stats-plus repo-stats --org-name my-org --auto-process-missing\n```\n\n### Batch Processing\n\nSplit a large organization into parallel batches (e.g., for GitHub Actions matrix jobs):\n\n```bash\n# Use a dedicated directory for this workflow/run to avoid mixing CSVs from other commands\nRUN_OUTPUT_DIR=\"output/run-$(date +%Y%m%d-%H%M%S)\"\nmkdir -p \"$RUN_OUTPUT_DIR\"\n\n# Process batch 0 of 50 repos each\ngh repo-stats-plus repo-stats \\\n  --org-name my-org \\\n  --batch-size 50 \\\n  --batch-index 0 \\\n  --output-dir \"$RUN_OUTPUT_DIR\"\n\n# Combine only this run's batch CSV files after all batches complete\ngh repo-stats-plus combine-stats \\\n  --files \"$RUN_OUTPUT_DIR\"/*.csv \\\n  --output-dir \"$RUN_OUTPUT_DIR\" \\\n  --output-file-name combined-stats.csv\n```\n\nSee the [Batch Processing Guide](docs/batch-processing.md) for complete GitHub Actions workflow examples.\n\n### Project Statistics\n\n```bash\n# Count ProjectsV2 linked to repositories via issues\ngh repo-stats-plus project-stats --org-name my-org\n\n# Process specific repos from a file\ngh repo-stats-plus project-stats --org-name my-org --repo-list repos.txt\n\n# Multiple organizations\ngh repo-stats-plus project-stats --org-list orgs.txt --continue-on-error\n\n# Resume interrupted processing\ngh repo-stats-plus project-stats --org-name my-org --resume-from-last-save\n```\n\n### Post-Processing\n\n```bash\n# Post-process a combined CSV with rules\ngh repo-stats-plus post-process \\\n  --input output/combined-stats.csv \\\n  --rules-file post-process.rules.json\n\n# Custom output file and directory\ngh repo-stats-plus post-process \\\n  --input output/combined-stats.csv \\\n  --rules-file rules.json \\\n  --output-file-name final-report.csv \\\n  --output-dir ./reports\n```\n\nSee the [Post-Process Command Reference](docs/commands/post-process.md) for rules configuration details and examples. A sample rules file is included at [`docs/examples/post-process.rules.json`](docs/examples/post-process.rules.json).\n\n### Rows-to-Columns\n\n```bash\n# Combine repo-stats with migration audit data\ngh repo-stats-plus rows-to-columns \\\n  --base-csv-file output/combined-stats.csv \\\n  --additional-csv-file output/migration-audit.csv \\\n  --header-column-keys type \\\n  --header-column-values message\n\n# Custom column mappings and output\ngh repo-stats-plus rows-to-columns \\\n  --base-csv-file output/stats.csv \\\n  --additional-csv-file output/audit.csv \\\n  --header-column-keys type \\\n  --header-column-values message \\\n  --base-csv-columns Org_Name,Repo_Name \\\n  --additional-csv-columns owner,name \\\n  --output-file-name final-report.csv\n```\n\nSee the [Rows-to-Columns Command Reference](docs/commands/rows-to-columns.md) for details on how values are parsed and examples.\n\n#### Repo Stats Options\n\n**Organization Selection** (one required):\n\n- `-o, --org-name \u003corg\u003e`: Process a single organization\n- `--org-list \u003cfile\u003e`: Process multiple organizations from a file (one org per line)\n\n**Multi-Organization Options**:\n\n- `--delay-between-orgs \u003cseconds\u003e`: Delay between processing organizations (Default: 5)\n- `--continue-on-error`: Continue processing other organizations if one fails\n\n**Authentication**:\n\n- `-t, --access-token \u003ctoken\u003e`: GitHub access token\n- `--app-id \u003cid\u003e`: GitHub App ID\n- `--private-key \u003ckey\u003e`: GitHub App private key\n- `--private-key-file \u003cfile\u003e`: Path to GitHub App private key file\n- `--app-installation-id \u003cid\u003e`: GitHub App installation ID\n\n**Processing Options**:\n\n- `--resume-from-last-save`: Resume from the last saved state\n- `--repo-list \u003cfile\u003e`: Path to file containing list of repositories to process (format: owner/repo_name)\n- `--auto-process-missing`: Automatically process any missing repositories when main processing is complete\n- `--clean-state`: Remove state file after successful completion\n\n**Batch Processing**:\n\n- `--batch-size \u003csize\u003e`: Number of repositories per batch\n- `--batch-index \u003cindex\u003e`: Zero-based index of the batch to process\n- `--batch-delay \u003cseconds\u003e`: Delay before starting a batch (multiplied by batch index to stagger parallel runs)\n\n**Configuration**:\n\n- `-u, --base-url \u003curl\u003e`: GitHub API base URL (Default: \u003chttps://api.github.com\u003e)\n- `--proxy-url \u003curl\u003e`: Proxy URL if required\n- `--output-dir \u003cdir\u003e`: Output directory for generated files (Default: ./output)\n- `-v, --verbose`: Enable verbose logging\n\n**Performance Tuning**:\n\n- `--page-size \u003csize\u003e`: Number of items per page (Default: 10)\n- `--extra-page-size \u003csize\u003e`: Extra page size (Default: 50)\n- `--rate-limit-check-interval \u003cseconds\u003e`: Interval for rate limit checks (Default: 60)\n- `--retry-max-attempts \u003cattempts\u003e`: Maximum number of retry attempts (Default: 3)\n- `--retry-initial-delay \u003cmilliseconds\u003e`: Initial delay for retry (Default: 1000)\n- `--retry-max-delay \u003cmilliseconds\u003e`: Maximum delay for retry (Default: 30000)\n- `--retry-backoff-factor \u003cfactor\u003e`: Backoff factor for retry delays (Default: 2)\n- `--retry-success-threshold \u003ccount\u003e`: Successful operations before resetting retry count (Default: 5)\n\n#### Project Stats Options\n\nThe `project-stats` command supports the same authentication, retry, multi-org, and processing options as `repo-stats` above, with these differences:\n\n- `--page-size \u003csize\u003e`: Number of issues per page (Default: 100)\n- No `--extra-page-size` or `--auto-process-missing` options\n\nSee the [Commands Reference](docs/commands.md) for the complete list of project-stats options.\n\n## Permissions\n\nThe permissions needed by repo-stats-ts depends on the authentication method:\n\n### For Personal Access Token (PAT)\n\n- `repo`: Full control of private repositories\n- `read:org`: Read organization membership\n- `read:project`: Read project information\n- `read:user`: Read user information\n\n### For GitHub App\n\nThe app requires `Read-only` permissions to the following:\n\n- Repository Administration\n- Repository Contents\n- Repository Issues\n- Repository Metadata\n- Repository Projects\n- Repository Pull requests\n- Organization Members\n\n## Output\n\nThe tool generates:\n\n1. A CSV file with repository statistics (or project statistics for the `project-stats` command)\n2. A `last_known_state.json` file with the current processing state\n3. Log files in the `logs/` directory\n\n### CSV Output Columns\n\nThe CSV output includes detailed information about each repository:\n\n- `Org_Name`: Organization login\n- `Repo_Name`: Repository name\n- `Is_Empty`: Whether the repository is empty\n- `Last_Push`: Date/time when a push was last made\n- `Last_Update`: Date/time when an update was last made\n- `isFork`: Whether the repository is a fork\n- `isArchived`: Whether the repository is archived\n- `isTemplate`: Whether the repository is a template repository\n- `Visibility`: Repository visibility (e.g., PUBLIC, PRIVATE, INTERNAL)\n- `Repo_Size_mb`: Size of the repository in megabytes\n- `Record_Count`: Total number of database records this repository represents\n- `Collaborator_Count`: Number of users who have contributed to this repository\n- `Protected_Branch_Count`: Number of branch protection rules on this repository\n- `Ruleset_Count`: Number of rulesets that apply to this repository, inclusive of active rulesets defined at the organization level\n- `PR_Review_Count`: Number of pull request reviews\n- `Milestone_Count`: Number of issue milestones\n- `Issue_Count`: Number of issues\n- `PR_Count`: Number of pull requests\n- `PR_Review_Comment_Count`: Number of pull request review comments\n- `Commit_Comment_Count`: Number of commit comments\n- `Issue_Comment_Count`: Number of issue comments\n- `Issue_Event_Count`: Number of issue events\n- `Release_Count`: Number of releases\n- `Project_Count`: Number of projects\n- `Branch_Count`: Number of branches\n- `Tag_Count`: Number of tags\n- `Discussion_Count`: Number of discussions\n- `Star_Count`: Number of stargazers\n- `Fork_Count`: Number of forks\n- `Watcher_Count`: Number of watchers\n- `Has_Wiki`: Whether the repository has wiki feature enabled\n- `Has_LFS`: Whether the repository has Git LFS tracking configured (see [LFS Detection Limitations](#lfs-detection-limitations))\n- `Default_Branch`: Name of the default branch\n- `Primary_Language`: Primary programming language of the repository\n- `Languages`: Semicolon-separated list of languages with usage percentages (e.g., `TypeScript:85.2%;JavaScript:14.8%`)\n- `License`: License identifier (SPDX ID or name)\n- `Topics`: Semicolon-separated list of repository topics\n- `Description`: Repository description\n- `Homepage_URL`: Repository homepage URL\n- `Auto_Merge_Allowed`: Whether auto-merge is enabled for pull requests\n- `Delete_Branch_On_Merge`: Whether branches are automatically deleted after merging\n- `Merge_Commit_Allowed`: Whether merge commits are allowed\n- `Squash_Merge_Allowed`: Whether squash merging is allowed\n- `Rebase_Merge_Allowed`: Whether rebase merging is allowed\n- `Full_URL`: Repository URL\n- `Migration_Issue`: Indicates whether the repository might have problems during migration due to:\n  - 60,000 or more objects being imported\n  - 1.5 GB or larger size on disk\n- `Created`: Date/time when the repository was created\n\n### LFS Detection Limitations\n\nThe `Has_LFS` column indicates whether the repository's `.gitattributes` file on the default branch contains `filter=lfs` entries. This is a lightweight check performed as part of the existing GraphQL query with no additional API calls.\n\n**Limitations to be aware of:**\n\n- **Default branch only**: The check reads `.gitattributes` from `HEAD` (the default branch). LFS tracking configured only on other branches will not be detected.\n- **Root `.gitattributes` only**: Nested `.gitattributes` files in subdirectories are not inspected.\n- **Detection, not sizing**: This column only indicates whether LFS is configured — it does not report the number or size of LFS objects.\n- **Empty repositories**: Empty repositories will always report `FALSE` since there is no `.gitattributes` file to read.\n\n**For actual LFS sizing**, use the standalone `script/lfs-size.sh` script to inspect individual repositories where `Has_LFS` is `TRUE`. This performs a shallow bare clone and reports per-file LFS sizes and totals. See the [LFS Sizing Guide](docs/lfs-sizing.md) for prerequisites and usage.\n\n### Project Stats CSV Output Columns\n\nThe `project-stats` command generates a separate CSV file with the following columns:\n\n- `Org_Name`: Organization login\n- `Repo_Name`: Repository name\n- `Issues_Linked_To_Projects`: Number of issues that have at least one linked ProjectV2\n- `Unique_Projects_Linked_By_Issues`: Count of distinct ProjectV2 items found across all issues\n- `Projects_Linked_To_Repo`: Total count of projects directly associated with the repository\n\n## 🛠️ Development Quick Start\n\n```bash\ngit clone https://github.com/mona-actions/gh-repo-stats-plus.git\ncd gh-repo-stats-plus\nnpm install\nnpm run build\nnpm test\n```\n\nSee the [Development Guide](docs/development.md) for detailed setup instructions.\n\n## Requirements\n\n- **Node.js** 20 or later\n- **GitHub CLI** (latest version recommended)\n- **GitHub Authentication** (personal token, GitHub App, or GitHub CLI)\n\n## Contributing\n\nWe welcome contributions! Please see our [Development Guide](docs/development.md) for setup instructions and guidelines.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmona-actions%2Fgh-repo-stats-plus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmona-actions%2Fgh-repo-stats-plus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmona-actions%2Fgh-repo-stats-plus/lists"}