Skip to content

Commit d395e45

Browse files
baijumclaude
andcommitted
fix: isolate preview deploys into separate directories
Give each preview its own clone at /opt/apps/{APP_NAME}-pr-{N} instead of sharing /opt/apps/{APP_NAME} with production. This eliminates the race condition where concurrent preview and production deploys could build from the wrong code. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d8cf89b commit d395e45

1 file changed

Lines changed: 25 additions & 18 deletions

File tree

.github/workflows/preview.yml

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,33 @@ jobs:
2525
APP_DB=$(echo "${APP_NAME}" | tr '-' '_')_db
2626
SCHEMA_NAME="pr_${PR_NUMBER}"
2727
28-
cd /opt/apps/${APP_NAME}
29-
30-
# Fetch and checkout the PR branch
31-
git fetch origin pull/${PR_NUMBER}/head:pr-${PR_NUMBER} --force
32-
git checkout pr-${PR_NUMBER}
28+
PREVIEW_DIR="/opt/apps/${APP_NAME}-pr-${PR_NUMBER}"
29+
30+
# Clone the repo into a dedicated preview directory (or pull if it exists)
31+
if [ -d "${PREVIEW_DIR}" ]; then
32+
cd "${PREVIEW_DIR}"
33+
git fetch origin pull/${PR_NUMBER}/head:pr-${PR_NUMBER} --force
34+
git checkout pr-${PR_NUMBER}
35+
else
36+
git clone /opt/apps/${APP_NAME} "${PREVIEW_DIR}"
37+
cd "${PREVIEW_DIR}"
38+
git fetch origin pull/${PR_NUMBER}/head:pr-${PR_NUMBER} --force
39+
git checkout pr-${PR_NUMBER}
40+
fi
3341
3442
# Create preview schema in the app's database
3543
docker compose -f /opt/platform/docker-compose.yml exec -T postgres \
3644
psql -U postgres -d ${APP_DB} -c "CREATE SCHEMA IF NOT EXISTS ${SCHEMA_NAME}"
3745
38-
# Read the app's .env and generate a preview-specific version
39-
# with DATABASE_URL pointing to the PR schema
40-
if [ ! -f deploy/.env ]; then
41-
echo "ERROR: deploy/.env not found. Create it from deploy/env.template first."
46+
# Copy production .env as base for preview config
47+
if [ ! -f /opt/apps/${APP_NAME}/deploy/.env ]; then
48+
echo "ERROR: /opt/apps/${APP_NAME}/deploy/.env not found. Deploy production first."
4249
exit 1
4350
fi
4451
4552
# Generate preview .env with schema-aware DATABASE_URL
4653
sed "s|^DATABASE_URL=.*|DATABASE_URL=postgresql://postgres:$(grep POSTGRES_PASSWORD /opt/platform/.env | cut -d= -f2)@postgres:5432/${APP_DB}?options=-csearch_path%3D${SCHEMA_NAME}|" \
47-
deploy/.env > deploy/.env.pr-${PR_NUMBER}
54+
/opt/apps/${APP_NAME}/deploy/.env > deploy/.env.pr-${PR_NUMBER}
4855
4956
# Build and start the app container (skip optional services like celery-worker)
5057
docker compose -p ${APP_NAME}-pr-${PR_NUMBER} -f deploy/docker-compose.yml \
@@ -65,9 +72,6 @@ jobs:
6572
docker compose -f /opt/platform/docker-compose.yml exec -T caddy \
6673
caddy reload --config /etc/caddy/Caddyfile
6774
68-
# Switch back to main so production deploys aren't affected
69-
git checkout main
70-
7175
- name: Post preview URL
7276
uses: actions/github-script@v7
7377
with:
@@ -113,9 +117,13 @@ jobs:
113117
APP_DB=$(echo "${APP_NAME}" | tr '-' '_')_db
114118
SCHEMA_NAME="pr_${PR_NUMBER}"
115119
120+
PREVIEW_DIR="/opt/apps/${APP_NAME}-pr-${PR_NUMBER}"
121+
116122
# Stop and remove preview containers
117-
cd /opt/apps/${APP_NAME}
118-
docker compose -p ${APP_NAME}-pr-${PR_NUMBER} -f deploy/docker-compose.yml down --rmi local || true
123+
if [ -d "${PREVIEW_DIR}" ]; then
124+
cd "${PREVIEW_DIR}"
125+
docker compose -p ${APP_NAME}-pr-${PR_NUMBER} -f deploy/docker-compose.yml down --rmi local || true
126+
fi
119127
120128
# Drop the preview schema
121129
docker compose -f /opt/platform/docker-compose.yml exec -T postgres \
@@ -128,6 +136,5 @@ jobs:
128136
docker compose -f /opt/platform/docker-compose.yml exec -T caddy \
129137
caddy reload --config /etc/caddy/Caddyfile
130138
131-
# Clean up preview .env and branch
132-
rm -f deploy/.env.pr-${PR_NUMBER}
133-
git branch -D pr-${PR_NUMBER} || true
139+
# Remove the preview directory entirely
140+
rm -rf "${PREVIEW_DIR}"

0 commit comments

Comments
 (0)