Deployment
CI/CD Pipeline
GitHub Actions workflow for automated testing and deployment
CI/CD Pipeline
This guide covers the GitHub Actions workflow for continuous integration and deployment.
Pipeline Overview
┌─────────────────────────────────────────────────────────────────┐
│ Push to Branch / PR │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ TEST JOB │
│ - Checkout code │
│ - Install dependencies │
│ - Run linting │
│ - Run type checking │
│ - Run tests │
│ - Build application │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
│ │
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ PREVIEW (PR only) │ │ STAGING (main only) │
│ - Build Docker │ │ - Build Docker │
│ - Push to Registry │ │ - Push to Registry │
│ - Deploy to Cloud │ │ - Deploy to Cloud │
│ Run (preview URL) │ │ Run (staging) │
└──────────────────────┘ └──────────────────────┘
│
▼
┌──────────────────────┐
│ PRODUCTION │
│ (requires approval) │
│ - Deploy to Cloud │
│ Run (production) │
└──────────────────────┘GitHub Repository Secrets
Add these secrets to your GitHub repository:
| Secret | Description | How to Get |
|---|---|---|
GCP_PROJECT_ID | GCP project ID | bluewoo-hrms |
GCP_REGION | GCP region | europe-west6 |
GCP_WORKLOAD_IDENTITY_PROVIDER | Workload identity provider | See infrastructure setup |
GCP_SERVICE_ACCOUNT | Service account email | github-actions@bluewoo-hrms.iam.gserviceaccount.com |
GitHub Actions Workflow
Create .github/workflows/deploy.yml:
name: Build and Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
PROJECT_ID: bluewoo-hrms
REGION: europe-west6
SERVICE_NAME: hrms-docs
REGISTRY: europe-west6-docker.pkg.dev
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linting
run: npm run lint
- name: Run type checking
run: npm run types:check
- name: Build
run: npm run build
deploy-preview:
if: github.event_name == 'pull_request'
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Configure Docker
run: gcloud auth configure-docker ${{ env.REGISTRY }}
- name: Build and Push
run: |
docker build -t ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/bluewoo-images/${{ env.SERVICE_NAME }}:pr-${{ github.event.number }} .
docker push ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/bluewoo-images/${{ env.SERVICE_NAME }}:pr-${{ github.event.number }}
- name: Deploy to Cloud Run (Preview)
run: |
gcloud run deploy ${{ env.SERVICE_NAME }}-pr-${{ github.event.number }} \
--image ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/bluewoo-images/${{ env.SERVICE_NAME }}:pr-${{ github.event.number }} \
--region ${{ env.REGION }} \
--platform managed \
--allow-unauthenticated \
--tag pr-${{ github.event.number }}
- name: Get Preview URL
id: preview-url
run: |
URL=$(gcloud run services describe ${{ env.SERVICE_NAME }}-pr-${{ github.event.number }} --region ${{ env.REGION }} --format 'value(status.url)')
echo "url=$URL" >> $GITHUB_OUTPUT
- name: Comment PR with Preview URL
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: '🚀 Preview deployed to: ${{ steps.preview-url.outputs.url }}'
})
deploy-staging:
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Configure Docker
run: gcloud auth configure-docker ${{ env.REGISTRY }}
- name: Build and Push
run: |
docker build -t ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/bluewoo-images/${{ env.SERVICE_NAME }}:${{ github.sha }} .
docker push ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/bluewoo-images/${{ env.SERVICE_NAME }}:${{ github.sha }}
- name: Deploy to Cloud Run (Staging)
run: |
gcloud run deploy ${{ env.SERVICE_NAME }}-staging \
--image ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/bluewoo-images/${{ env.SERVICE_NAME }}:${{ github.sha }} \
--region ${{ env.REGION }} \
--platform managed \
--allow-unauthenticated
deploy-production:
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
permissions:
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Deploy to Cloud Run (Production)
run: |
gcloud run deploy ${{ env.SERVICE_NAME }} \
--image ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/bluewoo-images/${{ env.SERVICE_NAME }}:${{ github.sha }} \
--region ${{ env.REGION }} \
--platform managed \
--allow-unauthenticatedGitHub Environment Setup
- Go to repository Settings → Environments
- Create environment named
production - Add required reviewers (yourself)
- Optionally add deployment branch rules
Workflow Triggers
| Event | Trigger | Actions |
|---|---|---|
| Push to branch | Create PR | Test job only |
| PR created/updated | PR event | Test + Preview deploy |
| Merge to main | Push to main | Test + Staging + Production (with approval) |
Rollback
To rollback production:
# List revisions
gcloud run revisions list --service=hrms-docs --region=europe-west6
# Route traffic to previous revision
gcloud run services update-traffic hrms-docs \
--region=europe-west6 \
--to-revisions=hrms-docs-PREVIOUS_REVISION=100Cleanup Preview Environments
Add a cleanup workflow for closed PRs:
name: Cleanup Preview
on:
pull_request:
types: [closed]
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Delete Preview Service
run: |
gcloud run services delete ${{ env.SERVICE_NAME }}-pr-${{ github.event.number }} \
--region ${{ env.REGION }} \
--quietWorkflow File Location
The complete workflow is at .github/workflows/deploy.yml in the repository.
Summary
| Job | Trigger | Purpose |
|---|---|---|
test | All pushes/PRs | Lint, type check, build |
deploy-preview | PR opened/updated | Deploy unique preview URL |
deploy-staging | Merge to main | Auto-deploy to staging |
deploy-production | After staging | Manual approval required |
cleanup-preview | PR closed | Delete preview resources |
Status: Verified - Workflow file created at .github/workflows/deploy.yml