Skip to content

feat: Added final clean up db step #8

feat: Added final clean up db step

feat: Added final clean up db step #8

Workflow file for this run

# ===============================================

Check failure on line 1 in .github/workflows/cd-base.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/cd-base.yml

Invalid workflow file

(Line: 179, Col: 5): Unexpected value 'secrets'
# CI/CD Pipeline: Pull GHCR image -> Re-tag -> Push to DockerHub -> Deploy with Terraform
# ===============================================
# Description:
# This workflow takes a Docker image from GHCR (GitHub Container Registry) generated by a PR or push,
# retags it with the DockerHub username, pushes it to DockerHub, and then deploys the latest image
# to Cloud Run using Terraform. It also handles initial database table creation if necessary.
#
# Inputs:
# - deployment_env: Deployment environment (e.g., staging, production)
# - image_uri: URI of the image in GHCR (e.g., ghcr.io/org/repo:tag)
#
# Outputs:
# - dockerhub_image: URI of the retagged image pushed to DockerHub
# ===============================================
on:
workflow_call:
inputs:
deployment_env:
required: true
type: string
image_uri: # GHCR Docker image URI
required: true
type: string
jobs:
# -----------------------------------------------
# Job: Pull image from GHCR, retag, and push to DockerHub
# -----------------------------------------------
pull-tag-push:
runs-on: ubuntu-latest
outputs:
dockerhub_image: ${{ steps.push.outputs.image_uri }}
steps:
- name: Log in Github container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract tag name from GHCR
id: extract
run: |
TAG=$(echo "${{ inputs.image_uri }}" | awk -F':' '{print $NF}')
echo "tag=${TAG}" >> $GITHUB_OUTPUT
APP_NAME=$(echo "${{ inputs.image_uri }}" | awk -F'/' '{print $NF}' | cut -d':' -f1)
echo "app_name=${APP_NAME}" >> $GITHUB_OUTPUT
- name: Pull -> re-tag -> push
id: push
run: |
PUBLIC_IMAGE="${{ steps.extract.outputs.app_name }}:${{ steps.extract.outputs.tag }}"
DOCKERHUB_IMAGE="${{ secrets.DOCKERHUB_USERNAME }}/${PUBLIC_IMAGE}"
docker pull ${{ inputs.image_uri }}
docker tag ${{ inputs.image_uri }} ${DOCKERHUB_IMAGE}
docker push ${DOCKERHUB_IMAGE}
echo "image_uri=${PUBLIC_IMAGE}" >> $GITHUB_OUTPUT # <-- output this way given that github actions will censor secrets
# -----------------------------------------------
# Job: Deploy application to GCP using Terraform
# -----------------------------------------------
deploy:
needs: pull-tag-push
runs-on: ubuntu-latest
environment: ${{ inputs.deployment_env }}
outputs:
db_host: ${{ steps.db.outputs.public_ip }}
api_url: ${{ steps.db.outputs.api_url }}
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Auth GCP
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}
- name: Init Terraform
working-directory: terraform
run: terraform init
- name: Use deployment env workspace
working-directory: terraform
run: |
terraform workspace select ${{ inputs.deployment_env }} || \
terraform workspace new ${{ inputs.deployment_env }}
- name: Debug dockerhub_image
run: |
echo "DockerHub image from previous job: '${{ needs.pull-tag-push.outputs.dockerhub_image }}'"
- name: Terraform plan
working-directory: terraform
run: |
terraform plan \
-var-file=environments/${{ inputs.deployment_env }}.tfvars \
-var="project_id=${{ secrets.GCP_PROJECT_ID }}" \
-var="db_name=${{ secrets.DB_NAME }}" \
-var="db_user=${{ secrets.DB_USER }}" \
-var="db_password=${{ secrets.DB_PASSWORD }}" \
-var="image_uri=docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ needs.pull-tag-push.outputs.dockerhub_image }}" \
-out=tfplan
- name: Terraform Apply
working-directory: terraform
run: terraform apply tfplan
- name: Get Terraform outputs
id: db
working-directory: terraform
run: |
echo "public_ip=$(terraform output -raw db_host)" >> $GITHUB_OUTPUT
echo "api_url=$(terraform output -raw cloud_run_service_url)" >> $GITHUB_OUTPUT
- name: Check if tickets table exists
id: check_table
env:
PGPASSWORD: ${{ secrets.DB_PASSWORD }}
run: |
# install postgres client
sudo apt-get update && sudo apt-get install -y postgresql-client
TABLE_EXISTS=$(psql -h ${{ steps.db.outputs.public_ip }} \
-U ${{ secrets.DB_USER }} \
-d ${{ secrets.DB_NAME }} \
-tAc "SELECT EXISTS (SELECT FROM pg_tables WHERE tablename = 'tickets');" \
)
echo "table_exist=$TABLE_EXISTS" >> $GITHUB_OUTPUT
- name: Create tables and populate (tickets table not existent)
if: steps.check_table.outputs.table_exist == 'f'
env:
PGPASSWORD: ${{ secrets.DB_PASSWORD }}
run: |
# if something fails stop
set -e
for file in $(ls src/db/scripts/init/*.sql | sort -V); do
echo "> Executing: $file"
psql -h ${{ steps.db.outputs.public_ip }} \
-U ${{ secrets.DB_USER }} \
-d ${{ secrets.DB_NAME }} \
-f "$file" \
-v DB_NAME=${{ secrets.DB_NAME }} \
-v ON_ERROR_STOP=1
done
- name: Skipped table creation (existent tickets table)
if: steps.check_table.outputs.table_exist == 't'
run: echo ""
run-integration-tests:
needs: deploy
uses: ./.github/workflows/integration-tests.yml
with:
deployment_env: ${{ inputs.deployment_env }}
db_host: ${{ needs.deploy.outputs.db_host }}
api_url: ${{ needs.deploy.outputs.api_url }}
secrets: inherit # pragma: allowlist secret
cleanup-database:
needs: run-integration-tests
runs-on: ubuntu-latest
secrets: inherit # pragma: allowlist secret
if: always() && github.event.inputs.deployment_env != 'local' # run even if integration test fail
steps:
- uses: actions/checkout@v4
- name: Cleanup SPs and tables
env:
PGPASSWORD: ${{ secrets.DB_PASSWORD }}
run: |
# install postgres client
sudo apt-get update && sudo apt-get install -y postgresql-client
# if something fails stop
set -e
for file in $(ls src/db/scripts/cleanup/*.sql | sort -V); do
echo "> Executing: $file"
psql -h ${{ steps.db.outputs.public_ip }} \
-U ${{ secrets.DB_USER }} \
-d ${{ secrets.DB_NAME }} \
-f "$file" \
-v DB_NAME=${{ secrets.DB_NAME }} \
-v ON_ERROR_STOP=1
done