-
Notifications
You must be signed in to change notification settings - Fork 78
130 lines (121 loc) · 6.2 KB
/
Copy pathweb-deploy.yml
File metadata and controls
130 lines (121 loc) · 6.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
name: Web Deploy (Cloudflare Pages)
# Deploys the web app (web/, a Vite SPA) to Cloudflare Pages from GitHub Actions
# instead of Cloudflare's git integration, which built on every push with no
# control over the toolchain or build state. This builds on the pinned Node
# version and ships only after the build succeeds.
#
# The web bundle inlines @nodetool-ai/* package SOURCE (the `nodetool-dev` Vite
# resolve condition) and reads generated pricing JSONs produced by
# `build:packages`, so package changes affect the bundle — hence this runs on
# every push to main except changes that can't reach the bundle.
#
# Required GitHub config (Settings → Secrets and variables → Actions):
# Secrets:
# CLOUDFLARE_API_TOKEN — token with "Cloudflare Pages: Edit" on the account
# CLOUDFLARE_ACCOUNT_ID — account that owns the Pages project
# Variables:
# CLOUDFLARE_WEB_PAGES_PROJECT — the Cloudflare Pages project name to deploy to
# VITE_API_URL — API base URL (e.g. https://api.nodetool.ai)
# VITE_SUPABASE_URL — Supabase project URL
# VITE_SUPABASE_ANON_KEY — Supabase anon (publishable) key baked into the
# build. It's a Variable, not a Secret: the key is
# public by design (RLS-protected) and is shipped in
# the client bundle anyway, so a Secret would only
# hide it from this workflow, not from users.
# VITE_AUTH_REDIRECT_URL — optional OAuth redirect URL
#
# This job runs in the `web-production` environment, so the secrets/variables
# above must be visible to it: set them either at the repository level or on the
# `web-production` environment itself (Settings → Environments → web-production).
# An env-scoped secret defined only on a DIFFERENT environment (e.g. the
# marketing deploy's `marketing-production`) is NOT available here — it expands to
# an empty string. For the Cloudflare creds, wrangler then fails with error 9106
# ("Authentication error" / missing Authorization header); for the Supabase build
# vars, the bundle silently falls back to localhost placeholders and breaks auth
# in production. The preflight step below catches both before the deploy runs.
#
# Disconnect the repo from the Cloudflare Pages git integration so the site is
# only deployed from here.
on:
push:
branches:
- main
paths-ignore:
- "marketing/**"
- "docs/**"
- "mobile/**"
- "electron/**"
- "**/*.md"
workflow_dispatch:
# Least-privilege token: the build only reads the repo; the Pages deploy
# authenticates with its own Cloudflare API token, not GITHUB_TOKEN.
permissions:
contents: read
# One deploy at a time; let an in-flight upload finish rather than cancelling it.
concurrency:
group: web-deploy
cancel-in-progress: false
jobs:
deploy:
name: Build & deploy to Cloudflare Pages
runs-on: ubuntu-latest
timeout-minutes: 30
environment:
name: web-production
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 1
# Fail fast with an actionable message if the Cloudflare credentials, the
# Pages project name, or the Supabase build vars are missing, rather than
# letting wrangler fail late with a cryptic "Must specify a project name" or
# 9106 auth error — or, worse, shipping a bundle that silently falls back to
# the `http://localhost` / `public-anon-key` Supabase placeholders in
# web/src/lib/supabaseClient.ts and breaks auth in production with no error.
# Secrets/vars must be visible to the `web-production` environment (see the
# header note); they expand to empty strings when they are not.
- name: Check Cloudflare deploy config
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_WEB_PAGES_PROJECT: ${{ vars.CLOUDFLARE_WEB_PAGES_PROJECT }}
VITE_SUPABASE_URL: ${{ vars.VITE_SUPABASE_URL }}
VITE_SUPABASE_ANON_KEY: ${{ vars.VITE_SUPABASE_ANON_KEY }}
run: |
missing=()
[ -n "$CLOUDFLARE_API_TOKEN" ] || missing+=("secret CLOUDFLARE_API_TOKEN")
[ -n "$CLOUDFLARE_ACCOUNT_ID" ] || missing+=("secret CLOUDFLARE_ACCOUNT_ID")
[ -n "$CLOUDFLARE_WEB_PAGES_PROJECT" ] || missing+=("variable CLOUDFLARE_WEB_PAGES_PROJECT")
[ -n "$VITE_SUPABASE_URL" ] || missing+=("variable VITE_SUPABASE_URL")
[ -n "$VITE_SUPABASE_ANON_KEY" ] || missing+=("variable VITE_SUPABASE_ANON_KEY")
if [ ${#missing[@]} -ne 0 ]; then
echo "::error::Missing required deploy config: ${missing[*]}"
echo "Set these at the repository level (Settings → Secrets and variables → Actions)"
echo "or on the 'web-production' environment (Settings → Environments → web-production)."
echo "An env-scoped secret on a different environment is NOT visible to this job."
exit 1
fi
echo "Deploy config present (project: $CLOUDFLARE_WEB_PAGES_PROJECT, Supabase URL: $VITE_SUPABASE_URL)."
# Installs the workspace and builds the backend packages, which generates
# the fal/kie pricing JSONs the Vite build aliases resolve.
- name: Set up Node, install deps, build packages
uses: ./.github/actions/setup-build
with:
build-packages: "true"
- name: Build (Vite)
working-directory: web
run: npx vite build
env:
VITE_API_URL: ${{ vars.VITE_API_URL }}
VITE_SUPABASE_URL: ${{ vars.VITE_SUPABASE_URL }}
VITE_SUPABASE_ANON_KEY: ${{ vars.VITE_SUPABASE_ANON_KEY }}
VITE_AUTH_REDIRECT_URL: ${{ vars.VITE_AUTH_REDIRECT_URL }}
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v4
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
wranglerVersion: "4.85.0"
workingDirectory: web
command: pages deploy dist --project-name=${{ vars.CLOUDFLARE_WEB_PAGES_PROJECT }} --branch=main