Appearance
CI/CD Pipeline Guide
Jubiloop uses GitHub Actions for automated continuous integration and deployment workflows.
Overview
All deployment configuration is centralized in infra/deploy/env.deploy.yml. This single file defines:
- Infrastructure settings (Terraform variables, backend config)
- Environment variables for all services
- Secret references (auto-discovered by scripts)
- Variable references (non-sensitive config)
Configuration Generation Scripts
The deployment system is powered by two main scripts that dynamically process env.deploy.yml.
generate-env-files.js
Generates environment configuration for all services.
Usage:
bash
# Generate .env files for server services (default)
node scripts/generate-env-files.js DEV
# Generate shell exports for web app
node scripts/generate-env-files.js DEV --web-app
# Generate shell exports for marketing
node scripts/generate-env-files.js PROD --marketing
# Preview without writing files
node scripts/generate-env-files.js DEV --dry-run
# List required secrets
node scripts/generate-env-files.js DEV --list-secretsFeatures:
- Auto-discovers services from env.deploy.yml
- Handles
from_secretspattern (generates secret names like DEV_SERVER_APP_KEY) - Supports explicit secrets (see Secret Management section)
- Validates environments and services
extract-config.js
Master configuration extractor for all deployment needs.
Usage:
bash
# Generate Terraform variables
node scripts/extract-config.js terraform-vars --env dev-qa
# Generate Terraform backend config
node scripts/extract-config.js backend-hcl
# Generate secret export script
node scripts/extract-config.js secret-exports
# Generate Ansible inventory
node scripts/extract-config.js ansible-inventory --env dev-qa
# Generate documentation
node scripts/extract-config.js documentation
# List all secrets
node scripts/extract-config.js list-secrets
# List all variables
node scripts/extract-config.js list-variablesGitHub Actions Workflows
terraform-deploy.yml
- Purpose: Manages infrastructure with Terraform
- Trigger: Manual dispatch only
- Environments: dev-qa or prod (both enabled)
- Actions: plan or apply
deploy-server.yml
- Purpose: Builds and deploys AdonisJS backend
- Automatic triggers:
- develop branch → dev environment
- qa branch → qa environment
- main branch → production environment
- Process: Builds Docker image, pushes to registry, deploys via Ansible
deploy-web-app.yml
- Purpose: Deploys React app to Cloudflare Pages
- Triggers: Changes in apps/webapp/ or manual dispatch
- Target: Cloudflare Pages
deploy-marketing.yml
- Purpose: Deploys Next.js marketing site to Cloudflare Pages
- Triggers: Changes in apps/marketing/ or manual dispatch
- Target: Cloudflare Pages
Secret Management
Two patterns for secrets:
Auto-generated:
from_secretscreates names like{ENV}_{SERVICE}_{KEY}- Example:
DEV.server.APP_KEY: from_secretsbecomesDEV_SERVER_APP_KEY
- Example:
Explicit: GitHub secrets syntax uses exact secret name
- Example:
PROD.server.DB_URL: '\$\{\{ secrets.NEON_DATABASE_URL }\}\'
- Example:
Adding secrets:
- Define in env.deploy.yml
- Add to GitHub Settings → Secrets and variables → Actions
- Verify with
node scripts/extract-config.js list-secrets
Environment Structure
Example env.deploy.yml structure:
yaml
INFRASTRUCTURE:
dev-qa:
droplet_size: 's-1vcpu-1gb'
region: 'nyc3'
DEV:
server:
PORT: 3333
NODE_ENV: 'development'
DATABASE_URL: from_secrets
webapp:
REACT_APP_API_URL: 'https://dev-api.jubiloop.ca'
PROD:
server:
PORT: 3333
NODE_ENV: 'production'
DATABASE_URL: '${{ secrets.NEON_DATABASE_URL }}' # Explicit secret referenceDeployment Process
- Configuration: Define everything in env.deploy.yml
- Secret Discovery: Scripts find all secret references
- GitHub Actions: Workflows generate configs dynamically
- Infrastructure: Terraform provisions resources
- Deployment: Ansible deploys applications
Local Testing
bash
cd infra/deploy
# Test server configs
node scripts/generate-env-files.js DEV --server --dry-run
# Check required secrets
node scripts/extract-config.js list-secrets
# Generate documentation
node scripts/extract-config.js documentationTroubleshooting
Common issues:
- Secret not found: Check
list-secretsoutput matches GitHub secrets - Files not generated: Check YAML syntax, use --dry-run
- Terraform issues: Verify R2 credentials and backend.hcl
Best Practices
- Never hardcode secrets
- Test with --dry-run first
- Keep service names consistent
- Use variables for non-sensitive config
- All config in env.deploy.yml
Detailed Script Documentation
generate-env-files.js Features
The script supports multiple environments and modes:
Environment Support:
- Single environments: DEV, QA, PROD
- Combined environment: DEV-QA (generates files for both)
Service Discovery:
- Automatically finds all services in env.deploy.yml
- No hardcoded service lists
- Validates service availability per environment
Output Formats:
- Server mode: Creates
.env.{service}files - Web mode: Outputs shell export commands
Secret Handling:
from_secrets: Auto-generates as{ENV}_{SERVICE}_{KEY}- Explicit references: Uses exact secret name from GitHub
extract-config.js Commands
terraform-vars:
- Extracts INFRASTRUCTURE section from env.deploy.yml
- Creates terraform.tfvars with all variables
- Supports environment-specific configurations
backend-hcl:
- Generates Terraform backend configuration
- Configures Cloudflare R2 for state storage
- Uses credentials from env.deploy.yml
secret-exports:
- Discovers all secrets and variables
- Generates shell script for GitHub Actions
- Exports secrets dynamically during workflow
ansible-inventory:
- Reads Terraform state output
- Creates dynamic inventory with server IPs
- Groups servers by environment
documentation:
- Generates markdown documentation
- Lists all secrets and variables
- Shows environment configurations
Adding New Services
Update env.deploy.yml:
yamlDEV: my_new_service: PORT: 8080 API_KEY: from_secretsAdd Docker Compose configuration
Test configuration:
bashnode scripts/generate-env-files.js DEV --dry-run node scripts/extract-config.js list-secretsAdd required secrets to GitHub
Script Documentation Details
How the Scripts Work Together
The deployment system is built around two core scripts that work in tandem:
extract-config.js reads
env.deploy.ymland extracts specific configurations:- Infrastructure variables for Terraform
- Secret and variable references for GitHub Actions
- Dynamic inventory generation from Terraform state
- Complete documentation of all settings
generate-env-files.js reads
env.deploy.ymland generates environment files:- Discovers all services dynamically (no hardcoded lists)
- Handles secret substitution from GitHub Actions environment
- Outputs appropriate format based on deployment target
Script Execution in GitHub Actions
The typical workflow execution:
bash
# 1. Export all secrets/variables to environment
./export_secrets.sh # Generated by extract-config.js secret-exports
# 2. Generate Terraform variables
node scripts/extract-config.js terraform-vars --env $ENVIRONMENT
# 3. Apply infrastructure changes
terraform apply -auto-approve
# 4. Generate Ansible inventory from Terraform state
node scripts/extract-config.js ansible-inventory --env $ENVIRONMENT
# 5. Generate environment files for all services
node scripts/generate-env-files.js $ENVIRONMENT --server
# 6. Deploy with Ansible
ansible-playbook -i inventory.ini playbook.ymlEnvironment Variable Substitution
The scripts handle three types of values:
Static values: Copied as-is
yamlPORT: 3333 # Becomes PORT=3333Auto-generated secrets:
from_secretsyamlAPP_KEY: from_secrets # Becomes APP_KEY=$DEV_SERVER_APP_KEYExplicit references: GitHub secrets/variables
yamlDATABASE_URL: '${{ secrets.PROD_DB_URL }}' # Becomes DATABASE_URL=$PROD_DB_URL
Multi-Environment Support
The scripts support both single and combined environments:
- Single:
DEV,QA,PROD- generates files for one environment - Combined:
DEV-QA- generates files for both dev and qa simultaneously
This allows the shared dev-qa server to be deployed with a single command.
Support
For deployment issues:
- Check generated configuration locally
- Review GitHub Actions workflow logs
- Contact team member directly
- Check 1Password for secret documentation