Metadata-Version: 2.4
Name: uhdeploy
Version: 0.1.4
Summary: Universal Local-to-VPS automated deployment CLI (SSH/SFTP, FTP, Docker, Local Build Pipelines)
Home-page: https://github.com/AbdullahAhmad-0/Universal-Deployer
Author: Abdullah Ahmad
License: MIT
Project-URL: Homepage, https://github.com/AbdullahAhmad-0/Universal-Deployer
Project-URL: Repository, https://github.com/AbdullahAhmad-0/Universal-Deployer
Project-URL: Issues, https://github.com/AbdullahAhmad-0/Universal-Deployer/issues
Keywords: deployment,vps,docker,ssh,sftp,ftp,devops,automation,cli
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Installation/Setup
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyyaml>=6.0
Requires-Dist: paramiko>=2.11.0
Requires-Dist: colorama>=0.4.6
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# 🚀 uhdeploy - Universal Deployer CLI

A modern, declarative, and color-rich deployment CLI tool for web applications, Docker containers, and static sites. Deploy seamlessly from your local machine to any Linux VPS or hosting server using **SSH/SFTP** or **FTP**.

---

## 📦 Installation

Install `uhdeploy` directly via pip:

```bash
pip install uhdeploy
```

Or install from source for development:

```bash
git clone https://github.com/AbdullahAhmad-0/Universal-Deployer.git
cd Universal-Deployer
pip install -e .
```

---

## ✨ Features

- **Global CLI Command**: Run `uhdeploy` anywhere in your terminal.
- **YAML + Dockerfile-Style Syntax**: Configure complex builds and deployments using intuitive directives like `RUN`, `COPY`, `CMD`, `WORKDIR`, and `ENV`.
- **Interactive File Discovery**: If `deploy.yml` is not found in the current folder, `uhdeploy` prompts you to enter your project directory or file path automatically.
- **Dual Protocol Support**:
  - **SSH / SFTP**: Full remote terminal execution (`paramiko`), automated directory sync, and Docker container orchestration.
  - **FTP**: Built-in FTP transfer (`ftplib`) for static/shared hosting environments (with graceful warnings for unsupported remote commands).
- **Flexible Docker Workflows**:
  - **Local Build & Tar Transfer (Default)**: Builds the Docker image locally, exports it to a `.tar` archive, transfers it via SFTP, and loads it into the remote Docker daemon. This saves RAM and CPU on low-spec VPS servers!
  - **Remote Build**: Syncs files and triggers `docker compose build` directly on the VPS.
  - **Auto Environment Sync**: Automatically detects and syncs environment files (e.g. `.env.production`) referenced in your `docker-compose.yml`.
- **Traditional (No Docker) Deployments**: Perfect for static frontends (React, Vue, Next.js static exports, Vite) or traditional Node/Python/PHP apps with local builds and Nginx reloading.
- **Dynamic Variable Substitution**: Seamlessly interpolate `${VPS_IP}`, `${SSH_KEY_PATH}`, or custom environment variables from `.env` or `.env.deploy` files.
- **Rich Terminal UI**: Full ANSI color formatting with `colorama`, interactive numbered selection menus, step badges (`[Docker]`, `[SSH]`, `[FTP]`), and upload progress bars.

---

## ⚡ Quick Start

### 1. Initialize Configuration
Generate a starter `deploy.yml` file in your project directory:

```bash
uhdeploy --init
```

Or view a commented example in your terminal:

```bash
uhdeploy --example
```

### 2. Configure Environment Variables (`.env`)
Create a `.env` file in your project root with your server credentials:

```dotenv
VPS_IP=123.45.67.89
VPS_USER=root
SSH_KEY_PATH=~/.ssh/id_rsa
SSH_PORT=22
# Optional:
SSH_PASSPHRASE=
VPS_PASSWORD=
```

### 3. Run Deployer
Launch the deployer:

```bash
# Interactive service selection menu
uhdeploy

# Or deploy a specific service directly
uhdeploy frontend

# Or deploy all services in order
uhdeploy all
```

*(You can also run it via `python -m uhdeploy` or `python deploy.py`)*

---

## 🛠️ Configuration Guide (`deploy.yml`)

The configuration file defines global server credentials and individual service deployment pipelines.

