A self-hosted code coverage tracking platform built with Laravel. Track, visualize, and monitor your code coverage across repositories, branches, and pull requests.
- 📊 Coverage Tracking - Upload and track code coverage reports across multiple repositories
- 🌳 Branch Management - Monitor coverage for different branches independently
- 📈 Visual Reports - Interactive file-level coverage visualization with line-by-line analysis
- 🏷️ Coverage Badges - Generate SVG badges for your README files
- 👥 Team Collaboration - Multi-user support with team-based access control
- 🔑 API Tokens - Secure token-based authentication for CI/CD integration
- 🔗 GitHub Integration - Native webhook support for automated coverage updates
- 🎯 Trend Analysis - Track coverage changes over time
- PHP 8.4+
- Composer
- Node.js 18+ and npm
- SQLite (default) or MySQL/PostgreSQL
git clone https://github.com/yourusername/covercraft.git
cd covercraft
composer install
npm installcp .env.example .env
php artisan key:generateUpdate your .env file with your database credentials if not using SQLite:
DB_CONNECTION=sqlite
# DB_CONNECTION=mysql
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=covercraft
# DB_USERNAME=root
# DB_PASSWORD=php artisan migratenpm run buildFor development with hot reloading:
npm run devphp artisan serveVisit http://localhost:8000 to access the application.
- Navigate to your CoverCraft instance (e.g.,
https://covercraft.yourdomain.com) - Click Register in the top navigation
- Fill in your details:
- Name
- Email address
- Password
- Click Register to create your account
- You'll be automatically logged in and redirected to the dashboard
- From the dashboard, click Repositories in the navigation
- Click New Repository
- Fill in the repository details:
- Repository Name: Your repository name (e.g.,
my-awesome-project) - Owner/Organization: The owner or organization name (e.g.,
acme-corp) - Description (optional): Brief description of the project
- Repository Name: Your repository name (e.g.,
- Click Create Repository
- Your repository will be created and you'll see it in your repositories list
API tokens are used to authenticate coverage uploads from your CI/CD pipeline.
- Click API Tokens in the navigation
- Click Generate New Token
- Fill in the token details:
- Token Name: A descriptive name (e.g.,
GitHub Actions - my-project) - Description (optional): Purpose or scope of the token
- Token Name: A descriptive name (e.g.,
- Click Create Token
- Important: Copy the generated token immediately - it will only be shown once
- Store the token securely (you'll need it for the next step)
- Go to your GitHub repository
- Navigate to Settings → Secrets and variables → Actions
- Click New repository secret
- Add the following secret:
- Name:
COVERCRAFT_TOKEN - Value: The API token you copied from Step 3
- Name:
- Click Add secret
Create a new workflow file in your repository at .github/workflows/coverage.yml:
name: Code Coverage
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
coverage: xdebug
- name: Install dependencies
run: composer install --prefer-dist --no-progress
- name: Run tests with coverage
run: vendor/bin/phpunit --coverage-clover coverage.xml
- name: Upload coverage to CoverCraft
env:
COVERCRAFT_TOKEN: ${{ secrets.COVERCRAFT_TOKEN }}
COVERCRAFT_URL: https://covercraft.yourdomain.com
run: |
curl -X POST "$COVERCRAFT_URL/api/coverage" \
-H "Authorization: Bearer $COVERCRAFT_TOKEN" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"repository": "${{ github.repository }}",
"branch": "${{ github.ref_name }}",
"commit": "${{ github.sha }}",
"coverage": $(cat coverage.xml | base64 -w 0)
}
EOFFor JavaScript/TypeScript projects using Jest:
- name: Run tests with coverage
run: npm test -- --coverage --coverageReporters=json
- name: Upload coverage to CoverCraft
env:
COVERCRAFT_TOKEN: ${{ secrets.COVERCRAFT_TOKEN }}
COVERCRAFT_URL: https://covercraft.yourdomain.com
run: |
curl -X POST "$COVERCRAFT_URL/api/coverage" \
-H "Authorization: Bearer $COVERCRAFT_TOKEN" \
-H "Content-Type: application/json" \
-d @- << EOF
{
"repository": "${{ github.repository }}",
"branch": "${{ github.ref_name }}",
"commit": "${{ github.sha }}",
"coverage": $(cat coverage/coverage-final.json | base64 -w 0)
}
EOFgit add .github/workflows/coverage.yml
git commit -m "Add code coverage reporting"
git pushThe workflow will run automatically on your next push or pull request.
Once you've uploaded coverage data, you can add a badge to your repository's README:
Replace:
covercraft.yourdomain.comwith your CoverCraft instance URLownerwith your repository owner/organizationrepository-namewith your repository namemainwith your default branch name
<!-- Basic badge -->

<!-- Badge with link to coverage report -->
[](https://covercraft.yourdomain.com/dashboard/acme-corp/my-project/main)Endpoint: POST /api/coverage
Headers:
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Request Body:
{
"repository": "owner/repository-name",
"branch": "main",
"commit": "abc123def456",
"coverage": "base64_encoded_coverage_data"
}Response:
{
"success": true,
"report_id": "uuid",
"coverage_percentage": 85.4
}Endpoint: GET /api/coverage/status/{report_id}
Response:
{
"status": "processed",
"repository": "owner/repository-name",
"branch": "main",
"coverage": 85.4,
"processed_at": "2026-02-17T10:30:00Z"
}- Create a new server in Laravel Forge
- Add your repository
- Set environment variables
- Configure the deployment script
- Enable Quick Deploy
# Start the application
./vendor/bin/sail up -d
# Run migrations
./vendor/bin/sail artisan migrate
# Build assets
./vendor/bin/sail npm run build# On your server
git pull origin main
composer install --no-dev --optimize-autoloader
npm run build
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cacheConfigure storage for coverage reports in config/filesystems.php. By default, reports are stored locally.
For better performance with large coverage reports, configure queues:
QUEUE_CONNECTION=databaseThen run the queue worker:
php artisan queue:work- Verify your API token is correct
- Check that the repository exists in CoverCraft
- Ensure the coverage file format is supported (Clover XML, JaCoCo XML, LCOV)
- Check application logs:
storage/logs/laravel.log
- Verify the badge URL is correct
- Ensure coverage has been uploaded for that branch
- Check that the repository and branch exist
If coverage generation takes too long:
- Reduce the number of files being analyzed
- Use parallel test execution
- Cache dependencies between workflow runs
Contributions are welcome! Please feel free to submit a Pull Request.
This project is open-sourced software licensed under the MIT license.
For issues, questions, or feature requests, please open an issue on GitHub.
Built with ❤️ using Laravel 12