Skip to content

Pin amy to cd65be2aa (amy#881) #134

Pin amy to cd65be2aa (amy#881)

Pin amy to cd65be2aa (amy#881) #134

name: Tulip web PR preview
# Per-PR preview of Tulip Web, deployed to a unique URL (tulip-pr-<N>.vercel.app)
# on the 'tulip-pr' Vercel project. It also bundles this PR's TULIP4_R11 firmware at
# /firmware/ (reused from the AMYboard-PR-preview run's tulip-firmware artifact — not
# rebuilt here) so a pro can `tulip.upgrade(pr=<N>)` to the PR build. Torn down when
# the PR closes by amyboard-pr-preview-cleanup.yml (extend that to tulip-pr if desired).
#
# Requires repo secret VERCEL_TOKEN (scope: bwhitmans-projects).
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- 'amy'
- 'tulip/web/**'
- 'tulip/esp32s3/**'
- 'tulip/shared/**'
- 'assets/**'
- '.github/workflows/tulip-pr-preview.yml'
permissions:
contents: read
actions: read # download the tulip-firmware artifact from the AMYboard PR preview run
pull-requests: write
concurrency:
group: tulip-pr-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
preview:
runs-on: ubuntu-latest
steps:
- name: Verify Vercel token can access the team
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
run: |
if [ -z "$VERCEL_TOKEN" ]; then
echo "::error::VERCEL_TOKEN secret is not set (scope bwhitmans-projects)."; exit 1
fi
npm i -g vercel@latest >/dev/null 2>&1
if ! vercel project ls --scope bwhitmans-projects --token "$VERCEL_TOKEN" >/dev/null 2>&1; then
echo "::error::VERCEL_TOKEN cannot access the 'bwhitmans-projects' team."; exit 1
fi
echo "Vercel token OK for bwhitmans-projects."
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Install web build deps
run: pip install numpy
- uses: mymindstorm/setup-emsdk@v14
with:
version: 4.0.22
- name: Build Tulip web stage/
run: |
cd tulip/web
./build.sh
# Bundle this PR's TULIP4_R11 firmware at /firmware/ so a pro can
# tulip.upgrade(pr=<N>). It's already built by the AMYboard PR preview (for HW
# CI), so we reuse that run's tulip-firmware artifact instead of rebuilding.
# Best-effort: web-only PRs don't run the AMYboard preview → deploy without it.
# (build.sh wipes stage/, so this must run AFTER the build.)
- name: Find the AMYboard PR preview run (has the tulip-firmware artifact)
id: fw
uses: actions/github-script@v7
with:
script: |
const owner = context.repo.owner, repo = context.repo.repo;
const sha = context.payload.pull_request.head.sha;
for (let i = 0; i < 50; i++) { // wait up to ~25 min (it's heavier than this job)
const { data } = await github.rest.actions.listWorkflowRunsForRepo({ owner, repo, head_sha: sha, per_page: 50 });
const run = data.workflow_runs.find(r => r.name === 'AMYboard PR preview');
if (run && run.status === 'completed') {
core.info(`AMYboard PR preview run ${run.id}: ${run.conclusion}`);
core.setOutput('run_id', run.conclusion === 'success' ? String(run.id) : '');
return;
}
if (i === 0) core.info('waiting for the AMYboard PR preview (it builds the Tulip firmware)…');
await new Promise(r => setTimeout(r, 30000));
}
core.info('AMYboard PR preview not finished in time — deploying web only (no PR firmware).');
core.setOutput('run_id', '');
- name: Download this PR's tulip-firmware artifact
if: steps.fw.outputs.run_id != ''
uses: actions/download-artifact@v4
with:
name: tulip-firmware
path: tulip/web/stage/firmware
run-id: ${{ steps.fw.outputs.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Flatten firmware into stage/firmware/
if: steps.fw.outputs.run_id != ''
run: |
cd tulip/web/stage/firmware
# ensure the .bin files sit at the root of /firmware/ (not nested)
find . -mindepth 2 -name '*.bin' -exec mv -f {} . \; 2>/dev/null || true
echo "bundled firmware:"; ls -la
- name: Deploy preview + per-PR alias
id: deploy
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
PR: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
npm i -g vercel@latest >/dev/null 2>&1
cd tulip/web
vercel link --yes --token "$VERCEL_TOKEN" --scope bwhitmans-projects --project tulip-pr --cwd stage
url=$(vercel deploy stage --token "$VERCEL_TOKEN" --scope bwhitmans-projects --yes)
alias="tulip-pr-${PR}.vercel.app"
vercel alias set "$url" "$alias" --token "$VERCEL_TOKEN" --scope bwhitmans-projects
echo "url=https://$alias" >> "$GITHUB_OUTPUT"
- name: Comment preview URL
if: success()
uses: actions/github-script@v7
env:
PREVIEW_URL: ${{ steps.deploy.outputs.url }}
HAS_FW: ${{ steps.fw.outputs.run_id != '' }}
with:
script: |
const url = process.env.PREVIEW_URL;
const pr = context.issue.number;
const marker = '<!-- tulip-pr-preview -->';
const lines = [
marker,
'### 🌷 Tulip Web PR preview',
'',
`**Tulip Web:** ${url}/run/`,
];
if (process.env.HAS_FW === 'true') {
lines.push('', `**Flash a Tulip to this build:** on-device run \`tulip.upgrade(pr=${pr})\`.`);
}
lines.push('', "Rebuilt on every push; removed when the PR closes.");
const body = lines.join('\n');
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
});
const existing = comments.find(c => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: existing.id, body });
} else {
await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body });
}