Skip to content
Open
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
109 changes: 87 additions & 22 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
push:
branches:
- master
tags:
- latest-stable
workflow_dispatch:
inputs:
web:
Expand Down Expand Up @@ -59,8 +61,6 @@ jobs:
RUSTC_WRAPPER: /usr/bin/sccache
CARGO_INCREMENTAL: 0
SCCACHE_DIR: /var/lib/github-actions/.cache
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>

steps:
- name: 📥 Clone repository
uses: actions/checkout@v6
Expand Down Expand Up @@ -90,9 +90,22 @@ jobs:
rustflags: ""
target: wasm32-unknown-unknown

- name: 🔀 Choose production deployment environment
id: production-env
if: github.event_name == 'push'
run: |
if [[ "${{ github.ref }}" == "refs/tags/latest-stable" ]]; then
echo "cf_project=graphite-editor" >> $GITHUB_OUTPUT
DOMAIN="editor.graphite.art"
else
echo "cf_project=graphite-dev" >> $GITHUB_OUTPUT
DOMAIN="dev.graphite.art"
fi
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

- name: ✂ Replace template in <head> of index.html
if: github.event_name == 'push'
run: sed -i "s|<!-- INDEX_HTML_HEAD_REPLACEMENT -->|$INDEX_HTML_HEAD_REPLACEMENT|" frontend/index.html
run: sed -i "s|<!-- INDEX_HTML_HEAD_REPLACEMENT -->|${{ steps.production-env.outputs.head_replacement }}|" frontend/index.html

- name: 🌐 Build Graphite web code
env:
Expand All @@ -105,27 +118,68 @@ jobs:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: |
MAX_ATTEMPTS=5
DELAY=30
if [ -z "$CLOUDFLARE_API_TOKEN" ]; then
echo "No Cloudflare API token available (fork PR), skipping deploy."
exit 0
fi
MAX_ATTEMPTS=8
DELAY=15
for ATTEMPT in $(seq 1 $MAX_ATTEMPTS); do
echo "Attempt $ATTEMPT of $MAX_ATTEMPTS..."
if OUTPUT=$(npx wrangler@3 pages deploy "frontend/dist" --project-name="graphite-dev" --commit-dirty=true 2>&1); then
URL=$(echo "$OUTPUT" | grep -oP 'https://[^\s]+\.pages\.dev' | head -1)
npx wrangler@3 pages deploy "frontend/dist" --project-name="${{ steps.production-env.outputs.cf_project || 'graphite-dev' }}" --commit-dirty=true 2>&1 | tee /tmp/wrangler_output
if [ ${PIPESTATUS[0]} -eq 0 ]; then
URL=$(grep -oP 'https://[^\s]+\.pages\.dev' /tmp/wrangler_output | head -1)
echo "url=$URL" >> "$GITHUB_OUTPUT"
echo "Published successfully: $URL"
exit 0
fi
echo "Attempt $ATTEMPT failed:"
echo "$OUTPUT"
echo "Attempt $ATTEMPT failed."
if [ "$ATTEMPT" -lt "$MAX_ATTEMPTS" ]; then
echo "Retrying in ${DELAY}s..."
sleep $DELAY
DELAY=$((DELAY * 3))
DELAY=$((DELAY * 2))
fi
done
echo "All $MAX_ATTEMPTS Cloudflare Pages publish attempts failed."
exit 1

