Skip to content

feat(sidebar): sort by recency, unread indicator, last-active date #148

feat(sidebar): sort by recency, unread indicator, last-active date

feat(sidebar): sort by recency, unread indicator, last-active date #148

Workflow file for this run

name: Deploy
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize]
permissions:
contents: read
id-token: write
deployments: write
pull-requests: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Create GitHub Deployment (Preview)
- name: Create GitHub Deployment
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
id: create_deployment
with:
script: |
const { owner, repo } = context.repo;
const ref = context.payload.pull_request.head.ref;
try {
const deployment = await github.rest.repos.createDeployment({
owner,
repo,
ref,
environment: `pr-${context.issue.number}`,
auto_merge: false,
required_contexts: [],
transient_environment: true,
description: `Preview for PR #${context.issue.number}`
});
if (deployment.status === 201) {
return deployment.data.id;
}
console.log('Deployment creation returned status:', deployment.status);
return null;
} catch (error) {
console.error('Error creating deployment:', error);
return null;
}
- name: Set Deployment Status Pending
if: github.event_name == 'pull_request' && steps.create_deployment.outputs.result != 'null'
uses: actions/github-script@v7
with:
script: |
const deployment_id = ${{ steps.create_deployment.outputs.result }};
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deployment_id,
state: 'pending',
description: 'Deploying to Cloud Run preview...',
});
- id: 'auth'
uses: 'google-github-actions/auth@v2'
with:
workload_identity_provider: '${{ secrets.GC_WORKLOAD_IDENTITY_PROVIDER }}'
service_account: '${{ secrets.GC_SERVICE_ACCOUNT }}'
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Configure Docker
run: gcloud auth configure-docker asia-east1-docker.pkg.dev
- name: Build and Push Images
env:
PROJECT_ID: ${{ secrets.GC_PROJECT_ID }}
SHA: ${{ github.sha }}
run: |
# Build frontend
docker build \
--build-arg VITE_LANGFUSE_PUBLIC_KEY=${{ secrets.LANGFUSE_PUBLIC_KEY }} \
--build-arg VITE_LANGFUSE_BASE_URL="https://langfuse.cofacts.tw" \
-t asia-east1-docker.pkg.dev/$PROJECT_ID/cofacts-ai/frontend:$SHA -f Dockerfile .
docker push asia-east1-docker.pkg.dev/$PROJECT_ID/cofacts-ai/frontend:$SHA
# Build backend
docker build -t asia-east1-docker.pkg.dev/$PROJECT_ID/cofacts-ai/backend:$SHA -f adk/Dockerfile adk
docker push asia-east1-docker.pkg.dev/$PROJECT_ID/cofacts-ai/backend:$SHA
echo "FRONTEND_IMAGE=asia-east1-docker.pkg.dev/$PROJECT_ID/cofacts-ai/frontend:$SHA" >> $GITHUB_ENV
echo "BACKEND_IMAGE=asia-east1-docker.pkg.dev/$PROJECT_ID/cofacts-ai/backend:$SHA" >> $GITHUB_ENV
- name: Prepare Traffic Block
id: traffic
run: |
# Fetch the current traffic state so we can preserve existing tags
CURRENT_TRAFFIC=$(gcloud run services describe cofacts-ai --region asia-east1 --format="json" 2>/dev/null || echo '{"status":{"traffic":[]}}')
if [ "${{ github.event_name }}" == "pull_request" ]; then
TAG="pr-${{ github.event.number }}"
# Find the revision currently handling 100% traffic
CURRENT_100_REV=$(echo "$CURRENT_TRAFFIC" | jq -r '(.status.traffic // []) | map(select(.percent == 100))[0].revisionName // empty')
if [ -z "$CURRENT_100_REV" ]; then
# First deployment or no 100% revision, default 100% to the new revision and tag it
TRAFFIC_JSON="[{\"latestRevision\": true, \"percent\": 100, \"tag\": \"$TAG\"}]"
else
# Extract all existing tags except the current PR tag so we update it safely
EXISTING_TAGS=$(echo "$CURRENT_TRAFFIC" | jq -c "[ (.status.traffic // [])[] | select(.tag != null and .tag != \"$TAG\") | {revisionName: .revisionName, tag: .tag, percent: 0} ]")
# Combine them together: maintain current 100% revision, tag the new revision, and keep existing tags
TRAFFIC_JSON=$(jq -n -c --arg rev "$CURRENT_100_REV" --arg tag "$TAG" --argjson extags "$EXISTING_TAGS" \
'[{"revisionName": $rev, "percent": 100}, {"latestRevision": true, "percent": 0, "tag": $tag}] + $extags')
fi
else
# Master: Send 100% to the new revision, and preserve all existing tags by keeping them with 0% traffic
EXISTING_TAGS=$(echo "$CURRENT_TRAFFIC" | jq -c "[ (.status.traffic // [])[] | select(.tag != null) | {revisionName: .revisionName, tag: .tag, percent: 0} ]")
TRAFFIC_JSON=$(jq -n -c --argjson extags "$EXISTING_TAGS" \
'[{"latestRevision": true, "percent": 100}] + $extags')
fi
echo "TRAFFIC_BLOCK=traffic: $TRAFFIC_JSON" >> $GITHUB_ENV
- name: Generate Service YAML
env:
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
LANGFUSE_PUBLIC_KEY: ${{ secrets.LANGFUSE_PUBLIC_KEY }}
LANGFUSE_SECRET_KEY: ${{ secrets.LANGFUSE_SECRET_KEY }}
# Cofacts.ai's PostgreSQL connection string
# postgresql+asyncpg://<sa>%40<project>.iam@localhost/<db>
DATABASE_URL: ${{ secrets.DATABASE_URL }}
# Service account that is dedicated to Cofacts.ai (<name>@<project>.iam.gserviceaccount.com)
# GC_SERVICE_ACCOUNT has been configured so that it can act as SERVICE_ACCOUNT_EMAIL.
SERVICE_ACCOUNT_EMAIL: ${{ secrets.SERVICE_ACCOUNT_EMAIL }}
GC_PROJECT_ID: ${{ secrets.GC_PROJECT_ID }}
run: |
envsubst '${FRONTEND_IMAGE} ${BACKEND_IMAGE} ${TRAFFIC_BLOCK} ${GOOGLE_API_KEY} ${LANGFUSE_PUBLIC_KEY} ${LANGFUSE_SECRET_KEY} ${DATABASE_URL} ${SERVICE_ACCOUNT_EMAIL} ${GC_PROJECT_ID}' < service.template.yaml > service.yaml
cat service.yaml
- name: Deploy to Cloud Run
run: |
gcloud run services replace service.yaml --region asia-east1
- name: Get Preview URL
if: github.event_name == 'pull_request'
id: get_url
run: |
TAG="pr-${{ github.event.number }}"
# Try to get URL from status.traffic
URL=$(gcloud run services describe cofacts-ai --region asia-east1 --format="value(status.traffic.filter(tag='$TAG').url)" | head -n 1)
if [ -z "$URL" ]; then
# Fallback: construct from base URL
BASE_URL=$(gcloud run services describe cofacts-ai --region asia-east1 --format="value(status.url)")
# Basic construction
URL="${BASE_URL/https:\/\//https:\/\/$TAG---}"
fi
echo "PREVIEW_URL=$URL" >> $GITHUB_ENV
- name: Set Deployment Status Success
if: github.event_name == 'pull_request' && success() && steps.create_deployment.outputs.result != 'null'
uses: actions/github-script@v7
with:
script: |
const deployment_id = ${{ steps.create_deployment.outputs.result }};
const preview_url = process.env.PREVIEW_URL;
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deployment_id,
state: 'success',
environment_url: preview_url,
description: 'Preview is ready!',
});
- name: Set Deployment Status Failure
if: github.event_name == 'pull_request' && failure() && steps.create_deployment.outputs.result != 'null'
uses: actions/github-script@v7
with:
script: |
const deployment_id = ${{ steps.create_deployment.outputs.result }};
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deployment_id,
state: 'failure',
description: 'Deployment failed.',
});