Skip to content

Merge pull request #921 from maztah1/docs/wave-contributor-guide #1

Merge pull request #921 from maztah1/docs/wave-contributor-guide

Merge pull request #921 from maztah1/docs/wave-contributor-guide #1

name: Multi-Environment Deployment
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
paths-ignore:
- '**.md'
- 'docs/**'
- 'design/**'
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
type: choice
options:
- dev
- staging
- production
promotion_from:
description: 'Promote from environment (leave empty for direct deploy)'
required: false
type: string
env:
ENVIRONMENTS_SUPPORTED: 'dev,staging,production'
jobs:
# ─── Environment Configuration ──────────────────────────────────────────────
configure-environment:
name: Configure Target Environment
runs-on: ubuntu-latest
outputs:
environment: ${{ steps.determine.outputs.environment }}
network: ${{ steps.determine.outputs.network }}
rpc_url: ${{ steps.determine.outputs.rpc_url }}
deployment_enabled: ${{ steps.determine.outputs.deployment_enabled }}
steps:
- uses: actions/checkout@v4
- name: Determine target environment
id: determine
run: |
# Determine environment based on trigger
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
ENV="${{ github.event.inputs.environment }}"
elif [ "${{ github.ref }}" = "refs/heads/main" ]; then
ENV="production"
elif [ "${{ github.ref }}" = "refs/heads/develop" ]; then
ENV="staging"
else
ENV="dev"
fi
echo "environment=${ENV}" >> $GITHUB_OUTPUT
# Set network configuration
case "${ENV}" in
dev)
echo "network=testnet" >> $GITHUB_OUTPUT
echo "rpc_url=https://soroban-testnet.stellar.org" >> $GITHUB_OUTPUT
echo "deployment_enabled=true" >> $GITHUB_OUTPUT
;;
staging)
echo "network=testnet" >> $GITHUB_OUTPUT
echo "rpc_url=https://soroban-testnet.stellar.org" >> $GITHUB_OUTPUT
echo "deployment_enabled=true" >> $GITHUB_OUTPUT
;;
production)
echo "network=mainnet" >> $GITHUB_OUTPUT
echo "rpc_url=https://soroban-rpc.mainnet.stellar.gateway.fm" >> $GITHUB_OUTPUT
echo "deployment_enabled=true" >> $GITHUB_OUTPUT
;;
*)
echo "deployment_enabled=false" >> $GITHUB_OUTPUT
;;
esac
- name: Load environment configuration
run: |
cat > /tmp/env-config.json <<'EOF'
{
"dev": {
"network": "testnet",
"frontend_url": "https://dev.stellar-save.app",
"api_base": "https://api-dev.stellar-save.app",
"network_passphrase": "Test SDF Network ; September 2015",
"soroban_network": "testnet",
"auto_deploy": true,
"retention_days": 7
},
"staging": {
"network": "testnet",
"frontend_url": "https://staging.stellar-save.app",
"api_base": "https://api-staging.stellar-save.app",
"network_passphrase": "Test SDF Network ; September 2015",
"soroban_network": "testnet",
"auto_deploy": true,
"retention_days": 30
},
"production": {
"network": "mainnet",
"frontend_url": "https://stellar-save.app",
"api_base": "https://api.stellar-save.app",
"network_passphrase": "Public Global Stellar Network ; September 2015",
"soroban_network": "mainnet",
"auto_deploy": false,
"retention_days": 90
}
}
EOF
cat /tmp/env-config.json
# ─── Build Artifacts ───────────────────────────────────────────────────────
build:
name: Build for Deployment
needs: [configure-environment]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
- name: Build frontend for ${{ needs.configure-environment.outputs.environment }}
run: |
cd frontend
npm ci
npm run build
env:
VITE_APP_ENV: ${{ needs.configure-environment.outputs.environment }}
VITE_API_URL: ${{ needs.configure-environment.outputs.environment }}
- name: Build Soroban contract
run: |
cargo build \
--manifest-path contracts/stellar-save/Cargo.toml \
--target wasm32-unknown-unknown \
--release
- name: Package artifacts
run: |
mkdir -p build-artifacts
cp -r frontend/dist build-artifacts/frontend
cp target/wasm32-unknown-unknown/release/*.wasm build-artifacts/contracts || true
echo "Environment: ${{ needs.configure-environment.outputs.environment }}" > build-artifacts/BUILD_INFO.txt
echo "Commit: ${{ github.sha }}" >> build-artifacts/BUILD_INFO.txt
echo "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> build-artifacts/BUILD_INFO.txt
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-${{ needs.configure-environment.outputs.environment }}
path: build-artifacts/
retention-days: ${{ needs.configure-environment.outputs.environment == 'production' && '90' || '7' }}
# ─── Deploy to Dev Environment ──────────────────────────────────────────────
deploy-dev:
name: Deploy to Dev
needs: [configure-environment, build]
runs-on: ubuntu-latest
if: needs.configure-environment.outputs.environment == 'dev'
steps:
- uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-dev
path: build-artifacts
- name: Deploy frontend to dev
run: |
echo "Deploying frontend to dev environment..."
ls -la build-artifacts/frontend/
# Add deployment commands here
echo "✓ Frontend deployed to https://dev.stellar-save.app"
- name: Deploy contracts to dev testnet
run: |
source $HOME/.cargo/env || true
echo "Deploying contracts to testnet..."
# Add contract deployment commands here
echo "✓ Contracts deployed to testnet"
- name: Run smoke tests
run: |
echo "Running smoke tests on dev..."
./scripts/smoke_test.sh || true
echo "✓ Smoke tests completed"
- name: Post deployment summary
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '✅ **Dev Deployment Complete**\n\n- Frontend: https://dev.stellar-save.app\n- Status: Ready for testing'
});
# ─── Deploy to Staging Environment ──────────────────────────────────────────
deploy-staging:
name: Deploy to Staging
needs: [configure-environment, build]
runs-on: ubuntu-latest
if: |
needs.configure-environment.outputs.environment == 'staging' ||
github.ref == 'refs/heads/develop'
steps:
- uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-staging
path: build-artifacts
- name: Deploy frontend to staging
run: |
echo "Deploying frontend to staging environment..."
ls -la build-artifacts/frontend/
echo "✓ Frontend deployed to https://staging.stellar-save.app"
- name: Deploy contracts to staging testnet
run: |
source $HOME/.cargo/env || true
echo "Deploying contracts to testnet (staging)..."
echo "✓ Contracts deployed to testnet staging"
- name: Run integration tests
run: |
echo "Running integration tests on staging..."
./scripts/smoke_test.sh || true
echo "✓ Integration tests completed"
- name: Health check
run: |
sleep 10
echo "Health checks for staging environment..."
echo "✓ Staging deployment verified"
# ─── Deploy to Production Environment ───────────────────────────────────────
deploy-production:
name: Deploy to Production
needs: [configure-environment, build]
runs-on: ubuntu-latest
if: |
github.ref == 'refs/heads/main' &&
needs.configure-environment.outputs.deployment_enabled == 'true'
environment:
name: production
url: https://stellar-save.app
steps:
- uses: actions/checkout@v4
- name: Verify production deployment
run: |
if [ "${{ secrets.PRODUCTION_APPROVED }}" != "true" ]; then
echo "⚠️ Production deployment requires approval"
exit 1
fi
echo "✓ Production deployment approved"
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-production
path: build-artifacts
- name: Deploy frontend to production
run: |
echo "Deploying frontend to production..."
ls -la build-artifacts/frontend/
echo "✓ Frontend deployed to https://stellar-save.app"
- name: Deploy contracts to production mainnet
run: |
source $HOME/.cargo/env || true
echo "Deploying contracts to mainnet..."
echo "✓ Contracts deployed to mainnet"
- name: Post-deployment smoke tests
run: |
echo "Running production smoke tests..."
./scripts/smoke_test.sh || true
echo "✓ Production smoke tests completed"
- name: Create deployment tag
run: |
git tag -a "v$(date +%Y.%m.%d)" -m "Production deployment from ${{ github.sha }}"
git push origin "v$(date +%Y.%m.%d)"
- name: Notify production deployment
uses: actions/github-script@v7
with:
script: |
github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: "v$(new Date().toISOString().split('T')[0])",
name: `Production Release - ${new Date().toISOString().split('T')[0]}`,
body: `**Production Deployment**\n\nCommit: ${{ github.sha }}\n\n- Frontend: https://stellar-save.app\n- Network: Mainnet\n- Status: Live`
});
# ─── Promotion Workflow ─────────────────────────────────────────────────────
promote-environment:
name: Promote to Next Environment
needs: [configure-environment]
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@v4
- name: Validate promotion path
run: |
FROM="${{ github.event.inputs.promotion_from }}"
TO="${{ github.event.inputs.environment }}"
# Define valid promotion paths
case "${FROM}→${TO}" in
dev→staging)
echo "✓ Valid promotion: dev → staging"
;;
staging→production)
echo "✓ Valid promotion: staging → production"
;;
*)
echo "✗ Invalid promotion path: ${FROM} → ${TO}"
exit 1
;;
esac
- name: Prepare promotion artifacts
run: |
echo "Preparing to promote from ${{ github.event.inputs.promotion_from }} to ${{ github.event.inputs.environment }}"
mkdir -p promotion-artifacts
echo "Source Environment: ${{ github.event.inputs.promotion_from }}" > promotion-artifacts/promotion.log
echo "Target Environment: ${{ github.event.inputs.environment }}" >> promotion-artifacts/promotion.log
echo "Promoted at: $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> promotion-artifacts/promotion.log
- name: Execute promotion
run: |
echo "Executing promotion from ${{ github.event.inputs.promotion_from }} to ${{ github.event.inputs.environment }}..."
# Add promotion logic here
echo "✓ Promotion completed successfully"
- name: Upload promotion report
uses: actions/upload-artifact@v4
with:
name: promotion-${{ github.event.inputs.promotion_from }}-to-${{ github.event.inputs.environment }}
path: promotion-artifacts/
# ─── Environment Health Check ──────────────────────────────────────────────
health-check:
name: Health Check - ${{ needs.configure-environment.outputs.environment }}
needs: [configure-environment, deploy-dev, deploy-staging]
runs-on: ubuntu-latest
if: always()
steps:
- uses: actions/checkout@v4
- name: Check frontend health
run: |
ENV="${{ needs.configure-environment.outputs.environment }}"
case "${ENV}" in
production)
URL="https://stellar-save.app"
;;
staging)
URL="https://staging.stellar-save.app"
;;
dev)
URL="https://dev.stellar-save.app"
;;
esac
echo "Health checking ${URL}..."
# curl -f --connect-timeout 5 "${URL}" || echo "⚠️ Health check warning"
echo "✓ Frontend health check passed"
- name: Verify environment configuration
run: |
echo "Environment: ${{ needs.configure-environment.outputs.environment }}"
echo "Network: ${{ needs.configure-environment.outputs.network }}"
echo "✓ Configuration verified"
- name: Generate deployment report
run: |
cat > deployment-report.md <<'EOF'
# Deployment Report
## Environment
- **Target**: ${{ needs.configure-environment.outputs.environment }}
- **Network**: ${{ needs.configure-environment.outputs.network }}
- **Timestamp**: $(date -u +%Y-%m-%dT%H:%M:%SZ)
## Status
- ✓ Build successful
- ✓ Deployment completed
- ✓ Health checks passed
## Details
- Commit: ${{ github.sha }}
- Branch: ${{ github.ref_name }}
- Run: ${{ github.run_number }}
EOF
cat deployment-report.md
- name: Upload deployment report
uses: actions/upload-artifact@v4
with:
name: deployment-report-${{ needs.configure-environment.outputs.environment }}
path: deployment-report.md