Compare commits

..

1 Commits

Author SHA1 Message Date
7711bf768c Iterate over binary ops (instead of recursing) 2025-04-08 17:15:33 -05:00
3321 changed files with 6544858 additions and 12499162 deletions

View File

@ -1,4 +1,3 @@
[codespell] [codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser,fromM,FromM ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser,fromM,FromM
skip: **/target,node_modules,build,dist,./out,**/Cargo.lock,./docs/**/*.md,./e2e/playwright/lib/console-error-whitelist.ts,.package-lock.json,**/package-lock.json,./openapi/*.json,./packages/codemirror-lang-kcl/test/all.test.ts,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo,./src/lib/machine-api.d.ts,./test-results,./playwright-report,./kcl-book/book skip: **/target,node_modules,build,dist,./out,**/Cargo.lock,./docs/kcl/*.md,.yarn.lock,**/yarn.lock,./openapi/*.json,./packages/codemirror-lang-kcl/test/all.test.ts,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo

View File

@ -1,5 +1,3 @@
# DO NOT commit secrets, overrides go in the ignored `.env.development.local`
NODE_ENV=development NODE_ENV=development
DEV=true DEV=true
@ -9,12 +7,7 @@ VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
VITE_KC_SITE_APP_URL=https://app.dev.zoo.dev VITE_KC_SITE_APP_URL=https://app.dev.zoo.dev
VITE_KC_SKIP_AUTH=false VITE_KC_SKIP_AUTH=false
VITE_KC_CONNECTION_TIMEOUT_MS=5000 VITE_KC_CONNECTION_TIMEOUT_MS=5000
#VITE_WASM_URL="optional way of overriding the wasm url, particular for unit tests which need this if you running not on the default 3000 port" # ONLY add your token in .env.development.local if you want to skip auth, otherwise this token takes precedence!
#VITE_KC_DEV_TOKEN="optional token to skip auth in the app" #VITE_KC_DEV_TOKEN="your token from dev.zoo.dev should go in .env.development.local"
#token="required token for playwright. TODO: clean up env vars in #3973"
RUST_BACKTRACE=1
PYO3_PYTHON=/usr/local/bin/python3
#KITTYCAD_API_TOKEN="required token for engine testing"
FAIL_ON_CONSOLE_ERRORS=true FAIL_ON_CONSOLE_ERRORS=true

View File

@ -19,11 +19,6 @@
"plugin:jsx-a11y/recommended", "plugin:jsx-a11y/recommended",
"plugin:react-hooks/recommended" "plugin:react-hooks/recommended"
], ],
"settings": {
"react": {
"version": "detect"
}
},
"rules": { "rules": {
"no-array-constructor": "off", // This is wrong; use the @typescript-eslint one instead. "no-array-constructor": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-array-constructor": "error", "@typescript-eslint/no-array-constructor": "error",
@ -66,7 +61,6 @@
"jsx-a11y/click-events-have-key-events": "off", "jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-autofocus": "off", "jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off", "jsx-a11y/no-noninteractive-element-interactions": "off",
"react/no-unknown-property": "error",
"no-restricted-globals": [ "no-restricted-globals": [
"error", "error",
{ {
@ -87,14 +81,6 @@
{ {
"selector": "CallExpression[callee.object.name='TOML'][callee.property.name='parse']", "selector": "CallExpression[callee.object.name='TOML'][callee.property.name='parse']",
"message": "Do not use TOML.parse directly. Use the wrappers in test-utils instead like tomlToSettings." "message": "Do not use TOML.parse directly. Use the wrappers in test-utils instead like tomlToSettings."
},
{
"selector": "CallExpression[callee.property.name='split'] > Literal[value='/']",
"message": "Avoid using split with '/'."
},
{
"selector": "CallExpression[callee.property.name='join'] > Literal[value='/']",
"message": "Avoid using join with '/'."
} }
], ],
"no-restricted-imports": [ "no-restricted-imports": [

3
.github/CODEOWNERS vendored
View File

@ -1,3 +0,0 @@
* @KittyCAD/frontend
/src/ @KittyCAD/frontend
/rust/ @KittyCAD/kcl

View File

@ -1,41 +0,0 @@
---
name: Release
about: Create a new release for the Zoo Design Studio
title: "Cut release v1.?.?"
labels: [meta/release]
---
> Instructions: https://github.com/KittyCAD/modeling-app/blob/main/CONTRIBUTING.md#shipping-releases
---
# Manual Checklist
Release builds URL: ???
## Windows via ???
* [ ] Download the release build for this platform
* [ ] Confirm the application opens (dismiss the updater)
* [ ] Create a project with a basic Text-to-CAD prompt
* [ ] Confirm the result is viewable in an engine stream
* [ ] Use 'Check for updates' to bring back the updater toast
* [ ] Confirm the app can update to the previous release
## macOS via ???
* [ ] Download the release build for this platform
* [ ] Confirm the application opens (dismiss the updater)
* [ ] Create a project with a basic Text-to-CAD prompt
* [ ] Confirm the result is viewable in an engine stream
* [ ] Use 'Check for updates' to bring back the updater toast
* [ ] Confirm the app can update to the previous release
## Linux via ???
* [ ] Download the release build for this platform
* [ ] Confirm the application opens (dismiss the updater)
* [ ] Create a project with a basic Text-to-CAD prompt
* [ ] Confirm the result is viewable in an engine stream
* [ ] Use 'Check for updates' to bring back the updater toast
* [ ] Confirm the app can update to the previous release

View File

@ -7,11 +7,11 @@ if [[ ! -f "test-results/.last-run.json" ]]; then
# If no last run artifact, than run Playwright normally # If no last run artifact, than run Playwright normally
echo "run playwright normally" echo "run playwright normally"
if [[ "$3" == *ubuntu* ]]; then if [[ "$3" == *ubuntu* ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:e2e:desktop -- --shard=$1/$2 || true xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu -- --shard=$1/$2 || true
elif [[ "$3" == *windows* ]]; then elif [[ "$3" == *windows* ]]; then
npm run test:e2e:desktop -- --grep=@windows --shard=$1/$2 || true yarn test:playwright:electron:windows -- --shard=$1/$2 || true
elif [[ "$3" == *macos* ]]; then elif [[ "$3" == *macos* ]]; then
npm run test:e2e:desktop -- --grep=@macos --shard=$1/$2 || true yarn test:playwright:electron:macos -- --shard=$1/$2 || true
else else
echo "Do not run Playwright. Unable to detect os runtime." echo "Do not run Playwright. Unable to detect os runtime."
exit 1 exit 1
@ -26,16 +26,16 @@ max_retries=1
# Retry failed tests, doing our own retries because using inbuilt Playwright retries causes connection issues # Retry failed tests, doing our own retries because using inbuilt Playwright retries causes connection issues
while [[ $retry -le $max_retries ]]; do while [[ $retry -le $max_retries ]]; do
if [[ -f "test-results/.last-run.json" ]]; then if [[ -f "test-results/.last-run.json" ]]; then
status=$(jq -r '.status' test-results/.last-run.json) failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ "$status" == "failed" ]]; then if [[ $failed_tests -gt 0 ]]; then
echo "retried=true" >>$GITHUB_OUTPUT echo "retried=true" >>$GITHUB_OUTPUT
echo "run playwright with last failed tests and retry $retry" echo "run playwright with last failed tests and retry $retry"
if [[ "$3" == *ubuntu* ]]; then if [[ "$3" == *ubuntu* ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:e2e:desktop -- --last-failed || true xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu -- --last-failed || true
elif [[ "$3" == *windows* ]]; then elif [[ "$3" == *windows* ]]; then
npm run test:e2e:desktop -- --grep=@windows --last-failed || true yarn test:playwright:electron:windows -- --last-failed || true
elif [[ "$3" == *macos* ]]; then elif [[ "$3" == *macos* ]]; then
npm run test:e2e:desktop -- --grep=@macos --last-failed || true yarn test:playwright:electron:macos -- --last-failed || true
else else
echo "Do not run playwright. Unable to detect os runtime." echo "Do not run playwright. Unable to detect os runtime."
exit 1 exit 1
@ -56,11 +56,10 @@ done
echo "retried=false" >>$GITHUB_OUTPUT echo "retried=false" >>$GITHUB_OUTPUT
if [[ -f "test-results/.last-run.json" ]]; then if [[ -f "test-results/.last-run.json" ]]; then
status=$(jq -r '.status' test-results/.last-run.json) failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ "$status" == "failed" ]]; then if [[ $failed_tests -gt 0 ]]; then
# If it still fails after retries, then fail the job # If it still fails after 3 retries, then fail the job
exit 1 exit 1
fi fi
fi fi
exit 0 exit 0

View File

@ -1,43 +0,0 @@
#!/bin/bash
set -euo pipefail
if [ -z "${TAB_API_URL:-}" ] || [ -z "${TAB_API_KEY:-}" ]; then
exit 0
fi
project="https://github.com/KittyCAD/modeling-app"
suite="${CI_SUITE:-unit}"
branch="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME:-}}"
commit="${CI_COMMIT_SHA:-${GITHUB_SHA:-}}"
echo "Uploading batch results"
curl --silent --request POST \
--header "X-API-Key: ${TAB_API_KEY}" \
--form "project=${project}" \
--form "suite=${suite}" \
--form "branch=${branch}" \
--form "commit=${commit}" \
--form "tests=@test-results/junit.xml" \
--form "CI_COMMIT_SHA=${CI_COMMIT_SHA:-}" \
--form "CI_PR_NUMBER=${CI_PR_NUMBER:-}" \
--form "GITHUB_BASE_REF=${GITHUB_BASE_REF:-}" \
--form "GITHUB_EVENT_NAME=${GITHUB_EVENT_NAME:-}" \
--form "GITHUB_HEAD_REF=${GITHUB_HEAD_REF:-}" \
--form "GITHUB_REF_NAME=${GITHUB_REF_NAME:-}" \
--form "GITHUB_REF=${GITHUB_REF:-}" \
--form "GITHUB_SHA=${GITHUB_SHA:-}" \
--form "GITHUB_WORKFLOW=${GITHUB_WORKFLOW:-}" \
--form "RUNNER_ARCH=${RUNNER_ARCH:-}" \
${TAB_API_URL}/api/results/bulk
echo
echo "Sharing updated report"
curl --silent --request POST \
--header "Content-Type: application/json" \
--header "X-API-Key: ${TAB_API_KEY}" \
--data "{
\"project\": \"${project}\",
\"branch\": \"${branch}\",
\"commit\": \"${commit}\"
}" \
${TAB_API_URL}/api/share

696
.github/dependabot.yml vendored
View File

@ -15,33 +15,20 @@ updates:
groups: groups:
security: security:
applies-to: security-updates applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
- minor
- patch
patch: patch:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- patch - patch
major: major:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
minor: minor:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- minor - minor
- patch - patch
@ -53,487 +40,28 @@ updates:
time: '03:00' time: '03:00'
timezone: America/Los_Angeles timezone: America/Los_Angeles
open-pull-requests-limit: 5 open-pull-requests-limit: 5
reviewers:
- adamchalmers
- franknoirot
- irev-dev
- jessfraz
groups: groups:
security: security:
applies-to: security-updates applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
- minor
- patch
patch: patch:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- patch - patch
major: major:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
minor: minor:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-lib
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-language-server
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-wasm-lib
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-bumper
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-lib/fuzz
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-to-core
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-derive-docs
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-python-bindings
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-language-server-release
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-test-server
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust/kcl-directory-test-macro
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- minor - minor
- patch - patch
@ -545,77 +73,28 @@ updates:
time: '03:00' time: '03:00'
timezone: America/Los_Angeles timezone: America/Los_Angeles
open-pull-requests-limit: 5 open-pull-requests-limit: 5
reviewers:
- adamchalmers
- franknoirot
- irev-dev
- jessfraz
groups: groups:
security: security:
applies-to: security-updates applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
- minor
- patch
patch: patch:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- patch - patch
major: major:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
minor: minor:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
- package-ecosystem: npm
directory: /packages/codemirror-lsp-client
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
groups:
security:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- major
patch:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- patch
major:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types:
- major
minor:
applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- minor - minor
- patch - patch
@ -627,36 +106,28 @@ updates:
time: '03:00' time: '03:00'
timezone: America/Los_Angeles timezone: America/Los_Angeles
open-pull-requests-limit: 5 open-pull-requests-limit: 5
reviewers:
- adamchalmers
- franknoirot
- irev-dev
- jessfraz
groups: groups:
security: security:
applies-to: security-updates applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
- minor
- patch
patch: patch:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- patch - patch
major: major:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
minor: minor:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- minor - minor
- patch - patch
@ -668,36 +139,61 @@ updates:
time: '03:00' time: '03:00'
timezone: America/Los_Angeles timezone: America/Los_Angeles
open-pull-requests-limit: 5 open-pull-requests-limit: 5
reviewers:
- adamchalmers
- franknoirot
- irev-dev
- jessfraz
groups: groups:
security: security:
applies-to: security-updates applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
- minor
- patch
patch:
applies-to: version-updates
update-types:
- patch
major:
applies-to: version-updates
update-types:
- major
minor:
applies-to: version-updates
update-types:
- minor
- patch
- package-ecosystem: npm
directory: /packages/codemirror-lsp-client
schedule:
interval: weekly
day: monday
time: '03:00'
timezone: America/Los_Angeles
open-pull-requests-limit: 5
reviewers:
- adamchalmers
- franknoirot
- irev-dev
- jessfraz
groups:
security:
applies-to: security-updates
update-types:
- major
- minor
- patch
patch: patch:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- patch - patch
major: major:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
minor: minor:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- minor - minor
- patch - patch
@ -709,36 +205,28 @@ updates:
time: '03:00' time: '03:00'
timezone: America/Los_Angeles timezone: America/Los_Angeles
open-pull-requests-limit: 5 open-pull-requests-limit: 5
reviewers:
- adamchalmers
- franknoirot
- irev-dev
- jessfraz
groups: groups:
security: security:
applies-to: security-updates applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
- minor
- patch
patch: patch:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- patch - patch
major: major:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
minor: minor:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- minor - minor
- patch - patch
@ -750,36 +238,28 @@ updates:
time: '03:00' time: '03:00'
timezone: America/Los_Angeles timezone: America/Los_Angeles
open-pull-requests-limit: 5 open-pull-requests-limit: 5
reviewers:
- adamchalmers
- franknoirot
- irev-dev
- jessfraz
groups: groups:
security: security:
applies-to: security-updates applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
- minor
- patch
patch: patch:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- patch - patch
major: major:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
minor: minor:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- minor - minor
- patch - patch
@ -791,36 +271,28 @@ updates:
time: '03:00' time: '03:00'
timezone: America/Los_Angeles timezone: America/Los_Angeles
open-pull-requests-limit: 5 open-pull-requests-limit: 5
reviewers:
- adamchalmers
- franknoirot
- irev-dev
- jessfraz
groups: groups:
security: security:
applies-to: security-updates applies-to: security-updates
exclude-patterns:
- kittycad*
update-types:
- minor
- patch
security-major:
applies-to: security-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
- minor
- patch
patch: patch:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- patch - patch
major: major:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- major - major
minor: minor:
applies-to: version-updates applies-to: version-updates
exclude-patterns:
- kittycad*
update-types: update-types:
- minor - minor
- patch - patch

View File

@ -13,9 +13,9 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Install dependencies - name: Install dependencies
run: npm install run: yarn
- name: Use correct Rust toolchain - name: Use correct Rust toolchain
shell: bash shell: bash
run: | run: |
@ -32,7 +32,7 @@ jobs:
with: with:
workspaces: rust workspaces: rust
- name: build wasm - name: build wasm
run: npm run build:wasm run: yarn build:wasm
# Upload the WASM bundle as an artifact # Upload the WASM bundle as an artifact

View File

@ -7,13 +7,14 @@ on:
- main - main
tags: tags:
- 'v[0-9]+.[0-9]+.[0-9]+' - 'v[0-9]+.[0-9]+.[0-9]+'
- 'nightly-v[0-9]+.[0-9]+.[0-9]+'
env: env:
IS_RELEASE: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }} IS_RELEASE: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }}
IS_STAGING: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} IS_NIGHTLY: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'nightly-v') }}
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
@ -28,9 +29,9 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- id: filter - id: filter
name: Check for Rust changes name: Check for Rust changes
@ -43,7 +44,7 @@ jobs:
- name: Download Wasm Cache - name: Download Wasm Cache
id: download-wasm id: download-wasm
if: ${{ github.event_name == 'pull_request' && steps.filter.outputs.rust == 'false' }} if: ${{ github.event_name == 'pull_request' && steps.filter.outputs.rust == 'false' }}
uses: dawidd6/action-download-artifact@v11 uses: dawidd6/action-download-artifact@v7
continue-on-error: true continue-on-error: true
with: with:
github_token: ${{secrets.GITHUB_TOKEN}} github_token: ${{secrets.GITHUB_TOKEN}}
@ -89,22 +90,20 @@ jobs:
- name: Run build:wasm - name: Run build:wasm
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
run: "npm run build:wasm" run: "yarn build:wasm"
- name: Set staging version, product name, release notes, and icons - name: Set nightly version, product name, release notes, and icons
if: ${{ env.IS_STAGING == 'true' }} if: ${{ env.IS_NIGHTLY == 'true' }}
run: | run: |
COMMIT=$(git rev-parse --short HEAD) export VERSION=${GITHUB_REF_NAME#nightly-v}
DATE=$(date +'%-y.%-m.%-d') yarn files:set-version
export VERSION=$DATE-main.$COMMIT yarn files:flip-to-nightly
npm run files:set-version
npm run files:flip-to-staging
- name: Set release version - name: Set release version
if: ${{ env.IS_RELEASE == 'true' }} if: ${{ env.IS_RELEASE == 'true' }}
run: | run: |
export VERSION=${GITHUB_REF_NAME#v} export VERSION=${GITHUB_REF_NAME#v}
npm run files:set-version yarn files:set-version
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
@ -123,6 +122,18 @@ jobs:
- id: export_notes - id: export_notes
run: echo "notes=`cat release-notes.md`" >> "$GITHUB_OUTPUT" run: echo "notes=`cat release-notes.md`" >> "$GITHUB_OUTPUT"
- name: Prepare electron-builder.yml file for updater test
if: ${{ env.IS_RELEASE == 'true' }}
run: |
yq -i '.publish[0].url = "https://dl.zoo.dev/releases/modeling-app/updater-test"' electron-builder.yml
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
with:
name: prepared-files-updater-test
path: |
electron-builder.yml
build-apps: build-apps:
needs: [prepare-files] needs: [prepare-files]
@ -130,14 +141,13 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: namespace-profile-macos-6-cores - os: macos-14
platform: macos platform: mac
- os: namespace-profile-windows-4-cores - os: windows-2022
platform: windows platform: win
- os: ubuntu-22.04 - os: ubuntu-22.04
platform: linux platform: linux
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
name: build-apps (${{ matrix.platform }})
env: env:
VERSION_NO_V: ${{ needs.prepare-files.outputs.version }} VERSION_NO_V: ${{ needs.prepare-files.outputs.version }}
steps: steps:
@ -162,19 +172,26 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' # Set this to npm, npm or pnpm. cache: 'yarn' # Set this to npm, yarn or pnpm.
- run: npm install - name: yarn install
# Windows is picky sometimes and fails on fetch. Step takes about ~30s
uses: nick-fields/retry@v3.0.2
with:
shell: bash
timeout_minutes: 2
max_attempts: 3
command: yarn install
- name: Prepare certificate and variables (Windows only) - name: Prepare certificate and variables (Windows only)
if: ${{ (env.IS_RELEASE == 'true' || env.IS_STAGING == 'true') && matrix.platform == 'windows' }} if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }}
run: | run: |
echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /c/Certificate_pkcs12.p12 echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
cat /c/Certificate_pkcs12.p12 cat /d/Certificate_pkcs12.p12
echo "::set-output name=version::${GITHUB_REF#refs/tags/v}" echo "::set-output name=version::${GITHUB_REF#refs/tags/v}"
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV" echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV" echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=C:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV" echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV" echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV"
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH
@ -182,7 +199,7 @@ jobs:
shell: bash shell: bash
- name: Setup certicate with SSM KSP (Windows only) - name: Setup certicate with SSM KSP (Windows only)
if: ${{ (env.IS_RELEASE == 'true' || env.IS_STAGING == 'true') && matrix.platform == 'windows' }} if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }}
run: | run: |
curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o smtools-windows-x64.msi curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o smtools-windows-x64.msi
msiexec /i smtools-windows-x64.msi /quiet /qn msiexec /i smtools-windows-x64.msi /quiet /qn
@ -190,23 +207,16 @@ jobs:
smctl.exe keypair ls smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe smksp_cert_sync.exe
smctl windows certsync
# This last line `smctl windows certsync` was added after windows codesign failures started happening
# with staging-v25.4.10. It looks like `smksp_cert_sync.exe` used to do the sync to the local cert store,
# but stopped doing it overnight. This extra call that I randomly got from this azure-related doc page
# https://docs.digicert.com/en/digicert-keylocker/code-signing/sign-with-third-party-signing-tools/windows-applications/sign-azure-apps-with-signtool-using-ksp-library.html#sync-certificates--windows-only--618365
# seems to be doing that extra sync that we need for scripts/sign-win.js to work.
# TODO: we still need to make sign-win.js errors fail the workflow, see issue #6276
shell: cmd shell: cmd
- name: Build the app (debug) - name: Build the app (debug)
if: ${{ env.IS_RELEASE == 'false' && env.IS_STAGING == 'false' }} if: ${{ env.IS_RELEASE == 'false' && env.IS_NIGHTLY == 'false' }}
# electron-builder doesn't have a concept of release vs debug, # electron-builder doesn't have a concept of release vs debug,
# this is just not doing any codesign or release yml generation, and points to dev infra # this is just not doing any codesign or release yml generation, and points to dev infra
run: npm run tronb:package:dev run: yarn tronb:package:dev
- name: Build the app (release) - name: Build the app (release)
if: ${{ env.IS_RELEASE == 'true' || env.IS_STAGING == 'true' }} if: ${{ env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true' }}
env: env:
APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
@ -216,7 +226,14 @@ jobs:
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }} CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }} WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
run: npm run tronb:package:${{ env.IS_STAGING == 'true' && 'dev' || 'prod' }} DEBUG: "electron-notarize*"
# TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures
uses: nick-fields/retry@v3.0.2
with:
shell: bash
timeout_minutes: 10
max_attempts: 3
command: yarn tronb:package:prod
- name: List artifacts in out/ - name: List artifacts in out/
run: ls -R out run: ls -R out
@ -240,21 +257,70 @@ jobs:
out/*-x86_64-linux.* out/*-x86_64-linux.*
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' || env.IS_STAGING == 'true' }} if: ${{ env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true' }}
with: with:
name: out-yml-${{ matrix.platform }} name: out-yml-${{ matrix.platform }}
path: | path: |
out/latest*.yml out/latest*.yml
# TODO: add the 'Build for Mac TestFlight' stage back # TODO: add the 'Build for Mac TestFlight (nightly)' stage back
# The steps below are for updater-test builds, only on release
- uses: actions/download-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
name: prepared-files-updater-test
- name: Copy updated electron-builder.yml file for updater test
if: ${{ env.IS_RELEASE == 'true' }}
run: |
ls -R prepared-files-updater-test
cp prepared-files-updater-test/electron-builder.yml electron-builder.yml
- name: Build the app (updater-test)
if: ${{ env.IS_RELEASE == 'true' }}
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
DEBUG: "electron-notarize*"
# TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures
uses: nick-fields/retry@v3.0.2
with:
shell: bash
timeout_minutes: 10
max_attempts: 3
command: yarn tronb:package:prod
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
with:
name: updater-test-arm64-${{ matrix.platform }}
path: |
out/*-arm64-win.exe
out/*-arm64-mac.dmg
out/*-arm64-linux.AppImage
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
with:
name: updater-test-x64-${{ matrix.platform }}
path: |
out/*-x64-win.exe
out/*-x64-mac.dmg
out/*-x86_64-linux.AppImage
upload-apps-release: upload-apps-release:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
permissions: permissions:
contents: write contents: write
# Equivalent to IS_RELEASE || IS_STAGING (but we can't access those env vars here) if: ${{ github.ref_type == 'tag' }}
if: ${{ (github.ref_type == 'tag' && startsWith(github.ref_name, 'v')) || (github.event_name == 'push' && github.ref == 'refs/heads/main') }}
env: env:
VERSION_NO_V: ${{ needs.prepare-files.outputs.version }} VERSION_NO_V: ${{ needs.prepare-files.outputs.version }}
VERSION: ${{ format('v{0}', needs.prepare-files.outputs.version) }} VERSION: ${{ format('v{0}', needs.prepare-files.outputs.version) }}
@ -264,32 +330,32 @@ jobs:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-arm64-windows name: out-arm64-win
path: out path: out
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-x64-windows name: out-x64-win
path: out path: out
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-yml-windows name: out-yml-win
path: out path: out
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-arm64-macos name: out-arm64-mac
path: out path: out
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-x64-macos name: out-x64-mac
path: out path: out
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-yml-macos name: out-yml-mac
path: out path: out
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
@ -311,8 +377,8 @@ jobs:
env: env:
NOTES: ${{ needs.prepare-files.outputs.notes }} NOTES: ${{ needs.prepare-files.outputs.notes }}
PUB_DATE: ${{ github.event.repository.updated_at }} PUB_DATE: ${{ github.event.repository.updated_at }}
WEBSITE_DIR: ${{ env.IS_STAGING == 'true' && 'dl.zoo.dev/releases/modeling-app/staging' || 'dl.zoo.dev/releases/modeling-app' }} WEBSITE_DIR: ${{ env.IS_NIGHTLY == 'true' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }}
URL_CODED_NAME: ${{ env.IS_STAGING == 'true' && 'Zoo%20Design%20Studio%20%28Staging%29' || 'Zoo%20Design%20Studio' }} URL_CODED_NAME: ${{ env.IS_NIGHTLY == 'true' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }}
run: | run: |
RELEASE_DIR=https://${WEBSITE_DIR} RELEASE_DIR=https://${WEBSITE_DIR}
jq --null-input \ jq --null-input \
@ -360,27 +426,38 @@ jobs:
- name: List artifacts - name: List artifacts
run: "ls -R out" run: "ls -R out"
- name: Set more complete nightly release notes
if: ${{ env.IS_NIGHTLY == 'true' }}
run: |
# Note: preferred going this way instead of a full clone in the checkout step,
# see https://github.com/actions/checkout/issues/1471
git fetch --prune --unshallow --tags
export TAG="nightly-${VERSION}"
export PREVIOUS_TAG=$(git tag --list --sort=-committerdate "nightly-v[0-9]*" | head -n2 | tail -n1)
export NOTES=$(./scripts/get-nightly-changelog.sh)
yarn files:set-notes
- name: Authenticate to Google Cloud - name: Authenticate to Google Cloud
if: ${{ env.IS_STAGING == 'true' }} if: ${{ env.IS_NIGHTLY == 'true' }}
uses: 'google-github-actions/auth@v2.1.10' uses: 'google-github-actions/auth@v2.1.8'
with: with:
credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}' credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}'
- name: Set up Google Cloud SDK - name: Set up Google Cloud SDK
if: ${{ env.IS_STAGING == 'true' }} if: ${{ env.IS_NIGHTLY == 'true' }}
uses: google-github-actions/setup-gcloud@v2.1.4 uses: google-github-actions/setup-gcloud@v2.1.4
with: with:
project_id: ${{ env.GOOGLE_CLOUD_PROJECT_ID }} project_id: ${{ env.GOOGLE_CLOUD_PROJECT_ID }}
- name: Upload staging files to public bucket - name: Upload nightly files to public bucket
if: ${{ env.IS_STAGING == 'true' }} if: ${{ env.IS_NIGHTLY == 'true' }}
uses: google-github-actions/upload-cloud-storage@v2.2.2 uses: google-github-actions/upload-cloud-storage@v2.2.2
with: with:
path: out path: out
glob: '*' glob: '*'
parent: false parent: false
destination: 'dl.kittycad.io/releases/modeling-app/staging' destination: 'dl.kittycad.io/releases/modeling-app/nightly'
- name: Invalidate bucket cache on latest*.yml and last_download.json files - name: Invalidate bucket cache on latest*.yml and last_download.json files
if: ${{ env.IS_STAGING == 'true' }} if: ${{ env.IS_NIGHTLY == 'true' }}
run: npm run files:invalidate-bucket:staging run: yarn files:invalidate-bucket:nightly

View File

@ -1,56 +0,0 @@
name: Build WASM
on:
workflow_call:
permissions:
contents: read
jobs:
npm-build-wasm:
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
run: npm install
- name: Use correct Rust toolchain
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # configured below
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Use Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: './rust'
- name: Build Wasm
shell: bash
run: npm run build:wasm
- uses: actions/upload-artifact@v4
with:
name: prepared-wasm
path: |
rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
- uses: actions/upload-artifact@v4
with:
name: prepared-ts-rs-bindings
path: |
rust/kcl-lib/bindings/*

View File

@ -26,8 +26,12 @@ name: cargo bench
jobs: jobs:
cargo-bench: cargo-bench:
name: cargo bench name: cargo bench
runs-on: ubuntu-latest runs-on:
- runs-on=${{ github.run_id }}
- runner=32cpu-linux-x64
- extras=s3-cache
steps: steps:
- uses: runs-on/action@v1
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use correct Rust toolchain - name: Use correct Rust toolchain
shell: bash shell: bash
@ -46,12 +50,13 @@ jobs:
- name: Build the benchmark target(s) - name: Build the benchmark target(s)
run: | run: |
cd rust cd rust
cargo codspeed build cargo codspeed build --measurement-mode walltime
- name: Run the benchmarks - name: Run the benchmarks
uses: CodSpeedHQ/action@v3 uses: CodSpeedHQ/action@v3
with: with:
working-directory: rust working-directory: rust
run: cargo codspeed run run: cargo codspeed run
token: ${{ secrets.CODSPEED_TOKEN }} token: ${{ secrets.CODSPEED_TOKEN }}
mode: walltime
env: env:
KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN }} KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN }}

View File

@ -31,15 +31,15 @@ jobs:
- name: Use correct Rust toolchain - name: Use correct Rust toolchain
shell: bash shell: bash
run: | run: |
cp .github/workflows/nightly-rust-toolchain.toml rust-toolchain.toml [ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust - name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache-workspaces: rust cache-workspaces: rust
components: rustfmt components: rustfmt
- name: Run nightly cargo fmt - name: Run cargo fmt
run: | run: |
cd rust cd rust
cargo +nightly fmt -- --check cargo fmt -- --check
shell: bash shell: bash

View File

@ -1,32 +1,23 @@
name: cargo test
on: on:
push: push:
branches: branches:
- main - main
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
schedule:
- cron: 0 * * * * # hourly
permissions: permissions:
contents: read contents: read
pull-requests: write pull-requests: write
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
name: cargo test
jobs: jobs:
build-test-artifacts: cargotest:
name: Build test artifacts name: cargo test
runs-on: runs-on: ubuntu-latest-8-cores
- runs-on=${{ github.run_id }}
- runner=8cpu-linux-x64
- extras=s3-cache
steps: steps:
- uses: runs-on/action@v2 - uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v2
id: app-token id: app-token
with: with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }} app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
@ -48,6 +39,7 @@ jobs:
env: env:
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }} GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
OS_NAME: ${{ env.OS_NAME }} OS_NAME: ${{ env.OS_NAME }}
- uses: taiki-e/install-action@cargo-llvm-cov
- uses: taiki-e/install-action@nextest - uses: taiki-e/install-action@nextest
- name: Install just - name: Install just
uses: taiki-e/install-action@just uses: taiki-e/install-action@just
@ -89,10 +81,9 @@ jobs:
run: | run: |
set -euo pipefail set -euo pipefail
cd rust cd rust
cargo nextest run --workspace --features artifact-graph --retries=10 --no-fail-fast --profile ci simulation_tests::kcl_samples 2>&1 | tee /tmp/github-actions.log cargo nextest run --workspace --retries=2 --no-fail-fast --profile ci simulation_tests::kcl_samples 2>&1 | tee /tmp/github-actions.log
env: env:
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}} KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
ZOO_HOST: https://api.dev.zoo.dev
RUST_BACKTRACE: full RUST_BACKTRACE: full
RUST_MIN_STACK: 10485760000 RUST_MIN_STACK: 10485760000
- name: Commit differences - name: Commit differences
@ -105,7 +96,9 @@ jobs:
popd popd
git add \ git add \
rust/kcl-lib/tests \ rust/kcl-lib/tests \
public/kcl-samples public/kcl-samples/manifest.json \
public/kcl-samples/README.md \
public/kcl-samples/screenshots
git config --local user.email "github-actions[bot]@users.noreply.github.com" git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]" git config --local user.name "github-actions[bot]"
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
@ -121,168 +114,27 @@ jobs:
env: env:
# The default is auto, and insta behaves differently in CI vs. not. # The default is auto, and insta behaves differently in CI vs. not.
INSTA_UPDATE: always INSTA_UPDATE: always
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}} KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
ZOO_HOST: https://api.dev.zoo.dev
# Configure nextest when it's run by insta (via just). # Configure nextest when it's run by insta (via just).
NEXTEST_PROFILE: ci NEXTEST_PROFILE: ci
RUST_BACKTRACE: full RUST_BACKTRACE: full
RUST_MIN_STACK: 10485760000 RUST_MIN_STACK: 10485760000
- name: Build and archive tests - name: cargo test
run: | if: steps.path-changes.outputs.outside-kcl-samples == 'true'
cd rust
cargo nextest archive --workspace --features artifact-graph --archive-file nextest-archive.tar.zst
- name: Upload archive to workflow
uses: actions/upload-artifact@v4
with:
name: nextest-archive
path: rust/nextest-archive.tar.zst
run-test-artifacts:
name: cargo test (shard ${{ matrix.partitionIndex}})
runs-on:
- runs-on=${{ github.run_id }}
- runner=32cpu-linux-x64
- extras=s3-cache
needs: build-test-artifacts
strategy:
fail-fast: false
matrix:
partitionIndex: [1, 2, 3, 4, 5, 6]
partitionTotal: [6]
steps:
- uses: runs-on/action@v2
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
- name: Use correct Rust toolchain
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- name: Start Vector
run: .github/ci-cd-scripts/start-vector-ubuntu.sh
env:
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
OS_NAME: ${{ env.OS_NAME }}
- uses: taiki-e/install-action@nextest
- name: Download archive
uses: actions/download-artifact@v4
with:
name: nextest-archive
- name: Run tests
shell: bash shell: bash
run: |- run: |-
cp nextest-archive.tar.zst rust/nextest-archive.tar.zst
ls -lah
cd rust cd rust
cargo nextest run \ cargo llvm-cov nextest --workspace --lcov --output-path lcov.info --retries=2 --no-fail-fast -P ci 2>&1 | tee /tmp/github-actions.log
--retries=10 --no-fail-fast --profile=ci --archive-file nextest-archive.tar.zst \
--partition count:${{ matrix.partitionIndex}}/${{ matrix.partitionTotal }} \
2>&1 | tee /tmp/github-actions.log
env: env:
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}} KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
ZOO_HOST: https://api.dev.zoo.dev
RUST_MIN_STACK: 10485760000 RUST_MIN_STACK: 10485760000
- name: Upload results - name: Upload to codecov.io
if: always() if: steps.path-changes.outputs.outside-kcl-samples == 'true'
run: .github/ci-cd-scripts/upload-results.sh uses: codecov/codecov-action@v5
env:
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
CI_SUITE: e2e:kcl
run-internal-kcl-samples:
name: cargo test (internal-kcl-samples)
runs-on:
- runs-on=${{ github.run_id }}
- runner=32cpu-linux-x64
- extras=s3-cache
steps:
- uses: runs-on/action@v2
- uses: actions/create-github-app-token@v2
id: app-token
with: with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }} token: ${{secrets.CODECOV_TOKEN}}
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }} fail_ci_if_error: true
owner: ${{ github.repository_owner }} flags: rust
- uses: actions/checkout@v4 verbose: true
with: files: lcov.info
token: ${{ steps.app-token.outputs.token }}
- name: Use correct Rust toolchain
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- name: Start Vector
run: .github/ci-cd-scripts/start-vector-ubuntu.sh
env:
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
OS_NAME: ${{ env.OS_NAME }}
- uses: taiki-e/install-action@nextest
- name: Download internal KCL samples
run: git clone --depth=1 https://x-access-token:${{ secrets.GH_PAT_KCL_SAMPLES_INTERNAL }}@github.com/KittyCAD/kcl-samples-internal public/kcl-samples/internal
- name: Run tests
shell: bash
run: |-
cd rust/kcl-lib
cargo nextest run \
--retries=10 --no-fail-fast --features artifact-graph --profile=ci \
internal \
2>&1 | tee /tmp/github-actions.log
env:
TWENTY_TWENTY: overwrite
INSTA_UPDATE: always
EXPECTORATE: overwrite
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
ZOO_HOST: https://api.dev.zoo.dev
MODELING_APP_INTERNAL_SAMPLES_SECRET: ${{secrets.MODELING_APP_INTERNAL_SAMPLES_SECRET}}
RUST_MIN_STACK: 10485760000
run-wasm-tests:
name: Run wasm tests
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Use correct Rust toolchain
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: './rust'
- name: Build Wasm
shell: bash
run: |
npm install
npm run build:wasm
- name: Run wasm tests
run: |
cd rust
cd kcl-wasm-lib
#wasm-pack test --headless --chrome
env:
KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
NODE_ENV: development

46
.github/workflows/check-exampleKcl.yml vendored Normal file
View File

@ -0,0 +1,46 @@
name: Check Onboarding KCL
on:
pull_request:
types: [opened, synchronize]
paths:
- 'src/lib/exampleKcl.ts'
permissions:
contents: read
issues: write
pull-requests: write
jobs:
comment:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Comment on PR
uses: actions/github-script@v7
with:
script: |
const message = '`src/lib/exampleKcl.ts` has been updated in this PR, please review and update the `src/routes/onboarding`, if needed.';
const issue_number = context.payload.pull_request.number;
const owner = context.repo.owner;
const repo = context.repo.repo;
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number
});
const commentExists = comments.some(comment => comment.body === message);
if (!commentExists) {
// Post a comment on the PR
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body: message,
});
}

View File

@ -11,7 +11,7 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
npm-unit-test: yarn-unit-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -19,11 +19,14 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
working-directory: packages/codemirror-lang-kcl
- run: npm run tsc --workspace=packages/codemirror-lang-kcl - run: yarn tsc
working-directory: packages/codemirror-lang-kcl
- name: run unit tests - name: run unit tests
run: npm run test --workspace=packages/codemirror-lang-kcl run: yarn test
working-directory: packages/codemirror-lang-kcl

View File

@ -1,9 +1,9 @@
name: E2E Tests name: E2E Tests
on: on:
push: push:
branches: branches:
- main - main
- all-e2e # this bypasses `fixme()` using `orRunWhenFullSuiteEnabled()`
pull_request: pull_request:
schedule: schedule:
- cron: 0 * * * * # hourly - cron: 0 * * * * # hourly
@ -19,15 +19,73 @@ permissions:
jobs: jobs:
prepare-wasm: conditions:
runs-on: ubuntu-latest
outputs:
significant: ${{ steps.path-changes.outputs.significant }}
should-run: ${{ steps.should-run.outputs.should-run }}
# separate job on Ubuntu to build or fetch the wasm blob once on the fastest runner
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Fetch the base branch
if: ${{ github.event_name == 'pull_request' }}
run: git fetch origin ${{ github.base_ref }} --depth=1
- name: Check for path changes
id: path-changes
shell: bash
run: |
set -euo pipefail
# Manual runs or push should run all tests.
if [[ ${{ github.event_name }} != 'pull_request' ]]; then
echo "significant=true" >> $GITHUB_OUTPUT
exit 0
fi
changed_files=$(git diff --name-only origin/${{ github.base_ref }})
echo "$changed_files"
if grep -Evq '^README.md|^public/kcl-samples/|^rust/kcl-lib/tests/kcl_samples/' <<< "$changed_files" ; then
echo "significant=true" >> $GITHUB_OUTPUT
else
echo "significant=false" >> $GITHUB_OUTPUT
fi
- name: Should run
id: should-run
shell: bash
run: |
set -euo pipefail
# We should run when this is a scheduled run or if there are
# significant changes in the diff.
if [[ ${{ github.event_name }} == 'schedule' || ${{ steps.path-changes.outputs.significant }} == 'true' ]]; then
echo "should-run=true" >> $GITHUB_OUTPUT
else
echo "should-run=false" >> $GITHUB_OUTPUT
fi
- name: Display conditions
shell: bash
run: |
# For debugging purposes
set -euo pipefail
echo "GITHUB_REF: $GITHUB_REF"
echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF"
echo "GITHUB_BASE_REF: $GITHUB_BASE_REF"
echo "significant: ${{ steps.path-changes.outputs.significant }}"
echo "should-run: ${{ steps.should-run.outputs.should-run }}"
prepare-wasm:
# separate job on Ubuntu to build or fetch the wasm blob once on the fastest runner
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
needs: conditions
steps:
- uses: actions/checkout@v4
if: needs.conditions.outputs.should-run == 'true'
- id: filter - id: filter
if: needs.conditions.outputs.should-run == 'true'
name: Check for Rust changes name: Check for Rust changes
uses: dorny/paths-filter@v3 uses: dorny/paths-filter@v3
with: with:
@ -36,17 +94,19 @@ jobs:
- 'rust/**' - 'rust/**'
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
if: needs.conditions.outputs.should-run == 'true'
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Install dependencies - name: Install dependencies
run: npm install if: needs.conditions.outputs.should-run == 'true'
run: yarn
- name: Download Wasm cache - name: Download Wasm Cache
id: download-wasm id: download-wasm
if: ${{ github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }} if: ${{ needs.conditions.outputs.should-run == 'true' && github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }}
uses: dawidd6/action-download-artifact@v11 uses: dawidd6/action-download-artifact@v7
continue-on-error: true continue-on-error: true
with: with:
github_token: ${{secrets.GITHUB_TOKEN}} github_token: ${{secrets.GITHUB_TOKEN}}
@ -55,8 +115,9 @@ jobs:
branch: main branch: main
path: rust/kcl-wasm-lib/pkg path: rust/kcl-wasm-lib/pkg
- name: Build Wasm condition - name: Build WASM condition
id: wasm id: wasm
if: needs.conditions.outputs.should-run == 'true'
run: | run: |
set -euox pipefail set -euox pipefail
# Build wasm if this is a scheduled run, there are Rust changes, or # Build wasm if this is a scheduled run, there are Rust changes, or
@ -68,49 +129,47 @@ jobs:
fi fi
- name: Use correct Rust toolchain - name: Use correct Rust toolchain
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
shell: bash shell: bash
run: | run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./ [ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install Rust - name: Install rust
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache: false # Configured below. cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
with: with:
tool: wasm-pack tool: wasm-pack
- name: Use Rust cache - name: Rust Cache
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
uses: Swatinem/rust-cache@v2 uses: Swatinem/rust-cache@v2
with: with:
workspaces: './rust' workspaces: './rust'
- name: Build Wasm - name: Build Wasm
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
shell: bash shell: bash
run: npm run build:wasm run: yarn build:wasm
- name: Upload compiled wasm artifacts - uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v4 if: needs.conditions.outputs.should-run == 'true'
with: with:
name: prepared-wasm name: prepared-wasm
path: | path: |
rust/kcl-wasm-lib/pkg/kcl_wasm_lib* rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
snapshots: snapshots:
needs: [prepare-wasm] name: playwright:snapshots:ubuntu
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64 runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
name: e2e:snapshots needs: [conditions, prepare-wasm]
steps: steps:
- uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v2 if: needs.conditions.outputs.should-run == 'true'
id: app-token id: app-token
with: with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }} app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
@ -118,13 +177,16 @@ jobs:
owner: ${{ github.repository_owner }} owner: ${{ github.repository_owner }}
- uses: actions/checkout@v4 - uses: actions/checkout@v4
if: needs.conditions.outputs.should-run == 'true'
with: with:
token: ${{ steps.app-token.outputs.token }} token: ${{ steps.app-token.outputs.token }}
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
if: needs.conditions.outputs.should-run == 'true'
name: prepared-wasm name: prepared-wasm
- name: Copy prepared Wasm - name: Copy prepared wasm
if: needs.conditions.outputs.should-run == 'true'
run: | run: |
ls -R prepared-wasm ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public cp prepared-wasm/kcl_wasm_lib_bg.wasm public
@ -132,74 +194,67 @@ jobs:
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
if: needs.conditions.outputs.should-run == 'true'
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Install dependencies - name: Install dependencies
run: npm install id: deps-install
if: needs.conditions.outputs.should-run == 'true'
run: yarn
- name: Download browser cache - name: Cache Playwright Browsers
if: needs.conditions.outputs.should-run == 'true'
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: | path: |
~/.cache/ms-playwright/ ~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
- name: Install browsers - name: Install Playwright Browsers
run: npm run playwright install --with-deps if: needs.conditions.outputs.should-run == 'true'
run: yarn playwright install --with-deps
- name: npm run test:snapshots - name: build web
if: needs.conditions.outputs.should-run == 'true'
run: yarn tronb:vite:dev
- name: Run ubuntu/chrome snapshots
if: needs.conditions.outputs.should-run == 'true'
uses: nick-fields/retry@v3.0.2 uses: nick-fields/retry@v3.0.2
with: with:
shell: bash shell: bash
command: npm run test:snapshots command: yarn test:snapshots
timeout_minutes: 5 timeout_minutes: 30
max_attempts: 5 max_attempts: 3
env: env:
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }} snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
CI_SUITE: e2e:snapshots
TARGET: web
- name: Update snapshots - uses: actions/upload-artifact@v4
if: always() if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
run: npm run test:snapshots -- --last-failed --update-snapshots
env:
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
CI_SUITE: e2e:snapshots
TARGET: web
- name: Upload playwright report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with: with:
name: playwright-report-snapshot-${{ github.sha }} name: playwright-report-ubuntu-snapshot-${{ github.sha }}
path: playwright-report/ path: playwright-report/
include-hidden-files: true include-hidden-files: true
retention-days: 30 retention-days: 30
overwrite: true overwrite: true
- name: Check diff - name: Check for changes
if: ${{ always() && github.ref != 'refs/heads/main' }} if: ${{ needs.conditions.outputs.should-run == 'true' && github.ref != 'refs/heads/main' }}
shell: bash shell: bash
id: git-check id: git-check
run: | run: |
git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots
if git status | grep --quiet "Changes to be committed" if git status | grep -q "Changes to be committed"
then echo "modified=true" >> $GITHUB_OUTPUT then echo "modified=true" >> $GITHUB_OUTPUT
else echo "modified=false" >> $GITHUB_OUTPUT else echo "modified=false" >> $GITHUB_OUTPUT
fi fi
- name: Commit changes - name: Commit changes, if any
if: ${{ always() && steps.git-check.outputs.modified == 'true' }} # TODO: find a more reliable way to detect visual changes
if: ${{ false && needs.conditions.outputs.should-run == 'true' && steps.git-check.outputs.modified == 'true' }}
shell: bash shell: bash
run: | run: |
git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots
@ -209,42 +264,48 @@ jobs:
git fetch origin git fetch origin
echo ${{ github.head_ref }} echo ${{ github.head_ref }}
git checkout ${{ github.head_ref }} git checkout ${{ github.head_ref }}
git commit --message "Update snapshots" || true git commit -m "A snapshot a day keeps the bugs away! 📷🐛" || true
git push git push
git push origin ${{ github.head_ref }} git push origin ${{ github.head_ref }}
web: electron:
needs: [prepare-wasm] needs: [conditions, prepare-wasm]
timeout-minutes: 60
env:
OS_NAME: ${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}
name: playwright:electron:${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}:${{ matrix.shardIndex }}:${{ matrix.shardTotal }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: # TODO: enable namespace-profile-windows-latest once available
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64" os:
- "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
- namespace-profile-macos-8-cores
- windows-latest-8-cores
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
# Disable macos and windows tests on hourly e2e tests since we only care
# about server side changes.
# Technique from https://github.com/joaomcteixeira/python-project-skeleton/pull/31/files
isScheduled:
- ${{ github.event_name == 'schedule' }}
exclude:
- os: namespace-profile-macos-8-cores - os: namespace-profile-macos-8-cores
- os: namespace-profile-windows-8-cores isScheduled: true
- os: windows-latest-8-cores
isScheduled: true
# TODO: add ref here for main and latest release tag
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
name: e2e:web (${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }})
env:
OS_NAME: ${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}
steps: steps:
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: if: needs.conditions.outputs.should-run == 'true'
token: ${{ steps.app-token.outputs.token }}
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
if: needs.conditions.outputs.should-run == 'true'
name: prepared-wasm name: prepared-wasm
- name: Copy prepared Wasm - name: Copy prepared wasm
if: needs.conditions.outputs.should-run == 'true'
run: | run: |
ls -R prepared-wasm ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public cp prepared-wasm/kcl_wasm_lib_bg.wasm public
@ -252,156 +313,49 @@ jobs:
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
if: needs.conditions.outputs.should-run == 'true'
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Install dependencies
run: npm install
- name: Download browser cache
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
- name: Install browsers
run: npm run playwright install --with-deps
- name: Start Vector
if: ${{ !contains(matrix.os, 'windows') }}
run: .github/ci-cd-scripts/start-vector-${{ env.OS_NAME }}.sh
env:
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
OS_NAME: ${{ env.OS_NAME }}
- name: npm run test:e2e:web
uses: nick-fields/retry@v3.0.2
with:
shell: bash
command: npm run test:e2e:web
timeout_minutes: 5
max_attempts: 5
env:
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
CI_SUITE: e2e:web
TARGET: web
- name: Upload playwright report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
with:
name: playwright-report-web-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
overwrite: true
desktop:
needs: [prepare-wasm]
strategy:
fail-fast: false
matrix:
include:
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
shardIndex: 1
shardTotal: 8
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
shardIndex: 2
shardTotal: 8
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
shardIndex: 3
shardTotal: 8
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
shardIndex: 4
shardTotal: 8
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
shardIndex: 5
shardTotal: 8
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
shardIndex: 6
shardTotal: 8
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
shardIndex: 7
shardTotal: 8
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
shardIndex: 8
shardTotal: 8
- os: namespace-profile-macos-8-cores
shardIndex: 1
shardTotal: 2
- os: namespace-profile-macos-8-cores
shardIndex: 2
shardTotal: 2
- os: namespace-profile-windows-8-cores
shardIndex: 1
shardTotal: 2
- os: namespace-profile-windows-8-cores
shardIndex: 2
shardTotal: 2
runs-on: ${{ matrix.os }}
name: e2e:desktop (${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}, shard ${{ matrix.shardIndex }})
env:
OS_NAME: ${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
name: prepared-wasm
- name: Copy prepared Wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies - name: Install dependencies
id: deps-install id: deps-install
run: npm install if: needs.conditions.outputs.should-run == 'true'
run: yarn
- name: Download browser cache - name: Cache Playwright Browsers
if: needs.conditions.outputs.should-run == 'true'
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: | path: |
~/.cache/ms-playwright/ ~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
- name: Install browsers - name: Install Playwright Browsers
run: npm run playwright install --with-deps if: needs.conditions.outputs.should-run == 'true'
run: yarn playwright install --with-deps
- name: Build web
if: needs.conditions.outputs.should-run == 'true'
run: yarn tronb:vite:dev
- name: Start Vector - name: Start Vector
if: ${{ !contains(matrix.os, 'windows') }} if: ${{ needs.conditions.outputs.should-run == 'true' && !contains(matrix.os, 'windows') }}
run: .github/ci-cd-scripts/start-vector-${{ env.OS_NAME }}.sh run: .github/ci-cd-scripts/start-vector-${{ env.OS_NAME }}.sh
env: env:
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }} GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
OS_NAME: ${{ env.OS_NAME }} OS_NAME: ${{ env.OS_NAME }}
- name: Build app
run: npm run tronb:vite:dev
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }} if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
continue-on-error: true continue-on-error: true
with: with:
name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }} name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/ path: test-results/
- name: npm run test:e2e:desktop - name: Run playwright/electron flow (with retries)
id: retry id: retry
if: ${{ !cancelled() && steps.deps-install.outcome == 'success' }} if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && steps.deps-install.outcome == 'success' }}
uses: nick-fields/retry@v3.0.2 uses: nick-fields/retry@v3.0.2
with: with:
shell: bash shell: bash
@ -411,28 +365,20 @@ jobs:
env: env:
FAIL_ON_CONSOLE_ERRORS: true FAIL_ON_CONSOLE_ERRORS: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
CI_SUITE: e2e:desktop
TARGET: desktop
- name: Upload test report - uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v4 if: ${{ needs.conditions.outputs.should-run == 'true' && always() }}
if: always()
with: with:
name: test-results-desktop-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }} name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/ path: test-results/
include-hidden-files: true include-hidden-files: true
retention-days: 30 retention-days: 30
overwrite: true overwrite: true
- name: Upload playwright report - uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v4 if: ${{ needs.conditions.outputs.should-run == 'true' && always() }}
if: always()
with: with:
name: playwright-report-desktop-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }} name: playwright-report-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/ path: playwright-report/
include-hidden-files: true include-hidden-files: true
retention-days: 30 retention-days: 30

View File

@ -21,10 +21,10 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- run: npm run generate:machine-api - run: yarn generate:machine-api
- run: npm run fmt || true - run: yarn fmt
- name: check for changes - name: check for changes
id: git-check id: git-check
run: | run: |

View File

@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/create-github-app-token@v2 - uses: actions/create-github-app-token@v1
id: app-token id: app-token
with: with:
# required # required
@ -38,13 +38,15 @@ jobs:
run: | run: |
mkdir -p documentation/content/pages/docs/kcl/ mkdir -p documentation/content/pages/docs/kcl/
# cleanup old # cleanup old
rm -rf documentation/content/pages/docs/kcl-std rm -rf documentation/content/pages/docs/kcl/*.md
rm -rf documentation/content/pages/docs/kcl-lang rm -rf documentation/content/pages/docs/kcl/types
rm -rf documentation/content/pages/docs/kcl/settings
rm -rf documentation/content/pages/docs/kcl/consts
# move new # move new
mv -f docs/kcl-std documentation/content/pages/docs mv -f docs/kcl/*.md documentation/content/pages/docs/kcl/
mv -f docs/kcl-lang documentation/content/pages/docs mv -f docs/kcl/types documentation/content/pages/docs/kcl/
# We don't need the README mv -f docs/kcl/settings documentation/content/pages/docs/kcl/
rm documentation/content/pages/docs/kcl-std/README.md mv -f docs/kcl/consts documentation/content/pages/docs/kcl/
- name: move kcl-samples - name: move kcl-samples
shell: bash shell: bash
run: | run: |

View File

@ -21,11 +21,14 @@ on:
- '**.rs' - '**.rs'
- .github/workflows/kcl-language-server.yml - .github/workflows/kcl-language-server.yml
workflow_dispatch: workflow_dispatch:
permissions: permissions:
contents: read contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
env: env:
CARGO_INCREMENTAL: 0 CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10 CARGO_NET_RETRY: 10
@ -35,9 +38,10 @@ env:
MACOSX_DEPLOYMENT_TARGET: 10.15 MACOSX_DEPLOYMENT_TARGET: 10.15
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
jobs: jobs:
test: test:
name: kcl-language-server (vscode tests) name: vscode tests
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -52,19 +56,21 @@ jobs:
node-version-file: ".nvmrc" node-version-file: ".nvmrc"
- name: Install dependencies - name: Install dependencies
run: | run: |
npm install yarn install
cd rust/kcl-language-server
yarn install
- name: Run tests - name: Run tests
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npm run build yarn build
npm run test-compile yarn test-compile
ls -la dist ls -la dist
xvfb-run -a npm run test xvfb-run -a yarn test
if: runner.os == 'Linux' if: runner.os == 'Linux'
- name: Run tests - name: Run tests
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npm run test yarn test
if: runner.os != 'Linux' if: runner.os != 'Linux'
build-release: build-release:
strategy: strategy:
@ -73,20 +79,22 @@ jobs:
include: include:
- os: windows-latest - os: windows-latest
target: x86_64-pc-windows-msvc target: x86_64-pc-windows-msvc
code-target: win32-x64 code-target:
#- os: windows-latest win32-x64
#target: i686-pc-windows-msvc #- os: windows-latest
#code-target: #target: i686-pc-windows-msvc
#win32-ia32 #code-target:
#- os: windows-latest #win32-ia32
#target: aarch64-pc-windows-msvc #- os: windows-latest
#code-target: win32-arm64 #target: aarch64-pc-windows-msvc
#code-target: win32-arm64
- os: ubuntu-latest - os: ubuntu-latest
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
code-target: linux-x64 code-target:
#- os: ubuntu-latest linux-x64
#target: aarch64-unknown-linux-musl #- os: ubuntu-latest
#code-target: linux-arm64 #target: aarch64-unknown-linux-musl
#code-target: linux-arm64
- os: ubuntu-latest - os: ubuntu-latest
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
code-target: linux-arm64 code-target: linux-arm64
@ -99,33 +107,41 @@ jobs:
- os: macos-latest - os: macos-latest
target: aarch64-apple-darwin target: aarch64-apple-darwin
code-target: darwin-arm64 code-target: darwin-arm64
name: kcl-language-server build-release (${{ matrix.target }})
name: build-release (${{ matrix.target }})
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
container: ${{ matrix.container }} container: ${{ matrix.container }}
env: env:
RA_TARGET: ${{ matrix.target }} RA_TARGET: ${{ matrix.target }}
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: ${{ env.FETCH_DEPTH }} fetch-depth: ${{ env.FETCH_DEPTH }}
- name: Use correct Rust toolchain - name: Use correct Rust toolchain
shell: bash shell: bash
run: | run: |
rm rust/rust-toolchain.toml rm rust/rust-toolchain.toml
- name: Install rust - name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache: rust cache: rust
components: rust-src components: rust-src
target: ${{ matrix.target }} target: ${{ matrix.target }}
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version-file: ".nvmrc" node-version-file: ".nvmrc"
- name: Update apt repositories - name: Update apt repositories
if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf' || matrix.os == 'ubuntu-latest' if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf' || matrix.os == 'ubuntu-latest'
run: sudo apt-get update run: sudo apt-get update
- if: ${{ matrix.os == 'ubuntu-latest' }} - if: ${{ matrix.os == 'ubuntu-latest' }}
name: Install deps name: Install deps
shell: bash shell: bash
@ -150,53 +166,63 @@ jobs:
zlib1g-dev zlib1g-dev
cargo install cross cargo install cross
- name: Install AArch64 target toolchain - name: Install AArch64 target toolchain
if: matrix.target == 'aarch64-unknown-linux-gnu' if: matrix.target == 'aarch64-unknown-linux-gnu'
run: sudo apt-get install gcc-aarch64-linux-gnu run: sudo apt-get install gcc-aarch64-linux-gnu
- name: Install ARM target toolchain - name: Install ARM target toolchain
if: matrix.target == 'arm-unknown-linux-gnueabihf' if: matrix.target == 'arm-unknown-linux-gnueabihf'
run: sudo apt-get install gcc-arm-linux-gnueabihf run: sudo apt-get install gcc-arm-linux-gnueabihf
- name: build - name: build
run: | run: |
cd rust cd rust
cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }} cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }}
- name: Install dependencies - name: Install dependencies
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
# npm will symlink which will cause issues w tarballing later
yarn install yarn install
- name: Package Extension (release) - name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/') if: startsWith(github.event.ref, 'refs/tags/')
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} npx vsce package -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }}
- name: Package Extension (nightly) - name: Package Extension (nightly)
if: startsWith(github.event.ref, 'refs/tags/') == false if: startsWith(github.event.ref, 'refs/tags/') == false
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release npx vsce package -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release
- name: remove server - name: remove server
if: matrix.target == 'x86_64-unknown-linux-gnu' if: matrix.target == 'x86_64-unknown-linux-gnu'
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
rm -rf server rm -rf server
- name: Package Extension (no server, release) - name: Package Extension (no server, release)
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/') if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/')
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix npx vsce package -o ../build/kcl-language-server-no-server.vsix
- name: Package Extension (no server, nightly) - name: Package Extension (no server, nightly)
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/') == false if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/') == false
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix --pre-release npx vsce package -o ../build/kcl-language-server-no-server.vsix --pre-release
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: release-${{ matrix.target }} name: release-${{ matrix.target }}
path: ./rust/build path: ./rust/build
build-release-x86_64-unknown-linux-musl: build-release-x86_64-unknown-linux-musl:
name: kcl-language-server build-release (x86_64-unknown-linux-musl) name: build-release (x86_64-unknown-linux-musl)
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
RA_TARGET: x86_64-unknown-linux-musl RA_TARGET: x86_64-unknown-linux-musl
@ -206,6 +232,7 @@ jobs:
image: alpine:latest image: alpine:latest
volumes: volumes:
- /usr/local/cargo/registry:/usr/local/cargo/registry - /usr/local/cargo/registry:/usr/local/cargo/registry
steps: steps:
- name: Install dependencies - name: Install dependencies
run: | run: |
@ -217,48 +244,56 @@ jobs:
lld \ lld \
musl-dev \ musl-dev \
nodejs \ nodejs \
npm \ yarn \
yarn npm
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: ${{ env.FETCH_DEPTH }} fetch-depth: ${{ env.FETCH_DEPTH }}
- name: Use correct Rust toolchain - name: Use correct Rust toolchain
shell: bash shell: bash
run: | run: |
rm rust/rust-toolchain.toml rm rust/rust-toolchain.toml
- name: Install rust - name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache: rust cache: rust
components: rust-src components: rust-src
target: ${{ matrix.target }} target: ${{ matrix.target }}
- name: build - name: build
run: | run: |
cd rust cd rust
cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }} cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }}
- name: Install dependencies - name: Install dependencies
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
# npm will symlink which will cause issues w tarballing later
yarn install yarn install
- name: Package Extension (release) - name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/') if: startsWith(github.event.ref, 'refs/tags/')
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64 npx vsce package -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64
- name: Package Extension (release) - name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/') == false if: startsWith(github.event.ref, 'refs/tags/') == false
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64 --pre-release npx vsce package -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64 --pre-release
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: release-x86_64-unknown-linux-musl name: release-x86_64-unknown-linux-musl
path: ./rust/build path: ./rust/build
publish: publish:
name: kcl-language-server (publish) name: publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: ["build-release", "build-release-x86_64-unknown-linux-musl"] needs: ["build-release", "build-release-x86_64-unknown-linux-musl"]
if: startsWith(github.event.ref, 'refs/tags') if: startsWith(github.event.ref, 'refs/tags')
@ -266,17 +301,22 @@ jobs:
contents: write contents: write
steps: steps:
- run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- run: 'echo "TAG: $TAG"' - run: 'echo "TAG: $TAG"'
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: ${{ env.FETCH_DEPTH }} fetch-depth: ${{ env.FETCH_DEPTH }}
- name: Install Nodejs - name: Install Nodejs
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version-file: ".nvmrc" node-version-file: ".nvmrc"
- run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
- run: 'echo "HEAD_SHA: $HEAD_SHA"' - run: 'echo "HEAD_SHA: $HEAD_SHA"'
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: release-aarch64-apple-darwin name: release-aarch64-apple-darwin
@ -304,31 +344,35 @@ jobs:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: release-x86_64-pc-windows-msvc name: release-x86_64-pc-windows-msvc
path: rust/build path:
#- uses: actions/download-artifact@v4 rust/build
#with: #- uses: actions/download-artifact@v4
#name: release-i686-pc-windows-msvc #with:
#path: #name: release-i686-pc-windows-msvc
#build #path:
#- uses: actions/download-artifact@v4 #build
#with: #- uses: actions/download-artifact@v4
#name: release-aarch64-pc-windows-msvc #with:
#path: rust/build #name: release-aarch64-pc-windows-msvc
#path: rust/build
- run: ls -al ./rust/build - run: ls -al ./rust/build
- name: Publish Release - name: Publish Release
uses: ./.github/actions/github-release uses: ./.github/actions/github-release
with: with:
files: "rust/build/*" files: "rust/build/*"
name: ${{ env.TAG }} name: ${{ env.TAG }}
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- name: move files to dir for upload - name: move files to dir for upload
shell: bash shell: bash
run: | run: |
cd rust cd rust
mkdir -p releases/language-server/${{ env.TAG }} mkdir -p releases/language-server/${{ env.TAG }}
cp -r build/* releases/language-server/${{ env.TAG }} cp -r build/* releases/language-server/${{ env.TAG }}
- name: "Authenticate to Google Cloud" - name: "Authenticate to Google Cloud"
uses: "google-github-actions/auth@v2.1.10" uses: "google-github-actions/auth@v2.1.8"
with: with:
credentials_json: "${{ secrets.GOOGLE_CLOUD_DL_SA }}" credentials_json: "${{ secrets.GOOGLE_CLOUD_DL_SA }}"
- name: Set up Cloud SDK - name: Set up Cloud SDK
@ -341,12 +385,15 @@ jobs:
with: with:
path: rust/releases path: rust/releases
destination: dl.kittycad.io destination: dl.kittycad.io
- run: rm rust/build/kcl-language-server-no-server.vsix - run: rm rust/build/kcl-language-server-no-server.vsix
- name: Publish Extension (Code Marketplace, release) - name: Publish Extension (Code Marketplace, release)
# token from https://dev.azure.com/kcl-language-server/ # token from https://dev.azure.com/kcl-language-server/
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce publish --pat ${{ secrets.VSCE_PAT }} --packagePath ../build/kcl-language-server-*.vsix npx vsce publish --pat ${{ secrets.VSCE_PAT }} --packagePath ../build/kcl-language-server-*.vsix
- name: Publish Extension (OpenVSX, release) - name: Publish Extension (OpenVSX, release)
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server

View File

@ -4,6 +4,7 @@
# maturin generate-ci github # maturin generate-ci github
# #
name: kcl-python-bindings name: kcl-python-bindings
on: on:
push: push:
branches: branches:
@ -26,14 +27,16 @@ on:
- '**.rs' - '**.rs'
- .github/workflows/kcl-python-bindings.yml - .github/workflows/kcl-python-bindings.yml
workflow_dispatch: workflow_dispatch:
permissions: permissions:
contents: read contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
linux-x86_64: linux-x86_64:
name: kcl-python-bindings (linux-x86_64)
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -55,8 +58,8 @@ jobs:
with: with:
name: wheels-linux-x86_64 name: wheels-linux-x86_64
path: rust/kcl-python-bindings/dist path: rust/kcl-python-bindings/dist
windows: windows:
name: kcl-python-bindings (windows)
runs-on: windows-16-cores runs-on: windows-16-cores
strategy: strategy:
matrix: matrix:
@ -81,8 +84,8 @@ jobs:
with: with:
name: wheels-windows-${{ matrix.target }} name: wheels-windows-${{ matrix.target }}
path: rust/kcl-python-bindings/dist path: rust/kcl-python-bindings/dist
macos: macos:
name: kcl-python-bindings (macos)
runs-on: macos-latest runs-on: macos-latest
strategy: strategy:
matrix: matrix:
@ -107,13 +110,13 @@ jobs:
with: with:
name: wheels-macos-${{ matrix.target }} name: wheels-macos-${{ matrix.target }}
path: rust/kcl-python-bindings/dist path: rust/kcl-python-bindings/dist
test: test:
name: kcl-python-bindings (test)
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v6 uses: astral-sh/setup-uv@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
- uses: taiki-e/install-action@just - uses: taiki-e/install-action@just
- name: Run tests - name: Run tests
@ -122,21 +125,20 @@ jobs:
just setup-uv just setup-uv
just test just test
env: env:
KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN }}
ZOO_HOST: https://api.dev.zoo.dev
sdist: sdist:
name: kcl-python-bindings (sdist)
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install the latest version of uv - name: Install the latest version of uv
uses: astral-sh/setup-uv@v6 uses: astral-sh/setup-uv@v5
- name: Install codespell - name: Install codespell
run: | run: |
uv venv .venv uv venv .venv
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
echo "$PWD/.venv/bin" >> $GITHUB_PATH echo "$PWD/.venv/bin" >> $GITHUB_PATH
uv pip install pip --upgrade uv pip install pip --upgrade
- name: Build sdist - name: Build sdist
uses: PyO3/maturin-action@v1 uses: PyO3/maturin-action@v1
with: with:
@ -148,6 +150,7 @@ jobs:
with: with:
name: wheels-sdist name: wheels-sdist
path: rust/kcl-python-bindings/dist path: rust/kcl-python-bindings/dist
release: release:
name: Release name: Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -161,14 +164,14 @@ jobs:
with: with:
path: rust/kcl-python-bindings path: rust/kcl-python-bindings
- name: Install the latest version of uv - name: Install the latest version of uv
uses: astral-sh/setup-uv@v6 uses: astral-sh/setup-uv@v5
- name: do uv things - name: do uv things
run: | run: |
cd rust/kcl-python-bindings cd rust/kcl-python-bindings
uv venv .venv uv venv .venv
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
echo "$PWD/.venv/bin" >> $GITHUB_PATH echo "$PWD/.venv/bin" >> $GITHUB_PATH
uv pip install pip --upgrade uv pip install pip --upgrade
- name: Publish to PyPI - name: Publish to PyPI
uses: PyO3/maturin-action@v1 uses: PyO3/maturin-action@v1
env: env:

View File

@ -1,3 +0,0 @@
[toolchain]
channel = "nightly"
components = ["rustfmt"]

View File

@ -1,55 +0,0 @@
name: Test Nix Flake
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
nix-flake-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: nix flake check for all platforms
run: |
nix flake check --all-systems
nix-build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: nix build . for x86_64-linux
run: nix build .
nix-build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: nix build . for x86_64-darwin
run: nix build .

View File

@ -19,7 +19,7 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Find tag workflow id - name: Find tag workflow id
id: tag_workflow_id id: tag_workflow_id
@ -31,42 +31,42 @@ jobs:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-arm64-windows name: out-arm64-win
path: out path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }} run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-x64-windows name: out-x64-win
path: out path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }} run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-yml-windows name: out-yml-win
path: out path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }} run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-arm64-macos name: out-arm64-mac
path: out path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }} run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-x64-macos name: out-x64-mac
path: out path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }} run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: out-yml-macos name: out-yml-mac
path: out path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }} run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
@ -105,10 +105,10 @@ jobs:
- name: Override release notes - name: Override release notes
env: env:
NOTES: ${{ github.event.release.body }} NOTES: ${{ github.event.release.body }}
run: npm run files:set-notes run: yarn files:set-notes
- name: Authenticate to Google Cloud - name: Authenticate to Google Cloud
uses: 'google-github-actions/auth@v2.1.10' uses: 'google-github-actions/auth@v2.1.8'
with: with:
credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}' credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}'
@ -126,7 +126,7 @@ jobs:
destination: 'dl.kittycad.io/releases/modeling-app' destination: 'dl.kittycad.io/releases/modeling-app'
- name: Invalidate bucket cache on latest*.yml and last_download.json files - name: Invalidate bucket cache on latest*.yml and last_download.json files
run: npm run files:invalidate-bucket run: yarn files:invalidate-bucket
- name: Upload release files to Github - name: Upload release files to Github
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}

View File

@ -16,31 +16,77 @@ permissions:
actions: read actions: read
jobs: jobs:
npm-fmt-check: yarn-fmt-check:
runs-on: 'ubuntu-22.04' runs-on: 'ubuntu-22.04'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- run: npm run fmt:check - run: yarn fmt-check
npm-build-wasm: yarn-build-wasm:
uses: ./.github/workflows/build-wasm.yml # Build the wasm blob once on the fastest runner.
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
steps:
- uses: actions/checkout@v4
npm-tsc: - uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Install dependencies
run: yarn install
- name: Use correct Rust toolchain
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: './rust'
- name: Build Wasm
shell: bash
run: yarn build:wasm
- uses: actions/upload-artifact@v4
with:
name: prepared-wasm
path: |
rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
- uses: actions/upload-artifact@v4
with:
name: prepared-ts-rs-bindings
path: |
rust/kcl-lib/bindings/*
yarn-tsc:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: npm-build-wasm needs: yarn-build-wasm
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -58,19 +104,19 @@ jobs:
mkdir rust/kcl-lib/bindings mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/ cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run tsc - run: yarn tsc
npm-lint: yarn-lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: npm-build-wasm needs: yarn-build-wasm
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -88,19 +134,19 @@ jobs:
mkdir rust/kcl-lib/bindings mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/ cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run lint - run: yarn lint
npm-circular-dependencies: yarn-circular-dependencies:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: npm-build-wasm needs: yarn-build-wasm
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -118,42 +164,130 @@ jobs:
mkdir rust/kcl-lib/bindings mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/ cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run circular-deps:diff - run: yarn circular-deps:diff
npm-url-checker:
runs-on: ubuntu-latest
needs: npm-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run url-checker:diff
python-codespell: python-codespell:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
- name: Install codespell
run: |
python -m pip install codespell
- name: Run codespell - name: Run codespell
uses: crate-ci/typos@v1.32.0 run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration.
yarn-unit-test-kcl-samples:
runs-on: ubuntu-latest
needs: yarn-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: yarn simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
- name: Install Chromium Browser
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: yarn playwright install chromium --with-deps
- name: run unit tests for kcl samples
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: yarn test:unit:kcl-samples
env:
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
yarn-unit-test:
runs-on: ubuntu-latest
needs: yarn-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: yarn simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
- name: Install Chromium Browser
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: yarn playwright install chromium --with-deps
- name: Run unit tests
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: xvfb-run -a yarn test:unit
env:
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- name: Check for changes
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
id: git-check
run: |
git add src/lang/std/artifactMapGraphs
if git status src/lang/std/artifactMapGraphs | grep -q "Changes to be committed"
then echo "modified=true" >> $GITHUB_OUTPUT
else echo "modified=false" >> $GITHUB_OUTPUT
fi
- name: Commit changes, if any
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' && steps.git-check.outputs.modified == 'true' }}
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
git fetch origin
echo ${{ github.head_ref }}
git checkout ${{ github.head_ref }}
# TODO when webkit works on ubuntu remove the os part of the commit message
git commit -am "Look at this (photo)Graph *in the voice of Nickelback*" || true
git push
git push origin ${{ github.head_ref }}

39
.github/workflows/tag-nightly.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: tag-nightly
permissions:
contents: write
on:
schedule:
- cron: '0 4 * * *'
# Daily at 04:00 AM UTC
# Will checkout the last commit from the default branch (main as of 2023-10-04)
jobs:
tag-nightly:
runs-on: ubuntu-22.04
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- run: yarn install
- name: Push tag
run: |
VERSION_NO_V=$(date +'%-y.%-m.%-d')
TAG="nightly-v$VERSION_NO_V"
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git tag $TAG
git push origin tag $TAG

View File

@ -1,124 +0,0 @@
name: Unit Tests
on:
pull_request:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
actions: read
jobs:
npm-build-wasm:
uses: ./.github/workflows/build-wasm.yml
npm-test-unit:
runs-on: ubuntu-latest
needs: npm-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
- name: Install Chromium Browser
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: npm run playwright install chromium --with-deps
- name: Run unit tests
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: xvfb-run -a npm run test:unit
env:
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- name: Check for changes
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
id: git-check
run: |
git add src/lang/std/artifactMapGraphs
if git status src/lang/std/artifactMapGraphs | grep -q "Changes to be committed"
then echo "modified=true" >> $GITHUB_OUTPUT
else echo "modified=false" >> $GITHUB_OUTPUT
fi
- name: Commit changes, if any
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' && steps.git-check.outputs.modified == 'true' }}
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
git fetch origin
echo ${{ github.head_ref }}
git checkout ${{ github.head_ref }}
# TODO when webkit works on ubuntu remove the os part of the commit message
git commit -am "Look at this (photo)Graph *in the voice of Nickelback*" || true
git push
git push origin ${{ github.head_ref }}
npm-test-unit-components:
runs-on: ubuntu-latest
needs: npm-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- name: Run component tests
run: npm run test:unit:components

45
.github/workflows/update-e2e-branch.yml vendored Normal file
View File

@ -0,0 +1,45 @@
name: update-e2e-branch
# This is used to sync the `all-e2e` branch with the `main` branch for the
# logic in the test utility `orRunWhenFullSuiteEnabled()` that allows all e2e
# tests to run on a particular branch to analyze failures metrics in Axiom.
on:
schedule:
- cron: '0 * * * *' # runs every hour
permissions:
contents: write
jobs:
update-branch:
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
- name: Sync with main
run: |
# Create the branch
git checkout all-e2e || git checkout -b all-e2e
# Reset to main
git fetch origin
git reset --hard origin/main
# Get a new SHA to prevent overwriting the commit status on main
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git commit --allow-empty --message="[all-e2e] $(git log --max-count=1 --pretty=%B)"
# Overwrite the branch
git remote set-url origin https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/${{ github.repository }}.git
git push --force origin all-e2e

6
.gitignore vendored
View File

@ -26,12 +26,10 @@ yarn-error.log*
.idea .idea
.vscode .vscode
.helix .helix
result
# rust # rust
rust/target rust/target
rust/kcl-lib/bindings rust/kcl-lib/bindings
rust/kcl-language-server/server
public/kcl_wasm_lib_bg.wasm public/kcl_wasm_lib_bg.wasm
rust/lcov.info rust/lcov.info
rust/kcl-wasm-lib/pkg rust/kcl-wasm-lib/pkg
@ -58,8 +56,6 @@ trace.zip
/public/kcl-samples/.github /public/kcl-samples/.github
/public/kcl-samples/screenshots/main.kcl /public/kcl-samples/screenshots/main.kcl
/public/kcl-samples/step/main.kcl /public/kcl-samples/step/main.kcl
/public/kcl-samples/internal
/rust/kcl-lib/tests/kcl_samples/internal
/test-results/ /test-results/
/playwright-report/ /playwright-report/
/blob-report/ /blob-report/
@ -86,5 +82,3 @@ dist
venv venv
.vscode-test .vscode-test
.biome/
.million

View File

@ -5,6 +5,6 @@ command = "vscode-eslint-language-server"
[[language]] [[language]]
name = "typescript" name = "typescript"
auto-format = true auto-format = true
formatter = { command = "./node_modules/@biomejs/biome/bin/biome", args = ["format", "--write", "--stdin-file-path=foo.ts"] } formatter = { command = "node_modules/.bin/prettier", args = ["--parser", "typescript"] }
# language-servers = [ { name = "eslint", only-features = [ "diagnostics" ] }, "typescript-language-server" ] language-servers = [ { name = "eslint", only-features = [ "diagnostics" ] }, "typescript-language-server" ]

View File

@ -1 +0,0 @@
npm run fmt

4
.husky/pre-push Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn fmt-check

1
.npmrc
View File

@ -1 +0,0 @@
legacy-peer-deps=true

View File

@ -1,337 +0,0 @@
# Contributor Guide
## Installing dependencies
Install a node version manager such as [fnm](https://github.com/Schniz/fnm?tab=readme-ov-#installation).
On Windows, it's also recommended to [upgrade your PowerShell version](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.5#winget), we're using 7.
Then in the repo run the following to install and use the node version specified in `.nvmrc`. You might need to specify your processor architecture with `--arch arm64` or `--arch x64` if it's not autodetected.
```
fnm install --corepack-enabled
fnm use
```
Install the NPM dependencies with:
```
npm install
```
This project uses a lot of Rust compiled to [WASM](https://webassembly.org/) within it. We have package scripts to run rustup, see `package.json` for reference:
```
# macOS/Linux
npm run install:rust
npm run install:wasm-pack:sh
# Windows
npm run install:rust:windows
npm run install:wasm-pack:cargo
```
## Building the app
To build the WASM layer, run:
```
# macOS/Linux
npm run build:wasm
# Windows
npm run build:wasm:windows
```
Or if you have the `gh` cli installed and want to download the latest main wasm bundle. Note that on Windows, you need to associate .ps1 files with PowerShell, which can be done via the right click menu, selecting `C:\Program Files\PowerShell\7\pwsh.exe`, and you can install tools like `gh` via `npm run install:tools:windows`.
```
# macOS/Linux
npm run fetch:wasm
# Windows
npm run fetch:wasm:windows
```
That will build the WASM binary and put in the `public` dir (though gitignored).
Finally, to run the web app only, run:
```
npm start
```
If you're not a Zoo employee you won't be able to access the dev environment, you should copy everything from `.env.production` to `.env.development.local` to make it point to production instead, then when you navigate to `localhost:3000` the easiest way to sign in is to paste `localStorage.setItem('TOKEN_PERSIST_KEY', "your-token-from-https://zoo.dev/account/api-tokens")` replacing the with a real token from https://zoo.dev/account/api-tokens of course, then navigate to `localhost:3000` again. Note that navigating to `localhost:3000/signin` removes your token so you will need to set the token again.
### Development environment variables
The Copilot LSP plugin in the editor requires a Zoo API token to run. In production, we authenticate this with a token via cookie in the browser and device auth token in the desktop environment, but this token is inaccessible in the dev browser version because the cookie is considered "cross-site" (from `localhost` to `zoo.dev`). There is an optional environment variable called `VITE_KC_DEV_TOKEN` that you can populate with a dev token in a `.env.development.local` file to not check it into Git, which will use that token instead of other methods for the LSP service.
### Developing in Chrome
Chrome is in the process of rolling out a new default which
[blocks Third-Party Cookies](https://developer.chrome.com/en/docs/privacy-sandbox/third-party-cookie-phase-out/).
If you're having trouble logging into the `modeling-app`, you may need to
enable third-party cookies. You can enable third-party cookies by clicking on
the eye with a slash through it in the URL bar, and clicking on "Enable
Third-Party Cookies".
### Developing with Electron
To spin up the desktop app, `npm install` and `npm run build:wasm` need to have been done before hand then:
```
npm run tron:start
```
This will start the application and hot-reload on changes.
Devtools can be opened with the usual Command-Option-I (macOS) or Ctrl-Shift-I (Linux and Windows).
To package the app for your platform with electron-builder, run `npm run tronb:package:dev` (or `npm run tronb:package:prod` to point to the .env.production variables).
## Running tests
### Playwright tests
Prepare these system dependencies:
- Set $token from https://zoo.dev/account/api-tokens
#### Snapshot tests (Google Chrome on Ubuntu only)
Only Ubuntu and Google Chrome is supported for the set of tests evaluating screenshot snapshots.
If you don't run Ubuntu locally or in a VM, you may use a GitHub Codespace.
```
npm run playwright -- install chrome
npm run test:snapshots
```
You may use `-- --update-snapshots` as needed.
#### Desktop tests (Electron on all platforms)
```
npm run playwright -- install chromium
npm run test:e2e:desktop:local
```
You may use `-- -g "my test"` to match specific test titles, or `-- path/to/file.spec.ts` for a test file.
#### Web tests (Google Chrome on all platforms)
```
npm run test:e2e:web
```
#### Debugger
However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying.
With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code.
If you want to limit to a single browser use `--project="webkit"` or `firefox`, `Google Chrome`
Or comment out browsers in `playwright.config.ts`.
note chromium has encoder compat issues which is why were testing against the branded 'Google Chrome'
You may consider using the VSCode extension, it's useful for running individual threads, but some some reason the "record a test" is locked to chromium with we can't use. A work around is to us the CI `npm run playwright codegen -b wk --load-storage ./store localhost:3000`
<details>
<summary>
Where `./store` should look like this
</summary>
```JSON
{
"cookies": [],
"origins": [
{
"origin": "http://localhost:3000",
"localStorage": [
{
"name": "store",
"value": "{\"state\":{\"openPanes\":[\"code\"]},\"version\":0}"
},
{
"name": "persistCode",
"value": ""
},
{
"name": "TOKEN_PERSIST_KEY",
"value": "your-token"
}
]
}
]
}
```
</details>
However because much of our tests involve clicking in the stream at specific locations, it's code-gen looks `await page.locator('video').click();` when really we need to use a pixel coord, so I think it's of limited use.
### Unit and component tests
If you already haven't, run the following:
```
npm
npm run build:wasm
npm start
```
and finally:
```
npm run test:unit
```
For individual testing:
```
npm run test abstractSyntaxTree -t "unexpected closed curly brace" --silent=false
```
Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro) tests, in interactive mode by default.
### Rust tests
Prepare these system dependencies:
- Set `$KITTYCAD_API_TOKEN` from https://zoo.dev/account/api-tokens
- Install `just` following [these instructions](https://just.systems/man/en/packages.html)
then run tests that target the KCL language:
```
npm run test:rust
```
### Fuzzing the parser
Make sure you install cargo fuzz:
```bash
$ cargo install cargo-fuzz
```
```bash
$ cd rust/kcl-lib
# list the fuzz targets
$ cargo fuzz list
# run the parser fuzzer
$ cargo +nightly fuzz run parser
```
For more information on fuzzing you can check out
[this guide](https://rust-fuzz.github.io/book/cargo-fuzz.html).
### Logging
To display logging (to the terminal or console) set `ZOO_LOG=1`. This will log some warnings and simple performance metrics. To view these in test runs, use `-- --nocapture`.
To enable memory metrics, build with `--features dhat-heap`.
## Running scripts
There are multiple scripts under the folder path `./scripts` which can be used in various settings.
### Pattern for a static file, npm run commands, and CI-CD checks
If you want to implement a static checker follow this pattern. Two static checkers we have are circular dependency checks in our typescript code and url checker to see if any hard coded URL is the typescript application 404s. We have a set of known files in `./scripts/known/*.txt` which is the baseline.
If you improve the baseline, run the overwrite command and commit the new smaller baseline. Try not to make the baseline bigger, the CI CD will complain.
These baselines are to hold us to higher standards and help implement automated testing against the repository
#### Output result to stdout
- `npm run circular-deps`
- `npm run url-checker`
- create a `<name>.sh` file that will run the static checker then output the result to `stdout`
#### Overwrite result to known .txt file on disk
If the application needs to overwrite the known file on disk use this pattern. This known .txt file will be source controlled as the baseline
- `npm run circular-deps:overwrite`
- `npm run url-checker:overwrite`
#### Diff baseline and current
These commands will write a /tmp/ file on disk and compare it to the known file in the repository. This command will also be used in the CI CD pipeline for automated checks
- create a `diff-<name>.sh` file that is the script to diff your tmp file to the baseline
e.g. `diff-url-checker.sh`
```bash
#!/bin/bash
set -euo pipefail
npm run url-checker > /tmp/urls.txt
diff --ignore-blank-lines -w /tmp/urls.txt ./scripts/known/urls.txt
```
- `npm run circular-deps:diff`
- `npm run url-checker:diff`
## Proposing changes
Before you submit a contribution PR to this repo, please ensure that:
- There is a corresponding issue for the changes you want to make, so that discussion of approach can be had before work begins.
- You have separated out refactoring commits from feature commits as much as possible
- You have run all of the following commands locally:
- `npm run fmt`
- `npm run tsc`
- `npm run test`
- Here they are all together: `npm run fmt && npm run tsc && npm run test`
## Shipping releases
#### 1. Create a 'Cut release $VERSION' issue
Use the **Release** issue template.
This will be used to facilitate changelog discussions and release testing.
https://github.com/KittyCAD/modeling-app/issues/new
#### 2. Push a new tag
Decide on a `v`-prefixed semver `VERSION` (e.g. `v1.2.3`) with the team and tag the repo on the latest main:
```
git tag $VERSION --message=""
git push origin $VERSION
```
This will trigger the `build-apps` workflow to set the version, build & sign the apps, and generate release files.
The workflow should be listed right away [in this list](https://github.com/KittyCAD/modeling-app/actions/workflows/build-apps.yml?query=event%3Apush).
#### 3. Manually test artifacts
The release builds can be found under the `out-{arch}-{platform}` zip files, at the very bottom of the `build-apps` summary page for the workflow (triggered by the tag in step 2).
Assign someone to each section of the manual checklist generated by the issue template.
#### 4. Bump the KCL version
Follow the instructions [here](./rust/README.md) to publish new crates.
This ensures that the KCL accepted by the app is also accepted by the CLI.
If there are documentation changes, merge the corresponding Dependabot PRs [here](https://github.com/KittyCAD/website/pulls/app%2Fdependabot) for the website.
You can trigger Dependabot to check for updates [here](https://github.com/KittyCAD/website/network/updates/17261214/jobs).
#### 5. Publish the release
Head over to https://github.com/KittyCAD/modeling-app/releases/new, pick the newly created tag and type it in the **Release title** field as well.
Click **Generate release notes** as a starting point to discuss the changelog in the issue. Once done, make sure **Set as the latest release** is checked, and click **Publish release**.
A new `publish-apps-release` workflow will start and you should be able to find it [here](https://github.com/KittyCAD/modeling-app/actions?query=event%3Arelease). On success, the files will be uploaded to the public bucket as well as to the GitHub release, and the announcement on Discord will be sent.
#### 6. Close the issue
If everything is well and the release is out to the public, the issue tracking the release shall be closed.

View File

@ -4,7 +4,7 @@ Compared to other CAD software, getting Zoo Design Studio up and running is quic
## Windows ## Windows
1. Download the [Zoo Design Studio installer](https://zoo.dev/design-studio/download) for Windows and for your processor type. 1. Download the [Zoo Design Studio installer](https://zoo.dev/modeling-app/download) for Windows and for your processor type.
2. Once downloaded, run the installer `Zoo Design Studio-{version}-{arch}-win.exe` which should take a few seconds. 2. Once downloaded, run the installer `Zoo Design Studio-{version}-{arch}-win.exe` which should take a few seconds.
@ -12,16 +12,16 @@ Compared to other CAD software, getting Zoo Design Studio up and running is quic
## macOS ## macOS
1. Download the [Zoo Design Studio installer](https://zoo.dev/design-studio/download) for macOS and for your processor type. 1. Download the [Zoo Design Studio installer](https://zoo.dev/modeling-app/download) for macOS and for your processor type.
2. Once downloaded, open the disk image `Zoo Design Studio-{version}-{arch}-mac.dmg` and drag the applications to your `Applications` directory. 2. Once downloaded, open the disk image `Zoo Design Studio-{version}-{arch}-mac.dmg` and drag the applications to your `Applications` directory.
3. You can then open your `Applications` directory and double-click on `Zoo Design Studio` to open. 3. You can then open your `Applications` directory and double-click on `Zoo Design Studio` to open.
## Linux ## Linux
1. Download the [Zoo Design Studio installer](https://zoo.dev/design-studio/download) for Linux and for your processor type. 1. Download the [Zoo Design Studio installer](https://zoo.dev/modeling-app/download) for Linux and for your processor type.
2. Install the dependencies needed to run the [AppImage format](https://appimage.org/). 2. Install the dependencies needed to run the [AppImage format](https://appimage.org/).
- On Ubuntu, install the FUSE library with these commands in a terminal. - On Ubuntu, install the FUSE library with these commands in a terminal.
@ -29,7 +29,7 @@ Compared to other CAD software, getting Zoo Design Studio up and running is quic
sudo apt update sudo apt update
sudo apt install libfuse2 sudo apt install libfuse2
``` ```
- Optionally, follow [these steps](https://github.com/probonopd/go-appimage/blob/master/src/appimaged/README.md#initial-setup) to install `appimaged`. It is a daemon that makes interacting with AppImage files more seamless. - Optionally, follow [these steps](https://github.com/probonopd/go-appimage/blob/master/src/appimaged/README.md#initial-setup) to install `appimaged`. It is a daemon that makes interacting with AppImage files more seamless.
- Once installed, copy the downloaded `Zoo Design Studio-{version}-{arch}-linux.AppImage` to the directory of your choice, for instance `~/Applications`. - Once installed, copy the downloaded `Zoo Design Studio-{version}-{arch}-linux.AppImage` to the directory of your choice, for instance `~/Applications`.
- `appimaged` should automatically find it and make it executable. If not, run: - `appimaged` should automatically find it and make it executable. If not, run:

104
Makefile
View File

@ -1,50 +1,46 @@
.PHONY: all .PHONY: all
all: install check build all: install build check
############################################################################### ###############################################################################
# INSTALL # INSTALL
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
export WINDOWS := true CARGO ?= ~/.cargo/bin/cargo.exe
ifndef MSYSTEM WASM_PACK ?= ~/.cargo/bin/wasm-pack.exe
export POWERSHELL := true
endif
endif
ifdef WINDOWS
CARGO ?= $(USERPROFILE)/.cargo/bin/cargo.exe
WASM_PACK ?= $(USERPROFILE)/.cargo/bin/wasm-pack.exe
else else
CARGO ?= $(shell which cargo || echo ~/.cargo/bin/cargo) CARGO ?= ~/.cargo/bin/cargo
WASM_PACK ?= $(shell which wasm-pack || echo ~/.cargo/bin/wasm-pack) WASM_PACK ?= ~/.cargo/bin/wasm-pack
endif endif
.PHONY: install .PHONY: install
install: node_modules/.package-lock.json $(CARGO) $(WASM_PACK) ## Install dependencies install: node_modules/.yarn-integrity $(CARGO) $(WASM_PACK) ## Install dependencies
node_modules/.package-lock.json: package.json package-lock.json node_modules/.yarn-integrity: package.json yarn.lock
npm prune yarn install
npm install ifeq ($(OS),Windows_NT)
@ type nul > $@
else
@ touch $@
endif
$(CARGO): $(CARGO):
ifdef WINDOWS ifeq ($(OS),Windows_NT)
npm run install:rust:windows yarn install:rust:windows
else else
npm run install:rust yarn install:rust
endif endif
$(WASM_PACK): $(WASM_PACK):
ifdef WINDOWS ifeq ($(OS),Windows_NT)
npm run install:wasm-pack:cargo yarn install:wasm-pack:cargo
else else
npm run install:wasm-pack:sh yarn install:wasm-pack:sh
endif endif
############################################################################### ###############################################################################
# BUILD # BUILD
CARGO_SOURCES := rust/.cargo/config.toml $(wildcard rust/Cargo.*) $(wildcard rust/**/Cargo.*) CARGO_SOURCES := rust/.cargo/config.toml $(wildcard rust/Cargo.*) $(wildcard rust/**/Cargo.*)
KCL_SOURCES := $(wildcard public/kcl-samples/**/*.kcl)
RUST_SOURCES := $(wildcard rust/**/*.rs) RUST_SOURCES := $(wildcard rust/**/*.rs)
REACT_SOURCES := $(wildcard src/*.tsx) $(wildcard src/**/*.tsx) REACT_SOURCES := $(wildcard src/*.tsx) $(wildcard src/**/*.tsx)
@ -52,23 +48,26 @@ TYPESCRIPT_SOURCES := tsconfig.* $(wildcard src/*.ts) $(wildcard src/**/*.ts)
VITE_SOURCES := $(wildcard vite.*) $(wildcard vite/**/*.tsx) VITE_SOURCES := $(wildcard vite.*) $(wildcard vite/**/*.tsx)
.PHONY: build .PHONY: build
build: install public/kcl_wasm_lib_bg.wasm public/kcl-samples/manifest.json .vite/build/main.js build: build-web build-desktop
.PHONY: build-web
build-web: install public/kcl_wasm_lib_bg.wasm build/index.html
.PHONY: build-desktop
build-desktop: install public/kcl_wasm_lib_bg.wasm .vite/build/main.js
public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES) public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES)
ifdef WINDOWS ifeq ($(OS),Windows_NT)
npm run build:wasm:dev:windows yarn build:wasm:dev:windows
else else
npm run build:wasm:dev yarn build:wasm:dev
endif endif
public/kcl-samples/manifest.json: $(KCL_SOURCES) build/index.html: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES)
ifndef WINDOWS yarn build:local
cd rust/kcl-lib && EXPECTORATE=overwrite cargo test generate_manifest
@ touch $@
endif
.vite/build/main.js: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES) .vite/build/main.js: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES)
npm run tronb:vite:dev yarn tronb:vite:dev
############################################################################### ###############################################################################
# CHECK # CHECK
@ -78,12 +77,12 @@ check: format lint
.PHONY: format .PHONY: format
format: install ## Format the code format: install ## Format the code
npm run fmt yarn fmt
.PHONY: lint .PHONY: lint
lint: install ## Lint the code lint: install ## Lint the code
npm run tsc yarn tsc
npm run lint yarn lint
############################################################################### ###############################################################################
# RUN # RUN
@ -94,12 +93,12 @@ TARGET ?= desktop
run: run-$(TARGET) run: run-$(TARGET)
.PHONY: run-web .PHONY: run-web
run-web: install build ## Start the web app run-web: install build-web ## Start the web app
npm run start yarn start
.PHONY: run-desktop .PHONY: run-desktop
run-desktop: install build ## Start the desktop app run-desktop: install build-desktop ## Start the desktop app
npm run tron:start yarn tron:start
############################################################################### ###############################################################################
# TEST # TEST
@ -113,28 +112,27 @@ test: test-unit test-e2e
.PHONY: test-unit .PHONY: test-unit
test-unit: install ## Run the unit tests test-unit: install ## Run the unit tests
npm run test:rust
npm run test:unit:components
@ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 ) @ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 )
npm run test:unit yarn test:unit
.PHONY: test-e2e .PHONY: test-e2e
test-e2e: test-e2e-$(TARGET) test-e2e: test-e2e-$(TARGET)
.PHONY: test-e2e-web .PHONY: test-e2e-web
test-e2e-web: install build ## Run the web e2e tests test-e2e-web: install build-web ## Run the web e2e tests
@ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 )
ifdef E2E_GREP ifdef E2E_GREP
npm run test:e2e:web -- --headed --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES) yarn chrome:test --headed --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
else else
npm run test:e2e:web -- --headed --workers='100%' yarn chrome:test --headed --workers='100%'
endif endif
.PHONY: test-e2e-desktop .PHONY: test-e2e-desktop
test-e2e-desktop: install build ## Run the desktop e2e tests test-e2e-desktop: install build-desktop ## Run the desktop e2e tests
ifdef E2E_GREP ifdef E2E_GREP
npm run test:e2e:desktop -- --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES) yarn test:playwright:electron --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
else else
npm run test:e2e:desktop -- --workers='100%' yarn test:playwright:electron --workers='100%'
endif endif
############################################################################### ###############################################################################
@ -142,8 +140,8 @@ endif
.PHONY: clean .PHONY: clean
clean: ## Delete all artifacts clean: ## Delete all artifacts
ifdef POWERSHELL ifeq ($(OS),Windows_NT)
git clean --force -d -x --exclude=.env* --exclude=**/*.env git clean --force -d -X
else else
rm -rf .vite/ build/ rm -rf .vite/ build/
rm -rf trace.zip playwright-report/ test-results/ rm -rf trace.zip playwright-report/ test-results/
@ -154,7 +152,7 @@ endif
.PHONY: help .PHONY: help
help: install help: install
ifdef POWERSHELL ifeq ($(OS),Windows_NT)
@ powershell -Command "Get-Content $(MAKEFILE_LIST) | Select-String -Pattern '^[^\s]+:.*##\s.*$$' | ForEach-Object { $$line = $$_.Line -split ':.*?##\s+'; Write-Host -NoNewline $$line[0].PadRight(30) -ForegroundColor Cyan; Write-Host $$line[1] }" @ powershell -Command "Get-Content $(MAKEFILE_LIST) | Select-String -Pattern '^[^\s]+:.*##\s.*$$' | ForEach-Object { $$line = $$_.Line -split ':.*?##\s+'; Write-Host -NoNewline $$line[0].PadRight(30) -ForegroundColor Cyan; Write-Host $$line[1] }"
else else
@ grep -E '^[^[:space:]]+:.*## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @ grep -E '^[^[:space:]]+:.*## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
@ -169,5 +167,5 @@ endif
# It should work for you other Linux users. # It should work for you other Linux users.
lee-electron-test: lee-electron-test:
Xephyr -br -ac -noreset -screen 1200x500 :2 & Xephyr -br -ac -noreset -screen 1200x500 :2 &
DISPLAY=:2 NODE_ENV=development PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ npm run tron:test -g "when using the file tree" DISPLAY=:2 NODE_ENV=development PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ yarn tron:test -g "when using the file tree"
killall Xephyr killall Xephyr

477
README.md
View File

@ -1,8 +1,8 @@
![Zoo Design Studio](/public/zma-logomark-outlined.png) ![Zoo Design Studio](/public/zma-logomark-outlined.png)
# Zoo Design Studio ## Zoo Design Studio
[zoo.dev/design-studio](https://zoo.dev/design-studio) download at [zoo.dev/modeling-app/download](https://zoo.dev/modeling-app/download)
A CAD application from the future, brought to you by the [Zoo team](https://zoo.dev). A CAD application from the future, brought to you by the [Zoo team](https://zoo.dev).
@ -23,7 +23,7 @@ Design Studio is a _hybrid_ user interface for CAD modeling. You can point-and-c
The 3D view in Design Studio is just a video stream from our hosted geometry engine. The app sends new modeling commands to the engine via WebSockets, which returns back video frames of the view within the engine. The 3D view in Design Studio is just a video stream from our hosted geometry engine. The app sends new modeling commands to the engine via WebSockets, which returns back video frames of the view within the engine.
## Technology ## Tools
- UI - UI
- [React](https://react.dev/) - [React](https://react.dev/)
@ -34,14 +34,475 @@ The 3D view in Design Studio is just a video stream from our hosted geometry eng
- WebSockets (via [KittyCAD TS client](https://github.com/KittyCAD/kittycad.ts)) - WebSockets (via [KittyCAD TS client](https://github.com/KittyCAD/kittycad.ts))
- Code Editor - Code Editor
- [CodeMirror](https://codemirror.net/) - [CodeMirror](https://codemirror.net/)
- [Custom WASM LSP Server](https://github.com/KittyCAD/modeling-app/tree/main/rust/kcl-lib/src/lsp/kcl) - Custom WASM LSP Server
- Modeling - Modeling
- [KittyCAD TypeScript client](https://github.com/KittyCAD/kittycad.ts) - [KittyCAD TypeScript client](https://github.com/KittyCAD/kittycad.ts)
## Get Started [Original demo video](https://drive.google.com/file/d/183_wjqGdzZ8EEZXSqZ3eDcJocYPCyOdC/view?pli=1)
We recommend downloading the latest application binary from our [website](https://zoo.dev/design-studio/download). If you don't see your platform or architecture supported there, please file an issue. See the [installation guide](INSTALL.md) for additional instructions. [Original demo slides](https://github.com/user-attachments/files/19010536/demo.pdf)
## Developing ## Get started
Finally, if you'd like to run a development build or contribute to the project, please visit our [contributor guide](CONTRIBUTING.md) to get started. To contribute to the KittyCAD Language, see the dedicated [readme](rust/kcl-lib/README.md) for KCL. We recommend downloading the latest application binary from [our Releases page](https://github.com/KittyCAD/modeling-app/releases). If you don't see your platform or architecture supported there, please file an issue.
## Running a development build
Install a node version manager such as [fnm](https://github.com/Schniz/fnm?tab=readme-ov-#installation).
On Windows, it's also recommended to [upgrade your PowerShell version](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.5#winget), we're using 7.
Then in the repo run the following to install and use the node version specified in `.nvmrc`. You might need to specify your processor architecture with `--arch arm64` or `--arch x64` if it's not autodetected.
```
fnm install --corepack-enabled
fnm use
```
Install the NPM dependencies with:
```
yarn install
```
This project uses a lot of Rust compiled to [WASM](https://webassembly.org/) within it. We have package scripts to run rustup, see `package.json` for reference:
```
# macOS/Linux
yarn install:rust
yarn install:wasm-pack:sh
# Windows
yarn install:rust:windows
yarn install:wasm-pack:cargo
```
Then to build the WASM layer, run:
```
# macOS/Linux
yarn build:wasm
# Windows
yarn build:wasm:windows
```
Or if you have the `gh` cli installed and want to download the latest main wasm bundle. Note that on Windows, you need to associate .ps1 files with PowerShell, which can be done via the right click menu, selecting `C:\Program Files\PowerShell\7\pwsh.exe`, and you can install tools like `gh` via `yarn install:tools:windows`.
```
# macOS/Linux
yarn fetch:wasm
# Windows
yarn fetch:wasm:windows
```
That will build the WASM binary and put in the `public` dir (though gitignored).
Finally, to run the web app only, run:
```
yarn start
```
If you're not a Zoo employee you won't be able to access the dev environment, you should copy everything from `.env.production` to `.env.development.local` to make it point to production instead, then when you navigate to `localhost:3000` the easiest way to sign in is to paste `localStorage.setItem('TOKEN_PERSIST_KEY', "your-token-from-https://zoo.dev/account/api-tokens")` replacing the with a real token from https://zoo.dev/account/api-tokens of course, then navigate to `localhost:3000` again. Note that navigating to `localhost:3000/signin` removes your token so you will need to set the token again.
### Development environment variables
The Copilot LSP plugin in the editor requires a Zoo API token to run. In production, we authenticate this with a token via cookie in the browser and device auth token in the desktop environment, but this token is inaccessible in the dev browser version because the cookie is considered "cross-site" (from `localhost` to `dev.zoo.dev`). There is an optional environment variable called `VITE_KC_DEV_TOKEN` that you can populate with a dev token in a `.env.development.local` file to not check it into Git, which will use that token instead of other methods for the LSP service.
### Developing in Chrome
Chrome is in the process of rolling out a new default which
[blocks Third-Party Cookies](https://developer.chrome.com/en/docs/privacy-sandbox/third-party-cookie-phase-out/).
If you're having trouble logging into the `modeling-app`, you may need to
enable third-party cookies. You can enable third-party cookies by clicking on
the eye with a slash through it in the URL bar, and clicking on "Enable
Third-Party Cookies".
## Desktop
To spin up the desktop app, `yarn install` and `yarn build:wasm` need to have been done before hand then:
```
yarn tron:start
```
This will start the application and hot-reload on changes.
Devtools can be opened with the usual Command-Option-I (macOS) or Ctrl-Shift-I (Linux and Windows).
To package the app for your platform with electron-builder, run `yarn tronb:package:dev` (or `yarn tronb:package:prod` to point to the .env.production variables).
## Checking out commits / Bisecting
Which commands from setup are one off vs. need to be run every time?
The following will need to be run when checking out a new commit and guarantees the build is not stale:
```bash
yarn install
yarn build:wasm
yarn start # or yarn build:local && yarn serve for slower but more production-like build
```
## Before submitting a PR
Before you submit a contribution PR to this repo, please ensure that:
- There is a corresponding issue for the changes you want to make, so that discussion of approach can be had before work begins.
- You have separated out refactoring commits from feature commits as much as possible
- You have run all of the following commands locally:
- `yarn fmt`
- `yarn tsc`
- `yarn test`
- Here they are all together: `yarn fmt && yarn tsc && yarn test`
## Release a new version
#### 1. Create a 'Cut release $VERSION' issue
It will be used to document changelog discussions and release testing.
https://github.com/KittyCAD/modeling-app/issues/new
#### 2. Push a new tag
Create a new tag and push it to the repo. The `semantic-release.sh` script will automatically bump the minor part, which we use the most. For instance going from `v0.27.0` to `v0.28.0`.
```
VERSION=$(./scripts/semantic-release.sh)
git tag $VERSION
git push origin --tags
```
This will trigger the `build-apps` workflow, set the version, build & sign the apps, and generate release files as well as updater-test artifacts.
The workflow should be listed right away [in this list](https://github.com/KittyCAD/modeling-app/actions/workflows/build-apps.yml?query=event%3Apush)).
#### 3. Manually test artifacts
##### Release builds
The release builds can be found under the `out-{arch}-{platform}` zip files, at the very bottom of the `build-apps` summary page for the workflow (triggered by the tag in 2.).
Manually test against this [list](https://github.com/KittyCAD/modeling-app/issues/3588) across Windows, MacOS, Linux and posting results as comments in the issue.
##### Updater-test builds
The other `build-apps` output in the release `build-apps` workflow (triggered by 2.) is `updater-test-{arch}-{platform}`. It's a semi-automated process: for macOS, Windows, and Linux, download the corresponding updater-test artifact file, install the app, run it, expect an updater prompt to a dummy v0.255.255, install it and check that the app comes back at that version.
The only difference with these builds is that they point to a different update location on the release bucket, with this dummy v0.255.255 always available. This helps ensuring that the version we release will be able to update to the next one available.
If the prompt doesn't show up, start the app in command line to grab the electron-updater logs. This is likely an issue with the current build that needs addressing (or the updater-test location in the storage bucket).
```
# Windows (PowerShell)
& 'C:\Program Files\Zoo Design Studio\Zoo Design Studio.exe'
# macOS
/Applications/Zoo\ Modeling\ App.app/Contents/MacOS/Zoo\ Modeling\ App
# Linux
./Zoo Design Studio-{version}-{arch}-linux.AppImage
```
#### 4. Publish the release
Head over to https://github.com/KittyCAD/modeling-app/releases/new, pick the newly created tag and type it in the _Release title_ field as well.
Hit _Generate release notes_ as a starting point to discuss the changelog in the issue. Once done, make sure _Set as the latest release_ is checked, and hit _Publish release_.
A new `publish-apps-release` will kick in and you should be able to find it [here](https://github.com/KittyCAD/modeling-app/actions?query=event%3Arelease). On success, the files will be uploaded to the public bucket as well as to the GitHub release, and the announcement on Discord will be sent.
#### 5. Close the issue
If everything is well and the release is out to the public, the issue tracking the release shall be closed.
## Fuzzing the parser
Make sure you install cargo fuzz:
```bash
$ cargo install cargo-fuzz
```
```bash
$ cd rust/kcl-lib
# list the fuzz targets
$ cargo fuzz list
# run the parser fuzzer
$ cargo +nightly fuzz run parser
```
For more information on fuzzing you can check out
[this guide](https://rust-fuzz.github.io/book/cargo-fuzz.html).
## Tests
### Playwright tests
You will need a `./e2e/playwright/playwright-secrets.env` file:
```bash
$ touch ./e2e/playwright/playwright-secrets.env
$ cat ./e2e/playwright/playwright-secrets.env
token=<dev.zoo.dev/account/api-tokens>
snapshottoken=<your-snapshot-token>
```
For a portable way to run Playwright you'll need Docker.
#### Generic example
After that, open a terminal and run:
```bash
docker run --network host --rm --init -it playwright/chrome:playwright-x.xx.x
```
and in another terminal, run:
```bash
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ yarn playwright test --project="Google Chrome" <test suite>
```
#### Specific example
open a terminal and run:
```bash
docker run --network host --rm --init -it playwright/chrome:playwright-1.46.0
```
and in another terminal, run:
```bash
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ yarn playwright test --project="Google Chrome" e2e/playwright/command-bar-tests.spec.ts
```
run a specific test change the test from `test('...` to `test.only('...`
(note if you commit this, the tests will instantly fail without running any of the tests)
**Gotcha**: running the docker container with a mismatched image against your `./node_modules/playwright` will cause a failure. Make sure the versions are matched and up to date.
run headed
```
yarn playwright test --headed
```
run with step through debugger
```
PWDEBUG=1 yarn playwright test
```
However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying.
With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code.
If you want to limit to a single browser use `--project="webkit"` or `firefox`, `Google Chrome`
Or comment out browsers in `playwright.config.ts`.
note chromium has encoder compat issues which is why were testing against the branded 'Google Chrome'
You may consider using the VSCode extension, it's useful for running individual threads, but some some reason the "record a test" is locked to chromium with we can't use. A work around is to us the CI `yarn playwright codegen -b wk --load-storage ./store localhost:3000`
<details>
<summary>
Where `./store` should look like this
</summary>
```JSON
{
"cookies": [],
"origins": [
{
"origin": "http://localhost:3000",
"localStorage": [
{
"name": "store",
"value": "{\"state\":{\"openPanes\":[\"code\"]},\"version\":0}"
},
{
"name": "persistCode",
"value": ""
},
{
"name": "TOKEN_PERSIST_KEY",
"value": "your-token"
}
]
}
]
}
```
</details>
However because much of our tests involve clicking in the stream at specific locations, it's code-gen looks `await page.locator('video').click();` when really we need to use a pixel coord, so I think it's of limited use.
### Unit and component tests
If you already haven't, run the following:
```
yarn
yarn build:wasm
yarn start
```
and finally:
```
yarn test:unit
```
For individual testing:
```
yarn test abstractSyntaxTree -t "unexpected closed curly brace" --silent=false
```
Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro) tests, in interactive mode by default.
### Rust tests
**Dependencies**
- `KITTYCAD_API_TOKEN`
- `cargo-nextest`
- `just`
#### Setting KITTYCAD_API_TOKEN
Use the production zoo.dev token, set this environment variable before running the tests
#### Installing cargonextest
```
cd rust
cargo search cargo-nextest
cargo install cargo-nextest
```
#### just
install [`just`](https://github.com/casey/just?tab=readme-ov-file#pre-built-binaries)
#### Running the tests
```bash
# With just
# Make sure KITTYCAD_API_TOKEN=<prod zoo.dev token> is set
# Make sure you installed cargo-nextest
# Make sure you installed just
cd rust
just test
```
```bash
# Without just
# Make sure KITTYCAD_API_TOKEN=<prod zoo.dev token> is set
# Make sure you installed cargo-nextest
cd rust
export RUST_BRACKTRACE="full" && cargo nextest run --workspace --test-threads=1
```
Where `XXX` is an API token from the production engine (NOT the dev environment).
We recommend using [nextest](https://nexte.st/) to run the Rust tests (its faster and is used in CI). Once installed, run the tests using
```
cd rust
KITTYCAD_API_TOKEN=XXX cargo run nextest
```
### Mapping CI CD jobs to local commands
When you see the CI CD fail on jobs you may wonder three things
- Do I have a bug in my code?
- Is the test flaky?
- Is there a bug in `main`?
To answer these questions the following commands will give you confidence to locate the issue.
#### Static Analysis
Part of the CI CD pipeline performs static analysis on the code. Use the following commands to mimic the CI CD jobs.
The following set of commands should get us closer to one and done commands to instantly retest issues.
```
yarn test-setup
```
> Gotcha, are packages up to date and is the wasm built?
```
yarn tsc
yarn fmt-check
yarn lint
yarn test:unit:local
```
> Gotcha: Our unit tests have integration tests in them. You need to run a localhost server to run the unit tests.
#### E2E Tests
**Playwright Electron**
These E2E tests run in electron. There are tests that are skipped if they are ran in a windows, linux, or macos environment. We can use playwright tags to implement test skipping.
```
yarn test:playwright:electron:local
yarn test:playwright:electron:windows:local
yarn test:playwright:electron:macos:local
yarn test:playwright:electron:ubuntu:local
```
> Why does it say local? The CI CD commands that run in the pipeline cannot be ran locally. A single command will not properly setup the testing environment locally.
#### Some notes on CI
The tests are broken into snapshot tests and non-snapshot tests, and they run in that order, they automatically commit new snap shots, so if you see an image commit check it was an intended change. If we have non-determinism in the snapshots such that they are always committing new images, hopefully this annoyance makes us fix them asap, if you notice this happening let Kurt know. But for the odd occasion `git reset --hard HEAD~ && git push -f` is your friend.
How to interpret failing playwright tests?
If your tests fail, click through to the action and see that the tests failed on a line that includes `await page.getByTestId('loading').waitFor({ state: 'detached' })`, this means the test fail because the stream never started. It's you choice if you want to re-run the test, or ignore the failure.
We run on ubuntu and macos, because safari doesn't work on linux because of the dreaded "no RTCPeerConnection variable" error. But linux runs first and then macos for the same reason that we limit the number of parallel tests to 1 because we limit stream connections per user, so tests would start failing we if let them run together.
If something fails on CI you can download the artifact, unzip it and then open `playwright-report/data/<UUID>.zip` with https://trace.playwright.dev/ to see what happened.
#### Getting started writing a playwright test in our app
Besides following the instructions above and using the playwright docs, our app is weird because of the whole stream thing, which means our testing is weird. Because we've just figured out this stuff and therefore docs might go stale quick here's a 15min vid/tutorial
https://github.com/KittyCAD/modeling-app/assets/29681384/6f5e8e85-1003-4fd9-be7f-f36ce833942d
<details>
<summary>
PS: for the debug panel, the following JSON is useful for snapping the camera
</summary>
```JSON
{"type":"modeling_cmd_req","cmd_id":"054e5472-e5e9-4071-92d7-1ce3bac61956","cmd":{"type":"default_camera_look_at","center":{"x":15,"y":0,"z":0},"up":{"x":0,"y":0,"z":1},"vantage":{"x":30,"y":30,"z":30}}}
```
</details>
## KCL
For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/rust/kcl-lib).
### Logging
To display logging (to the terminal or console) set `ZOO_LOG=1`. This will log some warnings and simple performance metrics. To view these in test runs, use `-- --nocapture`.
To enable memory metrics, build with `--features dhat-heap`.

View File

@ -1,40 +0,0 @@
[files]
extend-exclude = [
"**/target",
"node_modules",
"build",
"dist",
"out",
"**/Cargo.lock",
"docs/**/*.md",
"docs/**/*.json",
"e2e/playwright/lib/console-error-whitelist.ts",
".package-lock.json",
"**/package-lock.json",
"openapi/*.json",
"packages/codemirror-lang-kcl/test/all.test.ts",
"public/kcl-samples",
"rust/kcl-lib/tests/kcl_samples",
"tsconfig.tsbuildinfo",
"src/lib/machine-api.d.ts",
"kcl-book/book",
]
[default.extend-words]
metalness = "metalness" # appearance API
Hom = "Hom" # short for homogenous
typ = "typ" # used to declare a variable named 'type' which is a reserved keyword in Rust
ue = "ue" # short for UnaryExpression
THRE = "THRE" # Weird bug that wrongly detects THREEjs as a typo
nwo = "nwo" # don't know what this is about tbh
"ot" = "ot" # some abbreviation, idk what
"oe" = "oe" # some abbreviation, idk what
"colinear" = "colinear" # some engine shit, kidding
[default]
extend-ignore-identifiers-re = [
"\\dnd", # e.g. 2nd
]
extend-ignore-re = [
"@xstate-layout .*",
]