- name: 🚀 Create GitHub Deployment for "View deployment" button
if: inputs.checkout_repo == '' || inputs.checkout_repo == github.repository
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CF_URL: ${{ steps.cloudflare.outputs.url }}
run: |
if [ -z "$CF_URL" ]; then
echo "No Cloudflare URL available, skipping deployment."
exit 0
fi
if [ "${{ github.ref }}" = "refs/tags/latest-stable" ]; then
REF="latest-stable"
ENVIRONMENT="graphite-editor (Production)"
elif [ "${{ github.event_name }}" = "push" ]; then
REF="master"
ENVIRONMENT="graphite-dev (Production)"
else
REF="${{ inputs.checkout_ref || github.head_ref || github.ref_name }}"
ENVIRONMENT="graphite-dev (Preview)"
fi
DEPLOY_ID=$(gh api \
-X POST \
-H "Accept: application/vnd.github+json" \
repos/${{ github.repository }}/deployments \
--input - \
--jq '.id' <<EOF
{"ref":"$REF","environment":"$ENVIRONMENT","auto_merge":false,"required_contexts":[]}
EOF
)
gh api \
-X POST \
-H "Accept: application/vnd.github+json" \
repos/${{ github.repository }}/deployments/$DEPLOY_ID/statuses \
-f state=success \
-f environment_url="$CF_URL" \
-f log_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"

- name: 💬 Comment with the build link
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -140,15 +194,18 @@ jobs:
|-|
| $CF_URL |"

if [ "${{ github.event_name }}" = "push" ]; then
# Comment on the commit hash page
if [ "${{ github.ref }}" = "refs/tags/latest-stable" ]; then
# Push tag: skip commenting (commit was already commented on master merge)
echo "Tag push, skipping comment."
elif [ "${{ github.event_name }}" = "push" ]; then
# Push master: comment on the commit hash page
gh api \
-X POST \
-H "Accept: application/vnd.github+json" \
repos/${{ github.repository }}/commits/$(git rev-parse HEAD)/comments \
-f body="$COMMENT_BODY"
else
# Comment on the PR (use provided PR number from !build, or look it up by branch name)
elif [ "${{ github.event_name }}" != "pull_request" ] && [ "${{ github.event_name }}" != "merge_group" ]; then
# Manual trigger (workflow_dispatch, !build): comment on the PR
PR_NUMBER="${{ inputs.pr_number }}"
if [ -z "$PR_NUMBER" ]; then
BRANCH=$(git rev-parse --abbrev-ref HEAD)
Expand All @@ -162,18 +219,26 @@ jobs:
fi
fi

- name: ✂ Strip analytics script from built output for clean artifact
- name: ✂ Strip injected script from completed build for clean artifact
if: github.event_name == 'push'
run: sed -i "s|$INDEX_HTML_HEAD_REPLACEMENT||" frontend/dist/index.html
run: sed -i "s|${{ steps.production-env.outputs.head_replacement }}||" frontend/dist/index.html

- name: 📦 Upload web bundle artifact
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v6
with:
name: graphite-web-bundle
path: frontend/dist

- name: 👕 Lint Graphite web formatting
env:
NODE_ENV: production
run: |
cd frontend
npm run check

- name: 📃 Trigger website rebuild if auto-generated code docs are stale
if: github.event_name == 'push'
if: github.event_name == 'push' && github.ref != 'refs/tags/latest-stable'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
Expand All @@ -184,7 +249,7 @@ jobs:
|| gh workflow run website.yml --ref master

windows:
if: github.event_name == 'push' || inputs.windows
if: (github.event_name == 'push' && github.ref != 'refs/tags/latest-stable') || inputs.windows
runs-on: windows-latest
permissions:
contents: read
Expand Down Expand Up @@ -214,8 +279,8 @@ jobs:
uses: actions/cache@v5
with:
path: |
${{ env.USERPROFILE }}\.cargo\registry
${{ env.USERPROFILE }}\.cargo\git
~/.cargo/registry
~/.cargo/git
target
key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}

Expand Down Expand Up @@ -376,7 +441,7 @@ jobs:
path: target/artifacts

mac:
if: github.event_name == 'push' || inputs.mac
if: (github.event_name == 'push' && github.ref != 'refs/tags/latest-stable') || inputs.mac
runs-on: macos-latest
permissions:
contents: read
Expand Down Expand Up @@ -554,7 +619,7 @@ jobs:
path: target/artifacts

linux:
if: github.event_name == 'push' || inputs.linux
if: (github.event_name == 'push' && github.ref != 'refs/tags/latest-stable') || inputs.linux
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
77 changes: 5 additions & 72 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,78 +8,12 @@ env:
CARGO_TERM_COLOR: always

