Metadata-Version: 2.4
Name: minideploy
Version: 1.0.0
Summary: Simple deployment tool for your VPS
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: click>=8.3.1
Requires-Dist: jinja2>=3.1.6
Requires-Dist: paramiko>=4.0.0
Requires-Dist: pydantic>=2.12.5
Requires-Dist: pyyaml>=6.0.3
Requires-Dist: rich>=14.3.2
Description-Content-Type: text/markdown

# minideploy

Simple deployment tool for your VPS. Deploy applications with rolling updates, health checks, and automatic rollbacks.

## Features

- **Simple Configuration**: Single `deploy.yml` file per project
- **JSON Schema**: Full schema validation for IDE support
- **Multiple Service Managers**: Systemd, Docker Compose, PM2
- **Rolling Deployments**: Zero-downtime deployments with health checks
- **Release Management**: Automatic versioning with easy rollback
- **Built-in Health Checks**: Verify deployments before switching traffic
- **Deployment Hooks**: Run custom scripts at various deployment stages
- **SSH-based**: No agents required on the server
- **Shell Completions**: Tab completion for bash, zsh, and fish

## ⚠️ Service Manager Status

> **Systemd** ✅ Fully implemented and tested  
> **Docker Compose** ⚠️ Implemented but not fully tested  
> **PM2** ⚠️ Implemented but not fully tested  
>
> While Docker Compose and PM2 are implemented, they have not been extensively tested. Please report any issues you encounter.

## Installation

```bash
uv tool install minideploy
```

Or with pip:

```bash
pip install minideploy
```

## Quick Start

### 1. Initialize Configuration

```bash
cd your-project
minideploy init
```

This creates a `deploy.yml` file. Edit it for your project:

```yaml
app:
  name: "myapp"
  type: "web"

build:
  type: "custom"
  command: "echo 'Replace with your build command'"
  output_dir: "dist"

server:
  host: "your-server.com"
  user: "deploy"
  deploy_dir: "/opt/myapp"

service:
  type: "systemd"
  instances:
    - id: "1"
      port: 8080
      health_endpoint: "/health"
  systemd_options:
    user: "deploy"
    restart: "always"
    working_directory: "/opt/myapp/current"
    exec_start: "/opt/myapp/current/myapp"

deploy:
  strategy: "rolling"
  keep_releases: 3
  health_check:
    timeout: 30
    retries: 3
    wait_between_instances: 5
  hooks:
    pre_deploy: "echo 'Starting deployment'"
    post_deploy: "echo 'Deployment complete'"
```

### 2. Setup Server (run once)

```bash
minideploy setup
```

This creates the directory structure and sets up systemd services.

### 3. Deploy

```bash
minideploy deploy
```

## Commands

- `minideploy init` - Create a sample deploy.yml
- `minideploy setup` - Initial server setup
- `minideploy setup --regenerate` - Recreate service configuration
- `minideploy build` - Build the application locally
- `minideploy upload` - Upload build to server
- `minideploy deploy` - Full deployment (build + upload + deploy)
- `minideploy status` - Show deployment status
- `minideploy releases` - List all releases
- `minideploy rollback` - Rollback to previous release
- `minideploy health` - Run health checks
- `minideploy logs` - View service logs
- `minideploy service start|stop|restart|status` - Manage services
- `minideploy destroy` - Remove all server setup (services and directories)
- `minideploy ssh` - Open SSH session to server
- `minideploy completion <shell>` - Generate shell completions

## Shell Completions

minideploy supports tab completion for **bash**, **zsh**, and **fish** shells.

### Bash

Add to `~/.bashrc`:

```bash
eval "$(_MINIDEPLOY_COMPLETE=bash_source minideploy)"
```

Or use the built-in install command:

```bash
minideploy completion bash --install
source ~/.bashrc
```

### Zsh

Add to `~/.zshrc`:

```zsh
eval "$(_MINIDEPLOY_COMPLETE=zsh_source minideploy)"
```

Or use the built-in install command:

```bash
minideploy completion zsh --install
source ~/.zshrc
```

### Fish

Create file `~/.config/fish/completions/minideploy.fish`:

