A comprehensive Laravel package for handling GitHub webhooks with database storage, signature validation, event management, and automated deployment capabilities.
- PHP ^8.2
- Laravel ^11.0 or ^12.0
- Add the package to your local
composer.json:
{
"repositories": [
{
"type": "path",
"url": "./packages/github-webhooks"
}
],
"require": {
"laravel/github-webhooks": "*"
}
}- Install the package:
composer require laravel/github-webhooks- Publish configuration and migrations:
php artisan vendor:publish --tag=github-webhooks-config
php artisan vendor:publish --tag=github-webhooks-migrations- Run migrations:
php artisan migrateAdd these variables to your .env file:
# Secret for validating GitHub webhooks (optional but recommended)
GITHUB_WEBHOOK_SECRET=your-webhook-secret
# Route prefix (default: webhooks)
GITHUB_WEBHOOK_ROUTE_PREFIX=webhooks
# Store webhooks in database (default: true)
GITHUB_WEBHOOK_STORE=true
# Deployment Configuration
GITHUB_WEBHOOK_BRANCH=main
GITHUB_WEBHOOK_REPOSITORY_PATH=/path/to/your/project
GITHUB_WEBHOOK_RUN_COMPOSER=true
GITHUB_WEBHOOK_RUN_MIGRATIONS=true
GITHUB_WEBHOOK_RUN_NPM=false
GITHUB_WEBHOOK_RUN_CACHE_CLEAR=true
GITHUB_WEBHOOK_OPTIMIZE=true
GITHUB_WEBHOOK_CREATE_STORAGE_LINK=true
GITHUB_WEBHOOK_RESTART_QUEUE=falseThe package configuration file (config/github-webhooks.php) provides extensive options:
return [
// GitHub webhook secret for signature validation
'secret' => env('GITHUB_WEBHOOK_SECRET'),
// Route configuration
'route_prefix' => env('GITHUB_WEBHOOK_ROUTE_PREFIX', 'webhooks'),
'middleware' => [
// Add middleware like 'throttle:60,1'
],
// Storage configuration
'store_webhooks' => env('GITHUB_WEBHOOK_STORE', true),
// Handler configuration
'handlers' => [
'push' => [
App\Webhooks\Handlers\PushHandler::class,
],
'pull_request' => [
App\Webhooks\Handlers\PullRequestHandler::class,
],
'*' => [
App\Webhooks\Handlers\LogAllEventsHandler::class,
],
],
// Error handling
'continue_on_handler_failure' => true,
// Auto-deployment configuration
'auto_update_branches' => ['main', 'master', 'develop'],
'branch' => env('GITHUB_WEBHOOK_BRANCH', 'main'),
'repository_path' => env('GITHUB_WEBHOOK_REPOSITORY_PATH', base_path()),
'deployment' => [
'run_composer' => env('GITHUB_WEBHOOK_RUN_COMPOSER', true),
'run_migrations' => env('GITHUB_WEBHOOK_RUN_MIGRATIONS', true),
'run_npm' => env('GITHUB_WEBHOOK_RUN_NPM', false),
'cache_clear' => env('GITHUB_WEBHOOK_RUN_CACHE_CLEAR', true),
'optimize' => env('GITHUB_WEBHOOK_OPTIMIZE', true),
'create_storage_link' => env('GITHUB_WEBHOOK_CREATE_STORAGE_LINK', true),
'restart_queue' => env('GITHUB_WEBHOOK_RESTART_QUEUE', false),
]
];- Go to your GitHub repository settings
- Click "Webhooks" in the left menu
- Click "Add webhook"
- Configure:
- Payload URL:
https://your-domain.com/webhooks/github - Content type:
application/json - Secret: Your secret (same as
GITHUB_WEBHOOK_SECRET) - Events: Select the events you want to receive
- Payload URL:
- Webhook Reception: Secure endpoint for GitHub webhooks
- Signature Validation: HMAC-SHA256 signature verification
- Database Storage: Store webhook data for audit and replay
- Event Handling: Flexible handler system for different events
- Error Handling: Robust error handling with optional failure tolerance
- Automated Git Pull: Automatic repository updates on push events
- Composer Management: Automatic dependency installation
- NPM Support: Node.js dependency and build management
- Database Migrations: Automatic migration execution
- Cache Management: Cache clearing and optimization
- Queue Management: Worker restart capability
- Storage Links: Automatic symbolic link creation
- Webhook Management: List, filter, and reprocess webhooks
- Repository Operations: Clone and update repositories
- Secret Generation: Secure webhook secret generation
- Configuration Validation: Validate webhook setup
Create handlers to process GitHub events:
<?php
namespace App\Webhooks\Handlers;
use Illuminate\Http\Request;
use Laravel\GitHubWebhooks\Contracts\WebhookHandler;
class DeploymentHandler implements WebhookHandler
{
public function handle(string $event, array $payload, Request $request): mixed
{
if ($event === 'push') {
$branch = str_replace('refs/heads/', '', $payload['ref'] ?? '');
if ($branch === 'main') {
// Trigger deployment
$this->triggerDeployment($payload);
}
}
return ['deployed' => true];
}
private function triggerDeployment(array $payload): void
{
// Your deployment logic
}
}In config/github-webhooks.php:
'handlers' => [
'push' => [
App\Webhooks\Handlers\DeploymentHandler::class,
],
'pull_request' => [
App\Webhooks\Handlers\PullRequestHandler::class,
],
// Handler for all events
'*' => [
App\Webhooks\Handlers\LogAllEventsHandler::class,
],
],use Laravel\GitHubWebhooks\GitHubWebhooks;
// Register a handler on the fly
GitHubWebhooks::on('push', function ($event, $payload, $request) {
// Process push event
return ['status' => 'processed'];
});
// Register handler for multiple events
GitHubWebhooks::on(['push', 'pull_request'], new MyCustomHandler());The package includes a comprehensive deployment service for automated deployments:
use Laravel\GitHubWebhooks\Service\DeploymentService;
// In your webhook handler
public function handle(string $event, array $payload, Request $request): mixed
{
if ($event === 'push') {
$branch = str_replace('refs/heads/', '', $payload['ref'] ?? '');
if (in_array($branch, config('github-webhooks.auto_update_branches', ['main']))) {
$deploymentService = new DeploymentService();
$result = $deploymentService->deploy($payload);
return $result;
}
}
return ['status' => 'skipped'];
}The deployment service automatically handles:
- Git Pull: Updates repository from the specified branch
- Composer Install: Installs PHP dependencies with optimization
- NPM Operations: Installs and builds frontend assets
- Database Migrations: Runs pending migrations safely
- Cache Management: Clears and rebuilds application cache
- Optimization: Caches routes, config, and views for production
- Storage Links: Creates symbolic links for public storage
- Queue Restart: Restarts queue workers to load new code
Each step is configurable via the deployment configuration and logs detailed information for monitoring.
use Laravel\GitHubWebhooks\Events\GitHubWebhookReceived;
// In your EventServiceProvider
protected $listen = [
GitHubWebhookReceived::class => [
App\Listeners\HandleGitHubWebhook::class,
],
];<?php
namespace App\Listeners;
use Laravel\GitHubWebhooks\Events\GitHubWebhookReceived;
class HandleGitHubWebhook
{
public function handle(GitHubWebhookReceived $event): void
{
$eventType = $event->eventType;
$payload = $event->payload;
$deliveryId = $event->deliveryId;
// Your custom logic
}
}The package provides several Artisan commands for managing GitHub webhooks:
# Generate a new secure webhook secret
php artisan github-webhooks:generate-secret
# Show the secret without writing to .env
php artisan github-webhooks:generate-secret --show
# Force overwrite existing secret
php artisan github-webhooks:generate-secret --force
# Generate secret with custom length
php artisan github-webhooks:generate-secret --length=64# Validate complete configuration
php artisan github-webhooks:validate
# Test with specific URL
php artisan github-webhooks:validate --url=https://your-domain.com/webhooks/github# List all webhooks
php artisan github-webhooks:list
# Filter by event type
php artisan github-webhooks:list --event=push
# Show only unprocessed webhooks
php artisan github-webhooks:list --unprocessed
# Show only processed webhooks
php artisan github-webhooks:list --processed
# Limit number of results
php artisan github-webhooks:list --limit=5
# Reprocess specific webhook
php artisan github-webhooks:reprocess {webhook_id}# List all local repositories
php artisan github-webhooks:list-repos
# Update repository from GitHub
php artisan github-webhooks:update-repo owner/repo --branch=main --clone-url=https://github.com/owner/repo.git
# Force update (ignore local changes)
php artisan github-webhooks:update-repo owner/repo --force
# Use custom path
php artisan github-webhooks:list-repos --path=/custom/pathThe package stores webhooks in the git_hub_webhooks table with these fields:
id: Auto-incremented IDevent_type: GitHub event type (push, pull_request, etc.)delivery_id: GitHub delivery ID for deduplicationpayload: JSON webhook data from GitHubheaders: HTTP headers from the webhook requestprocessed_at: Processing timestamp (nullable)created_at/updated_at: Laravel timestamps
use Laravel\GitHubWebhooks\Models\GitHubWebhook;
// Get all unprocessed push webhooks
$webhooks = GitHubWebhook::eventType('push')
->unprocessed()
->get();
// Get all processed webhooks
$processedWebhooks = GitHubWebhook::processed()->get();
// Mark a webhook as processed
$webhook->update(['processed_at' => now()]);
// Get webhooks by delivery ID
$webhook = GitHubWebhook::where('delivery_id', $deliveryId)->first();The GitHubWebhook model includes these query scopes:
unprocessed(): Webhooks that haven't been processed yetprocessed(): Webhooks that have been processedeventType($type): Filter by specific GitHub event type
The package automatically validates GitHub signatures if you configure a secret. This validation:
- Uses HMAC-SHA256 algorithm as required by GitHub
- Compares securely with
hash_equals()to prevent timing attacks - Returns 401 error if signature is invalid
- Logs security violations for monitoring
The package provides specific exceptions for different error scenarios:
InvalidSignatureException: Thrown when webhook signature validation failsDeploymentFailedException: Thrown when automated deployment encounters errorsWebhookHandlerException: Thrown when custom handlers failRepositoryException: Thrown when repository operations failSlackNotificationException: Thrown when notification services fail
use Laravel\GitHubWebhooks\Exceptions\InvalidSignatureException;
use Laravel\GitHubWebhooks\Exceptions\DeploymentFailedException;
try {
// Your webhook handling code
} catch (InvalidSignatureException $e) {
// Handle signature validation failure
Log::warning('Invalid webhook signature', ['error' => $e->getMessage()]);
} catch (DeploymentFailedException $e) {
// Handle deployment failure
Log::error('Deployment failed', ['error' => $e->getMessage()]);
}Add middleware in configuration:
'middleware' => [
'throttle:60,1', // Rate limiting
'api', // API middleware
],The package can handle all GitHub events, including:
push: Commits pushedpull_request: Pull requests (opened, closed, synchronized, etc.)issues: Issues (opened, closed, labeled, etc.)release: Releasesdeployment: Deploymentsworkflow_run: GitHub Actions runs- And many more...
Enable debug logging by setting the log level to debug in your webhook handlers:
use Illuminate\Support\Facades\Log;
public function handle(string $event, array $payload, Request $request): mixed
{
Log::debug('Webhook received', [
'event' => $event,
'delivery_id' => $request->header('X-GitHub-Delivery'),
'payload_size' => strlen(json_encode($payload))
]);
// Your handling logic
}- Check URL accessibility: Ensure your webhook URL is publicly accessible
- Verify routing: Check that the route is properly registered
- Review middleware: Ensure middleware doesn't block the requests
- Check GitHub delivery: Review the "Recent Deliveries" tab in GitHub webhook settings
- Secret mismatch: Verify
GITHUB_WEBHOOK_SECRETmatches GitHub configuration - Encoding issues: Ensure the secret doesn't contain special characters that might be encoded differently
- Environment loading: Verify the
.envfile is properly loaded
- Permission issues: Ensure the web server has proper file permissions
- Git access: Verify the server can access the Git repository
- Dependencies: Check that required tools (git, composer, npm) are installed
- Path configuration: Verify
GITHUB_WEBHOOK_REPOSITORY_PATHis correct
Monitor webhook processing through Laravel logs:
# Follow real-time logs
tail -f storage/logs/laravel.log
# Search for webhook-related entries
grep -i "webhook" storage/logs/laravel.log
# Search for deployment logs
grep -i "deployment" storage/logs/laravel.logUse ngrok for local development and testing:
# Install ngrok
brew install ngrok # macOS
# or download from https://ngrok.com
# Expose local server
ngrok http 8000
# Use the generated URL in GitHub webhook configuration
# Example: https://abc123.ngrok.io/webhooks/githubUse the built-in validation command to check your setup:
php artisan github-webhooks:validateThis command checks:
- Configuration file validity
- Environment variables
- Route registration
- Handler class existence
- Database connectivity
You can manually test webhook processing using the reprocess command:
# List recent webhooks
php artisan github-webhooks:list --limit=5
# Reprocess a specific webhook
php artisan github-webhooks:reprocess {webhook_id}This package is designed to be extensible and welcomes contributions. You can:
- Create custom handlers: Implement the
WebhookHandlerinterface for specialized processing - Extend the GitHubWebhook model: Add custom attributes and relationships
- Add custom middleware: Implement additional security or processing layers
- Custom deployment steps: Extend the
DeploymentServicefor specific needs
- Clone the repository
- Install dependencies:
composer install - Run tests:
vendor/bin/phpunit - Follow PSR-12 coding standards
The package includes comprehensive tests. Run them with:
vendor/bin/phpunit- Name:
laravel/github-webhooks - Version: 1.0.0
- Author: Balesco ([email protected])
- License: MIT
- Requirements: PHP ^8.2, Laravel ^11.0|^12.0
This package is open-sourced software licensed under the MIT license.
For issues, feature requests, or questions:
- Check the troubleshooting section above
- Review existing GitHub issues
- Create a new issue with detailed information
- Include log outputs and configuration when reporting bugs