mirror of
https://github.com/LukeHagar/usage-statistics.git
synced 2025-12-06 04:21:55 +00:00
Refactor Usage Statistics Tracker to support multiple package types, removing the config input in favor of specific inputs for npm, GitHub, PyPI, Homebrew, PowerShell, Postman, and Go. Update action.yml, README, and examples to reflect new input structure and enhance documentation.
This commit is contained in:
@@ -10,7 +10,13 @@ Add this to your GitHub Actions workflow:
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: 'production'
|
||||
npm-packages: 'lodash,axios'
|
||||
github-repositories: 'microsoft/vscode,facebook/react'
|
||||
pypi-packages: 'requests,numpy'
|
||||
homebrew-formulas: 'git,node'
|
||||
powershell-modules: 'PowerShellGet,PSReadLine'
|
||||
postman-collections: '12345,67890'
|
||||
go-modules: 'github.com/gin-gonic/gin,github.com/go-chi/chi'
|
||||
json-output-path: 'stats.json'
|
||||
update-readme: 'true'
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -37,7 +43,13 @@ jobs:
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: 'production'
|
||||
npm-packages: 'lodash,axios'
|
||||
github-repositories: 'microsoft/vscode,facebook/react'
|
||||
pypi-packages: 'requests,numpy'
|
||||
homebrew-formulas: 'git,node'
|
||||
powershell-modules: 'PowerShellGet,PSReadLine'
|
||||
postman-collections: '12345,67890'
|
||||
go-modules: 'github.com/gin-gonic/gin,github.com/go-chi/chi'
|
||||
json-output-path: 'stats.json'
|
||||
csv-output-path: 'stats.csv'
|
||||
report-output-path: 'docs/usage-report.md'
|
||||
@@ -68,19 +80,17 @@ Last updated: 2025-07-29T18:53:52.619Z
|
||||
- **Unique Packages**: 8
|
||||
- **Platforms Tracked**: npm, pypi, homebrew, go
|
||||
|
||||
### Platform Totals
|
||||
- **HOMEBREW**: 380,163 downloads (2 packages)
|
||||
- **NPM**: 34,311 downloads (2 packages)
|
||||
- **GO**: 33 downloads (2 packages)
|
||||
|
||||
### Top Packages
|
||||
1. **node** (homebrew) - 226,882 downloads
|
||||
2. **git** (homebrew) - 153,281 downloads
|
||||
3. **axios** (npm) - 18,397 downloads
|
||||
4. **lodash** (npm) - 15,914 downloads
|
||||
5. **github.com/go-chi/chi** (go) - 33 downloads
|
||||
|
||||
### Recent Activity
|
||||
- **node** (homebrew) - 226,882 downloads on 7/29/2025
|
||||
- **git** (homebrew) - 153,281 downloads on 7/29/2025
|
||||
- **axios** (npm) - 722 downloads on 7/29/2025
|
||||
- **lodash** (npm) - 857 downloads on 7/29/2025
|
||||
- **axios** (npm) - 936 downloads on 7/28/2025
|
||||
<!-- USAGE_STATS_END -->
|
||||
```
|
||||
|
||||
|
||||
71
README.md
71
README.md
@@ -20,7 +20,13 @@ A comprehensive GitHub Action for tracking download statistics across multiple p
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: 'production'
|
||||
npm-packages: 'lodash,axios'
|
||||
github-repositories: 'microsoft/vscode,facebook/react'
|
||||
pypi-packages: 'requests,numpy'
|
||||
homebrew-formulas: 'git,node'
|
||||
powershell-modules: 'PowerShellGet,PSReadLine'
|
||||
postman-collections: '12345,67890'
|
||||
go-modules: 'github.com/gin-gonic/gin,github.com/go-chi/chi'
|
||||
json-output-path: 'stats.json'
|
||||
csv-output-path: 'stats.csv'
|
||||
report-output-path: 'report.md'
|
||||
@@ -50,7 +56,13 @@ bun test
|
||||
|
||||
| Parameter | Description | Required | Default |
|
||||
|-----------|-------------|----------|---------|
|
||||
| `config` | Configuration mode or JSON | No | `production` |
|
||||
| `npm-packages` | Comma-separated list of NPM packages | No | (empty) |
|
||||
| `github-repositories` | Comma-separated list of GitHub repos (owner/repo) | No | (empty) |
|
||||
| `pypi-packages` | Comma-separated list of PyPI packages | No | (empty) |
|
||||
| `homebrew-formulas` | Comma-separated list of Homebrew formulas | No | (empty) |
|
||||
| `powershell-modules` | Comma-separated list of PowerShell modules | No | (empty) |
|
||||
| `postman-collections` | Comma-separated list of Postman collection IDs | No | (empty) |
|
||||
| `go-modules` | Comma-separated list of Go modules | No | (empty) |
|
||||
| `json-output-path` | Path for JSON output | No | `stats.json` |
|
||||
| `csv-output-path` | Path for CSV output | No | (empty) |
|
||||
| `report-output-path` | Path for human-readable report | No | (empty) |
|
||||
@@ -61,30 +73,36 @@ bun test
|
||||
| `commit-message` | Commit message for changes | No | `chore: update usage statistics [skip ci]` |
|
||||
| `preview-mode` | Run with mock data | No | `false` |
|
||||
|
||||
### Configuration Modes
|
||||
### Configuration Examples
|
||||
|
||||
#### Production Mode
|
||||
#### NPM Packages Only
|
||||
```yaml
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: 'production'
|
||||
npm-packages: 'lodash,axios,react'
|
||||
```
|
||||
|
||||
#### Development Mode
|
||||
#### GitHub Repositories Only
|
||||
```yaml
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: 'development'
|
||||
github-repositories: 'microsoft/vscode,facebook/react,vercel/next.js'
|
||||
```
|
||||
|
||||
#### Custom JSON Configuration
|
||||
#### Mixed Platform Configuration
|
||||
```yaml
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: '{"npmPackages": ["lodash", "axios"], "githubRepositories": ["microsoft/vscode"]}'
|
||||
npm-packages: 'lodash,axios'
|
||||
github-repositories: 'microsoft/vscode,facebook/react'
|
||||
pypi-packages: 'requests,numpy'
|
||||
homebrew-formulas: 'git,node'
|
||||
powershell-modules: 'PowerShellGet,PSReadLine'
|
||||
postman-collections: '12345,67890'
|
||||
go-modules: 'github.com/gin-gonic/gin,github.com/go-chi/chi'
|
||||
```
|
||||
|
||||
### Outputs
|
||||
@@ -121,7 +139,13 @@ jobs:
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: 'production'
|
||||
npm-packages: 'lodash,axios'
|
||||
github-repositories: 'microsoft/vscode,facebook/react'
|
||||
pypi-packages: 'requests,numpy'
|
||||
homebrew-formulas: 'git,node'
|
||||
powershell-modules: 'PowerShellGet,PSReadLine'
|
||||
postman-collections: '12345,67890'
|
||||
go-modules: 'github.com/gin-gonic/gin,github.com/go-chi/chi'
|
||||
json-output-path: 'stats.json'
|
||||
update-readme: 'true'
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -141,7 +165,13 @@ jobs:
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: 'production'
|
||||
npm-packages: 'lodash,axios,react'
|
||||
github-repositories: 'microsoft/vscode,facebook/react'
|
||||
pypi-packages: 'requests,numpy'
|
||||
homebrew-formulas: 'git,node'
|
||||
powershell-modules: 'PowerShellGet,PSReadLine'
|
||||
postman-collections: '12345,67890'
|
||||
go-modules: 'github.com/gin-gonic/gin,github.com/go-chi/chi'
|
||||
json-output-path: 'data/stats.json'
|
||||
csv-output-path: 'data/stats.csv'
|
||||
report-output-path: 'docs/usage-report.md'
|
||||
@@ -172,7 +202,11 @@ jobs:
|
||||
id: stats
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: 'production'
|
||||
npm-packages: 'lodash,axios'
|
||||
github-repositories: 'microsoft/vscode,facebook/react'
|
||||
powershell-modules: 'PowerShellGet'
|
||||
postman-collections: '12345'
|
||||
go-modules: 'github.com/gin-gonic/gin'
|
||||
json-output-path: 'stats.json'
|
||||
|
||||
- name: Use Statistics Data
|
||||
@@ -198,19 +232,17 @@ Last updated: 2025-07-29T18:53:52.619Z
|
||||
- **Unique Packages**: 8
|
||||
- **Platforms Tracked**: npm, pypi, homebrew, go
|
||||
|
||||
### Platform Totals
|
||||
- **HOMEBREW**: 380,163 downloads (2 packages)
|
||||
- **NPM**: 34,311 downloads (2 packages)
|
||||
- **GO**: 33 downloads (2 packages)
|
||||
|
||||
### Top Packages
|
||||
1. **node** (homebrew) - 226,882 downloads
|
||||
2. **git** (homebrew) - 153,281 downloads
|
||||
3. **axios** (npm) - 18,397 downloads
|
||||
4. **lodash** (npm) - 15,914 downloads
|
||||
5. **github.com/go-chi/chi** (go) - 33 downloads
|
||||
|
||||
### Recent Activity
|
||||
- **node** (homebrew) - 226,882 downloads on 7/29/2025
|
||||
- **git** (homebrew) - 153,281 downloads on 7/29/2025
|
||||
- **axios** (npm) - 722 downloads on 7/29/2025
|
||||
- **lodash** (npm) - 857 downloads on 7/29/2025
|
||||
- **axios** (npm) - 936 downloads on 7/28/2025
|
||||
<!-- USAGE_STATS_END -->
|
||||
```
|
||||
|
||||
@@ -246,7 +278,6 @@ usage-statistics/
|
||||
├── src/
|
||||
│ ├── index.ts # Main library entry point
|
||||
│ ├── action.ts # GitHub Action entry point
|
||||
│ ├── config.ts # Configuration management
|
||||
│ ├── aggregator.ts # Statistics aggregation
|
||||
│ ├── types/ # TypeScript type definitions
|
||||
│ ├── trackers/ # Platform-specific trackers
|
||||
|
||||
46
action.yml
46
action.yml
@@ -3,11 +3,47 @@ description: 'Track download statistics across multiple platforms (NPM, GitHub,
|
||||
author: 'LukeHagar'
|
||||
|
||||
inputs:
|
||||
# Configuration
|
||||
config:
|
||||
description: 'Configuration for tracking (development, production, test, or custom JSON)'
|
||||
# NPM Configuration
|
||||
npm-packages:
|
||||
description: 'Comma-separated list of NPM packages to track'
|
||||
required: false
|
||||
default: 'production'
|
||||
default: ''
|
||||
|
||||
# GitHub Configuration
|
||||
github-repositories:
|
||||
description: 'Comma-separated list of GitHub repositories (format: owner/repo)'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
# PyPI Configuration
|
||||
pypi-packages:
|
||||
description: 'Comma-separated list of PyPI packages to track'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
# Homebrew Configuration
|
||||
homebrew-formulas:
|
||||
description: 'Comma-separated list of Homebrew formulas to track'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
# PowerShell Configuration
|
||||
powershell-modules:
|
||||
description: 'Comma-separated list of PowerShell modules to track'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
# Postman Configuration
|
||||
postman-collections:
|
||||
description: 'Comma-separated list of Postman collection IDs to track'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
# Go Configuration
|
||||
go-modules:
|
||||
description: 'Comma-separated list of Go modules to track'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
# Output paths
|
||||
json-output-path:
|
||||
@@ -80,4 +116,4 @@ outputs:
|
||||
|
||||
runs:
|
||||
using: 'node20'
|
||||
main: 'dist/index.js'
|
||||
main: 'dist/action.js'
|
||||
@@ -16,7 +16,13 @@ jobs:
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
config: 'production'
|
||||
npm-packages: 'lodash,axios'
|
||||
github-repositories: 'microsoft/vscode,facebook/react'
|
||||
pypi-packages: 'requests,numpy'
|
||||
homebrew-formulas: 'git,node'
|
||||
powershell-modules: 'PowerShellGet,PSReadLine'
|
||||
postman-collections: '12345,67890'
|
||||
go-modules: 'github.com/gin-gonic/gin,github.com/go-chi/chi'
|
||||
json-output-path: 'stats.json'
|
||||
csv-output-path: 'stats.csv'
|
||||
report-output-path: 'docs/usage-report.md'
|
||||
|
||||
59
examples/input-based-config.yml
Normal file
59
examples/input-based-config.yml
Normal file
@@ -0,0 +1,59 @@
|
||||
name: Usage Statistics with Input-Based Configuration
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Daily at midnight
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update-stats:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Usage Statistics Tracker
|
||||
uses: LukeHagar/usage-statistics@v1
|
||||
with:
|
||||
# NPM packages to track
|
||||
npm-packages: 'lodash,axios,react,vue'
|
||||
|
||||
# GitHub repositories to track
|
||||
github-repositories: 'microsoft/vscode,facebook/react,vercel/next.js'
|
||||
|
||||
# PyPI packages to track
|
||||
pypi-packages: 'requests,numpy,pandas'
|
||||
|
||||
# Homebrew formulas to track
|
||||
homebrew-formulas: 'git,node,postgresql'
|
||||
|
||||
# PowerShell modules to track
|
||||
powershell-modules: 'PowerShellGet,PSReadLine'
|
||||
|
||||
# Go modules to track
|
||||
go-modules: 'github.com/gin-gonic/gin,github.com/go-chi/chi'
|
||||
|
||||
# Output configuration
|
||||
json-output-path: 'data/stats.json'
|
||||
csv-output-path: 'data/stats.csv'
|
||||
report-output-path: 'docs/usage-report.md'
|
||||
|
||||
# README integration
|
||||
update-readme: 'true'
|
||||
readme-path: 'README.md'
|
||||
|
||||
# API tokens
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
postman-api-key: ${{ secrets.POSTMAN_API_KEY }}
|
||||
|
||||
# Commit settings
|
||||
commit-message: 'feat: update usage statistics with detailed report'
|
||||
|
||||
- name: Commit and push changes
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add data/stats.json data/stats.csv docs/usage-report.md README.md
|
||||
git commit -m "chore: update usage statistics [skip ci]" || echo "No changes to commit"
|
||||
git push
|
||||
@@ -3,12 +3,19 @@ import * as core from '@actions/core';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import { UsageStatisticsManager } from './index';
|
||||
import { getConfig, validateConfig } from './config';
|
||||
import type { TrackingConfig } from './types';
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
// Get inputs
|
||||
const configInput = core.getInput('config');
|
||||
const npmPackages = core.getInput('npm-packages');
|
||||
const githubRepositories = core.getInput('github-repositories');
|
||||
const pypiPackages = core.getInput('pypi-packages');
|
||||
const homebrewFormulas = core.getInput('homebrew-formulas');
|
||||
const powershellModules = core.getInput('powershell-modules');
|
||||
const postmanCollections = core.getInput('postman-collections');
|
||||
const goModules = core.getInput('go-modules');
|
||||
|
||||
const jsonOutputPath = core.getInput('json-output-path');
|
||||
const csvOutputPath = core.getInput('csv-output-path');
|
||||
const reportOutputPath = core.getInput('report-output-path');
|
||||
@@ -27,31 +34,35 @@ async function run() {
|
||||
process.env.POSTMAN_API_KEY = postmanApiKey;
|
||||
}
|
||||
|
||||
// Get configuration
|
||||
let trackingConfig;
|
||||
if (configInput === 'development' || configInput === 'production' || configInput === 'test') {
|
||||
trackingConfig = getConfig(configInput as 'development' | 'production' | 'test');
|
||||
} else {
|
||||
// Try to parse as JSON
|
||||
try {
|
||||
trackingConfig = JSON.parse(configInput);
|
||||
} catch (error) {
|
||||
core.setFailed(`Invalid config input: ${configInput}. Must be 'development', 'production', 'test', or valid JSON.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Build configuration from inputs
|
||||
const trackingConfig: TrackingConfig = {
|
||||
enableLogging: true,
|
||||
updateInterval: 60 * 60 * 1000, // 1 hour
|
||||
npmPackages: npmPackages ? npmPackages.split(',').map(p => p.trim()).filter(p => p) : [],
|
||||
githubRepos: githubRepositories ? githubRepositories.split(',').map(r => r.trim()).filter(r => r) : [],
|
||||
pythonPackages: pypiPackages ? pypiPackages.split(',').map(p => p.trim()).filter(p => p) : [],
|
||||
homebrewPackages: homebrewFormulas ? homebrewFormulas.split(',').map(f => f.trim()).filter(f => f) : [],
|
||||
powershellModules: powershellModules ? powershellModules.split(',').map(m => m.trim()).filter(m => m) : [],
|
||||
postmanCollections: postmanCollections ? postmanCollections.split(',').map(c => c.trim()).filter(c => c) : [],
|
||||
goModules: goModules ? goModules.split(',').map(m => m.trim()).filter(m => m) : []
|
||||
};
|
||||
|
||||
// Validate configuration
|
||||
try {
|
||||
validateConfig(trackingConfig);
|
||||
} catch (error) {
|
||||
core.setFailed(`Configuration validation failed: ${error}`);
|
||||
return;
|
||||
// Validate that at least one platform has packages configured
|
||||
const totalPackages = (trackingConfig.npmPackages?.length || 0) +
|
||||
(trackingConfig.githubRepos?.length || 0) +
|
||||
(trackingConfig.pythonPackages?.length || 0) +
|
||||
(trackingConfig.homebrewPackages?.length || 0) +
|
||||
(trackingConfig.powershellModules?.length || 0) +
|
||||
(trackingConfig.postmanCollections?.length || 0) +
|
||||
(trackingConfig.goModules?.length || 0);
|
||||
|
||||
if (totalPackages === 0 && !previewMode) {
|
||||
core.warning('No packages configured for tracking. Consider adding packages to track or enabling preview mode.');
|
||||
}
|
||||
|
||||
// Create manager
|
||||
const manager = new UsageStatisticsManager(trackingConfig);
|
||||
|
||||
|
||||
// Generate report
|
||||
let report;
|
||||
if (previewMode) {
|
||||
@@ -61,10 +72,10 @@ async function run() {
|
||||
core.info('📊 Generating comprehensive usage statistics report...');
|
||||
report = await manager.generateComprehensiveReport();
|
||||
}
|
||||
|
||||
|
||||
// Display report
|
||||
await manager.displayReport(report);
|
||||
|
||||
|
||||
// Write JSON output
|
||||
if (jsonOutputPath) {
|
||||
const jsonContent = JSON.stringify(report, null, 2);
|
||||
@@ -112,36 +123,28 @@ async function run() {
|
||||
}
|
||||
|
||||
async function generateHumanReadableReport(report: any): Promise<string> {
|
||||
let content = '# Usage Statistics Report\n\n';
|
||||
let content = '# Usage Statistics Summary\n\n';
|
||||
content += `Generated on: ${new Date().toISOString()}\n\n`;
|
||||
|
||||
// Summary
|
||||
content += '## Summary\n\n';
|
||||
// Overall Summary
|
||||
content += '## Overall Summary\n\n';
|
||||
content += `- **Total Downloads**: ${report.totalDownloads.toLocaleString()}\n`;
|
||||
content += `- **Unique Packages**: ${report.uniquePackages}\n`;
|
||||
content += `- **Platforms Tracked**: ${report.platforms.join(', ')}\n\n`;
|
||||
|
||||
// Platform Breakdown
|
||||
content += '## Platform Breakdown\n\n';
|
||||
// Platform Totals
|
||||
content += '## Platform Totals\n\n';
|
||||
for (const [platform, data] of Object.entries(report.platformBreakdown)) {
|
||||
content += `### ${platform.toUpperCase()}\n`;
|
||||
content += `- Downloads: ${data.totalDownloads.toLocaleString()}\n`;
|
||||
content += `- Packages: ${data.uniquePackages}\n`;
|
||||
content += `- Package List: ${data.packages.join(', ')}\n\n`;
|
||||
content += `- **Downloads**: ${data.totalDownloads.toLocaleString()}\n`;
|
||||
content += `- **Packages**: ${data.uniquePackages}\n\n`;
|
||||
}
|
||||
|
||||
// Top Packages
|
||||
content += '## Top Packages\n\n';
|
||||
report.topPackages.slice(0, 10).forEach((pkg: any, index: number) => {
|
||||
// Package Rankings
|
||||
content += '## Package Rankings\n\n';
|
||||
report.topPackages.forEach((pkg: any, index: number) => {
|
||||
content += `${index + 1}. **${pkg.name}** (${pkg.platform}) - ${pkg.downloads.toLocaleString()} downloads\n`;
|
||||
});
|
||||
content += '\n';
|
||||
|
||||
// Recent Activity
|
||||
content += '## Recent Activity\n\n';
|
||||
report.recentActivity.slice(0, 5).forEach((activity: any) => {
|
||||
content += `- **${activity.packageName}** (${activity.platform}) - ${activity.downloads.toLocaleString()} downloads on ${activity.timestamp.toLocaleDateString()}\n`;
|
||||
});
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -163,14 +166,14 @@ Last updated: ${new Date().toISOString()}
|
||||
- **Unique Packages**: ${report.uniquePackages}
|
||||
- **Platforms Tracked**: ${report.platforms.join(', ')}
|
||||
|
||||
### Top Packages
|
||||
${report.topPackages.slice(0, 10).map((pkg: any, index: number) =>
|
||||
`${index + 1}. **${pkg.name}** (${pkg.platform}) - ${pkg.downloads.toLocaleString()} downloads`
|
||||
### Platform Totals
|
||||
${Object.entries(report.platformBreakdown).map(([platform, data]: [string, any]) =>
|
||||
`- **${platform.toUpperCase()}**: ${data.totalDownloads.toLocaleString()} downloads (${data.uniquePackages} packages)`
|
||||
).join('\n')}
|
||||
|
||||
### Recent Activity
|
||||
${report.recentActivity.slice(0, 5).map((activity: any) =>
|
||||
`- **${activity.packageName}** (${activity.platform}) - ${activity.downloads.toLocaleString()} downloads on ${activity.timestamp.toLocaleDateString()}`
|
||||
### Top Packages
|
||||
${report.topPackages.map((pkg: any, index: number) =>
|
||||
`${index + 1}. **${pkg.name}** (${pkg.platform}) - ${pkg.downloads.toLocaleString()} downloads`
|
||||
).join('\n')}
|
||||
`;
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ export interface AggregatedStats {
|
||||
totalDownloads: number;
|
||||
uniquePackages: number;
|
||||
platforms: string[];
|
||||
timeRange: { start: Date; end: Date } | null;
|
||||
platformBreakdown: Record<string, {
|
||||
totalDownloads: number;
|
||||
uniquePackages: number;
|
||||
@@ -28,12 +27,6 @@ export interface AggregatedStats {
|
||||
platform: string;
|
||||
downloads: number;
|
||||
}>;
|
||||
recentActivity: Array<{
|
||||
packageName: string;
|
||||
platform: string;
|
||||
downloads: number;
|
||||
timestamp: Date;
|
||||
}>;
|
||||
}
|
||||
|
||||
export class DownloadStatsAggregator implements DownloadStatsAggregator {
|
||||
@@ -64,17 +57,10 @@ export class DownloadStatsAggregator implements DownloadStatsAggregator {
|
||||
}> = {};
|
||||
|
||||
const packageMap = new Map<string, { downloads: number; platform: string }>();
|
||||
const recentActivity: Array<{
|
||||
packageName: string;
|
||||
platform: string;
|
||||
downloads: number;
|
||||
timestamp: Date;
|
||||
}> = [];
|
||||
|
||||
let totalDownloads = 0;
|
||||
let uniquePackages = 0;
|
||||
const platforms = new Set<string>();
|
||||
const timeRange = { start: new Date(), end: new Date(0) };
|
||||
|
||||
// Process each stat
|
||||
for (const stat of stats) {
|
||||
@@ -104,27 +90,8 @@ export class DownloadStatsAggregator implements DownloadStatsAggregator {
|
||||
platformBreakdown[stat.platform].packages.push(stat.packageName);
|
||||
platformBreakdown[stat.platform].uniquePackages++;
|
||||
}
|
||||
|
||||
// Track recent activity
|
||||
recentActivity.push({
|
||||
packageName: stat.packageName,
|
||||
platform: stat.platform,
|
||||
downloads: stat.downloadCount,
|
||||
timestamp: stat.timestamp
|
||||
});
|
||||
|
||||
// Update time range
|
||||
if (stat.timestamp < timeRange.start) {
|
||||
timeRange.start = stat.timestamp;
|
||||
}
|
||||
if (stat.timestamp > timeRange.end) {
|
||||
timeRange.end = stat.timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort recent activity by timestamp
|
||||
recentActivity.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
||||
|
||||
// Get top packages
|
||||
const topPackages = Array.from(packageMap.entries())
|
||||
.map(([key, data]) => ({
|
||||
@@ -132,17 +99,14 @@ export class DownloadStatsAggregator implements DownloadStatsAggregator {
|
||||
platform: data.platform,
|
||||
downloads: data.downloads
|
||||
}))
|
||||
.sort((a, b) => b.downloads - a.downloads)
|
||||
.slice(0, 10);
|
||||
.sort((a, b) => b.downloads - a.downloads);
|
||||
|
||||
return {
|
||||
totalDownloads,
|
||||
uniquePackages,
|
||||
platforms: Array.from(platforms),
|
||||
timeRange: timeRange.start < timeRange.end ? timeRange : null,
|
||||
platformBreakdown,
|
||||
topPackages,
|
||||
recentActivity: recentActivity.slice(0, 20)
|
||||
topPackages
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
112
src/config.ts
112
src/config.ts
@@ -1,112 +0,0 @@
|
||||
/**
|
||||
* Configuration for usage statistics tracking
|
||||
* Customize this file to track your specific packages and tools
|
||||
*/
|
||||
|
||||
import type { TrackingConfig } from './types';
|
||||
|
||||
export const defaultConfig: TrackingConfig = {
|
||||
// NPM packages - Add your NPM package names here
|
||||
npmPackages: [
|
||||
'lodash',
|
||||
'axios'
|
||||
],
|
||||
|
||||
// GitHub repositories - Format: 'owner/repo'
|
||||
githubRepos: [
|
||||
'microsoft/vscode',
|
||||
'facebook/react'
|
||||
],
|
||||
|
||||
// PyPI packages - Add your Python package names here
|
||||
pythonPackages: [
|
||||
'requests',
|
||||
'numpy'
|
||||
],
|
||||
|
||||
// Homebrew formulae - Add your Homebrew package names here
|
||||
homebrewPackages: [
|
||||
'git',
|
||||
'node'
|
||||
],
|
||||
|
||||
// PowerShell modules - Add your PowerShell module names here
|
||||
powershellModules: [
|
||||
'PowerShellGet'
|
||||
],
|
||||
|
||||
// Postman collections - Add your Postman collection IDs here
|
||||
postmanCollections: [
|
||||
// Note: These are example IDs - replace with real collection IDs
|
||||
// For testing, we'll leave these empty to avoid errors
|
||||
],
|
||||
|
||||
// Go modules - Add your Go module paths here
|
||||
goModules: [
|
||||
'github.com/gin-gonic/gin',
|
||||
'github.com/go-chi/chi'
|
||||
],
|
||||
|
||||
// Update interval in milliseconds (default: 1 hour)
|
||||
updateInterval: 60 * 60 * 1000,
|
||||
|
||||
// Enable detailed logging
|
||||
enableLogging: true
|
||||
};
|
||||
|
||||
// Test configuration with minimal packages
|
||||
export const testConfig: TrackingConfig = {
|
||||
npmPackages: ['lodash'],
|
||||
githubRepos: [],
|
||||
pythonPackages: ['requests'],
|
||||
homebrewPackages: ['git'],
|
||||
powershellModules: [],
|
||||
postmanCollections: [],
|
||||
goModules: [],
|
||||
updateInterval: 60 * 60 * 1000,
|
||||
enableLogging: false
|
||||
};
|
||||
|
||||
// Environment-specific configurations
|
||||
export const developmentConfig: TrackingConfig = {
|
||||
...defaultConfig,
|
||||
enableLogging: true,
|
||||
updateInterval: 5 * 60 * 1000, // 5 minutes for development
|
||||
};
|
||||
|
||||
export const productionConfig: TrackingConfig = {
|
||||
...defaultConfig,
|
||||
enableLogging: false,
|
||||
updateInterval: 60 * 60 * 1000, // 1 hour for production
|
||||
};
|
||||
|
||||
// Helper function to get configuration based on environment
|
||||
export function getConfig(environment: 'development' | 'production' | 'default' | 'test' = 'default'): TrackingConfig {
|
||||
switch (environment) {
|
||||
case 'development':
|
||||
return developmentConfig;
|
||||
case 'production':
|
||||
return productionConfig;
|
||||
case 'test':
|
||||
return testConfig;
|
||||
default:
|
||||
return defaultConfig;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to validate configuration
|
||||
export function validateConfig(config: TrackingConfig): string[] {
|
||||
const errors: string[] = [];
|
||||
|
||||
if (!config.npmPackages && !config.githubRepos && !config.pythonPackages &&
|
||||
!config.homebrewPackages && !config.powershellModules &&
|
||||
!config.postmanCollections && !config.goModules) {
|
||||
errors.push('No packages configured for tracking. Please add packages to at least one platform.');
|
||||
}
|
||||
|
||||
if (config.updateInterval && config.updateInterval < 60000) {
|
||||
errors.push('Update interval should be at least 60 seconds to avoid rate limiting.');
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
@@ -1,12 +1,22 @@
|
||||
import { describe, it, expect, beforeEach } from "bun:test";
|
||||
import { UsageStatisticsManager } from "./index";
|
||||
import { getConfig } from "./config";
|
||||
import type { TrackingConfig } from "./types";
|
||||
|
||||
describe("UsageStatisticsManager", () => {
|
||||
let manager: UsageStatisticsManager;
|
||||
|
||||
beforeEach(() => {
|
||||
const config = getConfig('test');
|
||||
const config: TrackingConfig = {
|
||||
enableLogging: true,
|
||||
updateInterval: 60 * 60 * 1000,
|
||||
npmPackages: ['lodash', 'axios'],
|
||||
githubRepos: ['microsoft/vscode', 'facebook/react'],
|
||||
pythonPackages: ['requests', 'numpy'],
|
||||
homebrewPackages: ['git', 'node'],
|
||||
powershellModules: ['PowerShellGet'],
|
||||
postmanCollections: [],
|
||||
goModules: ['github.com/gin-gonic/gin', 'github.com/go-chi/chi']
|
||||
};
|
||||
manager = new UsageStatisticsManager(config);
|
||||
});
|
||||
|
||||
@@ -19,7 +29,7 @@ describe("UsageStatisticsManager", () => {
|
||||
expect(report.uniquePackages).toBeGreaterThanOrEqual(0);
|
||||
expect(Array.isArray(report.platforms)).toBe(true);
|
||||
expect(Array.isArray(report.topPackages)).toBe(true);
|
||||
expect(Array.isArray(report.recentActivity)).toBe(true);
|
||||
expect(report.topPackages.length).toBeGreaterThan(0);
|
||||
expect(typeof report.platformBreakdown).toBe('object');
|
||||
}, 30000); // 30 second timeout
|
||||
});
|
||||
@@ -72,27 +82,23 @@ describe("UsageStatisticsManager", () => {
|
||||
});
|
||||
|
||||
describe("Configuration", () => {
|
||||
it("should load development config", () => {
|
||||
const config = getConfig('development');
|
||||
|
||||
expect(config).toBeDefined();
|
||||
expect(config.enableLogging).toBe(true);
|
||||
expect(config.updateInterval).toBe(5 * 60 * 1000); // 5 minutes
|
||||
});
|
||||
|
||||
it("should load production config", () => {
|
||||
const config = getConfig('production');
|
||||
|
||||
expect(config).toBeDefined();
|
||||
expect(config.enableLogging).toBe(false);
|
||||
expect(config.updateInterval).toBe(60 * 60 * 1000); // 1 hour
|
||||
});
|
||||
|
||||
it("should load default config", () => {
|
||||
const config = getConfig('default');
|
||||
it("should create valid config", () => {
|
||||
const config: TrackingConfig = {
|
||||
enableLogging: true,
|
||||
updateInterval: 60 * 60 * 1000,
|
||||
npmPackages: ['lodash', 'axios'],
|
||||
githubRepos: ['microsoft/vscode'],
|
||||
pythonPackages: ['requests'],
|
||||
homebrewPackages: ['git'],
|
||||
powershellModules: ['PowerShellGet'],
|
||||
postmanCollections: [],
|
||||
goModules: ['github.com/gin-gonic/gin']
|
||||
};
|
||||
|
||||
expect(config).toBeDefined();
|
||||
expect(config.enableLogging).toBe(true);
|
||||
expect(config.updateInterval).toBe(60 * 60 * 1000); // 1 hour
|
||||
expect(config.npmPackages).toContain('lodash');
|
||||
expect(config.githubRepos).toContain('microsoft/vscode');
|
||||
});
|
||||
});
|
||||
96
src/index.ts
96
src/index.ts
@@ -2,7 +2,6 @@
|
||||
import type { TrackingConfig } from './types';
|
||||
import { DownloadStatsAggregator } from './aggregator';
|
||||
import type { AggregatedStats } from './aggregator';
|
||||
import { getConfig, validateConfig } from './config';
|
||||
import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import { execSync } from 'node:child_process';
|
||||
@@ -45,14 +44,9 @@ Last updated: ${new Date().toISOString()}
|
||||
- **Platforms Tracked**: ${stats.platforms.join(', ')}
|
||||
|
||||
### Top Packages
|
||||
${stats.topPackages.slice(0, 10).map((pkg, index) =>
|
||||
${stats.topPackages.map((pkg, index) =>
|
||||
`${index + 1}. **${pkg.name}** (${pkg.platform}) - ${pkg.downloads.toLocaleString()} downloads`
|
||||
).join('\n')}
|
||||
|
||||
### Recent Activity
|
||||
${stats.recentActivity.slice(0, 5).map(activity =>
|
||||
`- **${activity.packageName}** (${activity.platform}) - ${activity.downloads.toLocaleString()} downloads on ${activity.timestamp.toLocaleDateString()}`
|
||||
).join('\n')}
|
||||
`;
|
||||
|
||||
const startMarker = readmeContent.indexOf(STATS_MARKER_START);
|
||||
@@ -80,8 +74,6 @@ async function gitCommitAndPush(files: string[], message: string) {
|
||||
execSync(`git push`);
|
||||
}
|
||||
|
||||
const trackingConfig: TrackingConfig = getConfig(process.env.NODE_ENV as 'development' | 'production' || 'default');
|
||||
|
||||
class UsageStatisticsManager {
|
||||
private aggregator: DownloadStatsAggregator;
|
||||
private lastUpdateTime: Date | null = null;
|
||||
@@ -110,9 +102,9 @@ class UsageStatisticsManager {
|
||||
const report = await this.generateComprehensiveReport();
|
||||
|
||||
if (format === 'csv') {
|
||||
const csvHeader = 'Platform,Package,Downloads,Last Updated\n';
|
||||
const csvHeader = 'Platform,Package,Downloads\n';
|
||||
const csvRows = report.topPackages.map(pkg =>
|
||||
`${pkg.platform},${pkg.name},${pkg.downloads},${new Date().toISOString()}`
|
||||
`${pkg.platform},${pkg.name},${pkg.downloads}`
|
||||
).join('\n');
|
||||
return csvHeader + csvRows;
|
||||
}
|
||||
@@ -125,36 +117,27 @@ class UsageStatisticsManager {
|
||||
}
|
||||
|
||||
async displayReport(report: AggregatedStats) {
|
||||
console.log('🚀 Usage Statistics Report');
|
||||
console.log('📊 Usage Statistics Summary');
|
||||
console.log('==================================================\n');
|
||||
|
||||
console.log('📈 Summary:');
|
||||
// Overall Summary
|
||||
console.log('📈 Overall Summary:');
|
||||
console.log(`Total Downloads: ${report.totalDownloads.toLocaleString()}`);
|
||||
console.log(`Unique Packages: ${report.uniquePackages}`);
|
||||
console.log(`Platforms Tracked: ${report.platforms.join(', ')}`);
|
||||
if (report.timeRange) {
|
||||
console.log(`Time Range: ${report.timeRange.start.toLocaleDateString()} to ${report.timeRange.end.toLocaleDateString()}\n`);
|
||||
}
|
||||
console.log(`Platforms Tracked: ${report.platforms.join(', ')}\n`);
|
||||
|
||||
console.log('🏗️ Platform Breakdown:');
|
||||
// Platform Totals
|
||||
console.log('🏗️ Platform Totals:');
|
||||
for (const [platform, data] of Object.entries(report.platformBreakdown)) {
|
||||
console.log(` ${platform.toUpperCase()}:`);
|
||||
console.log(` Downloads: ${data.totalDownloads.toLocaleString()}`);
|
||||
console.log(` Packages: ${data.uniquePackages}`);
|
||||
console.log(` Package List: ${data.packages.join(', ')}`);
|
||||
console.log(` ${platform.toUpperCase()}: ${data.totalDownloads.toLocaleString()} downloads (${data.uniquePackages} packages)`);
|
||||
}
|
||||
console.log();
|
||||
console.log('');
|
||||
|
||||
console.log('🏆 Top Packages:');
|
||||
report.topPackages.slice(0, 10).forEach((pkg, index) => {
|
||||
// Package Rankings
|
||||
console.log('🏆 Package Rankings:');
|
||||
report.topPackages.forEach((pkg, index) => {
|
||||
console.log(` ${index + 1}. ${pkg.name} (${pkg.platform}) - ${pkg.downloads.toLocaleString()} downloads`);
|
||||
});
|
||||
console.log();
|
||||
|
||||
console.log('🕒 Recent Activity:');
|
||||
report.recentActivity.slice(0, 5).forEach(activity => {
|
||||
console.log(` ${activity.packageName} (${activity.platform}) - ${activity.downloads.toLocaleString()} downloads on ${activity.timestamp.toLocaleDateString()}`);
|
||||
});
|
||||
console.log('==================================================');
|
||||
}
|
||||
|
||||
@@ -167,41 +150,49 @@ class UsageStatisticsManager {
|
||||
platform: 'npm',
|
||||
packageName: 'lodash',
|
||||
downloadCount: 1500000,
|
||||
timestamp: new Date(),
|
||||
period: 'total' as const,
|
||||
metadata: { version: '4.17.21' }
|
||||
},
|
||||
{
|
||||
platform: 'npm',
|
||||
packageName: 'axios',
|
||||
downloadCount: 800000,
|
||||
timestamp: new Date(),
|
||||
period: 'total' as const,
|
||||
metadata: { version: '1.6.0' }
|
||||
},
|
||||
{
|
||||
platform: 'github',
|
||||
packageName: 'microsoft/vscode',
|
||||
downloadCount: 500000,
|
||||
timestamp: new Date(),
|
||||
period: 'total' as const,
|
||||
metadata: { release: 'v1.85.0' }
|
||||
},
|
||||
{
|
||||
platform: 'pypi',
|
||||
packageName: 'requests',
|
||||
downloadCount: 300000,
|
||||
timestamp: new Date(),
|
||||
period: 'total' as const,
|
||||
metadata: { version: '2.31.0' }
|
||||
},
|
||||
{
|
||||
platform: 'homebrew',
|
||||
packageName: 'git',
|
||||
downloadCount: 250000,
|
||||
timestamp: new Date(),
|
||||
period: 'total' as const,
|
||||
metadata: { version: '2.43.0' }
|
||||
},
|
||||
{
|
||||
platform: 'powershell',
|
||||
packageName: 'PowerShellGet',
|
||||
downloadCount: 120000,
|
||||
metadata: { version: '2.2.5' }
|
||||
},
|
||||
{
|
||||
platform: 'postman',
|
||||
packageName: 'Postman Collection',
|
||||
downloadCount: 75000,
|
||||
metadata: { collectionId: '12345' }
|
||||
},
|
||||
{
|
||||
platform: 'go',
|
||||
packageName: 'github.com/gin-gonic/gin',
|
||||
downloadCount: 45000,
|
||||
metadata: { version: 'v1.9.1' }
|
||||
}
|
||||
];
|
||||
|
||||
@@ -214,15 +205,20 @@ class UsageStatisticsManager {
|
||||
async function main() {
|
||||
console.log('🚀 Usage Statistics Tracker Starting...\n');
|
||||
|
||||
// Validate configuration
|
||||
try {
|
||||
validateConfig(trackingConfig);
|
||||
} catch (error) {
|
||||
console.error('❌ Configuration validation failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
// Create a default configuration for CLI usage
|
||||
const defaultConfig: TrackingConfig = {
|
||||
enableLogging: true,
|
||||
updateInterval: 60 * 60 * 1000, // 1 hour
|
||||
npmPackages: ['lodash', 'axios'],
|
||||
githubRepos: ['microsoft/vscode', 'facebook/react'],
|
||||
pythonPackages: ['requests', 'numpy'],
|
||||
homebrewPackages: ['git', 'node'],
|
||||
powershellModules: ['PowerShellGet'],
|
||||
postmanCollections: [],
|
||||
goModules: ['github.com/gin-gonic/gin', 'github.com/go-chi/chi']
|
||||
};
|
||||
|
||||
const manager = new UsageStatisticsManager(trackingConfig);
|
||||
const manager = new UsageStatisticsManager(defaultConfig);
|
||||
|
||||
try {
|
||||
// Check for preview mode
|
||||
@@ -263,4 +259,4 @@ if (import.meta.main) {
|
||||
main();
|
||||
}
|
||||
|
||||
export { UsageStatisticsManager, trackingConfig };
|
||||
export { UsageStatisticsManager };
|
||||
@@ -7,8 +7,6 @@ export interface BaseDownloadStats {
|
||||
packageName: string;
|
||||
version?: string;
|
||||
downloadCount: number;
|
||||
timestamp: Date;
|
||||
period?: 'daily' | 'weekly' | 'monthly' | 'total';
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
@@ -24,7 +22,6 @@ export interface DownloadStatsAggregator {
|
||||
totalDownloads: number;
|
||||
uniquePackages: number;
|
||||
platforms: string[];
|
||||
timeRange: { start: Date; end: Date } | null;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user