44 push :
55 branches :
66 - master
7+ tags :
8+ - latest-stable
79 workflow_dispatch :
810 inputs :
911 web :
5961 RUSTC_WRAPPER : /usr/bin/sccache
6062 CARGO_INCREMENTAL : 0
6163 SCCACHE_DIR : /var/lib/github-actions/.cache
62- INDEX_HTML_HEAD_REPLACEMENT : <script defer data-domain="dev.graphite.art" data-api="https://graphite.art/visit/event" src="https://graphite.art/visit/script.hash.js"></script>
63-
6464 steps :
6565 - name : 📥 Clone repository
6666 uses : actions/checkout@v6
9090 rustflags : " "
9191 target : wasm32-unknown-unknown
9292
93+ - name : 🔀 Choose production deployment environment
94+ id : production-env
95+ if : github.event_name == 'push'
96+ run : |
97+ if [[ "${{ github.ref }}" == "refs/tags/latest-stable" ]]; then
98+ echo "cf_project=graphite-editor" >> $GITHUB_OUTPUT
99+ DOMAIN="editor.graphite.art"
100+ else
101+ echo "cf_project=graphite-dev" >> $GITHUB_OUTPUT
102+ DOMAIN="dev.graphite.art"
103+ fi
104+ echo "head_replacement=<script defer data-domain=\"$DOMAIN\" data-api=\"https://graphite.art/visit/event\" src=\"https://graphite.art/visit/script.hash.js\"></script>" >> $GITHUB_OUTPUT
105+
93106 - name : ✂ Replace template in <head> of index.html
94107 if : github.event_name == 'push'
95- run : sed -i "s|<!-- INDEX_HTML_HEAD_REPLACEMENT -->|$INDEX_HTML_HEAD_REPLACEMENT |" frontend/index.html
108+ run : sed -i "s|<!-- INDEX_HTML_HEAD_REPLACEMENT -->|${{ steps.production-env.outputs.head_replacement }} |" frontend/index.html
96109
97110 - name : 🌐 Build Graphite web code
98111 env :
@@ -105,11 +118,15 @@ jobs:
105118 CLOUDFLARE_API_TOKEN : ${{ secrets.CLOUDFLARE_API_TOKEN }}
106119 CLOUDFLARE_ACCOUNT_ID : ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
107120 run : |
121+ if [ -z "$CLOUDFLARE_API_TOKEN" ]; then
122+ echo "No Cloudflare API token available (fork PR), skipping deploy."
123+ exit 0
124+ fi
108125 MAX_ATTEMPTS=5
109126 DELAY=30
110127 for ATTEMPT in $(seq 1 $MAX_ATTEMPTS); do
111128 echo "Attempt $ATTEMPT of $MAX_ATTEMPTS..."
112- if OUTPUT=$(npx wrangler@3 pages deploy "frontend/dist" --project-name="graphite-dev " --commit-dirty=true 2>&1); then
129+ if OUTPUT=$(npx wrangler@3 pages deploy "frontend/dist" --project-name="${{ steps.production-env.outputs.cf_project }} " --commit-dirty=true 2>&1); then
113130 URL=$(echo "$OUTPUT" | grep -oP 'https://[^\s]+\.pages\.dev' | head -1)
114131 echo "url=$URL" >> "$GITHUB_OUTPUT"
115132 echo "Published successfully: $URL"
@@ -126,6 +143,33 @@ jobs:
126143 echo "All $MAX_ATTEMPTS Cloudflare Pages publish attempts failed."
127144 exit 1
128145
146+ - name : 🚀 Create GitHub Deployment for "View deployment" button
147+ if : inputs.checkout_repo == '' || inputs.checkout_repo == github.repository
148+ env :
149+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
150+ CF_URL : ${{ steps.cloudflare.outputs.url }}
151+ run : |
152+ if [ -z "$CF_URL" ]; then
153+ echo "No Cloudflare URL available, skipping deployment."
154+ exit 0
155+ fi
156+ DEPLOY_ID=$(gh api \
157+ -X POST \
158+ -H "Accept: application/vnd.github+json" \
159+ repos/${{ github.repository }}/deployments \
160+ -f ref="$(git rev-parse HEAD)" \
161+ -f environment="graphite-dev (Preview)" \
162+ -F auto_merge=false \
163+ -F 'required_contexts=[]' \
164+ --jq '.id')
165+ gh api \
166+ -X POST \
167+ -H "Accept: application/vnd.github+json" \
168+ repos/${{ github.repository }}/deployments/$DEPLOY_ID/statuses \
169+ -f state=success \
170+ -f environment_url="$CF_URL" \
171+ -f log_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
172+
129173 - name : 💬 Comment with the build link
130174 env :
131175 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
@@ -140,15 +184,18 @@ jobs:
140184 |-|
141185 | $CF_URL |"
142186
143- if [ "${{ github.event_name }}" = "push" ]; then
144- # Comment on the commit hash page
187+ if [ "${{ github.ref }}" = "refs/tags/latest-stable" ]; then
188+ # Push tag: skip commenting (commit was already commented on master merge)
189+ echo "Tag push, skipping comment."
190+ elif [ "${{ github.event_name }}" = "push" ]; then
191+ # Push master: comment on the commit hash page
145192 gh api \
146193 -X POST \
147194 -H "Accept: application/vnd.github+json" \
148195 repos/${{ github.repository }}/commits/$(git rev-parse HEAD)/comments \
149196 -f body="$COMMENT_BODY"
150197 else
151- # Comment on the PR (use provided PR number from !build, or look it up by branch name)
198+ # Non-push (workflow_dispatch, !build): comment on the PR
152199 PR_NUMBER="${{ inputs.pr_number }}"
153200 if [ -z "$PR_NUMBER" ]; then
154201 BRANCH=$(git rev-parse --abbrev-ref HEAD)
@@ -162,18 +209,26 @@ jobs:
162209 fi
163210 fi
164211
165- - name : ✂ Strip analytics script from built output for clean artifact
212+ - name : ✂ Strip injected script from completed build for clean artifact
166213 if : github.event_name == 'push'
167- run : sed -i "s|$INDEX_HTML_HEAD_REPLACEMENT ||" frontend/dist/index.html
214+ run : sed -i "s|${{ steps.production-env.outputs.head_replacement }} ||" frontend/dist/index.html
168215
169216 - name : 📦 Upload web bundle artifact
217+ if : github.event_name != 'pull_request'
170218 uses : actions/upload-artifact@v6
171219 with :
172220 name : graphite-web-bundle
173221 path : frontend/dist
174222
223+ - name : 👕 Lint Graphite web formatting
224+ env :
225+ NODE_ENV : production
226+ run : |
227+ cd frontend
228+ npm run check
229+
175230 - name : 📃 Trigger website rebuild if auto-generated code docs are stale
176- if : github.event_name == 'push'
231+ if : github.event_name == 'push' && github.ref != 'refs/tags/latest-stable'
177232 env :
178233 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
179234 run : |
@@ -184,7 +239,7 @@ jobs:
184239 || gh workflow run website.yml --ref master
185240
186241 windows :
187- if : github.event_name == 'push' || inputs.windows
242+ if : ( github.event_name == 'push' && github.ref != 'refs/tags/latest-stable') || inputs.windows
188243 runs-on : windows-latest
189244 permissions :
190245 contents : read
@@ -214,8 +269,8 @@ jobs:
214269 uses : actions/cache@v5
215270 with :
216271 path : |
217- ${{ env.USERPROFILE }}\. cargo\ registry
218- ${{ env.USERPROFILE }}\. cargo\ git
272+ ~/. cargo/ registry
273+ ~/. cargo/ git
219274 target
220275 key : cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
221276
@@ -376,7 +431,7 @@ jobs:
376431 path : target/artifacts
377432
378433 mac :
379- if : github.event_name == 'push' || inputs.mac
434+ if : ( github.event_name == 'push' && github.ref != 'refs/tags/latest-stable') || inputs.mac
380435 runs-on : macos-latest
381436 permissions :
382437 contents : read
@@ -554,7 +609,7 @@ jobs:
554609 path : target/artifacts
555610
556611 linux :
557- if : github.event_name == 'push' || inputs.linux
612+ if : ( github.event_name == 'push' && github.ref != 'refs/tags/latest-stable') || inputs.linux
558613 runs-on : ubuntu-latest
559614 permissions :
560615 contents : read
0 commit comments