Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 16 additions & 154 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
name: Deploy to Cloudflare Containers
name: Deploy ObjectOS to Cloudflare Containers

# ─────────────────────────────────────────────────────────────────────────
# Build + push Docker images for cloud (cloud.objectos.app) and/or
# objectos (single-project runtime per env), then `wrangler deploy` the
# Build + push Docker image for the objectos runtime (single-project
# per-env containers fronting *.objectos.app), then `wrangler deploy` the
# matching Worker so the new image is pinned.
#
# NOTE: Cloud (cloud.objectos.app) deployment lives in the split private
# repo objectstack-ai/cloud and is NOT triggered from this workflow.
#
# Triggers:
# 1. Manual: Actions → "Deploy to Cloudflare Containers" → Run
# (choose `target` = cloud | objectos | both, and optionally
# the commit SHA to deploy; defaults to the workflow ref).
# 2. Tag: push a tag matching `deploy-cloud-*`, `deploy-objectos-*`,
# or `deploy-all-*`. The tag suffix is informational; the
# image tag = the resolved commit SHA (short, 8 chars) so a
# redeploy of the same SHA is idempotent.
# 1. Manual: Actions → "Deploy ObjectOS to Cloudflare Containers" → Run
# (optionally provide commit SHA; defaults to workflow ref).
# 2. Tag: push a tag matching `deploy-objectos-*`. The tag suffix is
# informational; the image tag = the resolved commit SHA
# (short, 8 chars) so a redeploy of the same SHA is idempotent.
#
# Image naming:
# registry.cloudflare.com/<ACCOUNT_ID>/objectstack-cloud:<sha8>
# registry.cloudflare.com/<ACCOUNT_ID>/objectos:<sha8>
#
# The corresponding `apps/<target>/wrangler.toml` is rewritten in-place to
# pin `image = "<registry>:<sha8>"` and committed back to `main` so the
# repo always tracks what is actually deployed.
# `apps/objectos/wrangler.toml` is rewritten in-place to pin
# `image = "<registry>:<sha8>"` and committed back to `main` so the repo
# always tracks what is actually deployed.
#
# Required secrets (Repository → Settings → Secrets and variables → Actions):
# CLOUDFLARE_API_TOKEN — token with Containers:Edit + Workers:Edit perms
Expand All @@ -30,37 +30,22 @@ name: Deploy to Cloudflare Containers
on:
workflow_dispatch:
inputs:
target:
description: 'Which app(s) to deploy'
required: true
default: 'both'
type: choice
options:
- cloud
- objectos
- both
ref:
description: 'Commit SHA or branch to deploy (default: workflow ref)'
required: false
default: ''
push:
tags:
- 'deploy-cloud-*'
- 'deploy-objectos-*'
- 'deploy-all-*'

concurrency:
# Serialize deploys per-target so two pushes don't race on `wrangler deploy`.
group: deploy-${{ github.event.inputs.target || github.ref_name }}
group: deploy-objectos-${{ github.ref_name }}
cancel-in-progress: false

jobs:
# ── Resolve which targets to build based on the trigger ──
plan:
runs-on: ubuntu-latest
outputs:
deploy_cloud: ${{ steps.plan.outputs.deploy_cloud }}
deploy_objectos: ${{ steps.plan.outputs.deploy_objectos }}
sha: ${{ steps.plan.outputs.sha }}
sha8: ${{ steps.plan.outputs.sha8 }}
steps:
Expand All @@ -71,143 +56,20 @@ jobs:
fetch-depth: 1

- id: plan
name: Plan targets + resolve SHA
name: Resolve SHA
run: |
set -euo pipefail
SHA="$(git rev-parse HEAD)"
SHA8="$(git rev-parse --short=8 HEAD)"
echo "sha=$SHA" >> "$GITHUB_OUTPUT"
echo "sha8=$SHA8" >> "$GITHUB_OUTPUT"

DEPLOY_CLOUD=false
DEPLOY_OBJECTOS=false
case "${{ github.event_name }}" in
workflow_dispatch)
T="${{ github.event.inputs.target }}"
[[ "$T" == "cloud" || "$T" == "both" ]] && DEPLOY_CLOUD=true
[[ "$T" == "objectos" || "$T" == "both" ]] && DEPLOY_OBJECTOS=true
;;
push)
REF="${{ github.ref_name }}"
[[ "$REF" == deploy-cloud-* || "$REF" == deploy-all-* ]] && DEPLOY_CLOUD=true
[[ "$REF" == deploy-objectos-* || "$REF" == deploy-all-* ]] && DEPLOY_OBJECTOS=true
;;
esac

