Skip to content

Commit bb41fdc

Browse files
committed
feat(preview): add cross-repo preview linking via PR body
Parse <!-- preview-link: tasks=N --> from PR body to automatically connect opencouncil previews to opencouncil-tasks previews. - Add workflow step to parse preview-link directive - Write TASK_API_URL and TASK_API_KEY to per-preview .env.local - Load .env.local in start script for runtime overrides - Show linked tasks preview in PR comment and step summary
1 parent 3f44c00 commit bb41fdc

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

.github/workflows/preview-deploy.yml

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,13 +189,33 @@ jobs:
189189
body: body,
190190
});
191191
192+
- name: Parse preview links from PR body
193+
id: preview-links
194+
uses: actions/github-script@v7
195+
with:
196+
script: |
197+
const prBody = context.payload.pull_request.body || '';
198+
199+
// Parse <!-- preview-link: tasks=N --> from PR body
200+
const tasksMatch = prBody.match(/<!--\s*preview-link:\s*tasks=(\d+)\s*-->/i);
201+
if (tasksMatch) {
202+
const tasksPrNum = tasksMatch[1];
203+
core.setOutput('tasks-pr', tasksPrNum);
204+
console.log(`Found linked tasks preview: PR #${tasksPrNum}`);
205+
} else {
206+
core.setOutput('tasks-pr', '');
207+
console.log('No linked tasks preview found in PR body');
208+
}
209+
192210
- name: Deploy to preview host
193211
env:
194212
SSH_PRIVATE_KEY: ${{ secrets.PREVIEW_DEPLOY_SSH_KEY }}
195213
PREVIEW_HOST: ${{ secrets.PREVIEW_HOST }}
196214
PREVIEW_USER: ${{ secrets.PREVIEW_USER || 'opencouncil' }}
197215
STORE_PATH: ${{ steps.store-path.outputs.path }}
198216
HAS_MIGRATIONS: ${{ needs.check-migrations.outputs.has-migrations }}
217+
LINKED_TASKS_PR: ${{ steps.preview-links.outputs.tasks-pr }}
218+
PREVIEW_TASKS_API_KEY: ${{ secrets.PREVIEW_TASKS_API_KEY }}
199219
run: |
200220
set -euo pipefail
201221
@@ -221,6 +241,19 @@ jobs:
221241
222242
# The droplet pulls the build from Cachix automatically (configured as a substituter).
223243
# Just SSH in and create the preview — nix-store --realise is called by the create script.
244+
245+
# Write per-preview env overrides BEFORE create (so service picks them up on first start)
246+
if [ -n "${LINKED_TASKS_PR:-}" ]; then
247+
echo "🔗 Linking to tasks preview PR #$LINKED_TASKS_PR"
248+
TASKS_URL="https://pr-${LINKED_TASKS_PR}.tasks.opencouncil.gr"
249+
$SSH_CMD "mkdir -p /var/lib/opencouncil-previews/pr-$PR_NUM && cat > /var/lib/opencouncil-previews/pr-$PR_NUM/.env.local <<EOF
250+
# Linked tasks preview (from PR body: <!-- preview-link: tasks=$LINKED_TASKS_PR -->)
251+
TASK_API_URL=$TASKS_URL
252+
TASK_API_KEY=${PREVIEW_TASKS_API_KEY:-}
253+
EOF
254+
chmod 600 /var/lib/opencouncil-previews/pr-$PR_NUM/.env.local"
255+
fi
256+
224257
echo "Creating/updating preview instance..."
225258
$SSH_CMD "sudo opencouncil-preview-create '$PR_NUM' '$STORE_PATH' $DEPLOY_FLAGS"
226259

@@ -233,6 +266,9 @@ jobs:
233266
else
234267
echo "Database: Shared staging" >> $GITHUB_STEP_SUMMARY
235268
fi
269+
if [ -n "${LINKED_TASKS_PR:-}" ]; then
270+
echo "Tasks API: https://pr-${LINKED_TASKS_PR}.tasks.opencouncil.gr" >> $GITHUB_STEP_SUMMARY
271+
fi
236272

237273
- name: Health check
238274
id: health-check
@@ -263,6 +299,7 @@ jobs:
263299
const healthStatus = '${{ steps.health-check.outputs.status }}';
264300
const logsUrl = context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId;
265301
const hasMigrations = '${{ needs.check-migrations.outputs.has-migrations }}' === 'true';
302+
const linkedTasksPr = '${{ steps.preview-links.outputs.tasks-pr }}';
266303
267304
const dbNote = hasMigrations
268305
? '*This preview uses an **isolated database** with seed data (migrations were applied).*'
@@ -271,8 +308,13 @@ jobs:
271308
let body = '## 🚀 Preview deployment ready!\n\n'
272309
+ '**Preview URL:** ' + previewUrl + '\n'
273310
+ '**Commit:** `' + commitSha + '`\n'
274-
+ '**Database:** ' + (hasMigrations ? 'Isolated (PostGIS 3.3.5, seed data)' : 'Shared staging') + '\n\n'
275-
+ 'The preview will be automatically updated when you push new commits.\n'
311+
+ '**Database:** ' + (hasMigrations ? 'Isolated (PostGIS 3.3.5, seed data)' : 'Shared staging') + '\n';
312+
313+
if (linkedTasksPr) {
314+
body += '**Tasks API:** https://pr-' + linkedTasksPr + '.tasks.opencouncil.gr\n';
315+
}
316+
317+
body += '\nThe preview will be automatically updated when you push new commits.\n'
276318
+ 'It will be destroyed when this PR is closed or merged.\n\n';
277319
278320
if (healthStatus === 'unhealthy') {

flake.nix

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,14 @@ EOF
12131213
fi
12141214
# Otherwise DATABASE_URL comes from EnvironmentFile (shared staging)
12151215
1216+
# Load per-preview env overrides (e.g., linked tasks preview)
1217+
if [ -f "$PR_DIR/.env.local" ]; then
1218+
echo "Loading per-preview env from .env.local"
1219+
set -a
1220+
. "$PR_DIR/.env.local"
1221+
set +a
1222+
fi
1223+
12161224
# Set per-PR URLs at runtime
12171225
export NEXT_PUBLIC_BASE_URL="https://pr-$PR_NUM.${cfg.previewDomain}"
12181226
# NEXTAUTH_URL is required for NextAuth to construct correct callback URLs

0 commit comments

Comments
 (0)