From 1f24188c62201217c753bdd40bc14cf01ed9da85 Mon Sep 17 00:00:00 2001 From: Luke Hagar Date: Tue, 29 Jul 2025 14:19:22 -0500 Subject: [PATCH] Add Usage Statistics Tracker GitHub Action with configuration options, outputs, and README integration --- .github/workflows/test-action.yml | 52 ++++ LICENSE | 21 ++ PUBLISHING.md | 258 +++++++++++++++++++ README.md | 405 ++++++++++++++++++++---------- action.yml | 83 ++++++ bun.lock | 15 ++ examples/basic-usage.yml | 33 +++ package.json | 5 +- src/action.ts | 196 +++++++++++++++ 9 files changed, 937 insertions(+), 131 deletions(-) create mode 100644 .github/workflows/test-action.yml create mode 100644 LICENSE create mode 100644 PUBLISHING.md create mode 100644 action.yml create mode 100644 examples/basic-usage.yml create mode 100644 src/action.ts diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml new file mode 100644 index 0000000..fe8995b --- /dev/null +++ b/.github/workflows/test-action.yml @@ -0,0 +1,52 @@ +name: Test GitHub Action + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +jobs: + test-action: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + + - name: Run tests + run: bun test + + - name: Build action + run: bun run action:build + + - name: Test action with preview mode + uses: ./ + with: + preview-mode: 'true' + json-output-path: 'test-stats.json' + csv-output-path: 'test-stats.csv' + report-output-path: 'test-report.md' + update-readme: 'false' + + - name: Check outputs + run: | + echo "Checking generated files..." + ls -la test-stats.* test-report.md || echo "No output files found (expected in preview mode)" + + echo "Checking action outputs..." + echo "JSON output: ${{ steps.test-action.outputs.json-output }}" + echo "CSV output: ${{ steps.test-action.outputs.csv-output }}" + echo "Report output: ${{ steps.test-action.outputs.report-output }}" + echo "Total downloads: ${{ steps.test-action.outputs.total-downloads }}" + echo "Unique packages: ${{ steps.test-action.outputs.unique-packages }}" + echo "Platforms tracked: ${{ steps.test-action.outputs.platforms-tracked }}" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fc592c9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Usage Statistics Tracker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/PUBLISHING.md b/PUBLISHING.md new file mode 100644 index 0000000..e9bd5c5 --- /dev/null +++ b/PUBLISHING.md @@ -0,0 +1,258 @@ +# Publishing to GitHub Marketplace + +This guide walks you through the process of publishing the Usage Statistics Tracker to the GitHub Marketplace. + +## Prerequisites + +1. **GitHub Account**: You need a GitHub account with a verified email +2. **Repository**: This repository should be public +3. **GitHub Actions**: Actions must be enabled on your repository + +## Step 1: Prepare Your Repository + +### 1.1 Build the Action + +```bash +# Install dependencies +bun install + +# Build the action for distribution +bun run action:build + +# Verify the build +ls -la dist/ +``` + +### 1.2 Commit the Built Files + +```bash +# Add the built files +git add dist/ + +# Commit with a descriptive message +git commit -m "build: add action distribution files for v1.0.0" + +# Push to main branch +git push origin main +``` + +### 1.3 Create a Release + +```bash +# Create and push a tag +git tag v1.0.0 +git push origin v1.0.0 + +# Or create a release via GitHub UI: +# 1. Go to your repository +# 2. Click "Releases" on the right +# 3. Click "Create a new release" +# 4. Choose the tag v1.0.0 +# 5. Add release notes +# 6. Publish release +``` + +## Step 2: Publish to Marketplace + +### 2.1 Access the Publishing Interface + +1. Go to your repository on GitHub +2. Click on the **Actions** tab +3. Look for a banner that says "Publish this Action to the GitHub Marketplace" +4. Click **Publish this Action** + +### 2.2 Fill in Action Details + +#### Basic Information +- **Action name**: `usage-statistics-tracker` +- **Description**: `Track download statistics across multiple platforms (NPM, GitHub, PyPI, Homebrew, PowerShell, Postman, Go)` +- **Category**: Choose `Data` or `Utilities` +- **Icon**: Upload a relevant icon (512x512px PNG recommended) +- **Color**: Choose a brand color (e.g., `#0366d6` for blue) + +#### Detailed Description +Use the content from the main README.md file, focusing on: +- Features and capabilities +- Usage examples +- Configuration options +- Supported platforms + +#### Keywords +Add relevant keywords: +- `statistics` +- `analytics` +- `downloads` +- `npm` +- `github` +- `pypi` +- `homebrew` +- `powershell` +- `postman` +- `go` +- `tracking` +- `usage` + +### 2.3 Marketplace Listing + +#### Action Name +- **Marketplace name**: `Usage Statistics Tracker` +- **Description**: `Comprehensive GitHub Action for tracking download statistics across multiple platforms with configurable outputs and README integration` + +#### Categories +- **Primary category**: `Data` +- **Secondary category**: `Utilities` + +#### Pricing +- **Pricing model**: Free +- **License**: MIT + +## Step 3: Version Management + +### 3.1 Semantic Versioning + +Follow semantic versioning for releases: +- **Major** (1.0.0): Breaking changes +- **Minor** (1.1.0): New features, backward compatible +- **Patch** (1.0.1): Bug fixes + +### 3.2 Release Process + +For each new version: + +```bash +# 1. Update version in package.json +# 2. Update CHANGELOG.md +# 3. Build the action +bun run action:build + +# 4. Commit changes +git add . +git commit -m "feat: release v1.1.0" + +# 5. Create and push tag +git tag v1.1.0 +git push origin v1.1.0 + +# 6. Create GitHub release +# Go to GitHub and create a release for the new tag +``` + +### 3.3 Changelog + +Maintain a `CHANGELOG.md` file: + +```markdown +# Changelog + +## [1.1.0] - 2025-01-XX +### Added +- New platform support for X +- Enhanced error handling +- Additional configuration options + +### Changed +- Improved performance for large datasets +- Updated dependencies + +### Fixed +- Bug fix for Y platform +- Resolved issue with Z feature + +## [1.0.0] - 2025-01-XX +### Added +- Initial release +- Support for NPM, GitHub, PyPI, Homebrew, PowerShell, Postman, Go +- Configurable outputs (JSON, CSV, human-readable) +- README integration +- Preview mode +``` + +## Step 4: Marketing and Documentation + +### 4.1 README Optimization + +Ensure your README includes: +- Clear installation instructions +- Multiple usage examples +- Configuration documentation +- Troubleshooting section +- Contributing guidelines + +### 4.2 Examples Repository + +Consider creating a separate repository with examples: +- Basic usage workflows +- Advanced configurations +- Custom integrations +- Troubleshooting guides + +### 4.3 Social Media + +Promote your action on: +- GitHub Discussions +- Reddit (r/github, r/devops) +- Twitter/X with relevant hashtags +- LinkedIn for professional audience + +## Step 5: Maintenance + +### 5.1 Monitoring + +- Monitor GitHub Issues for user feedback +- Track download statistics +- Respond to questions and bug reports +- Update documentation as needed + +### 5.2 Updates + +Regular maintenance tasks: +- Update dependencies +- Fix security vulnerabilities +- Add new platform support +- Improve performance +- Enhance documentation + +### 5.3 Community Engagement + +- Respond to issues promptly +- Help users with configuration +- Accept and review pull requests +- Maintain a welcoming community + +## Troubleshooting + +### Common Issues + +1. **Action not found**: Ensure the action is properly built and tagged +2. **Build failures**: Check that all dependencies are included +3. **Permission issues**: Verify GitHub token permissions +4. **Rate limiting**: Implement proper rate limiting in the action + +### Support + +- GitHub Issues: For bug reports and feature requests +- GitHub Discussions: For questions and community support +- Documentation: Comprehensive README and examples + +## Success Metrics + +Track these metrics to measure success: +- **Downloads**: Number of action downloads +- **Stars**: Repository stars +- **Forks**: Repository forks +- **Issues**: User engagement and feedback +- **Usage**: Number of repositories using the action + +## Legal Considerations + +- **License**: MIT License (included) +- **Privacy**: No personal data collection +- **Terms of Service**: Follow GitHub's terms +- **Attribution**: Credit original authors if applicable + +## Resources + +- [GitHub Actions Documentation](https://docs.github.com/en/actions) +- [GitHub Marketplace Guidelines](https://docs.github.com/en/developers/github-marketplace) +- [Action Metadata Syntax](https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions) +- [Publishing Actions](https://docs.github.com/en/actions/creating-actions/publishing-actions-in-github-marketplace) \ No newline at end of file diff --git a/README.md b/README.md index dff2fa1..27cdf41 100644 --- a/README.md +++ b/README.md @@ -1,184 +1,323 @@ -# Usage Statistics +# Usage Statistics Tracker -A Bun TypeScript script project for analyzing usage statistics with a clean, modern architecture. +A comprehensive GitHub Action for tracking download statistics across multiple platforms (NPM, GitHub, PyPI, Homebrew, PowerShell, Postman, Go) with configurable outputs and README integration. -## Features +## ๐Ÿš€ Features -- ๐Ÿš€ **Fast Execution**: Built with Bun for lightning-fast TypeScript execution -- ๐Ÿ“Š **Usage Analytics**: Track user actions and generate statistics -- ๐Ÿงช **Comprehensive Testing**: Full test suite with Bun's built-in test runner -- ๐Ÿ“ฆ **Modern Tooling**: TypeScript, ES modules, and modern JavaScript features -- ๐Ÿ”ง **Developer Friendly**: Hot reloading, watch mode, and excellent DX +- ๐Ÿ“Š **Multi-Platform Tracking**: NPM, GitHub, PyPI, Homebrew, PowerShell, Postman, Go +- ๐ŸŽญ **Preview Mode**: Test with mock data without external API calls +- ๐Ÿ“„ **Flexible Outputs**: JSON, CSV, and human-readable reports +- ๐Ÿ“ **README Integration**: Auto-update README with statistics +- โš™๏ธ **Configurable**: Custom configurations via JSON or preset modes +- ๐Ÿ”„ **GitHub Actions Ready**: Built for CI/CD workflows +- ๐Ÿงช **Comprehensive Testing**: Full test suite with Bun -## Prerequisites +## ๐Ÿ“ฆ Installation -- [Bun](https://bun.sh/) (version 1.0.0 or higher) +### As a GitHub Action -## Installation +```yaml +- name: Usage Statistics Tracker + uses: your-username/usage-statistics@v1 + with: + config: 'production' + json-output-path: 'stats.json' + csv-output-path: 'stats.csv' + report-output-path: 'report.md' + update-readme: 'true' + github-token: ${{ secrets.GITHUB_TOKEN }} +``` + +### Local Development ```bash # Install dependencies bun install -``` -## Usage - -### Running the Script - -```bash -# Run the main script +# Run the tracker bun start -# Preview the report with mock data (no external API calls) +# Preview mode (no external API calls) bun preview -# Run in development mode with hot reloading -bun run dev - -# Run directly with bun -bun run src/index.ts +# Run tests +bun test ``` -### Preview Mode +## ๐Ÿ”ง Configuration -The preview mode allows you to see how the report will look without making any external API calls or writing files: +### Input Parameters -```bash -# Generate a preview report with mock data -bun preview +| Parameter | Description | Required | Default | +|-----------|-------------|----------|---------| +| `config` | Configuration mode or JSON | No | `production` | +| `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) | +| `update-readme` | Whether to update README | No | `true` | +| `readme-path` | Path to README file | No | `README.md` | +| `github-token` | GitHub token for API access | No | `${{ github.token }}` | +| `postman-api-key` | Postman API key | No | (empty) | +| `commit-message` | Commit message for changes | No | `chore: update usage statistics [skip ci]` | +| `preview-mode` | Run with mock data | No | `false` | -# Or use the long flag -bun start --preview +### Configuration Modes + +#### Production Mode +```yaml +- name: Usage Statistics Tracker + uses: your-username/usage-statistics@v1 + with: + config: 'production' ``` -This is useful for: -- Testing the report format -- Demonstrating the functionality -- Development and debugging -- CI/CD testing without external dependencies - -### Building - -```bash -# Build the project -bun run build +#### Development Mode +```yaml +- name: Usage Statistics Tracker + uses: your-username/usage-statistics@v1 + with: + config: 'development' ``` -### Testing +#### Custom JSON Configuration +```yaml +- name: Usage Statistics Tracker + uses: your-username/usage-statistics@v1 + with: + config: '{"npmPackages": ["lodash", "axios"], "githubRepositories": ["microsoft/vscode"]}' +``` + +### Outputs + +| Output | Description | +|--------|-------------| +| `json-output` | Path to the generated JSON file | +| `csv-output` | Path to the generated CSV file | +| `report-output` | Path to the generated report file | +| `total-downloads` | Total downloads across all platforms | +| `unique-packages` | Number of unique packages tracked | +| `platforms-tracked` | Comma-separated list of platforms tracked | + +## ๐Ÿ“‹ Usage Examples + +### Basic Usage + +```yaml +name: Update Usage Statistics + +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: your-username/usage-statistics@v1 + with: + config: 'production' + json-output-path: 'stats.json' + update-readme: 'true' + github-token: ${{ secrets.GITHUB_TOKEN }} + + - 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 stats.json README.md + git commit -m "chore: update usage statistics [skip ci]" || echo "No changes to commit" + git push +``` + +### Advanced Usage with Multiple Outputs + +```yaml +- name: Usage Statistics Tracker + uses: your-username/usage-statistics@v1 + with: + config: 'production' + json-output-path: 'data/stats.json' + csv-output-path: 'data/stats.csv' + report-output-path: 'docs/usage-report.md' + update-readme: 'true' + readme-path: 'README.md' + github-token: ${{ secrets.GITHUB_TOKEN }} + postman-api-key: ${{ secrets.POSTMAN_API_KEY }} + commit-message: 'feat: update usage statistics with detailed report' +``` + +### Preview Mode for Testing + +```yaml +- name: Test Usage Statistics + uses: your-username/usage-statistics@v1 + with: + preview-mode: 'true' + json-output-path: 'test-stats.json' + csv-output-path: 'test-stats.csv' + report-output-path: 'test-report.md' + update-readme: 'false' +``` + +### Using Outputs in Subsequent Steps + +```yaml +- name: Usage Statistics Tracker + id: stats + uses: your-username/usage-statistics@v1 + with: + config: 'production' + json-output-path: 'stats.json' + +- name: Use Statistics Data + run: | + echo "Total downloads: ${{ steps.stats.outputs.total-downloads }}" + echo "Unique packages: ${{ steps.stats.outputs.unique-packages }}" + echo "Platforms: ${{ steps.stats.outputs.platforms-tracked }}" + echo "JSON file: ${{ steps.stats.outputs.json-output }}" +``` + +## ๐Ÿ“Š README Integration + +To enable automatic README updates, add these markers to your README.md: + +```markdown + +## ๐Ÿ“Š Usage Statistics + +Last updated: 2025-07-29T18:53:52.619Z + +### Summary +- **Total Downloads**: 414,533 +- **Unique Packages**: 8 +- **Platforms Tracked**: npm, pypi, homebrew, go + +### 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 + +``` + +## ๐Ÿ”ง Development + +### Prerequisites + +- [Bun](https://bun.sh/) (version 1.0.0 or higher) + +### Local Development ```bash -# Run all tests +# Install dependencies +bun install + +# Run in development mode +bun dev + +# Run tests bun test -# Run tests in watch mode -bun test --watch +# Build the action +bun run action:build + +# Test the action locally +bun run action:test ``` -## Project Structure +### Project Structure ``` usage-statistics/ โ”œโ”€โ”€ src/ -โ”‚ โ”œโ”€โ”€ index.ts # Main entry point -โ”‚ โ”œโ”€โ”€ index.test.ts # Test suite -โ”‚ โ””โ”€โ”€ test-setup.ts # Test configuration +โ”‚ โ”œโ”€โ”€ 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 +โ”‚ โ””โ”€โ”€ utils/ # Utility functions +โ”œโ”€โ”€ .github/ +โ”‚ โ””โ”€โ”€ workflows/ # GitHub Actions workflows +โ”œโ”€โ”€ action.yml # Action metadata โ”œโ”€โ”€ package.json # Project configuration -โ”œโ”€โ”€ tsconfig.json # TypeScript configuration -โ”œโ”€โ”€ bunfig.toml # Bun configuration -โ”œโ”€โ”€ .gitignore # Git ignore rules โ””โ”€โ”€ README.md # This file ``` -## API Reference +## ๐Ÿš€ Publishing to GitHub Marketplace -### UsageStatistics Class +### 1. Prepare Your Repository -The main class for tracking and analyzing usage data. +1. **Create a release tag**: + ```bash + git tag v1.0.0 + git push origin v1.0.0 + ``` -#### Methods +2. **Build the action**: + ```bash + bun run action:build + ``` -- `addUsage(userId: string, action: string, metadata?: Record)`: Add a new usage record -- `getAllData()`: Get all usage data -- `getUserData(userId: string)`: Get usage data for a specific user -- `getActionData(action: string)`: Get usage data for a specific action -- `getStatistics()`: Get comprehensive statistics summary +3. **Commit the built files**: + ```bash + git add dist/ + git commit -m "build: add action distribution files" + git push + ``` -#### Example Usage +### 2. Publish to Marketplace -```typescript -import { UsageStatistics } from './src/index'; +1. Go to your repository on GitHub +2. Click on the **Actions** tab +3. Click **Publish this Action to the GitHub Marketplace** +4. Fill in the required information: + - **Action name**: `usage-statistics-tracker` + - **Description**: `Track download statistics across multiple platforms` + - **Category**: `Data` or `Utilities` + - **Icon**: Upload an appropriate icon + - **Color**: Choose a brand color + - **README**: Use the content from this README -const stats = new UsageStatistics(); +### 3. Version Management -// Add usage data -stats.addUsage("user1", "login", { browser: "chrome" }); -stats.addUsage("user2", "logout"); - -// Get statistics -const summary = stats.getStatistics(); -console.log(`Total records: ${summary.totalRecords}`); -``` - -## Development - -### Scripts - -- `bun start`: Run the main script -- `bun run dev`: Run in development mode with file watching -- `bun run build`: Build the project for production -- `bun test`: Run the test suite - -### Adding Dependencies +For each new version: ```bash -# Add a production dependency -bun add +# Update version in package.json +# Build the action +bun run action:build -# Add a development dependency -bun add -d +# Create and push a new tag +git tag v1.1.0 +git push origin v1.1.0 ``` -## GitHub Actions Integration +## ๐Ÿ“ˆ Supported Platforms -This project includes a GitHub Actions workflow that automatically updates usage statistics and commits the results to the repository. +- **NPM**: Package download statistics +- **GitHub**: Release download statistics +- **PyPI**: Python package downloads +- **Homebrew**: Formula installation statistics +- **PowerShell**: Module download statistics +- **Postman**: Collection fork/download statistics +- **Go**: Module proxy statistics -### Setup - -1. **Enable the workflow**: The workflow file is located at `.github/workflows/update-stats.yml` -2. **Configure your packages**: Update `src/config.ts` with your actual package names -3. **Set up environment variables** (if needed): - - `GITHUB_TOKEN`: Automatically provided by GitHub Actions - - `POSTMAN_API_KEY`: If tracking Postman collections - -### Workflow Features - -- **Scheduled runs**: Updates stats daily at 2 AM UTC -- **Manual triggering**: Can be run manually via GitHub Actions UI -- **Rate limiting**: Built-in rate limiting to avoid API abuse -- **Auto-commit**: Automatically commits `stats.json` and updates README -- **Error handling**: Graceful handling of API failures - -### Customization - -Edit `src/config.ts` to track your specific packages: - -```typescript -export const defaultConfig: TrackingConfig = { - npmPackages: ['your-package-name'], - githubRepos: ['your-org/your-repo'], - // ... other platforms -}; -``` - -### Manual Execution - -Run locally with GitHub Action mode: - -```bash -GITHUB_TOKEN=your_token bun run src/index.ts --action -``` - -## Contributing +## ๐Ÿค Contributing 1. Fork the repository 2. Create a feature branch @@ -187,6 +326,12 @@ GITHUB_TOKEN=your_token bun run src/index.ts --action 5. Run the test suite 6. Submit a pull request -## License +## ๐Ÿ“„ License -This project is open source and available under the [MIT License](LICENSE). \ No newline at end of file +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## ๐Ÿ™ Acknowledgments + +- Built with [Bun](https://bun.sh/) for fast TypeScript execution +- Uses [Octokit](https://github.com/octokit/octokit.js) for GitHub API integration +- Inspired by the need for comprehensive usage analytics across multiple platforms \ No newline at end of file diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..48c8ae6 --- /dev/null +++ b/action.yml @@ -0,0 +1,83 @@ +name: 'Usage Statistics Tracker' +description: 'Track download statistics across multiple platforms (NPM, GitHub, PyPI, Homebrew, PowerShell, Postman, Go)' +author: 'Your Name' + +inputs: + # Configuration + config: + description: 'Configuration for tracking (development, production, test, or custom JSON)' + required: false + default: 'production' + + # Output paths + json-output-path: + description: 'Path for JSON output file' + required: false + default: 'stats.json' + + csv-output-path: + description: 'Path for CSV output file' + required: false + default: '' + + report-output-path: + description: 'Path for human-readable report file' + required: false + default: '' + + # README update + update-readme: + description: 'Whether to update README.md with statistics' + required: false + default: 'true' + + readme-path: + description: 'Path to README file to update' + required: false + default: 'README.md' + + # GitHub integration + github-token: + description: 'GitHub token for API access and commits' + required: false + default: '${{ github.token }}' + + # Postman integration + postman-api-key: + description: 'Postman API key for collection statistics' + required: false + + # Commit settings + commit-message: + description: 'Commit message for changes' + required: false + default: 'chore: update usage statistics [skip ci]' + + # Preview mode + preview-mode: + description: 'Run in preview mode with mock data (no external API calls)' + required: false + default: 'false' + +outputs: + json-output: + description: 'Path to the generated JSON file' + + csv-output: + description: 'Path to the generated CSV file' + + report-output: + description: 'Path to the generated report file' + + total-downloads: + description: 'Total downloads across all platforms' + + unique-packages: + description: 'Number of unique packages tracked' + + platforms-tracked: + description: 'Comma-separated list of platforms tracked' + +runs: + using: 'node20' + main: 'dist/index.js' \ No newline at end of file diff --git a/bun.lock b/bun.lock index 59b7691..ac22339 100644 --- a/bun.lock +++ b/bun.lock @@ -4,6 +4,7 @@ "": { "name": "usage-statistics", "dependencies": { + "@actions/core": "1.11.1", "@octokit/rest": "22.0.0", }, "devDependencies": { @@ -14,6 +15,16 @@ }, }, "packages": { + "@actions/core": ["@actions/core@1.11.1", "", { "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" } }, "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A=="], + + "@actions/exec": ["@actions/exec@1.1.1", "", { "dependencies": { "@actions/io": "^1.0.1" } }, "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w=="], + + "@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="], + + "@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="], + + "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], + "@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="], "@octokit/core": ["@octokit/core@7.0.3", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.1", "@octokit/request": "^10.0.2", "@octokit/request-error": "^7.0.0", "@octokit/types": "^14.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-oNXsh2ywth5aowwIa7RKtawnkdH6LgU1ztfP9AIUCQCvzysB+WeU8o2kyyosDPwBZutPpjZDKPQGIzzrfTWweQ=="], @@ -50,8 +61,12 @@ "fast-content-type-parse": ["fast-content-type-parse@3.0.0", "", {}, "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg=="], + "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + "undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], "universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="], diff --git a/examples/basic-usage.yml b/examples/basic-usage.yml new file mode 100644 index 0000000..4d848f1 --- /dev/null +++ b/examples/basic-usage.yml @@ -0,0 +1,33 @@ +name: Update Usage Statistics + +on: + schedule: + - cron: '0 0 * * *' # Daily at midnight + workflow_dispatch: # Allow manual triggering + +jobs: + update-stats: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Usage Statistics Tracker + uses: your-username/usage-statistics@v1 + with: + config: 'production' + json-output-path: 'stats.json' + csv-output-path: 'stats.csv' + report-output-path: 'docs/usage-report.md' + update-readme: 'true' + readme-path: 'README.md' + github-token: ${{ secrets.GITHUB_TOKEN }} + + - 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 stats.json stats.csv docs/usage-report.md README.md + git commit -m "chore: update usage statistics [skip ci]" || echo "No changes to commit" + git push \ No newline at end of file diff --git a/package.json b/package.json index 157f737..bbd43a1 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "preview": "bun run src/index.ts --preview", "dev": "bun --watch src/index.ts", "build": "bun build src/index.ts --outdir dist", - "test": "bun test" + "test": "bun test", + "action:build": "bun build src/action.ts --outdir dist --target node --minify", + "action:test": "bun test && bun run action:build" }, "devDependencies": { "@types/node": "^20.0.0", @@ -16,6 +18,7 @@ "typescript": "^5.0.0" }, "dependencies": { + "@actions/core": "1.11.1", "@octokit/rest": "22.0.0" }, "engines": { diff --git a/src/action.ts b/src/action.ts new file mode 100644 index 0000000..fdb9177 --- /dev/null +++ b/src/action.ts @@ -0,0 +1,196 @@ +#!/usr/bin/env bun +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'; + +async function run() { + try { + // Get inputs + const configInput = core.getInput('config'); + const jsonOutputPath = core.getInput('json-output-path'); + const csvOutputPath = core.getInput('csv-output-path'); + const reportOutputPath = core.getInput('report-output-path'); + const updateReadme = core.getInput('update-readme') === 'true'; + const readmePath = core.getInput('readme-path'); + const githubToken = core.getInput('github-token'); + const postmanApiKey = core.getInput('postman-api-key'); + const commitMessage = core.getInput('commit-message'); + const previewMode = core.getInput('preview-mode') === 'true'; + + // Set environment variables + if (githubToken) { + process.env.GITHUB_TOKEN = githubToken; + } + if (postmanApiKey) { + 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; + } + } + + // Validate configuration + try { + validateConfig(trackingConfig); + } catch (error) { + core.setFailed(`Configuration validation failed: ${error}`); + return; + } + + // Create manager + const manager = new UsageStatisticsManager(trackingConfig); + + // Generate report + let report; + if (previewMode) { + core.info('๐ŸŽญ Running in preview mode with mock data...'); + report = await manager.generatePreviewReport(); + } else { + 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); + await fs.writeFile(jsonOutputPath, jsonContent); + core.info(`๐Ÿ“„ JSON report written to ${jsonOutputPath}`); + core.setOutput('json-output', jsonOutputPath); + } + + // Write CSV output + if (csvOutputPath) { + const csvReport = await manager.exportReport('csv'); + await fs.writeFile(csvOutputPath, csvReport); + core.info(`๐Ÿ“Š CSV report written to ${csvOutputPath}`); + core.setOutput('csv-output', csvOutputPath); + } + + // Write human-readable report + if (reportOutputPath) { + const reportContent = await generateHumanReadableReport(report); + await fs.writeFile(reportOutputPath, reportContent); + core.info(`๐Ÿ“‹ Human-readable report written to ${reportOutputPath}`); + core.setOutput('report-output', reportOutputPath); + } + + // Update README if requested + if (updateReadme && readmePath) { + try { + await updateReadmeWithStats(report, readmePath); + core.info(`๐Ÿ“ README updated at ${readmePath}`); + } catch (error) { + core.warning(`Failed to update README: ${error}`); + } + } + + // Set outputs + core.setOutput('total-downloads', report.totalDownloads.toString()); + core.setOutput('unique-packages', report.uniquePackages.toString()); + core.setOutput('platforms-tracked', report.platforms.join(',')); + + core.info('โœ… Usage Statistics Tracker completed successfully!'); + + } catch (error) { + core.setFailed(`Action failed: ${error}`); + } +} + +async function generateHumanReadableReport(report: any): Promise { + let content = '# Usage Statistics Report\n\n'; + content += `Generated on: ${new Date().toISOString()}\n\n`; + + // Summary + content += '## 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'; + 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`; + } + + // Top Packages + content += '## Top Packages\n\n'; + report.topPackages.slice(0, 10).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; +} + +async function updateReadmeWithStats(report: any, readmePath: string) { + const STATS_MARKER_START = ''; + const STATS_MARKER_END = ''; + + try { + const readmeContent = await fs.readFile(readmePath, 'utf-8'); + + const statsSection = ` +## ๐Ÿ“Š Usage Statistics + +Last updated: ${new Date().toISOString()} + +### Summary +- **Total Downloads**: ${report.totalDownloads.toLocaleString()} +- **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` +).join('\n')} + +### Recent Activity +${report.recentActivity.slice(0, 5).map((activity: any) => + `- **${activity.packageName}** (${activity.platform}) - ${activity.downloads.toLocaleString()} downloads on ${activity.timestamp.toLocaleDateString()}` +).join('\n')} +`; + + const startMarker = readmeContent.indexOf(STATS_MARKER_START); + const endMarker = readmeContent.indexOf(STATS_MARKER_END); + + if (startMarker !== -1 && endMarker !== -1) { + const beforeStats = readmeContent.substring(0, startMarker + STATS_MARKER_START.length); + const afterStats = readmeContent.substring(endMarker); + const updatedContent = beforeStats + statsSection + afterStats; + await fs.writeFile(readmePath, updatedContent); + } else { + core.warning(`Stats markers not found in README. Please add ${STATS_MARKER_START} and ${STATS_MARKER_END} markers.`); + } + } catch (error) { + throw new Error(`Failed to update README: ${error}`); + } +} + +// Run the action +if (import.meta.main) { + run(); +} \ No newline at end of file