feat(SCOPONE-0010): vendor agent assets and clean docs
This commit is contained in:
601
.github/skills/deploy-app/README.md
vendored
Normal file
601
.github/skills/deploy-app/README.md
vendored
Normal file
@@ -0,0 +1,601 @@
|
||||
# Deploy Application Skill
|
||||
|
||||
Automated deployment of Dockerized applications to remote servers.
|
||||
|
||||
## Features
|
||||
|
||||
✅ **Automated Docker builds and registry pushes** to Gitea
|
||||
✅ **SSH-based remote deployment** with compose orchestration
|
||||
✅ **Automatic reverse proxy** configuration with Nginx Proxy Manager
|
||||
✅ **Subdomain routing** - Apps served as `{app-name}.{root-domain}`
|
||||
✅ **SSL certificate** generation via Let's Encrypt
|
||||
✅ **Smart .env handling** - Auto-generates secrets, infers service URLs
|
||||
✅ **Network topology** management (proxy, ollama)
|
||||
✅ **No host port publishing** - Webapps are reached through Docker network + Nginx Proxy Manager
|
||||
✅ **Organized data storage** - All volumes under `./data/`
|
||||
✅ **Health monitoring** and log inspection
|
||||
✅ **Rollback guidance** on failures
|
||||
✅ **Update-aware deployments** - Detects existing stack/proxy and performs safe in-place updates
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Run Setup Wizard
|
||||
|
||||
```bash
|
||||
cd .github/skills/deploy-app
|
||||
chmod +x setup-wizard.sh
|
||||
./setup-wizard.sh
|
||||
```
|
||||
|
||||
Follow the prompts to generate your deployment configuration.
|
||||
|
||||
### 2. Deploy Your App
|
||||
|
||||
```
|
||||
deploy production
|
||||
```
|
||||
|
||||
That's it! The agent will handle both first deploys and updates.
|
||||
|
||||
If the remote stack directory or proxy host already exists, deployment is treated as an **update** (with idempotent proxy handling and additive env/volume changes).
|
||||
|
||||
## Files
|
||||
|
||||
- **SKILL.md** - Complete skill documentation (for the agent)
|
||||
- **setup-wizard.sh** - Interactive configuration generator
|
||||
- **README.md** - This file (user documentation)
|
||||
|
||||
## What Gets Deployed
|
||||
|
||||
```
|
||||
Remote Server: /srv/docker/stacks/my-app/
|
||||
├── compose.yaml # Generated Docker Compose file
|
||||
├── .env # Environment variables (if detected)
|
||||
└── data/ # Persistent application data
|
||||
├── <app-data> # Main application data
|
||||
├── uploads/ # If app needs uploads (auto-detected)
|
||||
├── cache/ # If app needs cache (auto-detected)
|
||||
└── logs/ # If app needs logs (auto-detected)
|
||||
```
|
||||
|
||||
All volumes are organized under the `data/` directory for clean separation.
|
||||
|
||||
## Supported Application Types
|
||||
|
||||
- **webapp** - Web applications with reverse proxy and SSL
|
||||
- **service** - Backend services without public access
|
||||
- **worker** - Background workers and queue processors
|
||||
|
||||
## Requirements
|
||||
|
||||
**Local:**
|
||||
- Docker installed
|
||||
- Access to workspace with Dockerfile
|
||||
- Environment variable `DEPLOY_CONFIG_{TARGET}` configured
|
||||
|
||||
**Remote Server:**
|
||||
- Docker and Docker Compose installed
|
||||
- SSH access configured
|
||||
- Docker networks created (`proxy`, optionally `ollama`)
|
||||
|
||||
**Services:**
|
||||
- Gitea instance with container registry enabled
|
||||
- Nginx Proxy Manager (for webapps)
|
||||
|
||||
## Configuration
|
||||
|
||||
See configuration examples below for different deployment scenarios.
|
||||
|
||||
### Production Server
|
||||
|
||||
```bash
|
||||
export DEPLOY_CONFIG_PRODUCTION='{
|
||||
"gitea_registry_url": "gitea.mycompany.com",
|
||||
"gitea_username": "deploy-bot",
|
||||
"gitea_token": "a1b2c3d4e5f6g7h8i9j0",
|
||||
"gitea_namespace": "production-apps",
|
||||
"ssh_host": "prod-server",
|
||||
"stacks_dir": "/srv/docker/stacks",
|
||||
"domain": "sal.giize.com",
|
||||
"npm_url": "https://proxy.mycompany.com",
|
||||
"npm_username": "admin@mycompany.com",
|
||||
"npm_password": "npm-admin-password"
|
||||
}'
|
||||
|
||||
# All app-specific settings (name, port, env vars, volumes, type)
|
||||
# are auto-detected from your codebase!
|
||||
# App will be served at: {app-name}.sal.giize.com
|
||||
```
|
||||
|
||||
### Staging Server
|
||||
|
||||
```bash
|
||||
export DEPLOY_CONFIG_STAGING='{
|
||||
"gitea_registry_url": "gitea.mycompany.com",
|
||||
"gitea_username": "deploy-bot",
|
||||
"gitea_token": "a1b2c3d4e5f6g7h8i9j0",
|
||||
"gitea_namespace": "staging-apps",
|
||||
"ssh_host": "staging-server",
|
||||
"stacks_dir": "/home/deploy/stacks",
|
||||
"domain": "staging.sal.giize.com",
|
||||
"npm_url": "https://proxy-staging.mycompany.com",
|
||||
"npm_username": "admin@mycompany.com",
|
||||
"npm_password": "npm-admin-password"
|
||||
}'
|
||||
```
|
||||
|
||||
### AI Service with LLM
|
||||
|
||||
```bash
|
||||
export DEPLOY_CONFIG_AI_SERVICE='{
|
||||
"gitea_registry_url": "gitea.mycompany.com",
|
||||
"gitea_username": "deploy-bot",
|
||||
"gitea_token": "a1b2c3d4e5f6g7h8i9j0",
|
||||
"gitea_namespace": "ai-services",
|
||||
"ssh_host": "ai-server",
|
||||
"stacks_dir": "/srv/docker/stacks",
|
||||
"domain": "ai.sal.giize.com",
|
||||
"npm_url": "https://proxy.mycompany.com",
|
||||
"npm_username": "admin@mycompany.com",
|
||||
"npm_password": "npm-admin-password",
|
||||
"proxy_network": "proxy",
|
||||
"ollama_network": "ollama",
|
||||
"ollama_container_name": "ollama"
|
||||
}'
|
||||
|
||||
# Network names are customizable
|
||||
# App will auto-connect to Ollama at: http://ollama:11434
|
||||
# (or your custom ollama_container_name:11434)
|
||||
```
|
||||
|
||||
### Background Worker (No Web Interface)
|
||||
|
||||
For services without a web interface, omit the NPM fields:
|
||||
|
||||
```bash
|
||||
export DEPLOY_CONFIG_WORKER='{
|
||||
"gitea_registry_url": "gitea.mycompany.com",
|
||||
"gitea_username": "deploy-bot",
|
||||
"gitea_token": "a1b2c3d4e5f6g7h8i9j0",
|
||||
"gitea_namespace": "workers",
|
||||
"ssh_host": "worker-server",
|
||||
"stacks_dir": "/srv/docker/stacks"
|
||||
}'
|
||||
```
|
||||
|
||||
### Configuration Fields
|
||||
|
||||
**Required for All Deployments:**
|
||||
- `gitea_registry_url` - Your Gitea instance domain (without https://)
|
||||
- `gitea_username` - Gitea username
|
||||
- `gitea_token` - Access token with package permissions
|
||||
- `gitea_namespace` - Organization or username
|
||||
- `ssh_host` - SSH alias from ~/.ssh/config
|
||||
- `stacks_dir` - Directory on remote server for stacks
|
||||
|
||||
**Required for Webapps:**
|
||||
- `domain` - Root domain (e.g., `sal.giize.com`). App will be served at `{app-name}.{domain}`
|
||||
- `npm_url` - Nginx Proxy Manager URL
|
||||
- `npm_username` - NPM admin email
|
||||
- `npm_password` - NPM admin password
|
||||
|
||||
**Optional Network Configuration:**
|
||||
- `proxy_network` - Docker network name for reverse proxy (default: `proxy`)
|
||||
- `ollama_network` - Docker network name for Ollama LLM (default: `ollama`)
|
||||
- `ollama_container_name` - Ollama container name for URL generation (default: `ollama`)
|
||||
- Apps requiring LLM will auto-set `OLLAMA_BASE_URL=http://{ollama_container_name}:11434`
|
||||
|
||||
**Auto-Detected from Codebase:**
|
||||
- **App name** - From package.json, Cargo.toml, pyproject.toml, go.mod, or directory name
|
||||
- **Port** - From Dockerfile EXPOSE, .env PORT, code patterns, or defaults to 3000
|
||||
- Used as internal container port for proxy upstream (not published on host by default)
|
||||
- **App type** - webapp/service/worker based on dependencies and keywords
|
||||
- **Environment variables** - Smart .env processing:
|
||||
- 🔐 Auto-generates secrets (JWT_SECRET, APP_KEY, etc.) using secure random values
|
||||
- 🔌 Infers service URLs (DATABASE_URL, REDIS_URL) from dependencies
|
||||
- 📋 Copies simple values (NODE_ENV, LOG_LEVEL) as-is
|
||||
- ❓ Asks for external API keys and credentials
|
||||
- **Volume mounts** - From README, Dockerfile VOLUME, common directories (bound under ./data/)
|
||||
- **LLM requirements** - From dependencies (openai, ollama, llama)
|
||||
|
||||
All detected settings are confirmed with you before deployment.
|
||||
|
||||
**Volume Binding:** All volumes are automatically bound under `./data/` on the host.
|
||||
Example: If app needs uploads, it creates `./data/uploads:/app/uploads`
|
||||
|
||||
**Domain Handling:** The `domain` field is the root domain. Your app is served as a subdomain.
|
||||
Example: `domain: "sal.giize.com"` + app name `my-api` → URL: `my-api.sal.giize.com`
|
||||
|
||||
**DNS Requirements:** Ensure you have a wildcard DNS record or individual A/CNAME records:
|
||||
- Wildcard: `*.sal.giize.com` → `your-server-ip`
|
||||
- Individual: `my-api.sal.giize.com` → `your-server-ip`
|
||||
|
||||
## Deployment Flow
|
||||
|
||||
1. **Parse target** - Extract deployment target name
|
||||
2. **Auto-detect app** - Scan codebase for app name, port, type, env vars, volumes, LLM usage
|
||||
3. **Process .env** - Generate secrets, infer service URLs, identify user inputs
|
||||
4. **Load config** - Get server/credential configuration
|
||||
5. **Detect mode** - Classify deployment as `new` or `update` using existing remote stack/proxy state
|
||||
6. **Confirm detection** - Show detected config and mode, ask for approval
|
||||
7. **Confirm environment** - Review .env processing and provide any needed values
|
||||
8. **Validate** - Check Dockerfile exists
|
||||
9. **Build** - Test build locally
|
||||
10. **Push** - Tag and push to Gitea registry
|
||||
11. **Transfer** - SSH to remote server
|
||||
12. **Setup** - Create/update directories, deploy merged `.env` and compose files
|
||||
13. **Deploy** - `docker compose down`, `docker compose pull`, `docker compose up -d`
|
||||
14. **Configure** - Create or update reverse proxy (webapps)
|
||||
- Upstream target uses Docker service + internal port (for example `my-app:3000`)
|
||||
15. **Verify** - Inspect logs and test application availability
|
||||
|
||||
## Key Features Explained
|
||||
|
||||
### Subdomain Routing
|
||||
|
||||
Apps are automatically served as subdomains of your root domain:
|
||||
- Config: `"domain": "sal.giize.com"`
|
||||
- App name: `my-api` (auto-detected)
|
||||
- **Result:** App accessible at `my-api.sal.giize.com`
|
||||
|
||||
**DNS Setup:** Configure wildcard DNS: `*.sal.giize.com` → your server IP
|
||||
|
||||
### Volume Organization
|
||||
|
||||
All persistent data is organized under `./data/`:
|
||||
```
|
||||
data/
|
||||
├── <app-data>/ # Main app data (always created)
|
||||
├── uploads/ # Auto-detected from codebase
|
||||
├── cache/ # Auto-detected from codebase
|
||||
└── logs/ # Auto-detected from codebase
|
||||
```
|
||||
|
||||
Docker compose mounts: `./data/uploads:/app/uploads`
|
||||
|
||||
### Auto-Detection
|
||||
|
||||
The skill scans your codebase to detect:
|
||||
- App name from package.json, Cargo.toml, pyproject.toml, go.mod, or directory
|
||||
- Container port from Dockerfile EXPOSE, .env, or code patterns
|
||||
- App type (webapp/service/worker) from dependencies
|
||||
- Environment variables from .env files
|
||||
- Volume requirements from README, Dockerfile, common patterns
|
||||
- LLM dependencies (openai, ollama)
|
||||
|
||||
All detected settings shown to you for confirmation before deployment.
|
||||
|
||||
### Smart .env Handling
|
||||
|
||||
When a `.env`, `.env.example`, or `.env.template` file is detected, the skill intelligently processes it:
|
||||
|
||||
**🔐 Auto-Generated Secrets**
|
||||
Variables like `JWT_SECRET`, `APP_KEY`, `SESSION_SECRET` are automatically generated using secure random values:
|
||||
```bash
|
||||
JWT_SECRET=a1b2c3d4e5f6... # 32-byte hex string
|
||||
```
|
||||
|
||||
**🔌 Inferred Service URLs**
|
||||
Database and service connections are constructed from container names based on detected dependencies:
|
||||
```bash
|
||||
DATABASE_URL=postgresql://my-app-db:5432/my-app
|
||||
REDIS_URL=redis://my-app-redis:6379
|
||||
MONGODB_URI=mongodb://my-app-mongo:27017/my-app
|
||||
```
|
||||
|
||||
**📋 Copied Values**
|
||||
Simple configuration values are preserved:
|
||||
```bash
|
||||
NODE_ENV=production
|
||||
LOG_LEVEL=info
|
||||
TZ=UTC
|
||||
```
|
||||
|
||||
**❓ User Input**
|
||||
External API keys and credentials are identified and you're prompted for values:
|
||||
```bash
|
||||
STRIPE_SECRET_KEY=sk_live_... # You'll be asked to provide this
|
||||
SENDGRID_API_KEY=SG... # You'll be asked to provide this
|
||||
```
|
||||
|
||||
**Confirmation**
|
||||
Before deployment, you'll see:
|
||||
- What was generated (with secure random values)
|
||||
- What was inferred (service URLs)
|
||||
- What was copied (simple configs)
|
||||
- What needs your input (API keys)
|
||||
|
||||
You can proceed as-is or provide specific values. The complete `.env` file is deployed to the server with secure permissions (chmod 600).
|
||||
|
||||
### Update-Safe Drift Handling
|
||||
|
||||
When deployment mode is `update`, the skill applies additive and non-destructive changes:
|
||||
|
||||
- **Environment merge:** existing remote `.env` keys are preserved; newly required keys are appended.
|
||||
- **Required secrets:** unresolved required placeholders still block deployment until provided.
|
||||
- **Volume drift:** new host directories are created as needed; existing volume paths are kept intact.
|
||||
- **Compose stability:** service naming remains stable for idempotent updates.
|
||||
|
||||
This minimizes downtime and avoids accidental configuration loss during redeployments.
|
||||
|
||||
## Quick Setup Guide
|
||||
|
||||
### 1. Create Gitea Token
|
||||
|
||||
```bash
|
||||
# Login to Gitea
|
||||
# Navigate to Settings → Applications → Generate New Token
|
||||
# Select scopes: write:package, read:package
|
||||
# Copy the generated token
|
||||
```
|
||||
|
||||
### 2. Configure SSH
|
||||
|
||||
```bash
|
||||
# Edit ~/.ssh/config
|
||||
cat >> ~/.ssh/config << 'EOF'
|
||||
|
||||
Host prod-server
|
||||
HostName 192.168.1.100
|
||||
User deploy
|
||||
IdentityFile ~/.ssh/deploy_key
|
||||
StrictHostKeyChecking accept-new
|
||||
EOF
|
||||
|
||||
# Test connection
|
||||
ssh prod-server "echo 'Connection successful'"
|
||||
```
|
||||
|
||||
### 3. Prepare Remote Server
|
||||
|
||||
```bash
|
||||
# SSH to server
|
||||
ssh prod-server
|
||||
|
||||
# Install Docker
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
sudo usermod -aG docker $USER
|
||||
|
||||
# Create networks (run once per server)
|
||||
# Use your configured network names (defaults shown below)
|
||||
docker network create proxy # or your proxy_network value
|
||||
docker network create ollama # or your ollama_network value (for LLM apps)
|
||||
|
||||
# Create stacks directory
|
||||
sudo mkdir -p /srv/docker/stacks
|
||||
sudo chown $USER:$USER /srv/docker/stacks
|
||||
```
|
||||
|
||||
### 4. Set Environment Variable
|
||||
|
||||
**Linux/macOS** (add to ~/.bashrc or ~/.zshrc):
|
||||
```bash
|
||||
export DEPLOY_CONFIG_PRODUCTION='{ ... your JSON config ... }'
|
||||
```
|
||||
|
||||
**Windows PowerShell**:
|
||||
```powershell
|
||||
$config = @'
|
||||
{ ... your JSON config ... }
|
||||
'@
|
||||
[System.Environment]::SetEnvironmentVariable('DEPLOY_CONFIG_PRODUCTION', $config, 'User')
|
||||
```
|
||||
|
||||
### 5. Deploy
|
||||
|
||||
Just tell the agent:
|
||||
```
|
||||
deploy production
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
- Credentials stored in environment variables only
|
||||
- SSH key-based authentication
|
||||
- Secrets never logged to output
|
||||
- HTTPS with Let's Encrypt certificates
|
||||
- Docker registry authentication
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Quick Diagnostics
|
||||
|
||||
```bash
|
||||
# Check environment variable
|
||||
echo $DEPLOY_CONFIG_PRODUCTION
|
||||
|
||||
# Test SSH
|
||||
ssh prod-server "docker ps"
|
||||
|
||||
# Test Gitea registry
|
||||
docker login gitea.example.com -u username
|
||||
|
||||
# Check remote deployment
|
||||
ssh prod-server "cd /srv/docker/stacks/my-app && docker compose logs"
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
**"DEPLOY_CONFIG_{TARGET} not found"**
|
||||
- Make sure you've exported the environment variable
|
||||
- Restart your terminal/VS Code after setting it
|
||||
- Check spelling and capitalization
|
||||
|
||||
**"Cannot connect to {ssh_host}"**
|
||||
- Verify SSH config: `cat ~/.ssh/config`
|
||||
- Test connection: `ssh {ssh_host} "echo test"`
|
||||
- Check SSH key permissions: `chmod 600 ~/.ssh/deploy_key`
|
||||
|
||||
**"Authentication failed" (Gitea)**
|
||||
- Regenerate token with correct permissions
|
||||
- Ensure token hasn't expired
|
||||
- Verify username is correct
|
||||
|
||||
**"Docker login failed"**
|
||||
- Check gitea_registry_url doesn't have protocol (no https://)
|
||||
- Verify token has package write permission
|
||||
- Try manual login: `echo "TOKEN" | docker login gitea.example.com -u user --password-stdin`
|
||||
|
||||
**Container fails to start**
|
||||
- Check logs: `ssh server "cd /srv/docker/stacks/app && docker compose logs"`
|
||||
- Verify environment variables are correct
|
||||
- Check port conflicts on server
|
||||
- Ensure image pulled successfully
|
||||
|
||||
**Environment variables not working**
|
||||
- Check .env file exists: `ssh server "cat /srv/docker/stacks/app/.env"`
|
||||
- Verify .env file permissions: `ssh server "ls -la /srv/docker/stacks/app/.env"` (should be 600)
|
||||
- Ensure compose.yaml has `env_file: [.env]` directive
|
||||
- Test variable loading: `ssh server "cd /srv/docker/stacks/app && docker compose config"` (shows resolved env vars)
|
||||
- Restart containers after .env changes: `ssh server "cd /srv/docker/stacks/app && docker compose restart"`
|
||||
|
||||
**Missing or incorrect service URLs**
|
||||
- Verify service containers are running in same network
|
||||
- Check container names match .env URLs (e.g., `my-app-db` for DATABASE_URL)
|
||||
- Test connectivity: `ssh server "docker exec my-app ping my-app-db"`
|
||||
- Review auto-generated URLs in deployment confirmation step
|
||||
|
||||
**NPM SSL certificate fails**
|
||||
- Verify domain DNS points to your server
|
||||
- Check ports 80 and 443 are open
|
||||
- Ensure domain is publicly accessible
|
||||
- Check NPM can reach Let's Encrypt servers
|
||||
|
||||
## API Documentation
|
||||
|
||||
### Gitea Container Registry
|
||||
|
||||
Gitea uses an OCI-compliant container registry. No special API calls needed - just standard Docker commands:
|
||||
|
||||
```bash
|
||||
docker login {gitea_url}
|
||||
docker tag image:tag {gitea_url}/{namespace}/{name}:tag
|
||||
docker push {gitea_url}/{namespace}/{name}:tag
|
||||
```
|
||||
|
||||
Images are automatically visible in Gitea under Packages.
|
||||
|
||||
### Nginx Proxy Manager API
|
||||
|
||||
Main endpoints used:
|
||||
|
||||
- `POST /api/tokens` - Authentication
|
||||
- `POST /api/nginx/proxy-hosts` - Create reverse proxy
|
||||
- `POST /api/nginx/certificates` - Request SSL cert
|
||||
- `PUT /api/nginx/proxy-hosts/{id}` - Update with SSL
|
||||
|
||||
## Examples
|
||||
|
||||
### Deploy to Production
|
||||
|
||||
```
|
||||
deploy production
|
||||
```
|
||||
|
||||
If `production` already exists remotely, this runs as an update rollout.
|
||||
|
||||
### Deploy to Staging
|
||||
|
||||
```
|
||||
deploy staging
|
||||
```
|
||||
|
||||
If the stack already exists, the skill updates it in place.
|
||||
|
||||
### Deploy AI Service with LLM
|
||||
|
||||
```
|
||||
deploy ai-service
|
||||
```
|
||||
|
||||
For existing deployments, proxy and stack are updated idempotently.
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Modifying Environment Variables After Deployment
|
||||
|
||||
If you need to update environment variables after deployment:
|
||||
|
||||
**Option 1: Edit .env on server**
|
||||
```bash
|
||||
# SSH to server and edit
|
||||
ssh prod-server
|
||||
cd /srv/docker/stacks/my-app
|
||||
nano .env
|
||||
|
||||
# Restart containers to apply changes
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
**Option 2: Redeploy with updated .env**
|
||||
Update your local `.env` file and redeploy - the skill will process it again in update mode and merge new required keys without deleting existing ones.
|
||||
|
||||
### Adding Service Containers
|
||||
|
||||
If your app needs a database or other services, create them in the same stack:
|
||||
|
||||
```bash
|
||||
ssh prod-server
|
||||
cd /srv/docker/stacks/my-app
|
||||
nano compose.yaml
|
||||
```
|
||||
|
||||
Add service definitions:
|
||||
```yaml
|
||||
services:
|
||||
my-app:
|
||||
# ... existing config
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
|
||||
db:
|
||||
image: postgres:16
|
||||
container_name: my-app-db
|
||||
environment:
|
||||
POSTGRES_DB: my-app
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
volumes:
|
||||
- ./data/postgres:/var/lib/postgresql/data
|
||||
|
||||
redis:
|
||||
image: redis:7
|
||||
container_name: my-app-redis
|
||||
volumes:
|
||||
- ./data/redis:/data
|
||||
```
|
||||
|
||||
The DATABASE_URL and REDIS_URL will already be correctly set by the auto-detection!
|
||||
|
||||
### Additional Volumes
|
||||
|
||||
```json
|
||||
{
|
||||
"volumes": [
|
||||
"./uploads:/app/uploads",
|
||||
"./cache:/app/cache:ro"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Multiple Targets
|
||||
|
||||
Create multiple configs:
|
||||
|
||||
```bash
|
||||
export DEPLOY_CONFIG_PRODUCTION='{ ... }'
|
||||
export DEPLOY_CONFIG_STAGING='{ ... }'
|
||||
export DEPLOY_CONFIG_DEVELOPMENT='{ ... }'
|
||||
```
|
||||
|
||||
Deploy to any target:
|
||||
|
||||
```
|
||||
deploy development
|
||||
deploy staging
|
||||
deploy production
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Part of the Copilot Agents skill library.
|
||||
Reference in New Issue
Block a user