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,43 @@ 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+ if [ "${{ github.ref }}" = "refs/tags/latest-stable" ]; then
157+ REF="latest-stable"
158+ ENVIRONMENT="graphite-editor (Production)"
159+ elif [ "${{ github.event_name }}" = "push" ]; then
160+ REF="master"
161+ ENVIRONMENT="graphite-dev (Production)"
162+ else
163+ REF="${{ inputs.checkout_ref || github.head_ref || github.ref_name }}"
164+ ENVIRONMENT="graphite-dev (Preview)"
165+ fi
166+ DEPLOY_ID=$(gh api \
167+ -X POST \
168+ -H "Accept: application/vnd.github+json" \
169+ repos/${{ github.repository }}/deployments \
170+ --input - \
171+ --jq '.id' <<EOF
172+ {"ref":"$REF","environment":"$ENVIRONMENT","auto_merge":false,"required_contexts":[]}
173+ EOF
174+ )
175+ gh api \
176+ -X POST \
177+ -H "Accept: application/vnd.github+json" \
178+ repos/${{ github.repository }}/deployments/$DEPLOY_ID/statuses \
179+ -f state=success \
180+ -f environment_url="$CF_URL" \
181+ -f log_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
182+
129183 - name : 💬 Comment with the build link
130184 env :
131185 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
@@ -140,15 +194,18 @@ jobs:
140194 |-|
141195 | $CF_URL |"
142196
143- if [ "${{ github.event_name }}" = "push" ]; then
144- # Comment on the commit hash page
197+ if [ "${{ github.ref }}" = "refs/tags/latest-stable" ]; then
198+ # Push tag: skip commenting (commit was already commented on master merge)
199+ echo "Tag push, skipping comment."
200+ elif [ "${{ github.event_name }}" = "push" ]; then
201+ # Push master: comment on the commit hash page
145202 gh api \
146203 -X POST \
147204 -H "Accept: application/vnd.github+json" \
148205 repos/${{ github.repository }}/commits/$(git rev-parse HEAD)/comments \
149206 -f body="$COMMENT_BODY"
150207 else
151- # Comment on the PR (use provided PR number from !build, or look it up by branch name)
208+ # Non-push (workflow_dispatch, !build): comment on the PR
152209 PR_NUMBER="${{ inputs.pr_number }}"
153210 if [ -z "$PR_NUMBER" ]; then
154211 BRANCH=$(git rev-parse --abbrev-ref HEAD)
@@ -162,18 +219,26 @@ jobs:
162219 fi
163220 fi
164221
165- - name : ✂ Strip analytics script from built output for clean artifact
222+ - name : ✂ Strip injected script from completed build for clean artifact
166223 if : github.event_name == 'push'
167- run : sed -i "s|$INDEX_HTML_HEAD_REPLACEMENT ||" frontend/dist/index.html
224+ run : sed -i "s|${{ steps.production-env.outputs.head_replacement }} ||" frontend/dist/index.html
168225
169226 - name : 📦 Upload web bundle artifact
227+ if : github.event_name != 'pull_request'
170228 uses : actions/upload-artifact@v6
171229 with :
172230 name : graphite-web-bundle
173231 path : frontend/dist
174232
233+ - name : 👕 Lint Graphite web formatting
234+ env :
235+ NODE_ENV : production
236+ run : |
237+ cd frontend
238+ npm run check
239+
175240 - name : 📃 Trigger website rebuild if auto-generated code docs are stale
176- if : github.event_name == 'push'
241+ if : github.event_name == 'push' && github.ref != 'refs/tags/latest-stable'
177242 env :
178243 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
179244 run : |
@@ -184,7 +249,7 @@ jobs:
184249 || gh workflow run website.yml --ref master
185250
186251 windows :
187- if : github.event_name == 'push' || inputs.windows
252+ if : ( github.event_name == 'push' && github.ref != 'refs/tags/latest-stable') || inputs.windows
188253 runs-on : windows-latest
189254 permissions :
190255 contents : read
@@ -214,8 +279,8 @@ jobs:
214279 uses : actions/cache@v5
215280 with :
216281 path : |
217- ${{ env.USERPROFILE }}\. cargo\ registry
218- ${{ env.USERPROFILE }}\. cargo\ git
282+ ~/. cargo/ registry
283+ ~/. cargo/ git
219284 target
220285 key : cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
221286
@@ -376,7 +441,7 @@ jobs:
376441 path : target/artifacts
377442
378443 mac :
379- if : github.event_name == 'push' || inputs.mac
444+ if : ( github.event_name == 'push' && github.ref != 'refs/tags/latest-stable') || inputs.mac
380445 runs-on : macos-latest
381446 permissions :
382447 contents : read
@@ -554,7 +619,7 @@ jobs:
554619 path : target/artifacts
555620
556621 linux :
557- if : github.event_name == 'push' || inputs.linux
622+ if : ( github.event_name == 'push' && github.ref != 'refs/tags/latest-stable') || inputs.linux
558623 runs-on : ubuntu-latest
559624 permissions :
560625 contents : read
0 commit comments