Skip to content

Deploy Production

Deploy Production #126

Workflow file for this run

name: Deploy Production
permissions:
contents: read
deployments: write
id-token: write
security-events: write # Required for Trivy SARIF upload in test workflow
concurrency:
group: roboledger-app-deploy
cancel-in-progress: false
on:
workflow_dispatch: # Manual triggering only
jobs:
runner:
runs-on: ubuntu-latest
outputs:
runners_available: ${{ steps.check.outputs.runners_available }}
runner_type: ${{ steps.check.outputs.runner_type }}
runner_config: ${{ steps.check.outputs.runner_config }}
steps:
- name: Checkout
uses: actions/checkout@v7
with:
repository: ${{ github.repository }}
ref: ${{ github.ref }}
token: ${{ github.token }}
- name: Check runner availability
id: check
uses: RoboFinSystems/robosystems/.github/actions/select-runner@main
with:
runner_labels: ${{ vars.RUNNER_LABELS || 'github-hosted' }}
runner_scope: ${{ vars.RUNNER_SCOPE || 'both' }}
github_token: ${{ github.token }}
test:
needs: [runner]
uses: ./.github/workflows/test.yml
with:
runner_config: ${{ needs.runner.outputs.runner_config }}
secrets: inherit
create-deployment:
needs: [runner]
runs-on: ${{ fromJSON(needs.runner.outputs.runner_config) }}
# Every downstream job gates on this, so required reviewers on the "production" environment approve the whole pipeline.
environment: production
outputs:
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
steps:
- name: Create GitHub Deployment
id: deployment
uses: chrnorm/deployment-action@500aa6a23c81ffa1acf71072aee3cfa2cc2e556a # v2
with:
token: ${{ github.token }}
environment: production
description: 'Production Deployment Created'
- name: Update Deployment Status
uses: chrnorm/deployment-status@6df8d036fd2fee9eb82936733953da1f8382b41e # v2
with:
token: ${{ github.token }}
state: in_progress
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
description: 'Production Deployment In Progress'
deploy-s3:
needs: [runner, test, create-deployment]
uses: ./.github/workflows/deploy-s3.yml
with:
runner_config: ${{ needs.runner.outputs.runner_config }}
stack_name: RoboLedgerAppS3Prod
environment: ${{ vars.ENVIRONMENT_PROD || 'prod' }}
aws_account_id: ${{ vars.AWS_ACCOUNT_ID }}
aws_region: ${{ vars.AWS_REGION || 'us-east-1' }}
namespace: ${{ vars.AWS_ACCOUNT_ID }}
secrets: inherit
build:
uses: ./.github/workflows/build.yml
needs: [runner, test, deploy-s3]
with:
runner_config: ${{ needs.runner.outputs.runner_config }}
environment: ${{ vars.ENVIRONMENT_PROD || 'prod' }}
region: ${{ vars.AWS_REGION || 'us-east-1' }}
robosystems_api_url: ${{ vars.ROBOSYSTEMS_API_URL_PROD || 'https://api.robosystems.ai' }}
roboledger_app_url: ${{ vars.ROBOLEDGER_APP_URL_PROD || 'https://roboledger.ai' }}
roboinvestor_app_url: ${{ vars.ROBOINVESTOR_APP_URL_PROD || 'https://roboinvestor.ai' }}
robosystems_app_url: ${{ vars.ROBOSYSTEMS_APP_URL_PROD || 'https://robosystems.ai' }}
maintenance_mode: ${{ vars.MAINTENANCE_MODE_PROD || 'false' }}
turnstile_site_key: ${{ vars.TURNSTILE_SITE_KEY || '' }}
cf_analytics_token: ${{ vars.CF_ANALYTICS_TOKEN || '' }}
static_assets_bucket_name: ${{ needs.deploy-s3.outputs.static_assets_bucket_name }}
secrets: inherit
deploy-app:
needs: [runner, create-deployment, deploy-s3, build]
uses: ./.github/workflows/deploy-app.yml
with:
# GHA Runner Configuration
runner_config: ${{ needs.runner.outputs.runner_config }}
# Environment & AWS Configuration
environment: ${{ vars.ENVIRONMENT_PROD || 'prod' }}
aws_account_id: ${{ vars.AWS_ACCOUNT_ID }}
aws_region: ${{ vars.AWS_REGION || 'us-east-1' }}
stack_name: RoboLedgerAppProd
# Access Mode Configuration
app_access_mode: ${{ vars.APP_ACCESS_MODE_PROD || 'public' }}
# S3 Bucket Configuration (from deploy-s3 outputs)
static_assets_bucket_name: ${{ needs.deploy-s3.outputs.static_assets_bucket_name }}
static_assets_bucket_arn: ${{ needs.deploy-s3.outputs.static_assets_bucket_arn }}
static_assets_bucket_domain: ${{ needs.deploy-s3.outputs.static_assets_bucket_domain }}
# Container & Application Configuration
ecr_repository: ${{ vars.ECR_REPOSITORY || 'roboledger-app' }}
ecr_image_tag: ${{ needs.build.outputs.image_tag }}
# App Runner Compute Configuration
cpu: ${{ vars.CPU_PROD || '0.25 vCPU' }}
memory: ${{ vars.MEMORY_PROD || '0.5 GB' }}
# Auto-scaling Configuration
capacity_min: ${{ vars.CAPACITY_MIN_PROD || '1' }}
capacity_max: ${{ vars.CAPACITY_MAX_PROD || '10' }}
max_concurrency: ${{ vars.MAX_CONCURRENCY_PROD || '100' }}
# Domain & DNS Configuration (required for public mode)
domain_name: ${{ vars.DOMAIN_NAME_PROD || 'roboledger.ai' }}
domain_name_root: ${{ vars.DOMAIN_NAME_ROOT || 'roboledger.ai' }}
notification_email: ${{ vars.AWS_SNS_ALERT_EMAIL || '' }}
secrets: inherit
# Gated on the ECR build (same Dockerfile, amd64) so a failure here is the arm64/Hub half; runs parallel to deploy-app, nothing depends on it.
dockerhub:
needs: [runner, create-deployment, build]
if: ${{ vars.DOCKERHUB_PUBLISHING_ENABLED == 'true' && (startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/release/')) }}
uses: ./.github/workflows/dockerhub.yml
with:
runner_config: ${{ needs.runner.outputs.runner_config }}
secrets: inherit
deployment-successful:
needs: [runner, test, create-deployment, build, deploy-app]
runs-on: ${{ fromJSON(needs.runner.outputs.runner_config) }}
outputs:
deployment_id: ${{ needs.create-deployment.outputs.deployment_id }}
steps:
- name: Update Deployment Status
uses: chrnorm/deployment-status@6df8d036fd2fee9eb82936733953da1f8382b41e # v2
with:
token: ${{ github.token }}
state: success
deployment-id: ${{ needs.create-deployment.outputs.deployment_id }}
description: 'Production Deployment Succeeded'
handle-deployment-failure:
needs: [runner, test, create-deployment, build, deploy-app]
if: always() && contains(needs.*.result, 'failure')
runs-on: ${{ fromJSON(needs.runner.outputs.runner_config) }}
steps:
- name: Checkout Code
uses: actions/checkout@v7
with:
repository: ${{ github.repository }}
ref: ${{ github.ref }}
token: ${{ github.token }}
- name: Handle Deployment Failure
uses: RoboFinSystems/robosystems/.github/actions/handle-deployment-failure@main
with:
deployment-id: ${{ needs.create-deployment.outputs.deployment_id }}
environment: production
github-token: ${{ github.token }}