```yaml
# =============================================================================
# 🌐 GLOBAL SERVER SETTINGS (Inherited by all services)
# =============================================================================
server:
  type: ssh                    # "ssh" (SFTP + Shell) or "ftp" (File transfer only)
  host: ${VPS_IP}              # VPS Hostname or IP (from .env)
  user: ${VPS_USER:-root}      # SSH/FTP Username (defaults to root)
  port: 22                     # Port: 22 for SSH, 21 for FTP
  key_path: ${SSH_KEY_PATH}    # Path to private key file
  passphrase: ${SSH_PASSPHRASE}# (Optional) Private key passphrase
  password: ${VPS_PASSWORD}    # (Optional) SSH or FTP password
  remote_dir: /opt/my-app      # Remote base directory on VPS

# Optional custom env file to load (default: .env or .env.deploy)
env_file: .env

# =============================================================================
# 📦 SERVICES DEFINITION
# =============================================================================
services:

  # ---------------------------------------------------------------------------
  # 1. Frontend Service (WITHOUT DOCKER)
  # ---------------------------------------------------------------------------
  frontend:
    description: "Build Next.js / React frontend and sync static files"
    docker: false              # Disable docker for this service
    work_dir: ./frontend       # Working directory relative to project root

    # Local build steps (Dockerfile-style string commands):
    build:
      - RUN npm install
      - RUN npm run build
      - COPY package.json dist/package.json

    # Upload files or directories to the VPS:
    upload:
      - dist/ -> ${remote_dir}/frontend/dist
      - public/ -> ${remote_dir}/frontend/public

    # (Optional) Wipe remote destination directory before uploading:
    # clean_remote: true

    # Commands executed on VPS after uploading (SSH only):
    run_in_vps:
      - RUN systemctl reload nginx
      - RUN echo "Frontend updated and Nginx reloaded!"

  # ---------------------------------------------------------------------------
  # 2. Backend Service (WITH DOCKER)
  # ---------------------------------------------------------------------------
  backend:
    description: "FastAPI / Node API running in Docker Compose"
    work_dir: ./backend

    docker:
      enabled: true
      compose_file: docker-compose.yml # Compose file (defaults to docker-compose.yml)
      # (Optional: .env.production referenced in compose is auto-synced!)
      service_name: backend            # Name of service inside docker-compose.yml
      build_mode: local                # "local" (build tarball & upload) or "remote"
      image: my-backend:latest
      context: ./backend
      dockerfile: ./backend/Dockerfile # (Optional)

    # Remote steps executed on VPS BEFORE starting Docker:
    before_deploy:
      - RUN mkdir -p ${remote_dir}/backend/data

    # Remote steps executed on VPS AFTER starting Docker:
    # (Note: 'docker compose up -d <service>' is already executed automatically!)
    run_in_vps:
      - RUN docker compose ps
      - RUN docker compose logs --tail=25 backend

  # ---------------------------------------------------------------------------
  # 3. API / Worker (Direct Working Directory Upload with Ignore Rules)
  # ---------------------------------------------------------------------------
  api:
    description: "Sync current working directory directly to VPS with ignore rules"
    docker: false
    work_dir: ./api

    # Upload entire working directory (.) to remote VPS destination:
    upload:
      - . -> ${remote_dir}/api

    # Files and folders to ignore when uploading:
    # (You can also put these into a .deployignore file!)
    ignore:
      - node_modules
      - .venv
      - venv
      - __pycache__
      - .git
      - .env.local
      - "*.log"
      - "*.pyc"

    # (Optional) Wipe destination directory before uploading:
    # clean_remote: true

    run_in_vps:
      - RUN pm2 restart api || pm2 start index.js --name api
```

---

## 🧩 Step Directives Reference

Within `build`, `before_deploy`, and `run_in_vps`, you can write steps as clean strings or structured objects:

| Directive | Example | Description |
|-----------|---------|-------------|
| `RUN <cmd>` | `- RUN npm run build` | Runs a shell command (locally in `build`, or on the VPS in `before_deploy` / `run_in_vps`). |
| `CMD <cmd>` | `- CMD python manage.py migrate` | Alias for `RUN`. |
| `COPY <src> <dst>` | `- COPY ./dist -> ${remote_dir}/dist` | Copies local files/folders locally or uploads them to the remote server. |
| `WORKDIR <dir>` | `- WORKDIR ./subfolder` | Changes current working directory for subsequent steps. |
| `ENV <k>=<v>` | `- ENV NODE_ENV=production` | Sets an environment variable for subsequent steps. |