```fish
_MINIDEPLOY_COMPLETE=fish_source minideploy | source
```

Or use the built-in install command:

```bash
minideploy completion fish --install
```

## Managing Server Setup

### Regenerate Service Configuration

If you need to update the service configuration (e.g., change systemd options):

```bash
# This removes existing services and recreates them
minideploy setup --regenerate
```

### Destroy Server Setup

To completely remove a project from the server (services and all files):

```bash
# This will prompt for confirmation
minideploy destroy

# Force destroy without confirmation
minideploy destroy --force
```

**Warning**: This permanently deletes:
- All systemd/docker/pm2 services for the app
- The entire deployment directory (`/opt/<app-name>/`)
- All releases and uploaded files

## Options

- `-c, --config` - Path to configuration file (default: deploy.yml)
- `-v, --verbose` - Enable verbose output
- `--dry-run` - Show what would be done without executing

## Directory Structure on Server

```
/opt/<app-name>/
├── current -> releases/<current-release>  # Symlink to active release
├── releases/                              # Versioned releases
│   ├── release_20240213_143022/
│   ├── release_20240213_120000/
│   └── ...
└── uploads/                               # Temporary upload directory
```

## Configuration Reference

### App
- `name` - Application name
- `type` - Application type (for documentation)

### Build
- `type` - Build type: `dotnet`, `npm`, `custom`, `docker`, etc.
- `command` - Build command to execute
- `output_dir` - Build output directory
- `env_file` - Environment file to upload (optional)
- `pre_build` - Command to run before build (optional)
- `post_build` - Command to run after build (optional)

### Server
- `host` - Server hostname or IP
- `user` - SSH user (default: deploy)
- `port` - SSH port (default: 22)
- `ssh_key` - Path to SSH private key (optional)
- `deploy_dir` - Deployment directory on server

### Service
- `type` - Service manager: `systemd`, `docker-compose`, `pm2`
- `instances` - List of service instances
  - `id` - Instance identifier
  - `port` - Port for health checks
  - `health_endpoint` - Health check endpoint
- `template` - Custom service template file (optional)

#### Systemd Options
- `user` - User to run service as
- `group` - Group to run service as (optional)
- `restart` - Restart policy (default: always)
- `working_directory` - Working directory
- `exec_start` - Command to execute (use `%i` for instance id)
- `environment_file` - Path to environment file (optional)
- `environment` - Environment variables as key-value pairs (optional)
- `additional_options` - Additional [Service] section options

#### PM2 Options
- `script` - Script to run (e.g., `server.js`, `dist/main.js`)
- `interpreter` - Interpreter to use (optional, e.g., `python`, `node`)
- `instances` - Number of instances per app (default: 1)
- `exec_mode` - Execution mode: `fork` or `cluster` (default: fork)
- `max_memory_restart` - Restart if memory exceeds limit (e.g., `500M`)
- `env` - Environment variables as key-value pairs (optional)
- `cwd` - Working directory (optional)

#### Docker Compose Options
- `build` - Build images before starting (default: false)
- `pull` - Pull images before starting (default: true)
- `remove_orphans` - Remove orphan containers (default: true)
- `force_recreate` - Force recreate containers (default: false)
- `env_file` - Path to environment file (optional)

### Deploy
- `strategy` - Deployment strategy: `rolling`, `blue-green`
- `keep_releases` - Number of releases to keep (default: 3)
- `health_check` - Health check configuration
  - `timeout` - Timeout in seconds (default: 30)
  - `retries` - Number of retries (default: 3)
  - `interval` - Interval between retries in seconds (default: 5)
  - `wait_between_instances` - Wait time between deployments (default: 5)
  - `success_codes` - List of HTTP status codes considered successful (default: [200])
- `hooks` - Deployment hooks (optional)
  - `pre_deploy` - Command to run before deployment
  - `post_deploy` - Command to run after successful deployment
  - `pre_rollback` - Command to run before rollback
  - `post_rollback` - Command to run after successful rollback
  - `on_failure` - Command to run when deployment fails

## Examples

### .NET Application

