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:
Luke Hagar
2025-07-29 14:50:30 -05:00
parent ce4a2e80ee
commit cb1866631c
11 changed files with 303 additions and 307 deletions

View File

@@ -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 -->
```

View File

@@ -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

View File

@@ -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'

View File

@@ -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'

View 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

View File

@@ -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,26 +34,30 @@ 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
@@ -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')}
`;

View File

@@ -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,26 +90,7 @@ 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())
@@ -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
};
}

View File

@@ -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;
}

View File

@@ -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');
});
});

View File

@@ -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 };

View File

@@ -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;
};
}