Script Payloads
Script payloads run a script file that lives in a configured storage backend, enabling complex deployment logic with conditionals, loops, and error handling.
A script payload is not a script body you type into a text box. Instead, it references a file by name (and optional relative path) inside a storage backend you have configured. Mantis tells the target to execute that file with the chosen executor.
When to Use Scripts
Section titled “When to Use Scripts”| Use Scripts For | Use Commands Instead |
|---|---|
| Multi-step workflows | Single operations |
| Conditional logic | Simple tool invocations |
| Error handling | Atomic commands |
| Loops and iteration | Quick system commands |
| Variable manipulation | One-liners |
How a Script Payload Is Defined
Section titled “How a Script Payload Is Defined”A script payload is made up of:
| Field | Description |
|---|---|
| Storage backend | The configured storage where the script file is located. |
| File name | The name of the script file to execute. |
| Relative path | Optional path within the storage backend, if the file lives in a subfolder. |
| Executor | How the script is run (see Executor Reference). |
| Arguments | Optional arguments passed to the script. |
To create a script payload:
- Select a configured storage backend.
- Reference the script file by its file name (and relative path if it is in a subfolder).
- Choose an executor.
- Optionally supply arguments.
The script file itself is authored and stored in your storage backend, not edited inline in Mantis.
Example Script Files
Section titled “Example Script Files”The following are examples of script files you would place in your storage backend and then reference from a script payload.
Bash Scripts
Section titled “Bash Scripts”#!/bin/bashset -e # Exit on error
# Your deployment logicecho "Starting deployment..."cd /opt/myapp
# Pull latest codegit pull origin main
# Restart servicesystemctl restart myapp
echo "Deployment complete!"PowerShell Scripts
Section titled “PowerShell Scripts”$ErrorActionPreference = "Stop"
Write-Host "Starting deployment..."
# Your deployment logicSet-Location C:\Apps\MyApp
# Copy new filesCopy-Item -Path "\\server\share\release\*" -Destination "." -Recurse -Force
# Restart serviceRestart-Service -Name "MyAppService"
Write-Host "Deployment complete!"Python Scripts
Section titled “Python Scripts”#!/usr/bin/env python3import subprocessimport sys
def main(): print("Starting deployment...")
# Your deployment logic result = subprocess.run(["docker", "compose", "up", "-d"], check=True)
print("Deployment complete!") return 0
if __name__ == "__main__": sys.exit(main())Executor Reference
Section titled “Executor Reference”| Executor | Shebang | Error Handling |
|---|---|---|
| Default | N/A (direct exec) | Process exit code |
| Sh | #!/bin/sh | set -e |
| Bash | #!/bin/bash | set -e |
| Pwsh | #!/usr/bin/env pwsh | $ErrorActionPreference = "Stop" |
Variables and Substitution
Section titled “Variables and Substitution”Mantis handles runtime values in two distinct ways, and it is important to use the right one.
Placeholders in the File Name and Arguments
Section titled “Placeholders in the File Name and Arguments”Mantis substitutes placeholders into the script’s file name and arguments before execution. It uses two placeholder forms:
| Pattern | Where it applies | Example argument value | Result |
|---|---|---|---|
{{version}} | File name, arguments | 1.2.3 | 1.2.3 |
${version} | File name, arguments | latest | latest |
For example, an argument of --version={{version}} becomes --version=1.2.3 before the script runs. A file name of deploy-{{environment}}.sh resolves to deploy-staging.sh.
Values Inside the Script Body: MANTIS_* Environment Variables
Section titled “Values Inside the Script Body: MANTIS_* Environment Variables”To use runtime values inside a script, read them from environment variables. Mantis merges resolved variables into the execution environment as MANTIS_* environment variables (for example, MANTIS_VERSION, MANTIS_ENVIRONMENT). Your script reads these the normal way for its shell, and the shell on the target expands them as usual.
Bash:
#!/bin/bashset -e
echo "Deploying version $MANTIS_VERSION to $MANTIS_ENVIRONMENT"
docker pull myregistry/myapp:"$MANTIS_VERSION"docker tag myregistry/myapp:"$MANTIS_VERSION" myregistry/myapp:currentPowerShell:
$ErrorActionPreference = "Stop"
Write-Host "Deploying version $env:MANTIS_VERSION to $env:MANTIS_ENVIRONMENT"Python:
import osversion = os.environ.get("MANTIS_VERSION")print(f"Deploying version {version}")Environment Variables
Section titled “Environment Variables”Setting in Mantis
Section titled “Setting in Mantis”Define environment variables on the action:
| Name | Value | Sensitive |
|---|---|---|
DB_HOST | db.example.com | No |
DB_PASSWORD | *** | Yes |
These are in addition to the MANTIS_* variables Mantis injects for resolved deployment variables.
Accessing in Scripts
Section titled “Accessing in Scripts”Bash:
#!/bin/bashecho "Connecting to $DB_HOST"psql -h "$DB_HOST" -U admin -c "SELECT 1"PowerShell:
Write-Host "Connecting to $env:DB_HOST"Invoke-Sqlcmd -ServerInstance $env:DB_HOST -Query "SELECT 1"Python:
import osdb_host = os.environ.get("DB_HOST")print(f"Connecting to {db_host}")Error Handling
Section titled “Error Handling”#!/bin/bashset -e # Exit on any errorset -o pipefail # Exit on pipe failures
# Or handle errors explicitlyif ! docker pull myimage; then echo "Failed to pull image" exit 1fi
# Cleanup on errorcleanup() { echo "Cleaning up..." rm -f /tmp/deploy-*}trap cleanup EXITPowerShell
Section titled “PowerShell”$ErrorActionPreference = "Stop"
try { # Deployment logic Copy-Item -Path $source -Destination $dest Restart-Service -Name $serviceName}catch { Write-Error "Deployment failed: $_" exit 1}finally { # Cleanup Remove-Item -Path $tempFiles -ErrorAction SilentlyContinue}Python
Section titled “Python”#!/usr/bin/env python3import subprocessimport sys
try: subprocess.run(["docker", "compose", "up", "-d"], check=True)except subprocess.CalledProcessError as e: print(f"Deployment failed: {e}", file=sys.stderr) sys.exit(1)except Exception as e: print(f"Unexpected error: {e}", file=sys.stderr) sys.exit(1)Common Patterns
Section titled “Common Patterns”These scripts live in your storage backend. Runtime values are read from MANTIS_* environment variables.
Blue-Green Deployment
Section titled “Blue-Green Deployment”#!/bin/bashset -e
CURRENT=$(readlink /opt/app/current || echo "blue")NEW=$([ "$CURRENT" = "blue" ] && echo "green" || echo "blue")
echo "Current: $CURRENT, Deploying to: $NEW"
# Deploy to new slotcd /opt/app/$NEWdocker compose pulldocker compose up -d
# Health checkfor i in {1..30}; do if curl -sf http://localhost:808${NEW: -1}/health; then echo "Health check passed" break fi sleep 2done
# Switch trafficln -sfn /opt/app/$NEW /opt/app/currentnginx -s reload
# Stop oldcd /opt/app/$CURRENTdocker compose downDatabase Migration
Section titled “Database Migration”#!/bin/bashset -e
BACKUP_FILE="/backups/pre-migration-$(date +%Y%m%d-%H%M%S).sql"
echo "Creating backup..."pg_dump "$DATABASE_URL" > "$BACKUP_FILE"
echo "Running migrations..."if ! alembic upgrade head; then echo "Migration failed, restoring backup..." psql "$DATABASE_URL" < "$BACKUP_FILE" exit 1fi
echo "Migrations complete!"Rolling Service Update
Section titled “Rolling Service Update”#!/bin/bashset -e
SERVICES=(web-1 web-2 web-3)VERSION="$MANTIS_VERSION"
for service in "${SERVICES[@]}"; do echo "Updating $service..."
# Remove from load balancer curl -X POST "http://lb/api/remove?host=$service"
# Update service ssh "$service" "docker pull myapp:$VERSION && docker compose up -d"
# Wait for health until curl -sf "http://$service/health"; do sleep 5 done
# Add back to load balancer curl -X POST "http://lb/api/add?host=$service"
echo "$service updated"done
echo "Rolling update complete!"Working with Files
Section titled “Working with Files”File Downloads
Section titled “File Downloads”#!/bin/bashset -e
ARTIFACT_URL="$MANTIS_ARTIFACT_URL"DEST_DIR="/opt/app"
# Download artifactcurl -fSL "$ARTIFACT_URL" -o /tmp/release.tar.gz
# Extracttar -xzf /tmp/release.tar.gz -C "$DEST_DIR"
# Cleanuprm /tmp/release.tar.gzConfiguration Templates
Section titled “Configuration Templates”#!/bin/bashset -e
# Generate config from template using injected MANTIS_* valuescat > /opt/app/config.yml << EOFserver: host: 0.0.0.0 port: ${MANTIS_PORT}database: host: ${DB_HOST} name: ${MANTIS_DB_NAME}logging: level: ${MANTIS_LOG_LEVEL}EOF
echo "Configuration written"Logging Best Practices
Section titled “Logging Best Practices”Structured Output
Section titled “Structured Output”#!/bin/bash
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"}
log "Starting deployment"log "Version: $MANTIS_VERSION"log "Environment: $MANTIS_ENVIRONMENT"
# ... deployment steps ...
log "Deployment complete"Progress Indicators
Section titled “Progress Indicators”#!/bin/bash
echo "Step 1/4: Pulling images..."docker pull myapp:"$MANTIS_VERSION"
echo "Step 2/4: Stopping services..."docker compose down
echo "Step 3/4: Starting services..."docker compose up -d
echo "Step 4/4: Running health checks..."./health-check.sh
echo "Deployment successful"Security Considerations
Section titled “Security Considerations”Never Echo Secrets
Section titled “Never Echo Secrets”Bad:
echo "Using password: $DB_PASSWORD"Good:
echo "Connecting to database..."# Password is in environment, not loggedUse Secure Temporary Files
Section titled “Use Secure Temporary Files”#!/bin/bashTEMP_DIR=$(mktemp -d)trap "rm -rf $TEMP_DIR" EXIT
# Use $TEMP_DIR for temporary filesValidate Inputs
Section titled “Validate Inputs”#!/bin/bashset -e
VERSION="$MANTIS_VERSION"
# Validate version formatif [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "Invalid version format: $VERSION" exit 1fiPerformance Tips
Section titled “Performance Tips”- Minimize network calls - Batch operations where possible
- Use parallel execution - When operations are independent
- Cache dependencies - Avoid re-downloading unchanged files
- Clean up - Remove temporary files to free disk space
Troubleshooting
Section titled “Troubleshooting”Script Exits Immediately
Section titled “Script Exits Immediately”Cause: set -e with a failing command
Solution: Handle expected failures explicitly:
set -esome_command || true # Ignore failureVariables Not Expanded
Section titled “Variables Not Expanded”Cause: Using single quotes, which prevent the shell from expanding variables.
Fix:
# Wrongecho 'Version: $MANTIS_VERSION'
# Rightecho "Version: $MANTIS_VERSION"Placeholders Not Substituted Inside the Script
Section titled “Placeholders Not Substituted Inside the Script”Cause: Using {{...}} or ${...} placeholders inside the script body. Mantis only substitutes placeholders into the file name and arguments, not into script contents.
Fix: Read runtime values from MANTIS_* environment variables inside the script instead.
Windows Line Endings
Section titled “Windows Line Endings”Cause: A script file created on Windows may use CRLF (\r\n) line endings.
Fix: Convert the file to Unix (LF) line endings before storing it in your storage backend.
Next Steps
Section titled “Next Steps”- Command Payloads - For simpler operations
- Testing Actions - Validate scripts before deployment
- Versioning - Managing script changes
