dennenboom/harvest

Zero downtime deployment tool for Laravel applications

v1.0.0 2025-05-23 21:43 UTC

This package is auto-updated.

Last update: 2025-05-27 14:38:44 UTC


README

Harvest is a robust deployment system for Laravel applications that ensures zero downtime, reliable rollbacks, and consistent deployment across multiple servers.

Requirements

  • PHP 8.1+
  • Git
  • Composer
  • npm (for applications with frontend assets)
  • Ubuntu server (recommended)
  • Laravel 10+ application

Installation

Global Installation (Recommended)

Install Harvest globally on your deployment server(s):

composer global require dennenboom/harvest

Ensure Composer's global bin directory is in your PATH:

# Add this to your .bashrc or .zshrc
export PATH="$PATH:$HOME/.composer/vendor/bin"

# Reload your shell or run:
source ~/.bashrc

Verify installation:

harvest --version

Project-Specific Installation

If you prefer to include Harvest as a project dependency:

composer require dennenboom/harvest --dev

Then use it with:

vendor/bin/harvest deploy

Quick Start

1. Initialize Configuration

Create your configuration directory and copy the template:

# Create configuration directory
mkdir -p ~/.harvest

# Copy the template (adjust path based on your installation)
cp ~/.composer/vendor/dennenboom/harvest/config/harvest.php ~/.harvest/config.php

2. Configure Your Applications

Edit the configuration file:

nano ~/.harvest/config.php

Update the configuration with your application details:

<?php

return [
    'applications' => [
        'my-app' => [
            'name' => 'my-app',
            'repository' => 'git@github.com:your-org/your-repo.git',
            'branch' => 'main',
            'path' => '/var/www/my-app',
            'releases_to_keep' => 5,
            // ... other settings
        ],
    ],
    
    'default_app' => 'my-app',
    
    // Global settings...
];

3. Prepare Your Server

Ensure your deployment directory exists and has proper permissions:

# Create deployment directory
sudo mkdir -p /var/www/my-app
sudo chown $USER:www-data /var/www/my-app
sudo chmod 755 /var/www/my-app

# Create shared directory for persistent files
mkdir -p /var/www/my-app/shared/storage

4. Configure Your Web Server

Point your web server to the current/public directory:

Nginx Example:

server {
    listen 80;
    server_name yourdomain.com;
    root /var/www/my-app/current/public;
    
    index index.php;
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

5. Set Up SSH Keys

Ensure your server can access your Git repositories:

# Generate SSH key if you don't have one
ssh-keygen -t ed25519 -C "your-email@example.com"

# Add the public key to your Git provider (GitHub, GitLab, etc.)
cat ~/.ssh/id_ed25519.pub

# Test SSH access
ssh -T git@github.com

6. Deploy Your Application

harvest deploy

Usage

Deploying

Deploy the default application:

harvest deploy

Deploy a specific application:

harvest deploy my-app

Deploy with options:

harvest deploy my-app --branch=develop --no-tests --force

Available Options:

  • --branch=BRANCH - Deploy a specific branch
  • --no-tests - Skip running tests
  • --no-migrations - Skip running migrations
  • --force - Force deployment even if tests fail

Listing Releases

harvest releases [app-name]

Rolling Back

Rollback to the previous release:

harvest rollback [app-name]

Rollback to a specific release:

harvest rollback my-app --release=20240508123456

One-Time Scripts

Harvest supports executing scripts that should run only once during deployment:

  1. Create a deploy-scripts directory in your project root
  2. Add PHP scripts that you want to run during deployment
  3. Scripts are executed once and moved to deploy-scripts/executed/

Example script (deploy-scripts/update-permissions.php):

<?php
// This script will run once during deployment

echo "Updating file permissions...\n";

// Your one-time deployment code here
exec('chmod -R 755 storage/');

echo "Permissions updated successfully.\n";
exit(0); // Return 0 for success

Directory Structure

After deployment, your application directory will look like this:

/var/www/my-app/
├── current -> /var/www/my-app/releases/20240508123456  (symlink)
├── releases/
│   ├── 20240508123456/  (latest release)
│   ├── 20240507123456/  (previous release)
│   ├── 20240506123456/
│   ├── 20240505123456/
│   └── 20240504123456/
└── shared/
    ├── .env
    └── storage/
        ├── app/
        ├── framework/
        └── logs/

Troubleshooting

Permission Issues

# Fix ownership
sudo chown -R www-data:www-data /var/www/my-app

# Fix storage permissions
sudo chmod -R 775 /var/www/my-app/shared/storage

Git Authentication

# Test SSH access to your Git provider
ssh -T git@github.com

# If using HTTPS, cache credentials
git config --global credential.helper cache

Config File Not Found

If you get a "config file not found" error:

# Check if config exists
ls -la ~/.harvest/config.php

# Copy template if missing
cp ~/.composer/vendor/dennenboom/harvest/config/harvest.php ~/.harvest/config.php

Failed Deployment Cleanup

If a deployment fails, Harvest automatically cleans up. However, you can manually clean up if needed:

# Remove a failed release
rm -rf /var/www/my-app/releases/20240508123456

# Check current symlink
ls -la /var/www/my-app/current

License

The MIT License (MIT). Please see License File for more information.