Skip to content

Hotfix projects home when pin_order is unavailable #152

Hotfix projects home when pin_order is unavailable

Hotfix projects home when pin_order is unavailable #152

name: Deploy to Testing
on:
push:
branches:
- testing
env:
REGISTRY: registry.digitalocean.com/dbr-cr
GITOPS_REPO: dembrane/echo-gitops
PYTHON_VERSION: "3.11"
jobs:
generate-tag:
name: Generate Image Tag
runs-on: ubuntu-latest
outputs:
image-tag: ${{ steps.meta.outputs.tag }}
steps:
- name: Generate image tag
id: meta
run: |
SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7)
echo "tag=$SHORT_SHA" >> $GITHUB_OUTPUT
echo "📦 Image tag: $SHORT_SHA"
build-api:
name: Build & Push API Server
runs-on: ubuntu-latest
needs: [generate-tag]
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to DigitalOcean Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DO_REGISTRY_TOKEN }}
password: ${{ secrets.DO_REGISTRY_TOKEN }}
- name: Build and Push API Server
uses: docker/build-push-action@v5
with:
context: ./echo/server
file: ./echo/server/Dockerfile
push: true
tags: |
${{ env.REGISTRY }}/dbr-echo-server:${{ needs.generate-tag.outputs.image-tag }}
${{ env.REGISTRY }}/dbr-echo-server:testing
cache-from: type=gha
cache-to: type=gha,mode=max
build-agent:
name: Build & Push Agent Service
runs-on: ubuntu-latest
needs: [generate-tag]
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to DigitalOcean Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DO_REGISTRY_TOKEN }}
password: ${{ secrets.DO_REGISTRY_TOKEN }}
- name: Build and Push Agent Service
uses: docker/build-push-action@v5
with:
context: ./echo/agent
file: ./echo/agent/Dockerfile
push: true
tags: |
${{ env.REGISTRY }}/dbr-echo-agent:${{ needs.generate-tag.outputs.image-tag }}
${{ env.REGISTRY }}/dbr-echo-agent:testing
cache-from: type=gha
cache-to: type=gha,mode=max
build-directus:
name: Build & Push Directus
runs-on: ubuntu-latest
needs: [generate-tag]
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to DigitalOcean Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DO_REGISTRY_TOKEN }}
password: ${{ secrets.DO_REGISTRY_TOKEN }}
- name: Build and Push Directus
uses: docker/build-push-action@v5
with:
context: ./echo/directus
file: ./echo/directus/Dockerfile
push: true
tags: |
${{ env.REGISTRY }}/dbr-echo-directus:${{ needs.generate-tag.outputs.image-tag }}
${{ env.REGISTRY }}/dbr-echo-directus:testing
cache-from: type=gha
cache-to: type=gha,mode=max
deploy-dashboard:
name: Deploy Dashboard to Vercel
runs-on: ubuntu-latest
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_DASHBOARD_TESTING }}
steps:
- uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Setup pnpm cache
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('echo/frontend/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install Dependencies
run: pnpm install --frozen-lockfile
working-directory: echo/frontend
- name: Install Vercel CLI
run: pnpm add --global vercel@latest
working-directory: echo/frontend
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
working-directory: echo/frontend
- name: Debug Environment Variables
run: |
echo "=== Checking .vercel directory ==="
ls -la .vercel/ || echo "No .vercel directory"
echo ""
echo "=== Production environment file ==="
cat .vercel/.env.production.local || echo "No production env file"
echo ""
echo "=== Looking for VITE variables ==="
grep -r "VITE_" .vercel/ || echo "No VITE vars found"
working-directory: echo/frontend
- name: Build Project Artifacts
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
working-directory: echo/frontend
- name: Deploy to Vercel
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
working-directory: echo/frontend
deploy-portal:
name: Deploy Portal to Vercel
runs-on: ubuntu-latest
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_PORTAL_TESTING }}
steps:
- uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Setup pnpm cache
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('echo/frontend/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install Dependencies
run: pnpm install --frozen-lockfile
working-directory: echo/frontend
- name: Install Vercel CLI
run: pnpm add --global vercel@latest
working-directory: echo/frontend
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
working-directory: echo/frontend
- name: Debug Environment Variables
run: |
echo "=== Checking .vercel directory ==="
ls -la .vercel/ || echo "No .vercel directory"
echo ""
echo "=== Production environment file ==="
cat .vercel/.env.production.local || echo "No production env file"
echo ""
echo "=== Looking for VITE variables ==="
grep -r "VITE_" .vercel/ || echo "No VITE vars found"
working-directory: echo/frontend
- name: Build Project Artifacts
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
working-directory: echo/frontend
- name: Deploy to Vercel
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
working-directory: echo/frontend
update-gitops:
name: Update GitOps Repo
runs-on: ubuntu-latest
needs: [generate-tag, build-api, build-agent, build-directus]
steps:
- name: Checkout GitOps repo
uses: actions/checkout@v4
with:
repository: ${{ env.GITOPS_REPO }}
token: ${{ secrets.GITOPS_REPO_TOKEN }}
ref: main
- name: Update image tag in values-testing.yaml
run: |
IMAGE_TAG="${{ needs.generate-tag.outputs.image-tag }}"
echo "Updating imageTag to: $IMAGE_TAG"
sed -i "s/imageTag: \".*\"/imageTag: \"$IMAGE_TAG\"/" helm/echo/values-testing.yaml
echo "Updated values-testing.yaml:"
grep "imageTag:" helm/echo/values-testing.yaml
- name: Commit and push changes
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add helm/echo/values-testing.yaml
git commit -m "Update testing image tag to ${{ needs.generate-tag.outputs.image-tag }}"
git push origin main
wait-for-deployment:
name: Wait for ArgoCD Deployment
runs-on: ubuntu-latest
needs: [update-gitops, generate-tag]
steps:
- uses: actions/checkout@v4
- name: Wait for deployment
run: |
echo "⏳ Waiting for ArgoCD to sync and deploy..."
echo "Image tag: ${{ needs.generate-tag.outputs.image-tag }}"
MAX_WAIT=600 # 10 minutes
INTERVAL=15
ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
echo "Checking API health (${ELAPSED}s elapsed)..."
if curl -f -s https://api.echo-testing.dembrane.com/api/health > /dev/null 2>&1; then
echo "✅ API is healthy!"
exit 0
fi
sleep $INTERVAL
ELAPSED=$((ELAPSED + INTERVAL))
done
echo "❌ Deployment did not become healthy within ${MAX_WAIT}s"
exit 1
smoke-tests:
name: Run Smoke Tests
runs-on: ubuntu-latest
needs: [wait-for-deployment, generate-tag]
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: |
cd echo/server
pip install -r requirements.lock
pip install requests
- name: Run Smoke Tests
env:
TEST_API_URL: https://api.echo-testing.dembrane.com
TEST_DIRECTUS_URL: https://directus.echo-testing.dembrane.com
run: |
cd echo/server
pytest tests/smoke/ -v --maxfail=1 -m smoke
# TODO: Enable E2E tests once Playwright tests are created (Phase 4)
# e2e-tests:
# name: Run E2E Tests
# runs-on: ubuntu-latest
# needs: [smoke-tests]
# timeout-minutes: 10
# steps:
# - uses: actions/checkout@v4
#
# - name: Setup Node.js
# uses: actions/setup-node@v4
# with:
# node-version: "20"
#
# - name: Install pnpm
# uses: pnpm/action-setup@v2
# with:
# version: 8
#
# - name: Install dependencies
# run: |
# cd echo/frontend
# pnpm install
#
# - name: Install Playwright Browsers
# run: |
# cd echo/frontend
# pnpm exec playwright install --with-deps chromium
#
# - name: Run Playwright Tests
# env:
# TEST_BASE_URL: https://api.echo-testing.dembrane.com
# run: |
# cd echo/frontend
# pnpm exec playwright test
#
# - name: Upload Playwright Report
# if: always()
# uses: actions/upload-artifact@v4
# with:
# name: playwright-report
# path: echo/frontend/playwright-report/
# retention-days: 7
notify-slack:
name: Notify Slack
runs-on: ubuntu-latest
needs: [generate-tag, smoke-tests]
if: always()
steps:
- name: Determine status
id: status
run: |
if [ "${{ needs.smoke-tests.result }}" == "success" ]; then
echo "result=success" >> $GITHUB_OUTPUT
echo "emoji=✅" >> $GITHUB_OUTPUT
echo "color=good" >> $GITHUB_OUTPUT
else
echo "result=failure" >> $GITHUB_OUTPUT
echo "emoji=❌" >> $GITHUB_OUTPUT
echo "color=danger" >> $GITHUB_OUTPUT
fi
- name: Send Slack notification
uses: slackapi/slack-github-action@v1.24.0
with:
payload: |
{
"attachments": [
{
"color": "${{ steps.status.outputs.color }}",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "${{ steps.status.outputs.emoji }} Testing Deployment: ${{ steps.status.outputs.result }}"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Repository:*\necho"
},
{
"type": "mrkdwn",
"text": "*Branch:*\ntesting"
},
{
"type": "mrkdwn",
"text": "*Image Tag:*\n`${{ needs.generate-tag.outputs.image-tag }}`"
},
{
"type": "mrkdwn",
"text": "*Commit:*\n<https://github.com/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}>"
}
]
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Smoke Tests:*\n${{ needs.smoke-tests.result }}"
},
{
"type": "mrkdwn",
"text": "*E2E Tests:*\nPending (Phase 4)"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Links:*\n• <https://api.echo-testing.dembrane.com|API>\n• <https://directus.echo-testing.dembrane.com|Directus>\n• <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|GitHub Actions>"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "${{ steps.status.outputs.result == 'failure' && '⚠️ *Rollback Instructions:*\n```\ncd echo-gitops\ngit revert HEAD\ngit push origin main\n```\nOr keep for debugging and fix forward.' || '🎉 All tests passed! Environment is stable.' }}"
}
}
]
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK