Skip to content

fix: handle access_token param in auth callback + accept bearer header #104

fix: handle access_token param in auth callback + accept bearer header

fix: handle access_token param in auth callback + accept bearer header #104

Workflow file for this run

name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
# Grant GITHUB_TOKEN the permissions required for this workflow
permissions:
contents: read
packages: write
jobs:
# Step 1: Quick Validation - Fail fast on basic issues
validate:
name: Quick Validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- 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('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run linter
run: pnpm run lint || echo "::warning::Linting failed but continuing..."
- name: Type check
run: pnpm exec tsc --noEmit || echo "::warning::Type checking failed but continuing..."
- name: Run tests (REQUIRED)
run: pnpm run test:ci
- name: Verify build can complete
run: pnpm run build || echo "::error::Build failed but continuing to show all issues"
# Step 2: Full Build
build:
name: Full Build
runs-on: ubuntu-latest
needs: validate # Only proceed if validation passes
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- 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('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build application
run: pnpm run build
env:
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL || 'http://localhost:3000' }}
- name: Run tests
run: pnpm test || true # Add tests when available
# Cache build artifacts for deployment
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: |
.next
public
package.json
pnpm-lock.yaml
next.config.js
retention-days: 1
# Step 3: Build Docker Image
docker:
name: Build Docker Image
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.production
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
NEXT_PUBLIC_API_URL=${{ secrets.NEXT_PUBLIC_API_URL || 'http://localhost:3000' }}
# Step 4: Deploy to Digital Ocean App Platform
# Note: DO App Platform auto-deploys on push via deploy_on_push: true
# This job waits for deployment and verifies health
deploy:
name: Deploy to Digital Ocean
runs-on: ubuntu-latest
needs: [build]
if: github.ref == 'refs/heads/main' && needs.build.result == 'success'
environment:
name: production
url: https://hanzo.app
steps:
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Wait for DO deployment
run: |
echo "Waiting for Digital Ocean App Platform to deploy..."
# DO auto-deploys on push, wait for it to complete
sleep 60
# Check deployment status
for i in {1..20}; do
STATUS=$(doctl apps list-deployments ${{ secrets.DO_APP_ID }} --format Phase --no-header | head -1)
echo "Deployment status: $STATUS"
if [ "$STATUS" = "ACTIVE" ]; then
echo "Deployment successful!"
break
elif [ "$STATUS" = "ERROR" ]; then
echo "Deployment failed!"
exit 1
fi
echo "Attempt $i: Waiting for deployment to complete..."
sleep 30
done
- name: Get app URL
id: app-url
run: |
APP_URL=$(doctl apps get ${{ secrets.DO_APP_ID }} --format DefaultIngress --no-header)
echo "url=$APP_URL" >> $GITHUB_OUTPUT
echo "App URL: $APP_URL"
- name: Health check
run: |
for i in {1..10}; do
if curl -f -s -o /dev/null -w "%{http_code}" ${{ steps.app-url.outputs.url }}/api/health | grep -q "200"; then
echo "Health check passed"
exit 0
fi
echo "Attempt $i: Waiting for app to be healthy..."
sleep 10
done
echo "Health check failed after 10 attempts"
exit 1
# Step 5: Notify on Success/Failure
notify:
name: Send Notifications
runs-on: ubuntu-latest
needs: [validate, build, deploy]
if: always()
steps:
- name: Determine status
id: status
run: |
if [ "${{ needs.deploy.result }}" == "success" ]; then
echo "status=success" >> $GITHUB_OUTPUT
echo "emoji=✅" >> $GITHUB_OUTPUT
echo "message=Successfully deployed to production" >> $GITHUB_OUTPUT
elif [ "${{ needs.deploy.result }}" == "skipped" ]; then
echo "status=skipped" >> $GITHUB_OUTPUT
echo "emoji=⏭️" >> $GITHUB_OUTPUT
echo "message=Deployment skipped (not main branch)" >> $GITHUB_OUTPUT
else
echo "status=failure" >> $GITHUB_OUTPUT
echo "emoji=❌" >> $GITHUB_OUTPUT
echo "message=Deployment failed" >> $GITHUB_OUTPUT
fi
# Discord webhook notification (optional - fails silently if not configured)
- name: Discord Notification
run: |
curl -H "Content-Type: application/json" \
-d '{
"embeds": [{
"title": "${{ steps.status.outputs.emoji }} Deployment ${{ steps.status.outputs.status }}",
"description": "${{ steps.status.outputs.message }}",
"color": ${{ steps.status.outputs.status == 'success' && '3066993' || '15158332' }},
"fields": [
{
"name": "Branch",
"value": "${{ github.ref_name }}",
"inline": true
},
{
"name": "Commit",
"value": "[`${{ github.sha }}`](${{ github.event.head_commit.url }})",
"inline": true
},
{
"name": "Author",
"value": "${{ github.actor }}",
"inline": true
},
{
"name": "Message",
"value": "${{ github.event.head_commit.message }}"
}
],
"timestamp": "${{ github.event.head_commit.timestamp }}"
}]
}' \
${{ secrets.DISCORD_WEBHOOK_URL }} || true
# Slack webhook notification (optional - fails silently if not configured)
- name: Slack Notification
run: |
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"text": "${{ steps.status.outputs.emoji }} *Deployment ${{ steps.status.outputs.status }}*",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*${{ steps.status.outputs.message }}*\n\n*Branch:* ${{ github.ref_name }}\n*Commit:* <${{ github.event.head_commit.url }}|${{ github.sha }}>\n*Author:* ${{ github.actor }}\n*Message:* ${{ github.event.head_commit.message }}"
}
}
]
}' \
${{ secrets.SLACK_WEBHOOK_URL }} || true