View File

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

View File

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 259 KiB

View File

@ -1,48 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/1.6.0/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedVariables": "error"
},
"suspicious": {
"noExplicitAny": "warn"
},
"style": {
"useBlockStatements": "error",
"useShorthandArrayType": "error"
}
}
},
"formatter": {
"enabled": true,
"indentWidth": 2,
"indentStyle": "space",
"lineWidth": 80,
"formatWithErrors": true
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"jsxQuoteStyle": "double",
"trailingCommas": "es5",
"semicolons": "asNeeded"
},
"parser": {
"unsafeParameterDecoratorsEnabled": true
}
},
"css": {
"parser": {
"cssModules": true
}
},
"files": {
"ignore": ["**/*.json"]
}
}

View File

@ -1,53 +0,0 @@
---
title: "Arithmetic and logic"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
KCL supports the usual arithmetic operators on numbers and logic operators on booleans:
| Operator | Meaning |
|----------|---------|
| `+` | Addition |
| `-` | Subtraction or unary negation |
| `*` | Multiplication |
| `/` | Division |
| `%` | Modulus aka remainder |
| `^` | Power, e.g., `x ^ 2` means `x` squared |
| `&` | Logical 'and' |
| `|` | Logical 'or' |
| `!` | Unary logical 'not' |
KCL also supports comparsion operators which operate on numbers and produce booleans:
| Operator | Meaning |
|----------|---------|
| `==` | Equal |
| `!=` | Not equal |
| `<` | Less than |
| `>` | Greater than |
| `<=` | Less than or equal |
| `>=` | Greater than or equal |
Arithmetics and logic expressions can be arbitrairly combined with the usual rules of associativity and precedence, e.g.,
```
myMathExpression = 3 + 1 * 2 / 3 - 7
```
You can also nest expressions in parenthesis:
```
myMathExpression = 3 + (1 * 2 / (3 - 7))
```
KCL numbers are implemented using [floating point numbers](https://en.wikipedia.org/wiki/Floating-point_arithmetic). This means that there are occasionally representation and rounding issues, and some oddities such as supporting positive and negative zero.
Some operators can be applied to other types:
- `+` can be used to concatenate strings, e.g., `'hello' + ' ' + 'world!'`
- Unary `-` can be used with planes or line-like objects such as axes to produce an object with opposite orientation, e.g., `-XY` is a plain which is aligned with `XY` but whose normal aligns with the negative Z axis.
- The following operators can be used with solids as shorthand for CSG operations:
- `+` or `|` for [`union`](/docs/kcl-std/union).
- `-` for [`subtract`](/docs/kcl-std/subtract).
- `&` for [`intersect`](/docs/kcl-std/intersect)

View File

@ -1,33 +0,0 @@
---
title: "Arrays and ranges"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
Arrays are sequences of values.
Arrays can be written out as *array literals* using a sequence of expressions surrounded by square brackets, e.g., `['hello', 'world']` is an array of strings, `[x, x + 1, x + 2]` is an array of numbers (assuming `x` is a number), `[]` is an empty array, and `['hello', 42, true]` is a mixed array.
A value in an array can be accessed by indexing using square brackets where the index is a number, for example, `arr[0]`, `arr[42]`, `arr[i]` (where `arr` is an array and `i` is a (whole) number).
There are some useful functions for working with arrays in the standard library, see [std::array](/docs/kcl-std/modules/std-array) for details.
## Array types
Arrays have their own types: `[T]` where `T` is the type of the elements of the array, for example, `[string]` means an array of `string`s and `[any]` means an array of any values.
Array types can also include length information: `[T; n]` denotes an array of length `n` (where `n` is a number literal) and `[T; n+]` denotes an array whose length is at least `n`. The common case for that is `[T; 1+]`, i.e., a non-empty array. E.g., `[string; 1+]` and `[number(mm); 3]` are valid array types.
## Ranges
Ranges are a succinct way to create an array of sequential numbers. The syntax is `[start .. end]` where `start` and `end` evaluate to whole numbers (integers). Ranges are inclusive of the start and end. The end must be greater than the start. A range which is exclusive of its end is written with `<end`. Examples:
```kcl,norun
[0..3] // [0, 1, 2, 3]
[3..10] // [3, 4, 5, 6, 7, 8, 9, 10]
[3..<10] // [3, 4, 5, 6, 7, 8, 9]
x = 2
[x..x+1] // [2, 3]
```
The units of the start and end numbers must be the same and the result inherits those units.

View File

@ -1,30 +0,0 @@
---
title: "Attributes"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
Attributes are syntax which affects the language item they annotate. In KCL they are indicated using `@`. For example, `@settings` affects the file in which it appears.
There are two kinds of attributes: named and unnamed attributes. Named attributes (e.g., `@settings`) have a name immediately after the `@` (e.g., `settings`) and affect their surrounding scope. Unnamed attributes have no name and affect the following item, e.g.,
```kcl,norun
@(lengthUnit = ft, coords = opengl)
import "tests/inputs/cube.obj"
```
has an unnamed attribute on the `import` statement.
Named and unnamed attributes may take a parenthesized list of arguments (like a function). Named attributes may also appear without any arguments (e.g., `@no_std`).
## Named attributes
The `@settings` attribute affects the current file and accepts the following arguments: `defaultLengthUnit`, `defaultAngleUnit`, and `kclVersion`. See [settings](/docs/kcl-lang/settings) for details.
The `@no_std` attribute affects the current file, takes no arguments, and causes the standard library to not be implicitly available. It can still be used by being explicitly imported.
## Unnamed attributes
Unnamed attributes may be used on `import` statements when importing non-KCL files. See [projects, modules, and imports](/docs/kcl-lang/modules) for details.
Other unnamed attributes are used on functions inside the standard library, but these are not available in user code.

View File

@ -1,99 +0,0 @@
---
title: "Importing geometry from other CAD systems"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
`import` can also be used to import files from other CAD systems. The format of the statement is the
same as for KCL files. You can only import the whole file, not items from it. E.g.,
```norun
import "tests/inputs/cube.obj"
// Use `cube` just like a KCL object.
```
```kcl
import "tests/inputs/cube.sldprt" as cube
// Use `cube` just like a KCL object.
```
For formats lacking unit data (such as STL, OBJ, or PLY files), the default
unit of measurement is millimeters. Alternatively you may specify the unit
by using an attribute. Likewise, you can also specify a coordinate system. E.g.,
```kcl
@(lengthUnit = ft, coords = opengl)
import "tests/inputs/cube.obj"
```
When importing a GLTF file, the bin file will be imported as well.
Import paths are relative to the current project directory. Imports currently only work when
using the native Design Studio, not in the browser.
### Supported values
File formats: `fbx`, `gltf`/`glb`, `obj`+, `ply`+, `sldprt`, `step`/`stp`, `stl`+. (Those marked with a
'+' support customising the length unit and coordinate system).
Length units: `mm` (the default), `cm`, `m`, `inch`, `ft`, `yd`.
Coordinate systems:
- `zoo` (the default), forward: -Y, up: +Z, handedness: right
- `opengl`, forward: +Z, up: +Y, handedness: right
- `vulkan`, forward: +Z, up: -Y, handedness: left
---
## Performance deepdive for foreignfile imports
Parallelized foreignfile imports now let you overlap file reads, initialization,
and rendering. To maximize throughput, you need to understand the three distinct
stages—reading, initializing (background render start), and invocation (blocking)
—and structure your code to defer blocking operations until the end.
### Foreign import execution stages
1. **Import (Read / Initialization) Stage**
```kcl
import "tests/inputs/cube.step" as cube
```
- Reads the file from disk and makes its API available.
- Starts engine rendering but **does not block** your script.
- This kickstarts the render pipeline while you keep executing other code.
2. **Invocation (Blocking) Stage**
```kcl
import "tests/inputs/cube.step" as cube
cube
|> translate(z=10) // ← blocks here only
```
- Any method call (e.g., `translate`, `scale`, `rotate`) waits for the background render to finish before applying transformations.
### Best practices
#### 1. Defer blocking calls
```kcl
import "tests/inputs/cube.step" as cube // 1) Read / Background render starts
// --- perform other operations and calculations here ---
cube
|> translate(z=10) // 2) Blocks only here
```
#### 2. Split heavy work into separate modules
Place computationally expensive or IOheavy work into its own module so it can render in parallel while `main.kcl` continues.
#### Future improvements
Upcoming releases will autoanalyse dependencies and only block when truly necessary. Until then, explicit deferral will give you the best performance.

View File

@ -1,46 +0,0 @@
---
title: "Functions"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
We have support for defining your own functions. Functions can take in any
type of argument. Below is an example of the syntax:
```
fn myFn(x) {
return x
}
```
As you can see above `myFn` just returns whatever it is given.
KCL uses keyword arguments:
```
// If you declare a function like this
fn add(left, right) {
return left + right
}
// You can call it like this:
total = add(left = 1, right = 2)
```
Functions can also declare one *unlabeled* arg. If you do want to declare an unlabeled arg, it must
be the first arg declared.
```
// The @ indicates an argument is used without a label.
// Note that only the first argument can use @.
fn increment(@x) {
return x + 1
}
fn add(@x, delta) {
return x + delta
}
two = increment(1)
three = add(1, delta = 2)
```

View File

@ -1,22 +0,0 @@
---
title: "KCL Language Reference"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
This is a reference for KCL. If you are learning KCL, you may prefer the [guide](https://zoo.dev/docs/kcl-book/intro.html) which explains
things in a more tutorial fashion. See also our documentation of the [standard library](/docs/kcl-std).
## Topics
* [Pipelines](/docs/kcl-lang/pipelines)
* [Arithmetic and logic](/docs/kcl-lang/arithmetic)
* [Values and types](/docs/kcl-lang/types)
* [Numeric types and units](/docs/kcl-lang/numeric)
* [Functions](/docs/kcl-lang/functions)
* [Arrays and ranges](/docs/kcl-lang/arrays)
* [Projects and modules](/docs/kcl-lang/modules)
* [Attributes](/docs/kcl-lang/attributes)
* [Importing geometry from other CAD systems](/docs/kcl-lang/foreign-imports)
* [Settings](/docs/kcl-lang/settings)
* [Known Issues](/docs/kcl-lang/known-issues)

View File

@ -1,279 +0,0 @@
---
title: "Projects and modules"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
`KCL` allows splitting code up into multiple files. Each file is somewhat
isolated from other files as a separate module.
When you define a function, you can use `export` before it to make it available
to other modules.
```kcl
// util.kcl
export fn increment(@x) {
return x + 1
}
```
Other files in the project can now import functions that have been exported.
This makes them available to use in another file.
```norun
// main.kcl
import increment from "util.kcl"
answer = increment(41)
```
Import statements must be at the top-level of a file. It is not allowed to have
an `import` statement inside a function or in the body of an ifelse.
Multiple functions can be exported in a file.
```kcl
// util.kcl
export fn increment(@x) {
return x + 1
}
export fn decrement(@x) {
return x - 1
}
```
When importing, you can import multiple functions at once.
```norun
import increment, decrement from "util.kcl"
```
Imported symbols can be renamed for convenience or to avoid name collisions.
```norun
import increment as inc, decrement as dec from "util.kcl"
```
You can import files from the current directory or from subdirectories, but if importing from a
subdirectory you can only import `main.kcl`.
---
## Functions vs `clone`
There are two common patterns for reusing geometry:
1. **Wrap the construction in a function** flexible and fully parametric.
2. **Duplicate an existing object with `clone`** lightningfast, but an exact
duplicate.
### Parametric function example
```kcl
fn cube(center) {
return startSketchOn(XY)
|> startProfile(at = [center[0] - 10, center[1] - 10])
|> line(endAbsolute = [center[0] + 10, center[1] - 10])
|> line(endAbsolute = [center[0] + 10, center[1] + 10])
|> line(endAbsolute = [center[0] - 10, center[1] + 10])
|> close()
|> extrude(length = 10)
}
myCube = cube(center = [0, 0])
```
*Pros*
- Any argument can be a parameter size, position, appearance, etc.
- Works great inside loops, arrays, or optimisation sweeps.
*Cons*
- Every invocation rebuilds the entire feature tree.
- **Slower** than a straight duplicate each call is its own render job.
### `clone` example
```kcl
sketch001 = startSketchOn(-XZ)
|> circle(center = [0, 0], radius = 10)
|> extrude(length = 5)
|> appearance(color = "#ff0000", metalness = 90, roughness = 90)
sketch002 = clone(sketch001) // ✓ instant copy
```
*Pros*
- Roughly an O(1) operation we just duplicate the underlying engine handle.
- Perfect when you need ten identical bolts or two copies of the same imported STEP file.
*Cons*
- **Not parametric** the clone is exactly the same shape as the source.
- If you need to tweak dimensions perinstance, youre back to a function.
> **Rule of thumb** Reach for `clone` when the geometry is already what you want. Reach for a function when you need customisation.
---
## Modulelevel parallelism
Under the hood, the Design Studio runs **every module in parallel** where it can. This means:
- The toplevel code of `foo.kcl`, `bar.kcl`, and `baz.kcl` all start executing immediately and concurrently.
- Imports that read foreign files (STEP/OBJ/…) overlap their I/O and background render.
- CPUbound calculations in separate modules get their own worker threads.
### Why modules beat onebigfile
If you shoehorn everything into `main.kcl`, each statement runs sequentially:
```norun
import "big.step" as gizmo // blocks main while reading
gizmo |> translate(x=50) // blocks again while waiting for render
```
Split `gizmo` into its own file and the read/render can overlap whatever else `main.kcl` is doing.
```norun
// gizmo.kcl (worker A)
import "big.step"
// main.kcl (worker B)
import "gizmo.kcl" as gizmo // nonblocking
// ... other setup ...
gizmo |> translate(x=50) // only blocks here
```
### Gotcha: defining but **not** calling functions
Defining a function inside a module is instantaneous we just record the bytecode. The heavy lifting happens when the function is **called**. So:
```norun
// util.kcl
export fn makeBolt(size) { /* … expensive CAD … */ }
```
If `main.kcl` waits until the very end to call `makeBolt`, *none* of that work was parallelised youve pushed the cost back onto the serial tail of your script.
**Better:** call it early or move the invocation into another module.
```norun
// bolt_instance.kcl
import makeBolt from "util.kcl"
bolt = makeBolt(5) // executed in parallel
bolt
```
Now `main.kcl` can `import "bolt_instance.kcl" as bolt` and get the result that was rendered while it was busy doing other things.
---
## Whole module import
You can also import the whole module. This is useful if you want to use the
result of a module as a variable, like a part.
```norun
import "cube.kcl"
cube
|> translate(x=10)
```
This imports the whole module and makes it available as `cube`. You can then
use it like any other object. The `cube` variable is now a reference to the
result of the module. This means that if you change the module, the `cube`
variable will change as well.
In `cube.kcl`, you cannot have multiple objects. It has to be a single part. If
you have multiple objects, you will get an error. This is because the module is
expected to return a single object that can be used as a variable.
The last expression or variable definition becomes the module's return value.
The module is expected to return a single object that can be used as a variable
by whatever imports it.
So for example, this is allowed:
```norun
... a bunch of code to create cube and cube2 ...
myUnion = union([cube, cube2])
```
You can also do this:
```norun
... a bunch of code to create cube and cube2 ...
union([cube, cube2])
```
Either way, the last line will return the union of the two objects.
Or what you could do instead is:
```norun
... a bunch of code to create cube and cube2 ...
myUnion = union([cube, cube2])
myUnion
```
This will assign the union of the two objects to a variable, and then return it
on the last statement. It's simply another way of doing the same thing.
The final statement is what's important because it's the return value of the
entire module. The module is expected to return a single object that can be used
as a variable by the file that imports it.
The name of the file or subdirectory is used as the name of the variable within the importing program.
If you want to use a different name, you can do so by using the `as` keyword:
```kcl,norun
import "cube.kcl" // Introduces a new variable called `cube`.
import "cube.kcl" as block // Introduces a new variable called `block`.
import "cube/main.kcl" // Introduces a new variable called `cube`.
import "cube/main.kcl" as block // Introduces a new variable called `block`.
```
If the filename includes hyphens (`-`) or starts with an underscore (`_`), then you must specify a
variable name.
---
## Multiple instances of the same import
Whether you are importing a file from another CAD system or a KCL file, that
file represents object(s) in memory. If you import the same file multiple times,
it will only be rendered once.
If you want to have multiple instances of the same object, you can use the
[`clone`](/docs/kcl/clone) function. This will render a new instance of the object in memory.
```norun
import cube from "cube.kcl"
cube
|> translate(x=10)
clone(cube)
|> translate(x=20)
```
In the sample above, the `cube` object is imported from a KCL file. The first
instance is translated 10 units in the x direction. The second instance is
cloned and translated 20 units in the x direction. The two instances are now
separate objects in memory, and can be manipulated independently.
Here is an example with a file from another CAD system:
```kcl
import "tests/inputs/cube.step"
cube
|> translate(x=10)
clone(cube)
|> translate(x=20)
```

View File

@ -1,52 +0,0 @@
---
title: "Numeric types and units"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
Numbers and numeric types in KCL include information about the units of the numbers. So rather than just having a number like `42`, we always have information about the units so we don't confuse 42 mm with 42 inches.
## Numeric literals
When writing a number literal, you can use a unit suffix to explicitly state the unit, e.g., `42mm`. The following units are available:
- Length units:
- metric: `mm`, `cm`, `m`
- imperial: `in`, `ft`, `yd`
- Angle units: `deg`, `rad`
- `_` to indicate a unitless number such as a count or ratio.
If you write a numeric literal without a suffix, then the defaults for the current file are used. These defaults are specified using the `@settings` attribute, see [settings](/docs/kcl-lang/settings) for details. Note that if using the defaults, the KCL interpreter won't know whether you intend the number to be a length, angle, or count and will treat it as being possibly any of them.
## Numeric types
Just like numbers carry units information, the `number` type also includes units information. Units are written in parentheses after the type, e.g., `number(mm)`.
Any of the suffixes described above can be used meaning that values with that type have the supplied units. E.g., `number(mm)` is the type of number values with mm units and `number(_)` is the type of number values with no units.
You can also use `number(Length)`, `number(Angle)`, or `number(Count)`. These types mean a number with any length, angle, or unitless (count) units, respectively (note that `number(_)` and `number(Count)` are equivalent since there is only one kind of unitless-ness).
Using just `number` means accepting any kind of number, even where the units are unknown by KCL.
## Function calls
When calling a function with an argument with numeric type, the declared numeric type in the function signature and the units of the argument value used in the function call must be compatible. Units are adjusted automatically. For example, if a function requires an argument with type `number(mm)`, then you can call it with `2in` and the units will be automatically adjusted, but calling it with `90deg` will cause an error.
## Mixing units with arithmetic
When doing arithmetic or comparisons, units will be adjusted as necessary if possible. However, often arithmetic expressions exceed the ability of KCL to accurately choose units which can result in warnings in your code or sometimes errors. In these cases, you will need to give KCL more information. Sometimes this can be done by making units explicit using suffixes. If not, then you will need to use *type ascription*, which asserts that an expression has the supplied type. For example, `(x * y): number(mm)` tells KCL that the units of `x * y` is mm. Note that type ascription does not do any adjustment of the numbers, e.g., `2mm: number(in)` has the value `2in` (note that this would be a very non-idiomatic way to use numeric type ascription, you could simply write `2in`. Usually type ascription is only necessary for supplying type information about the result of computation).
KCL has no support for area, volume, or other higher dimension units. When internal unit tracking requires multiple dimensions, KCL essentially gives up. This is usually where the extra type information described above is needed. If doing computation with higher dimensioned units, you must ensure that all adjustments occur before any computation. E.g., if you want to compute an area with unknown units, you must convert all numbers to the same unit before starting.
## Explicit conversions
You might sometimes need to convert from one unit to another for some calculation. You can do this implicitly when calling a function (see above), but if you can't or don't want to, then you can use the explicit conversion functions in the [`std::units`](/docs/kcl-std/modules/std-units) module.
KCL cannot know about changes to units caused by arithmetic. For example, you may intend for `10in * 25.4` to be the value `254mm` (i.e., `10in` in mm), however, the result of that computation in KCL is `254in`. It is always better to rely on automatic conversion or to use the explicit conversion functions, where possible.
Converting between degrees and radians using π ([`PI`](/docs/kcl-std/consts/std-math-PI) in KCL) is especially prone to this error and so the `PI` constant always requires specifying units of any computation it is used with. E.g., `radius = (circumference / (2 * PI)): number(mm)`.

View File

@ -1,66 +0,0 @@
---
title: "Pipelines"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
It can be hard to read repeated function calls, because of all the nested brackets.
```norun
i = 1
x = h(g(f(i)))
```
You can make this easier to read by breaking it into many declarations, but that is a bit annoying.
```norun
i = 1
x0 = f(i)
x1 = g(x0)
x = h(x1)
```
Instead, you can use the pipeline operator (`|>`) to simplify this.
Basically, `x |> f(%)` is a shorthand for `f(x)`. The left-hand side of the `|>` gets put into
the `%` in the right-hand side.
So, this means `x |> f(%) |> g(%)` is shorthand for `g(f(x))`. The code example above, with its
somewhat-clunky `x0` and `x1` constants could be rewritten as
```norun
i = 1
x = i
|> f(%)
|> g(%)
|> h(%)
```
This helps keep your code neat and avoid unnecessary declarations.
## Pipelines and keyword arguments
Say you have a long pipeline of sketch functions, like this:
```norun
startSketchOn(XZ)
|> line(%, end = [3, 4])
|> line(%, end = [10, 10])
|> line(%, end = [-13, -14])
|> close(%)
```
In this example, each function call outputs a sketch, and it gets put into the next function call via
the `%`, into the first (unlabeled) argument.
If a function call uses an unlabeled first parameter, it will default to `%` if it's not given. This
means that `|> line(%, end = [3, 4])` and `|> line(end = [3, 4])` are equivalent! So the above
could be rewritten as
```norun
startSketchOn(XZ)
|> line(end = [3, 4])
|> line(end = [10, 10])
|> line(end = [-13, -14])
|> close()
```

View File

@ -1,165 +0,0 @@
---
title: "Values and types"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
`KCL` defines the following types and keywords the language.
All these types can be nested in various forms where nesting applies. Like
arrays can hold objects and vice versa.
## Constant declaration
Constants are defined with a name and a value, like so:
```
myBool = false
```
Currently you cannot redeclare a constant.
## Objects
An object is defined with `{}` braces. Here is an example object:
```
myObj = { a = 0, b = "thing" }
```
To get the property of an object, you can call `myObj.a`, which in the above
example returns 0.
## `ImportedGeometry`
Using `import` you can import geometry defined using other CAD software. In KCL,
these objects have type `ImportedGeometry` and can mostly be treated like any
other solid (they can be rotated, scaled, etc.), although there is no access to
their internal components. See the [modules and imports docs](modules) for more
detail on importing geometry.
## Tags
Tags are used to give a name (tag) to a specific path.
### Tag declarations - `TagDecl`
The syntax for declaring a tag is `$myTag` you would use it in the following
way:
```norun
startSketchOn(XZ)
|> startProfile(at = origin)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001)
|> angledLine(
angle = segAng(rectangleSegmentA001) - 90,
length = 196.99,
tag = $rectangleSegmentB001,
)
|> angledLine(
angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001),
tag = $rectangleSegmentC001,
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
```
When a function requires declaring a new tag (using the `$` syntax), the argument has type [`TagDecl`](/docs/kcl-std/types/std-types-TagDecl).
### Tag identifiers
A tag created using a tag declarator can be used by writing its name without the `$`, e.g., `myTag`.
Where necessary to disambiguate from tag declarations, we call these tag identifiers.
In the example above we use the tag identifier `rectangleSegmentA001` to get the angle of the segment
using `segAng(rectangleSegmentA001)`.
Tags can identify either an edge or face of a solid, or a line or other edge of a sketch. Functions
which take a tag identifier as an argument will use either [`TaggedEdge`](/docs/kcl-std/types/std-types-TaggedEdge) (for the edge of a
solid or sketch) or [`TaggedFace`](/docs/kcl-std/types/std-types-TaggedFace).
If a line in a sketch is tagged and then the sketch is extruded, the tag is a `TaggedEdge` before
extrusion and a `TaggedFace` after extrusion.
#### `START` and `END`
[`START`](/docs/kcl-std/consts/std-START) and [`END`](/docs/kcl-std/consts/std-END) are special tags
for identifying the starting and ending faces of an extruded solid.
### Tag Scope
Tags are scoped globally if in the root context meaning in this example you can
use the tag `rectangleSegmentA001` in any function or expression in the file.
However if the code was written like this:
```norun
fn rect(origin) {
return startSketchOn(XZ)
|> startProfile(at = origin)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001)
|> angledLine(
angle = segAng(rectangleSegmentA001) - 90,
length = 196.99,
tag = $rectangleSegmentB001,
)
|> angledLine(
angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001),
tag = $rectangleSegmentC001,
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
}
rect(origin = [0, 0])
rect(origin = [20, 0])
```
Those tags would only be available in the `rect` function and not globally.
However you likely want to use those tags somewhere outside the `rect` function.
Tags are accessible through the sketch group they are declared in.
For example the following code works.
```norun
fn rect(origin) {
return startSketchOn(XZ)
|> startProfile(at = origin)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001)
|> angledLine(
angle = segAng(rectangleSegmentA001) - 90,
length = 196.99,
tag = $rectangleSegmentB001,
)
|> angledLine(
angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001),
tag = $rectangleSegmentC001,
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
}
rect(origin = [0, 0])
myRect = rect(origin = [20, 0])
myRect
|> extrude(length = 10)
|> fillet(radius = 0.5, tags = [myRect.tags.rectangleSegmentA001])
```
See how we use the tag `rectangleSegmentA001` in the `fillet` function outside
the `rect` function. This is because the `rect` function is returning the
sketch group that contains the tags.
---
If you find any issues using any of the above expressions or syntax,
please file an issue with the `ast` label on the [modeling-app
repo](https://github.com/KittyCAD/modeling-app/issues/new).

View File

@ -1,5 +0,0 @@
# Autogenerated docs
Everything in this directory and its subdirectories (except this file) is automatically generated. Do not edit anything in this directory directly, your changes will be lost.
The directory contents are generated by running the `test_generate_stdlib_markdown_docs` test in `/rust/kcl-lib/src/docs/gen_std_tests.rs`. Files are generated from the standard library declared in KCL (`/rust/kcl-lib/std`) and in Rust (`/rust/kcl-lib/src/std`), and by copying files from `../kcl-src`.

View File

@ -1,20 +0,0 @@
---
title: "END"
subtitle: "Constant in std"
excerpt: "Identifies the ending face of an extrusion. I.e., the new face created by an extrusion."
layout: manual
---
Identifies the ending face of an extrusion. I.e., the new face created by an extrusion.
```kcl
END: TaggedFace
```
### Type
[`TaggedFace`](/docs/kcl-std/types/std-types-TaggedFace) - A tag which references a face of a solid, including the distinguished tags `START` and `END`.

View File

@ -1,20 +0,0 @@
---
title: "START"
subtitle: "Constant in std"
excerpt: "Identifies the starting face of an extrusion. I.e., the face which is extruded."
layout: manual
---
Identifies the starting face of an extrusion. I.e., the face which is extruded.
```kcl
START: TaggedFace
```
### Type
[`TaggedFace`](/docs/kcl-std/types/std-types-TaggedFace) - A tag which references a face of a solid, including the distinguished tags `START` and `END`.

View File

@ -1,20 +0,0 @@
---
title: "X"
subtitle: "Constant in std"
excerpt: "The X-axis (can be used in both 2d and 3d contexts)."
layout: manual
---
The X-axis (can be used in both 2d and 3d contexts).
```kcl
X: Axis3d
```
### Type
[`Axis3d`](/docs/kcl-std/types/std-types-Axis3d) - An abstract and infinite line in 3d space.

View File

@ -1,20 +0,0 @@
---
title: "XY"
subtitle: "Constant in std"
excerpt: "An abstract 3d plane aligned with the X and Y axes. Its normal is the positive Z axis."
layout: manual
---
An abstract 3d plane aligned with the X and Y axes. Its normal is the positive Z axis.
```kcl
XY: Plane
```
### Type
[`Plane`](/docs/kcl-std/types/std-types-Plane) - An abstract plane.

View File

@ -1,20 +0,0 @@
---
title: "XZ"
subtitle: "Constant in std"
excerpt: "An abstract 3d plane aligned with the X and Z axes. Its normal is the negative Y axis."
layout: manual
---
An abstract 3d plane aligned with the X and Z axes. Its normal is the negative Y axis.
```kcl
XZ: Plane
```
### Type
[`Plane`](/docs/kcl-std/types/std-types-Plane) - An abstract plane.

View File

@ -1,20 +0,0 @@
---
title: "Y"
subtitle: "Constant in std"
excerpt: "The Y-axis (can be used in both 2d and 3d contexts)."
layout: manual
---
The Y-axis (can be used in both 2d and 3d contexts).
```kcl
Y: Axis3d
```
### Type
[`Axis3d`](/docs/kcl-std/types/std-types-Axis3d) - An abstract and infinite line in 3d space.

View File

@ -1,20 +0,0 @@
---
title: "YZ"
subtitle: "Constant in std"
excerpt: "An abstract 3d plane aligned with the Y and Z axes. Its normal is the positive X axis."
layout: manual
---
An abstract 3d plane aligned with the Y and Z axes. Its normal is the positive X axis.
```kcl
YZ: Plane
```
### Type
[`Plane`](/docs/kcl-std/types/std-types-Plane) - An abstract plane.

View File

@ -1,20 +0,0 @@
---
title: "Z"
subtitle: "Constant in std"
excerpt: "The 3D Z-axis."
layout: manual
---
The 3D Z-axis.
```kcl
Z: Axis3d
```
### Type
[`Axis3d`](/docs/kcl-std/types/std-types-Axis3d) - An abstract and infinite line in 3d space.

View File

@ -1,20 +0,0 @@
---
title: "sweep::SKETCH_PLANE"
subtitle: "Constant in std::sweep"
excerpt: "Local/relative to a position centered within the plane being sketched on"
layout: manual
---
Local/relative to a position centered within the plane being sketched on
```kcl
sweep::SKETCH_PLANE: string = 'sketchPlane'
```
### Type
[`string`](/docs/kcl-std/types/std-types-string) - A sequence of characters

View File

@ -1,20 +0,0 @@
---
title: "sweep::TRAJECTORY"
subtitle: "Constant in std::sweep"
excerpt: "Local/relative to the trajectory curve"
layout: manual
---
Local/relative to the trajectory curve
```kcl
sweep::TRAJECTORY: string = 'trajectoryCurve'
```
### Type
[`string`](/docs/kcl-std/types/std-types-string) - A sequence of characters

View File

@ -1,20 +0,0 @@
---
title: "turns::HALF_TURN"
subtitle: "Constant in std::turns"
excerpt: "A half turn, 180 degrees or π radians."
layout: manual
---
A half turn, 180 degrees or π radians.
```kcl
turns::HALF_TURN: number(deg) = 180deg
```
### Type
[`number(deg)`](/docs/kcl-std/types/std-types-number) - A number.

View File

@ -1,20 +0,0 @@
---
title: "turns::QUARTER_TURN"
subtitle: "Constant in std::turns"
excerpt: "A quarter turn, 90 degrees or π/2 radians."
layout: manual
---
A quarter turn, 90 degrees or π/2 radians.
```kcl
turns::QUARTER_TURN: number(deg) = 90deg
```
### Type
[`number(deg)`](/docs/kcl-std/types/std-types-number) - A number.

View File

@ -1,20 +0,0 @@
---
title: "turns::THREE_QUARTER_TURN"
subtitle: "Constant in std::turns"
excerpt: "Three quarters of a turn, 270 degrees or 1.5*π radians."
layout: manual
---
Three quarters of a turn, 270 degrees or 1.5*π radians.
```kcl
turns::THREE_QUARTER_TURN: number(deg) = 270deg
```
### Type
[`number(deg)`](/docs/kcl-std/types/std-types-number) - A number.

View File

@ -1,20 +0,0 @@
---
title: "turns::ZERO"
subtitle: "Constant in std::turns"
excerpt: "No turn, zero degrees/radians."
layout: manual
---
No turn, zero degrees/radians.
```kcl
turns::ZERO: number(Angle)
```
### Type
[`number(Angle)`](/docs/kcl-std/types/std-types-number) - A number.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,60 +0,0 @@
---
title: "assert"
subtitle: "Function in std"
excerpt: "Check a value meets some expected conditions at runtime. Program terminates with an error if conditions aren't met. If you provide multiple conditions, they will all be checked and all must be met."
layout: manual
---
Check a value meets some expected conditions at runtime. Program terminates with an error if conditions aren't met. If you provide multiple conditions, they will all be checked and all must be met.
```kcl
assert(
@actual: number,
isGreaterThan?: number,
isLessThan?: number,
isGreaterThanOrEqual?: number,
isLessThanOrEqual?: number,
isEqualTo?: number,
tolerance?: number,
error?: string,
)
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `actual` | [`number`](/docs/kcl-std/types/std-types-number) | Value to check. If this is the boolean value true, assert passes. Otherwise it fails.. | Yes |
| `isGreaterThan` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is greater than this. | No |
| `isLessThan` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is less than this. | No |
| `isGreaterThanOrEqual` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is greater than or equal to this. | No |
| `isLessThanOrEqual` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is less than or equal to this. | No |
| `isEqualTo` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is less than or equal to this. | No |
| `tolerance` | [`number`](/docs/kcl-std/types/std-types-number) | If `isEqualTo` is used, this is the tolerance to allow for the comparison. This tolerance is used because KCL's number system has some floating-point imprecision when used with very large decimal places. | No |
| `error` | [`string`](/docs/kcl-std/types/std-types-string) | If the value was false, the program will terminate with this error message | No |
### Examples
```kcl
n = 10
assert(n, isEqualTo = 10)
assert(
n,
isGreaterThanOrEqual = 0,
isLessThan = 100,
error = "number should be between 0 and 100",
)
assert(
1.0000000000012,
isEqualTo = 1,
tolerance = 0.0001,
error = "number should be almost exactly 1",
)
```

View File

@ -1,36 +0,0 @@
---
title: "assertIs"
subtitle: "Function in std"
excerpt: "Asserts that a value is the boolean value true."
layout: manual
---
Asserts that a value is the boolean value true.
```kcl
assertIs(
@actual: bool,
error?: string,
)
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `actual` | [`bool`](/docs/kcl-std/types/std-types-bool) | Value to check. If this is the boolean value true, assert passes. Otherwise it fails.. | Yes |
| `error` | [`string`](/docs/kcl-std/types/std-types-string) | If the value was false, the program will terminate with this error message | No |
### Examples
```kcl
kclIsFun = true
assertIs(kclIsFun)
```

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,41 +0,0 @@
---
title: "atan"
subtitle: "Function in std::math"
excerpt: "Compute the arctangent of a number."
layout: manual
---
Compute the arctangent of a number.
```kcl
atan(@num: number(_)): number(rad)
```
Consider using `atan2()` instead for the true inverse of tangent.
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `num` | [`number(_)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
### Returns
[`number(rad)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
sketch001 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> angledLine(angle = atan(1.25), length = 20)
|> yLine(endAbsolute = 0)
|> close()
extrude001 = extrude(sketch001, length = 5)
```

File diff suppressed because one or more lines are too long

View File

@ -1,39 +0,0 @@
---
title: "legAngX"
subtitle: "Function in std::math"
excerpt: "Compute the angle of the given leg for x."
layout: manual
---
Compute the angle of the given leg for x.
```kcl
legAngX(
hypotenuse: number(Length),
leg: number(Length),
): number(deg)
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `hypotenuse` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of the triangle's hypotenuse. | Yes |
| `leg` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of one of the triangle's legs (i.e. non-hypotenuse side). | Yes |
### Returns
[`number(deg)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
legAngX(hypotenuse = 5, leg = 3)
```

View File

@ -1,39 +0,0 @@
---
title: "legAngY"
subtitle: "Function in std::math"
excerpt: "Compute the angle of the given leg for y."
layout: manual
---
Compute the angle of the given leg for y.
```kcl
legAngY(
hypotenuse: number(Length),
leg: number(Length),
): number(deg)
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `hypotenuse` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of the triangle's hypotenuse. | Yes |
| `leg` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of one of the triangle's legs (i.e. non-hypotenuse side). | Yes |
### Returns
[`number(deg)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
legAngY(hypotenuse = 5, leg = 3)
```

View File

@ -1,39 +0,0 @@
---
title: "legLen"
subtitle: "Function in std::math"
excerpt: "Compute the length of the given leg."
layout: manual
---
Compute the length of the given leg.
```kcl
legLen(
hypotenuse: number(Length),
leg: number(Length),
): number(Length)
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `hypotenuse` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of the triangle's hypotenuse. | Yes |
| `leg` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of one of the triangle's legs (i.e. non-hypotenuse side). | Yes |
### Returns
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
legLen(hypotenuse = 5, leg = 3)
```

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More