Skip to content

GCP: updating production subdomain #28

GCP: updating production subdomain

GCP: updating production subdomain #28

Workflow file for this run

# ActivityPub Testbed CI/CD Pipeline
#
# This workflow provides continuous integration testing and automated deployment to Google Cloud Run.
#
# ## Workflow Jobs
#
# 1. test-python: Runs Django tests with PostgreSQL database
# 2. deploy: Deploys to Google Cloud Run (staging or production)
#
# ## Deployment Flow
#
# - Push to main branch: Automatically deploys to Staging environment
# - Manual trigger (workflow_dispatch): Choose Staging or Production environment
#
# ## Required Configuration
#
# ### GitHub Environment Variables (per environment: Staging, Production)
#
# - DJANGO_SETTINGS_MODULE: Python path to Django settings module for the environment
# - GCP_PROJECT_ID: Google Cloud Platform project identifier
# - CLOUD_RUN_SERVICE_NAME: Name of the Cloud Run service to deploy to
# - SERVICE_ACCOUNT_NAME: Email address of the service account used for Cloud Run
# - DATABASE_NAME: PostgreSQL database name in Cloud SQL
# - ARTIFACT_REGISTRY: Name of the container image
#
# ### GitHub Environment Secrets (per environment: Staging, Production)
#
# - GCP_CREDENTIALS: JSON credentials for the GCP service account (for authentication and storage)
# - CLOUD_SQL_ICN: Cloud SQL Instance Connection Name (format: PROJECT:REGION:INSTANCE)
# - POSTGRES_CREDENTIALS: PostgreSQL credentials (format: username:password, may contain special characters)
# - DJANGO_SECRET_KEY: Django secret key for cryptographic signing
#
# ### Shared Secret (available to all environments)
#
# - EMAIL_HOST_PASSWORD: SMTP password for sending emails (e.g., Gmail app password)
#
# ## Deployment Steps
#
# The deploy job performs these operations:
# 1. Authenticates to Google Cloud Platform
# 2. Runs database migrations via Cloud SQL Auth Proxy
# 3. Compiles SCSS to CSS
# 4. Collects static files and uploads to Google Cloud Storage
# 5. Configures CORS for the storage bucket
# 6. Deploys application to Cloud Run using --source flag (builds from Dockerfile)
name: CI-CD
on:
pull_request:
branches: [ main ]
push:
branches: [ main ]
workflow_dispatch:
inputs:
environment:
type: environment
description: Select the target environment
jobs:
# Test Python/Django code with PostgreSQL database
test-python:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:17
env:
POSTGRES_USER: activitypub_testbed_dbuser
POSTGRES_PASSWORD: activitypub_testbed_testpass
POSTGRES_DB: activitypub_testbed_database
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Create test environment file
run: |
echo "DEBUG=True" > .env
echo "DJANGO_SECRET_KEY=test-secret-key-for-ci" >> .env
echo "DJ_DATABASE_CONN_STRING=postgres://activitypub_testbed_dbuser:activitypub_testbed_testpass@localhost:5432/activitypub_testbed_database" >> .env
- name: Run Tests
run: pytest --ds=testbed.settings.ci
# Deploy to Google Cloud Run
deploy:
# Only deploy on push to main or manual trigger
if: |
(github.event_name == 'push' && github.ref == 'refs/heads/main')
|| github.event_name == 'workflow_dispatch'
# Wait for tests to pass
needs: [test-python]
runs-on: ubuntu-latest
environment:
name: ${{ inputs.environment || 'Staging' }}
env:
DJANGO_SETTINGS_MODULE: ${{ vars.DJANGO_SETTINGS_MODULE }}
# Temporary placeholder - real value passed during Cloud Run deployment
EMAIL_HOST_PASSWORD: 'placeholder'
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Create service-account-credentials.json
uses: jsdaniell/[email protected]
with:
name: service-account-credentials.json
json: ${{ secrets.GCP_CREDENTIALS }}
- uses: 'google-github-actions/auth@v2'
with:
project_id: ${{ vars.GCP_PROJECT_ID }}
credentials_json: '${{ secrets.GCP_CREDENTIALS }}'
- name: Set up Cloud SDK
uses: 'google-github-actions/setup-gcloud@v2'
with:
project_id: ${{ vars.GCP_PROJECT_ID }}
- name: URL-encode database credentials for special characters
env:
POSTGRES_CREDENTIALS: ${{ secrets.POSTGRES_CREDENTIALS }}
run: |
# URL encode credentials to handle special characters like *, !, (, )
# Extract and encode password securely without exposing it in logs
ENCODED_CREDENTIALS=$(python3 -c "
import urllib.parse, os, sys
try:
creds = os.environ['POSTGRES_CREDENTIALS']
if ':' in creds:
user, password = creds.split(':', 1)
encoded_password = urllib.parse.quote(password, safe='')
print(f'{user}:{encoded_password}')
else:
print(creds)
except Exception:
sys.exit(1)
")
if [ $? -eq 0 ]; then
echo "ENCODED_DB_CREDENTIALS=$ENCODED_CREDENTIALS" >> $GITHUB_ENV
echo "Database credentials encoded successfully"
else
echo "Failed to encode database credentials"
exit 1
fi
- name: Download and run the Cloud SQL Auth Proxy
run: |
curl -o cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.10.1/cloud-sql-proxy.linux.amd64
chmod +x cloud-sql-proxy
./cloud-sql-proxy --address 0.0.0.0 --port 1234 ${{ secrets.CLOUD_SQL_ICN }} &
- name: Run migrations
env:
DJ_DATABASE_CONN_STRING: postgres://${{ env.ENCODED_DB_CREDENTIALS }}@localhost:1234/${{ vars.DATABASE_NAME }}
DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}
run: python3 manage.py migrate
- name: Stop Cloud SQL Auth Proxy
run: pkill cloud-sql-proxy
- name: Compile SCSS
env:
DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}
DJ_DATABASE_CONN_STRING: postgres://${{ env.ENCODED_DB_CREDENTIALS }}@localhost:1234/${{ vars.DATABASE_NAME }}
run: python3 manage.py compilescss
- name: Collect static files
env:
DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}
DJ_DATABASE_CONN_STRING: postgres://${{ env.ENCODED_DB_CREDENTIALS }}@localhost:1234/${{ vars.DATABASE_NAME }}
run: python3 manage.py collectstatic --no-input --ignore=*.scss
- name: Configure CORS for storage bucket
env:
DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}
DJ_DATABASE_CONN_STRING: postgres://${{ env.ENCODED_DB_CREDENTIALS }}@localhost:1234/${{ vars.DATABASE_NAME }}
run: |
python3 manage.py create_gcp_cors_config
export GS_BUCKET_NAME=$(python3 -c "from django.conf import settings; print(settings.GS_BUCKET_NAME)")
gcloud storage buckets update gs://$GS_BUCKET_NAME --cors-file=gcp-cors-config.json
- name: Deploy to Cloud Run
run: >
gcloud run deploy ${{ vars.CLOUD_RUN_SERVICE_NAME }}
--region us-central1
--source .
--service-account ${{ vars.SERVICE_ACCOUNT_NAME }}
--add-cloudsql-instances=${{ secrets.CLOUD_SQL_ICN }}
--set-env-vars DJANGO_SETTINGS_MODULE="${{ vars.DJANGO_SETTINGS_MODULE }}"
--set-env-vars DJANGO_SECRET_KEY="${{ secrets.DJANGO_SECRET_KEY }}"
--set-env-vars DJ_DATABASE_CONN_STRING="postgres://${{ env.ENCODED_DB_CREDENTIALS }}@//cloudsql/${{ secrets.CLOUD_SQL_ICN }}/${{ vars.DATABASE_NAME }}"
--set-env-vars EMAIL_HOST_PASSWORD="${{ secrets.EMAIL_HOST_PASSWORD }}"
--allow-unauthenticated