Skip to content

fix(ci): simplify environment field - always use environment name #3

fix(ci): simplify environment field - always use environment name

fix(ci): simplify environment field - always use environment name #3

name: Reusable Deployment Workflow
on:
workflow_call:
inputs:
environment:
description: 'Target environment (dev, staging, prod)'
required: true
type: string
stack-name:
description: 'Pulumi stack name'
required: true
type: string
coverage-threshold:
description: 'Minimum test coverage percentage'
required: false
type: number
default: 70
test-scope:
description: 'Test scope (unit or all)'
required: false
type: string
default: 'unit'
skip-tests:
description: 'Skip pre-deployment tests'
required: false
type: boolean
default: false
deploy-infrastructure:
description: 'Deploy infrastructure stack first'
required: false
type: boolean
default: false
create-release:
description: 'Create GitHub release'
required: false
type: boolean
default: false
require-approval:
description: 'Require manual approval (GitHub environment)'
required: false
type: boolean
default: false
secrets:
AWS_ACCESS_KEY_ID:
required: true
AWS_SECRET_ACCESS_KEY:
required: true
PULUMI_ACCESS_TOKEN:
required: true
GITHUB_TOKEN:

Check failure on line 51 in .github/workflows/deploy-reusable.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/deploy-reusable.yml

Invalid workflow file

secret name `GITHUB_TOKEN` within `workflow_call` can not be used since it would collide with system reserved name
required: false
jobs:
pre-deployment-checks:
name: Pre-Deployment Validation
runs-on: ubuntu-latest
if: ${{ !inputs.skip-tests }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Set up uv
uses: astral-sh/setup-uv@v5
with:
version: "latest"
enable-cache: true
- name: Create virtual environment
run: uv venv .venv
- name: Install dependencies
run: |
source .venv/bin/activate
uv pip install -r coaching/requirements.txt
uv pip install -r coaching/requirements-dev.txt
shell: bash
- name: Run Ruff Linting
run: |
source .venv/bin/activate
python -m ruff check . --exclude=".venv,venv,__pycache__,.pytest_cache"
shell: bash
- name: Run MyPy Type Checking
run: |
source .venv/bin/activate
python -m mypy coaching/src/ shared/ --config-file=pyproject.toml
shell: bash
- name: Run Tests
run: |
source .venv/bin/activate
if [ "${{ inputs.test-scope }}" == "all" ]; then
python -m pytest coaching/tests/ -v --cov=coaching/src --cov-fail-under=${{ inputs.coverage-threshold }}
else
python -m pytest coaching/tests/unit/ -v --cov=coaching/src --cov-fail-under=${{ inputs.coverage-threshold }}
fi
shell: bash
env:
PYTHONPATH: coaching:shared:.
deploy-infrastructure:
name: Deploy Infrastructure
runs-on: ubuntu-latest
needs: [pre-deployment-checks]
if: |
always() &&
inputs.deploy-infrastructure &&
(needs.pre-deployment-checks.result == 'success' || inputs.skip-tests)
permissions:
id-token: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Pulumi Python dependencies
working-directory: infrastructure/pulumi
run: pip install -r requirements.txt
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-1
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Deploy Infrastructure
uses: pulumi/actions@v5
with:
command: up
stack-name: ${{ inputs.stack-name }}
work-dir: infrastructure/pulumi
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
deploy-coaching:
name: Deploy to ${{ inputs.environment }}
runs-on: ubuntu-latest
needs: [pre-deployment-checks, deploy-infrastructure]
if: |
always() &&
(needs.pre-deployment-checks.result == 'success' || inputs.skip-tests) &&
(needs.deploy-infrastructure.result == 'success' || needs.deploy-infrastructure.result == 'skipped')
permissions:
id-token: write
contents: write
environment: ${{ inputs.environment }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Pulumi Python dependencies
working-directory: coaching/pulumi
run: pip install -r requirements.txt
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-1
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Deploy Coaching Service
uses: pulumi/actions@v5
with:
command: up
stack-name: ${{ inputs.stack-name }}
work-dir: coaching/pulumi
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
- name: Get API Gateway URL
id: api-url
working-directory: coaching/pulumi
run: |
URL=$(pulumi stack output customDomainUrl --stack ${{ inputs.stack-name }})
echo "url=$URL" >> $GITHUB_OUTPUT
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
- name: Create GitHub Release
if: ${{ inputs.create-release }}
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ github.run_number }}
release_name: Release v${{ github.run_number }}
body: |
Production deployment of PurposePath Coaching API
**Deployment Details:**
- Environment: ${{ inputs.environment }}
- Stack: ${{ inputs.stack-name }}
- API URL: ${{ steps.api-url.outputs.url }}
- Deployed at: ${{ github.event.head_commit.timestamp }}
- Commit: ${{ github.sha }}
draft: false
prerelease: false
continue-on-error: true
- name: Deployment Summary
run: |
echo "## 🚀 Deployment Summary - ${{ inputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Deployment successful" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Environment:** ${{ inputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "**Stack:** ${{ inputs.stack-name }}" >> $GITHUB_STEP_SUMMARY
echo "**API URL:** ${{ steps.api-url.outputs.url }}" >> $GITHUB_STEP_SUMMARY
echo "**Region:** us-east-1" >> $GITHUB_STEP_SUMMARY
if [ "${{ inputs.create-release }}" == "true" ]; then
echo "**Release:** v${{ github.run_number }}" >> $GITHUB_STEP_SUMMARY
fi
echo "**Deployed at:** $(date -u)" >> $GITHUB_STEP_SUMMARY
smoke-tests:
name: Post-Deployment Smoke Tests
runs-on: ubuntu-latest
needs: [deploy-coaching]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Pulumi CLI
uses: pulumi/actions@v5
with:
pulumi-version: 'latest'
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-1
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Get API Gateway URL
id: api-url
working-directory: coaching/pulumi
run: |
URL=$(pulumi stack output customDomainUrl --stack ${{ inputs.stack-name }})
echo "url=$URL" >> $GITHUB_OUTPUT
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
- name: Health Check
run: |
echo "Testing API health endpoint..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" ${{ steps.api-url.outputs.url }}/health || echo "000")
if [ "$HTTP_CODE" == "200" ] || [ "$HTTP_CODE" == "404" ]; then
echo "✅ API is responding (HTTP $HTTP_CODE)"
else
echo "⚠️ API returned HTTP $HTTP_CODE"
if [ "${{ inputs.environment }}" == "prod" ]; then
echo "Production deployment verification failed!"
exit 1
fi
fi
- name: Smoke Test Summary
run: |
echo "## Smoke Tests - ${{ inputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Health check passed" >> $GITHUB_STEP_SUMMARY
echo "✅ API is responsive" >> $GITHUB_STEP_SUMMARY
if [ "${{ inputs.environment }}" == "prod" ]; then
echo "✅ Production deployment verified" >> $GITHUB_STEP_SUMMARY
fi
notify-deployment:
name: Notify Team
runs-on: ubuntu-latest
needs: [deploy-coaching, smoke-tests]
if: always() && inputs.create-release
steps:
- name: Deployment Status
run: |
if [ "${{ needs.deploy-coaching.result }}" == "success" ] && [ "${{ needs.smoke-tests.result }}" == "success" ]; then
echo "✅ ${{ inputs.environment }} deployment completed successfully"
else
echo "❌ ${{ inputs.environment }} deployment encountered issues"
exit 1
fi