echo "deploy_cloud=$DEPLOY_CLOUD" >> "$GITHUB_OUTPUT"
echo "deploy_objectos=$DEPLOY_OBJECTOS" >> "$GITHUB_OUTPUT"
echo "─────────────────────────────────"
echo "Trigger: ${{ github.event_name }}"
echo "SHA: $SHA"
echo "Image tag: $SHA8"
echo "Cloud: $DEPLOY_CLOUD"
echo "ObjectOS: $DEPLOY_OBJECTOS"

# ── Build + push cloud image; pin tag in wrangler.toml; wrangler deploy ──
cloud:
needs: plan
if: needs.plan.outputs.deploy_cloud == 'true'
runs-on: ubuntu-latest
permissions:
contents: write # to commit the wrangler.toml tag bump back to main
env:
ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
IMAGE_NAME: objectstack-cloud
SHA8: ${{ needs.plan.outputs.sha8 }}
steps:
- uses: actions/checkout@v5
with:
ref: ${{ needs.plan.outputs.sha }}
# Need full history so we can push back the tag-bump commit.
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up pnpm
uses: pnpm/action-setup@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- name: Install workspace deps (for wrangler bundle)
run: pnpm install --frozen-lockfile --prefer-offline

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build cloud image (local)
uses: docker/build-push-action@v6
with:
context: .
file: apps/cloud/Dockerfile
platforms: linux/amd64
# Load to the local daemon — `wrangler containers push` reads from
# the local daemon and re-pushes with Cloudflare-issued temporary
# registry credentials (the registry rejects plain docker login).
load: true
tags: registry.cloudflare.com/${{ env.ACCOUNT_ID }}/${{ env.IMAGE_NAME }}:${{ env.SHA8 }}
# GitHub Actions cache — drops cloud rebuild from ~20m to ~3-6m
# after the first run.
cache-from: type=gha,scope=cloud
cache-to: type=gha,scope=cloud,mode=max

- name: Push image via wrangler (handles CF registry auth)
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ env.ACCOUNT_ID }}
run: |
npx --yes wrangler@4 containers push \
"registry.cloudflare.com/${ACCOUNT_ID}/${IMAGE_NAME}:${SHA8}"

- name: Pin image tag in wrangler.toml
run: |
set -euo pipefail
NEW="registry.cloudflare.com/${ACCOUNT_ID}/${IMAGE_NAME}:${SHA8}"
sed -i -E "s#^image = .*${IMAGE_NAME}:.*#image = \"${NEW}\"#" apps/cloud/wrangler.toml
echo "Pinned to: $NEW"
grep '^image' apps/cloud/wrangler.toml

- name: Wrangler deploy (cloud)
working-directory: apps/cloud
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ env.ACCOUNT_ID }}
run: npx --yes wrangler@4 deploy --config wrangler.toml

- name: Commit pinned tag back to main
if: github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/')
run: |
set -euo pipefail
if git diff --quiet apps/cloud/wrangler.toml; then
echo "No tag change to commit."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -B deploy/cloud-${SHA8}
git add apps/cloud/wrangler.toml
git commit -m "chore(deploy): pin cloud image tag to ${SHA8}

Auto-bumped by .github/workflows/deploy.yml after successful Cloudflare
Containers deploy of registry.cloudflare.com/${ACCOUNT_ID}/${IMAGE_NAME}:${SHA8}.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>"
# Fast-forward push to main if possible; otherwise leave the branch
# for a human to PR. We never force-push main.
git fetch origin main
if git merge-base --is-ancestor origin/main HEAD; then
git push origin HEAD:main
else
git push origin HEAD
echo "::warning::Could not fast-forward main; pushed branch deploy/cloud-${SHA8} instead. Open a PR."
fi

# ── Build + push objectos image; pin tag; wrangler deploy ──
objectos:
needs: plan
if: needs.plan.outputs.deploy_objectos == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down
49 changes: 0 additions & 49 deletions apps/cloud/.dockerignore

This file was deleted.

13 changes: 0 additions & 13 deletions apps/cloud/.env.cloudflare.example

This file was deleted.

42 changes: 0 additions & 42 deletions apps/cloud/.env.cloudflare.secrets.example

This file was deleted.

27 changes: 0 additions & 27 deletions apps/cloud/.gitignore

This file was deleted.

26 changes: 0 additions & 26 deletions apps/cloud/CHANGELOG.md

This file was deleted.

Loading