jobs:
# Build the web app on the self-hosted wasm runner
# Build the web app via the shared build workflow
build:
runs-on: [self-hosted, target/wasm]
permissions:
contents: write
deployments: write
pull-requests: write
actions: write
env:
RUSTC_WRAPPER: /usr/bin/sccache
CARGO_INCREMENTAL: 0
SCCACHE_DIR: /var/lib/github-actions/.cache

steps:
- name: 📥 Clone repository
uses: actions/checkout@v6

- name: 🚦 Check if CI can be skipped
id: skip-check
uses: cariad-tech/merge-queue-ci-skipper@main

- name: 🗑 Clear wasm-bindgen cache
if: steps.skip-check.outputs.skip-check != 'true'
run: rm -r ~/.cache/.wasm-pack || true

- name: 🟢 Install Node.js
if: steps.skip-check.outputs.skip-check != 'true'
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc

- name: 🚧 Install build dependencies
if: steps.skip-check.outputs.skip-check != 'true'
run: |
cd frontend
npm run setup

- name: 🦀 Install Rust
if: steps.skip-check.outputs.skip-check != 'true'
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
override: true
cache: false
rustflags: ""
target: wasm32-unknown-unknown

- name: 🦀 Fetch Rust dependencies
if: steps.skip-check.outputs.skip-check != 'true'
run: cargo fetch --locked

- name: 🌐 Build Graphite web code
if: steps.skip-check.outputs.skip-check != 'true'
env:
NODE_ENV: production
run: mold -run cargo run build web

- name: 📤 Publish to Cloudflare Pages
if: steps.skip-check.outputs.skip-check != 'true'
continue-on-error: true
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: npx wrangler@3 pages deploy "frontend/dist" --project-name="graphite-dev" --commit-dirty=true

- name: 👕 Lint Graphite web formatting
if: steps.skip-check.outputs.skip-check != 'true'
env:
NODE_ENV: production
run: |
cd frontend
npm run check
uses: ./.github/workflows/build.yml
secrets: inherit
with:
web: true

# Run the Rust tests on the self-hosted native runner
test:
Expand All @@ -88,7 +22,6 @@ jobs:
RUSTC_WRAPPER: /usr/bin/sccache
CARGO_INCREMENTAL: 0
SCCACHE_DIR: /var/lib/github-actions/.cache

steps:
- name: 📥 Clone repository
uses: actions/checkout@v6
Expand Down
72 changes: 0 additions & 72 deletions .github/workflows/release.yml

This file was deleted.

4 changes: 3 additions & 1 deletion editor/src/messages/frontend/frontend_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::messages::tool::tool_messages::eyedropper_tool::PrimarySecondary;
use graph_craft::document::NodeId;
use graphene_std::raster::Image;
use graphene_std::raster::color::Color;
use graphene_std::text::{Font, TextAlign};
use graphene_std::text::{Font, TextAlign, VerticalAlign};
use std::path::PathBuf;

#[cfg(not(target_family = "wasm"))]
Expand Down Expand Up @@ -50,6 +50,8 @@ pub enum FrontendMessage {
#[serde(rename = "maxHeight")]
max_height: Option<f64>,
align: TextAlign,
#[serde(rename = "verticalAlign")]
vertical_align: VerticalAlign,
},
DisplayEditableTextboxUpdateFontData {
#[serde(rename = "fontData")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ impl<'a> ModifyInputsContext<'a> {
Some(NodeInput::value(TaggedValue::F64(typesetting.max_height.unwrap_or(100.)), false)),
Some(NodeInput::value(TaggedValue::F64(typesetting.tilt), false)),
Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)),
Some(NodeInput::value(TaggedValue::VerticalAlign(typesetting.vertical_align), false)),
]);
let transform = resolve_network_node_type("Transform").expect("Transform node does not exist").default_node_template();
let stroke = resolve_proto_node_type(graphene_std::vector_nodes::stroke::IDENTIFIER)
Expand Down
Loading