```yaml
app:
  name: "myapi"
  type: "dotnet"

build:
  type: "dotnet"
  command: "dotnet publish -c Release -r linux-x64 --self-contained -o publish"
  output_dir: "publish"

server:
  host: "myvps"
  user: "deploy"
  deploy_dir: "/opt/myapi"

service:
  type: "systemd"
  instances:
    - id: "1"
      port: 5001
      health_endpoint: "/health"
    - id: "2"
      port: 5002
      health_endpoint: "/health"
  systemd_options:
    user: "deploy"
    restart: "always"
    working_directory: "/opt/myapi/current"
    exec_start: "/opt/myapi/current/MyApi --urls http://localhost:500%i"
```

### Node.js Application with PM2

```yaml
app:
  name: "myapp"
  type: "node"

build:
  type: "npm"
  command: "npm ci && npm run build"
  output_dir: "dist"

server:
  host: "myvps"
  user: "deploy"
  deploy_dir: "/opt/myapp"

service:
  type: "pm2"
  instances:
    - id: "1"
      port: 3000
      health_endpoint: "/health"
  pm2_config: "ecosystem.config.js"
  pm2_options:
    script: "dist/server.js"
    instances: 2
    exec_mode: "cluster"
    max_memory_restart: "500M"
    env:
      NODE_ENV: "production"

deploy:
  strategy: "rolling"
  keep_releases: 5
  hooks:
    pre_deploy: "npm run db:migrate"
    post_deploy: "curl -X POST https://api.slack.com/notify -d 'Deployed!'"
    on_failure: "curl -X POST https://api.slack.com/notify -d 'Deploy failed!'"
```

### Docker Compose Application

```yaml
app:
  name: "myapp"
  type: "docker"

build:
  type: "docker"
  output_dir: "."

server:
  host: "myvps"
  user: "deploy"
  deploy_dir: "/opt/myapp"

service:
  type: "docker-compose"
  instances:
    - id: "1"
      port: 8080
      health_endpoint: "/health"
  docker_compose_file: "docker-compose.yml"
  docker_compose_options:
    build: true
    force_recreate: true
    remove_orphans: true

deploy:
  strategy: "rolling"
  health_check:
    timeout: 60
    retries: 5
    success_codes: [200, 204]
```

## JSON Schema

A JSON Schema is available for `deploy.yml` validation and IDE autocomplete support:

**schema.json**

Add the schema to your `deploy.yml` for IDE support:

```yaml
# yaml-language-server: $schema=https://raw.githubusercontent.com/hamidriaz1998/minideploy/main/schema.json

app:
  name: "myapp"
  # ... rest of your config
```

### VS Code

Install the [YAML extension](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) and add to your settings:

```json
{
  "yaml.schemas": {
    "https://raw.githubusercontent.com/hamidriaz1998/minideploy/main/schema.json": "deploy.yml"
  }
}
```

### PyCharm / IntelliJ

Go to **Settings → Languages & Frameworks → Schemas and DTDs → JSON Schema Mappings** and add:

- **Schema file or URL**: `https://raw.githubusercontent.com/hamidriaz1998/minideploy/main/schema.json`
- **File path pattern**: `deploy.yml`

### Other Editors

Most modern editors support JSON Schema validation through the [YAML Language Server](https://github.com/redhat-developer/yaml-language-server).

## Deployment Hooks

Hooks allow you to run custom commands at different stages of the deployment process. All hooks run on the remote server in the deployment directory.

| Hook | When it runs |
|------|--------------|
| `pre_deploy` | Before deployment starts (after upload) |
| `post_deploy` | After successful deployment |
| `pre_rollback` | Before rollback starts |
| `post_rollback` | After successful rollback |
| `on_failure` | When deployment fails (before rollback) |

### Example Use Cases

```yaml
deploy:
  hooks:
    # Run database migrations before deploying
    pre_deploy: "cd current && ./migrate.sh"
    
    # Clear cache and notify team after deployment
    post_deploy: |
      curl -X POST http://localhost:8080/cache/clear
      curl -X POST https://slack.com/webhook -d '{"text":"Deployed successfully!"}'
    
    # Notify on failure
    on_failure: "curl -X POST https://slack.com/webhook -d '{\"text\":\"Deployment failed!\"}'"
```

## License

MIT
