mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
fix(ci): promote versioned Daytona snapshots to Render (#1073)
Co-authored-by: Omar McAdam <omar@OpenWork-Studio.localdomain>
This commit is contained in:
99
.github/workflows/deploy-den.yml
vendored
Normal file
99
.github/workflows/deploy-den.yml
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
name: Deploy Den
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
daytona_snapshot:
|
||||
description: "Daytona snapshot name to promote into Render"
|
||||
required: true
|
||||
type: string
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
daytona_snapshot:
|
||||
description: "Daytona snapshot name to promote into Render"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: deploy-den-${{ inputs.daytona_snapshot }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
deploy-den:
|
||||
name: Update Render Daytona Snapshot
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
env:
|
||||
RENDER_API_BASE: https://api.render.com/v1
|
||||
RENDER_API_KEY: ${{ secrets.RENDER_API_KEY }}
|
||||
RENDER_SERVICE_ID: ${{ secrets.RENDER_DEN_CONTROL_PLANE_SERVICE_ID }}
|
||||
DAYTONA_SNAPSHOT: ${{ inputs.daytona_snapshot }}
|
||||
steps:
|
||||
- name: Validate required configuration
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ -z "${DAYTONA_SNAPSHOT:-}" ]; then
|
||||
echo "daytona_snapshot input is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${RENDER_API_KEY:-}" ]; then
|
||||
echo "Missing required secret: RENDER_API_KEY" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${RENDER_SERVICE_ID:-}" ]; then
|
||||
echo "Missing required secret: RENDER_DEN_CONTROL_PLANE_SERVICE_ID" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Update DAYTONA_SNAPSHOT on Render
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
payload="$(python3 -c 'import json, sys; print(json.dumps({"value": sys.argv[1]}))' "$DAYTONA_SNAPSHOT")"
|
||||
response_file="$(mktemp)"
|
||||
status_code="$(curl -sS -o "$response_file" -w "%{http_code}" \
|
||||
-X PUT "${RENDER_API_BASE}/services/${RENDER_SERVICE_ID}/env-vars/DAYTONA_SNAPSHOT" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${RENDER_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data "$payload")"
|
||||
|
||||
if [ "$status_code" -lt 200 ] || [ "$status_code" -ge 300 ]; then
|
||||
echo "Failed to update Render DAYTONA_SNAPSHOT (HTTP $status_code)" >&2
|
||||
python3 -c 'from pathlib import Path; import sys; print(Path(sys.argv[1]).read_text(errors="replace"))' "$response_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Render DAYTONA_SNAPSHOT set to ${DAYTONA_SNAPSHOT}"
|
||||
|
||||
- name: Trigger Render deploy
|
||||
id: deploy
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
response_file="$(mktemp)"
|
||||
status_code="$(curl -sS -o "$response_file" -w "%{http_code}" \
|
||||
-X POST "${RENDER_API_BASE}/services/${RENDER_SERVICE_ID}/deploys" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${RENDER_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{}')"
|
||||
|
||||
if [ "$status_code" -lt 200 ] || [ "$status_code" -ge 300 ]; then
|
||||
echo "Failed to trigger Render deploy (HTTP $status_code)" >&2
|
||||
python3 -c 'from pathlib import Path; import sys; print(Path(sys.argv[1]).read_text(errors="replace"))' "$response_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
deploy_id="$(python3 -c 'import json, sys; from pathlib import Path; text = Path(sys.argv[1]).read_text(errors="replace").strip(); data = json.loads(text) if text else {}; print(data.get("id", "") if isinstance(data, dict) else "")' "$response_file")"
|
||||
|
||||
echo "deploy_id=${deploy_id}" >> "$GITHUB_OUTPUT"
|
||||
echo "Triggered Render deploy ${deploy_id:-<unknown>} for snapshot ${DAYTONA_SNAPSHOT}"
|
||||
28
.github/workflows/release-daytona-snapshot.yml
vendored
28
.github/workflows/release-daytona-snapshot.yml
vendored
@@ -7,6 +7,11 @@ on:
|
||||
description: "Tag to build from (e.g., v0.11.200). Defaults to current ref."
|
||||
required: false
|
||||
type: string
|
||||
deploy_den:
|
||||
description: "Whether to promote the published snapshot into the Den Render service"
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
snapshot_name:
|
||||
description: "Optional explicit Daytona snapshot name"
|
||||
required: false
|
||||
@@ -21,6 +26,11 @@ on:
|
||||
description: "Tag to build from (e.g., v0.11.200). Defaults to release tag/current ref."
|
||||
required: false
|
||||
type: string
|
||||
deploy_den:
|
||||
description: "Whether to promote the published snapshot into the Den Render service"
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
snapshot_name:
|
||||
description: "Optional explicit Daytona snapshot name"
|
||||
required: false
|
||||
@@ -41,6 +51,10 @@ jobs:
|
||||
publish-daytona-snapshot:
|
||||
name: Build and Push Daytona Snapshot
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
outputs:
|
||||
release_tag: ${{ steps.resolve.outputs.release_tag }}
|
||||
snapshot_name: ${{ steps.resolve.outputs.snapshot_name }}
|
||||
snapshot_region: ${{ steps.resolve.outputs.snapshot_region }}
|
||||
steps:
|
||||
- name: Resolve release tag and snapshot name
|
||||
id: resolve
|
||||
@@ -49,7 +63,6 @@ jobs:
|
||||
INPUT_TAG: ${{ inputs.tag }}
|
||||
INPUT_SNAPSHOT_NAME: ${{ inputs.snapshot_name }}
|
||||
INPUT_SNAPSHOT_REGION: ${{ inputs.snapshot_region }}
|
||||
DEFAULT_SNAPSHOT_NAME: ${{ vars.DAYTONA_SNAPSHOT }}
|
||||
SNAPSHOT_NAME_BASE: ${{ vars.DAYTONA_SNAPSHOT_NAME_BASE }}
|
||||
DEFAULT_SNAPSHOT_REGION: ${{ vars.DAYTONA_SNAPSHOT_REGION }}
|
||||
run: |
|
||||
@@ -67,11 +80,9 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
base_name="${SNAPSHOT_NAME_BASE:-openwork-runtime}"
|
||||
base_name="${SNAPSHOT_NAME_BASE:-openwork}"
|
||||
if [ -n "${INPUT_SNAPSHOT_NAME:-}" ]; then
|
||||
snapshot_name="${INPUT_SNAPSHOT_NAME}"
|
||||
elif [ -n "${DEFAULT_SNAPSHOT_NAME:-}" ]; then
|
||||
snapshot_name="${DEFAULT_SNAPSHOT_NAME}"
|
||||
else
|
||||
snapshot_name="${base_name}-${tag#v}"
|
||||
fi
|
||||
@@ -150,3 +161,12 @@ jobs:
|
||||
|
||||
echo "Publishing Daytona snapshot: ${DAYTONA_SNAPSHOT_NAME}"
|
||||
./scripts/create-daytona-openwork-snapshot.sh "${DAYTONA_SNAPSHOT_NAME}"
|
||||
|
||||
deploy-den:
|
||||
name: Promote Daytona Snapshot to Den Render Service
|
||||
needs: [publish-daytona-snapshot]
|
||||
if: ${{ inputs.deploy_den }}
|
||||
uses: ./.github/workflows/deploy-den.yml
|
||||
with:
|
||||
daytona_snapshot: ${{ needs.publish-daytona-snapshot.outputs.snapshot_name }}
|
||||
secrets: inherit
|
||||
|
||||
@@ -67,7 +67,7 @@ Expected: worker creation `202` with a healthy cloud-backed instance once provis
|
||||
|
||||
- `.github/workflows/deploy-den.yml`
|
||||
|
||||
It updates Render env vars and triggers a deploy for the configured service ID. Daytona is intended for local/dev worker testing unless you build a separate hosted Den deployment path for it.
|
||||
It updates Render env vars and triggers a deploy for the configured service ID. Release snapshot publishing now calls it after a successful Daytona snapshot push so Den picks up the new `DAYTONA_SNAPSHOT` value.
|
||||
|
||||
## Common failure modes
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ Useful optional overrides:
|
||||
After the snapshot is pushed, set it in `.env.daytona`:
|
||||
|
||||
```env
|
||||
DAYTONA_SNAPSHOT=openwork-runtime
|
||||
DAYTONA_SNAPSHOT=openwork-0.11.174
|
||||
```
|
||||
|
||||
Then start Den in Daytona mode:
|
||||
@@ -146,9 +146,10 @@ If you do not set `DAYTONA_SNAPSHOT`, Den falls back to `DAYTONA_SANDBOX_IMAGE`.
|
||||
GitHub workflow `.github/workflows/release-daytona-snapshot.yml` builds and pushes a new Daytona snapshot whenever a GitHub release is published.
|
||||
|
||||
- Trigger: `release.published` (or manual `workflow_dispatch`)
|
||||
- Snapshot naming: `DAYTONA_SNAPSHOT` repo variable if set, otherwise `openwork-runtime-<tag-without-v>`
|
||||
- Snapshot naming: `snapshot_name` input if provided, otherwise `${DAYTONA_SNAPSHOT_NAME_BASE:-openwork}-<tag-without-v>`
|
||||
- Required secret: `DAYTONA_API_KEY`
|
||||
- Optional repo vars: `DAYTONA_API_URL`, `DAYTONA_TARGET`, `DAYTONA_SNAPSHOT_REGION`, `DAYTONA_SNAPSHOT_NAME_BASE`
|
||||
- After the snapshot publish succeeds, the workflow calls `.github/workflows/deploy-den.yml` to set Render's `DAYTONA_SNAPSHOT` env var and trigger a Den controller deploy.
|
||||
|
||||
## Auth setup (Better Auth)
|
||||
|
||||
@@ -186,7 +187,7 @@ pnpm db:migrate:sql
|
||||
|
||||
## CI deployment (dev == prod)
|
||||
|
||||
The workflow `.github/workflows/deploy-den.yml` updates Render env vars and deploys the service on every push to `dev` when this service changes.
|
||||
The workflow `.github/workflows/deploy-den.yml` updates Render env vars and triggers a deploy for the Den controller service. It can be run manually with a snapshot name, and release automation calls it after successful Daytona snapshot publishing.
|
||||
|
||||
Required GitHub Actions secrets:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user