---

## 📁 Directory Uploads, Ignore Rules & Clean Remote

### 1. Uploading Current Working Directory (`.`)
If you want to upload the entire codebase of your working directory (e.g., Python, Node.js, PHP, or Go apps) rather than just a `dist/` subfolder, specify `.`:

```yaml
upload:
  - . -> ${remote_dir}/api
```

### 2. Ignoring Files and Folders (`ignore:`)
When uploading directories, you can exclude heavy, generated, or sensitive files using the `ignore:` (or `exclude:`) list in your `deploy.yml`:

```yaml
ignore:
  - node_modules
  - .venv
  - venv
  - __pycache__
  - .git
  - .env.local
  - "*.log"
  - "*.pyc"
```

> [!TIP]
> **Fast Folder Pruning**: Ignored directories like `node_modules` or `.venv` are never traversed, ensuring fast uploads without scanning tens of thousands of unnecessary files.

### 3. Using `.deployignore`
You can also place a **`.deployignore`** file in your service directory or project root using standard `.gitignore` syntax. `uhdeploy` will detect and apply these rules automatically.

### 4. Overwrite Behavior vs. `clean_remote`
- **Default (Safe Overwrite)**: `uhdeploy` overwrites matching files on the server with new ones. Any existing files already on the server that are not in your upload (e.g., user uploads, runtime database files, logs) **remain untouched and safe**.
- **Wiping Destination Folder (`clean_remote: true`)**: If you want to empty the target folder on the VPS before uploading fresh files, simply set:
  ```yaml
  clean_remote: true
  ```

---

## 🔒 SSH vs. 📡 FTP Differences

| Feature | SSH / SFTP | FTP (`ftplib`) |
|---------|:----------:|:--------------:|
| File & Directory Sync | ✅ Yes | ✅ Yes |
| Progress Indicator | ✅ Yes | ✅ Yes |
| Remote Shell Execution (`RUN`) | ✅ Yes | ❌ Not supported by FTP |
| Docker Container Management | ✅ Yes | ❌ Not supported by FTP |
| Authentication | Key file, Passphrase, or Password | Username & Password |

> [!NOTE]
> When `type: ftp` is selected, any remote command steps (e.g. `run_in_vps`) are safely skipped with a helpful warning notice instead of breaking your deployment.

---

## 🖥️ Command-Line Interface (CLI)

```
Usage:
  uhdeploy [OPTIONS] [SERVICE_NAME]
  (or python -m uhdeploy [OPTIONS] [SERVICE_NAME])

Options:
  -h, --help               Show full colorful help screen and exit.
  -e, --example            Display a syntax-highlighted example deploy.yml.
  --init                   Generate a starter deploy.yml in the current directory.
  -f, --file PATH          Specify path to deploy configuration file.
  -p, --project DIR        Specify project directory containing deploy configuration.
  -s, --service NAME       Name of service to deploy (or 'all').
  -l, --list               List all services available in the configuration file.
  --dry-run                Validate configuration and simulate steps without connecting.
```

### CLI Examples

```bash
# Preview build and deployment steps without making server changes:
uhdeploy backend --dry-run

# List configured services in a custom deploy file:
uhdeploy -f ./custom-deploy.yml --list

# Deploy a specific service from an external project directory:
uhdeploy -p D:/Projects/my-app frontend
```

---

## 🚢 Publishing to PyPI

To build and publish `uhdeploy` to PyPI:

1. **Install build tools**:
   ```bash
   pip install --upgrade build twine
   ```

2. **Build distribution packages (tar.gz and .whl)**:
   ```bash
   python -m build
   ```

3. **Check distribution packages**:
   ```bash
   twine check dist/*
   ```

4. **Upload to PyPI**:
   ```bash
   twine upload dist/*
   ```

Once published, anyone can install your package with:
```bash
pip install uhdeploy
```

---

## 📄 License

MIT License. Created by Abdullah Ahmad. Feel free to customize and extend for your deployment pipelines!
