Compare commits

..

1 Commits

Author SHA1 Message Date
c44f81aa1e Disable rectangle tool 2024-07-30 13:10:12 -04:00
3906 changed files with 397435 additions and 13214434 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,absolutey,atleast,ue
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,**/Cargo.lock,./docs/kcl/*.md,./src-tauri/gen/schemas

View File

@ -1,19 +1,6 @@
# DO NOT commit secrets, overrides go in the ignored `.env.development.local`
NODE_ENV=development
DEV=true
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev VITE_KC_SITE_BASE_URL=https://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_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

View File

@ -1,7 +1,5 @@
NODE_ENV=production
VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.zoo.dev VITE_KC_API_BASE_URL=https://api.zoo.dev
VITE_KC_SITE_BASE_URL=https://zoo.dev VITE_KC_SITE_BASE_URL=https://zoo.dev
VITE_KC_SITE_APP_URL=https://app.zoo.dev
VITE_KC_SKIP_AUTH=false VITE_KC_SKIP_AUTH=false
VITE_KC_CONNECTION_TIMEOUT_MS=15000 VITE_KC_CONNECTION_TIMEOUT_MS=15000

12
.envrc
View File

@ -1,13 +1 @@
# Load optional shared environment variables
source_up_if_exists
# Load default development environment variables
dotenv .env.development
# Load optional environment variables overrides
dotenv_if_exists .env.development.local
# Load optional testing environment variables
dotenv_if_exists e2e/playwright/playwright-secrets.env
use flake . use flake .

View File

@ -1,6 +1,2 @@
rust/**/*.ts src/wasm-lib/*
!rust/kcl-language-server/client/src/**/*.ts
*.typegen.ts *.typegen.ts
packages/codemirror-lsp-client/dist/*
e2e/playwright/snapshots/prompt-to-edit/*
.vscode-test

38
.eslintrc Normal file
View File

@ -0,0 +1,38 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": [
"css-modules",
"suggest-no-throw",
],
"extends": [
"react-app",
"react-app/jest",
"plugin:css-modules/recommended"
],
"rules": {
"semi": [
"error",
"never"
],
"react-hooks/exhaustive-deps": "off",
"suggest-no-throw/suggest-no-throw": "warn",
},
"overrides": [
{
"files": ["e2e/**/*.ts"], // Update the pattern based on your file structure
"rules": {
"@typescript-eslint/no-floating-promises": "warn",
"testing-library/prefer-screen-queries": "off"
}
},
{
"files": ["src/**/*.test.ts"],
"rules": {
"suggest-no-throw/suggest-no-throw": "off",
}
}
]
}

View File

@ -1,141 +0,0 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": [
"react-perf",
"css-modules",
"jest",
"jsx-a11y",
"react",
"react-hooks",
"suggest-no-throw",
"testing-library",
"@typescript-eslint"
],
"extends": [
"plugin:css-modules/recommended",
"plugin:jsx-a11y/recommended",
"plugin:react-hooks/recommended"
],
"settings": {
"react": {
"version": "detect"
}
},
"rules": {
"no-array-constructor": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-array-delete": "error",
"@typescript-eslint/no-duplicate-enum-values": "error",
"@typescript-eslint/no-duplicate-type-constituents": "error",
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-extra-non-null-assertion": "error",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-for-in-array": "error",
"no-implied-eval": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-implied-eval": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
"@typescript-eslint/no-redundant-type-constituents": "error",
"@typescript-eslint/no-this-alias": "warn",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-unnecessary-type-constraint": "error",
"no-unused-vars": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-unused-vars": [
"error",
{
"varsIgnorePattern": "^_",
"argsIgnorePattern": "^_",
"ignoreRestSiblings": true,
"vars": "all",
"args": "none"
}
],
"@typescript-eslint/no-unsafe-unary-minus": "error",
"@typescript-eslint/no-wrapper-object-types": "error",
"no-throw-literal": "off", // Use @typescript-eslint/only-throw-error instead.
"@typescript-eslint/only-throw-error": "error",
"@typescript-eslint/prefer-as-const": "warn",
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",
"react/no-unknown-property": "error",
"no-restricted-globals": [
"error",
{
"name": "isNaN",
"message": "Use Number.isNaN() instead."
}
],
"no-restricted-syntax": [
"error",
{
"selector": "CallExpression[callee.object.name='Array'][callee.property.name='isArray']",
"message": "Use isArray() in lib/utils.ts instead of Array.isArray()."
},
{
"selector": "CallExpression[callee.object.name='TOML'][callee.property.name='stringify']",
"message": "Do not use TOML.stringify directly. Use the wrappers in test-utils instead like settingsToToml."
},
{
"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."
},
{
"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": [
"error",
{
"patterns": [
// Restrict all relative imports except for .css files.
{
"group": ["./*", "../*", "!./*.css", "!../*.css"],
"message": "Use absolute imports instead."
}
]
}
],
"semi": ["error", "never"],
"react-hooks/exhaustive-deps": "off",
"suggest-no-throw/suggest-no-throw": "error"
},
"overrides": [
{
"files": ["e2e/**/*.ts"], // Update the pattern based on your file structure
"extends": ["plugin:testing-library/react"],
"rules": {
"suggest-no-throw/suggest-no-throw": "off",
"testing-library/prefer-screen-queries": "off",
"jest/valid-expect": "off"
}
},
{
"files": ["src/**/*.test.ts"],
"extends": ["plugin:testing-library/react"],
"rules": {
"suggest-no-throw/suggest-no-throw": "off"
}
},
{
"files": ["packages/**/*.ts", "rust/**/*.ts"],
"extends": [],
"rules": {
"no-restricted-imports": "off"
}
}
]
}

13
.gitattributes vendored
View File

@ -1,13 +0,0 @@
# Set default behavior to automatically normalize line endings.
* text=auto
# Force batch scripts to always use CRLF line endings so that if a repo is accessed
# in Windows via a file share from Linux, the scripts will work.
*.{cmd,[cC][mM][dD]} text working-tree-encoding=UTF-16LE eol=CRLF
*.{bat,[bB][aA][tT]} text working-tree-encoding=UTF-16LE eol=CRLF
*.{ics,[iI][cC][sS]} text working-tree-encoding=UTF-16LE eol=CRLF
*.{ps1,[iP][sS][1]} text working-tree-encoding=UTF-16LE eol=CRLF
# Force bash scripts to always use LF line endings so that if a repo is accessed
# in Unix via a file share from Windows, the scripts will work.
*.sh text eol=lfol=lf

View File

@ -1,5 +1,5 @@
name: Bug Report name: Bug Report
description: File a bug report for the Zoo Design Studio description: File a bug report for the Zoo Modeling App
title: "[BUG]: " title: "[BUG]: "
labels: ["bug"] labels: ["bug"]
assignees: [] assignees: []
@ -70,7 +70,7 @@ body:
id: version id: version
attributes: attributes:
label: Version label: Version
description: "The version of the Zoo Design Studio you're using." description: "The version of the Zoo Modeling App you're using."
placeholder: "example: v0.15.0. You can find this in the settings." placeholder: "example: v0.15.0. You can find this in the settings."
validations: validations:
required: true required: true

View File

@ -1,8 +0,0 @@
FROM node:slim
COPY . /action
WORKDIR /action
RUN npm install --production
ENTRYPOINT ["node", "/action/main.js"]

View File

@ -1,21 +0,0 @@
# github-release
Copy-pasted from
https://github.com/bytecodealliance/wasmtime/tree/8acfdbdd8aa550d1b84e0ce1e6222a6605d14e38/.github/actions/github-release
An action used to publish GitHub releases for `wasmtime`.
As of the time of this writing there's a few actions floating around which
perform github releases but they all tend to have their set of drawbacks.
Additionally nothing handles deleting releases which we need for our rolling
`dev` release.
To handle all this, this action rolls its own implementation using the
actions/toolkit repository and packages published there. These run in a Docker
container and take various inputs to orchestrate the release from the build.
More comments can be found in `main.js`.
Testing this is really hard. If you want to try though run `npm install` and
then `node main.js`. You'll have to configure a bunch of env vars though to get
anything reasonably working.

View File

@ -1,15 +0,0 @@
name: "wasmtime github releases"
description: "wasmtime github releases"
inputs:
token:
description: ""
required: true
name:
description: ""
required: true
files:
description: ""
required: true
runs:
using: "docker"
image: "Dockerfile"

View File

@ -1,143 +0,0 @@
const core = require("@actions/core");
const path = require("path");
const fs = require("fs");
const github = require("@actions/github");
const glob = require("glob");
function sleep(milliseconds) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function runOnce() {
// Load all our inputs and env vars. Note that `getInput` reads from `INPUT_*`
const files = core.getInput("files");
const name = core.getInput("name");
const token = core.getInput("token");
const slug = process.env.GITHUB_REPOSITORY;
const owner = slug.split("/")[0];
const repo = slug.split("/")[1];
const sha = process.env.HEAD_SHA;
core.info(`files: ${files}`);
core.info(`name: ${name}`);
const options = {
request: {
timeout: 30000,
},
};
const octokit = github.getOctokit(token, options);
// Delete the previous release since we can't overwrite one. This may happen
// due to retrying an upload or it may happen because we're doing the dev
// release.
const releases = await octokit.paginate("GET /repos/:owner/:repo/releases", { owner, repo });
for (const release of releases) {
if (release.tag_name !== name) {
continue;
}
const release_id = release.id;
core.info(`deleting release ${release_id}`);
await octokit.rest.repos.deleteRelease({ owner, repo, release_id });
}
// We also need to update the `dev` tag while we're at it on the `dev` branch.
if (name == "nightly") {
try {
core.info(`updating nightly tag`);
await octokit.rest.git.updateRef({
owner,
repo,
ref: "tags/nightly",
sha,
force: true,
});
} catch (e) {
core.error(e);
core.info(`creating nightly tag`);
await octokit.rest.git.createTag({
owner,
repo,
tag: "nightly",
message: "nightly release",
object: sha,
type: "commit",
});
}
}
// Creates an official GitHub release for this `tag`, and if this is `dev`
// then we know that from the previous block this should be a fresh release.
core.info(`creating a release`);
const release = await octokit.rest.repos.createRelease({
owner,
repo,
name,
tag_name: name,
target_commitish: sha,
prerelease: name === "nightly",
});
const release_id = release.data.id;
// Upload all the relevant assets for this release as just general blobs.
for (const file of glob.sync(files)) {
const size = fs.statSync(file).size;
const name = path.basename(file);
await runWithRetry(async function () {
// We can't overwrite assets, so remove existing ones from a previous try.
let assets = await octokit.rest.repos.listReleaseAssets({
owner,
repo,
release_id,
});
for (const asset of assets.data) {
if (asset.name === name) {
core.info(`delete asset ${name}`);
const asset_id = asset.id;
await octokit.rest.repos.deleteReleaseAsset({ owner, repo, asset_id });
}
}
core.info(`upload ${file}`);
const headers = { "content-length": size, "content-type": "application/octet-stream" };
const data = fs.createReadStream(file);
await octokit.rest.repos.uploadReleaseAsset({
data,
headers,
name,
url: release.data.upload_url,
});
});
}
}
async function runWithRetry(f) {
const retries = 10;
const maxDelay = 4000;
let delay = 1000;
for (let i = 0; i < retries; i++) {
try {
await f();
break;
} catch (e) {
if (i === retries - 1) throw e;
core.error(e);
const currentDelay = Math.round(Math.random() * delay);
core.info(`sleeping ${currentDelay} ms`);
await sleep(currentDelay);
delay = Math.min(delay * 2, maxDelay);
}
}
}
async function run() {
await runWithRetry(runOnce);
}
run().catch((err) => {
core.error(err);
core.setFailed(err.message);
});

View File

@ -1,10 +0,0 @@
{
"name": "wasmtime-github-release",
"version": "0.0.0",
"main": "main.js",
"dependencies": {
"@actions/core": "^1.6",
"@actions/github": "^6.0",
"glob": "^11.0.1"
}
}

View File

@ -1,66 +0,0 @@
#!/bin/bash
# bash strict mode
set -euo pipefail
if [[ ! -f "test-results/.last-run.json" ]]; then
# If no last run artifact, than run Playwright normally
echo "run playwright normally"
if [[ "$3" == *ubuntu* ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:playwright:electron -- --shard=$1/$2 || true
elif [[ "$3" == *windows* ]]; then
npm run test:playwright:electron -- --grep=@windows --shard=$1/$2 || true
elif [[ "$3" == *macos* ]]; then
npm run test:playwright:electron -- --grep=@macos --shard=$1/$2 || true
else
echo "Do not run Playwright. Unable to detect os runtime."
exit 1
fi
# Log failures for Axiom to pick up
node playwrightProcess.mjs > /tmp/github-actions.log
fi
retry=1
max_retries=1
# Retry failed tests, doing our own retries because using inbuilt Playwright retries causes connection issues
while [[ $retry -le $max_retries ]]; do
if [[ -f "test-results/.last-run.json" ]]; then
status=$(jq -r '.status' test-results/.last-run.json)
if [[ "$status" == "failed" ]]; then
echo "retried=true" >>$GITHUB_OUTPUT
echo "run playwright with last failed tests and retry $retry"
if [[ "$3" == *ubuntu* ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:playwright:electron -- --last-failed || true
elif [[ "$3" == *windows* ]]; then
npm run test:playwright:electron -- --grep=@windows --last-failed || true
elif [[ "$3" == *macos* ]]; then
npm run test:playwright:electron -- --grep=@macos --last-failed || true
else
echo "Do not run playwright. Unable to detect os runtime."
exit 1
fi
# Log failures for Axiom to pick up
node playwrightProcess.mjs > /tmp/github-actions.log
retry=$((retry + 1))
else
echo "retried=false" >>$GITHUB_OUTPUT
exit 0
fi
else
echo "retried=false" >>$GITHUB_OUTPUT
exit 0
fi
done
echo "retried=false" >>$GITHUB_OUTPUT
if [[ -f "test-results/.last-run.json" ]]; then
status=$(jq -r '.status' test-results/.last-run.json)
if [[ "$status" == "failed" ]]; then
# If it still fails after retries, then fail the job
exit 1
fi
fi
exit 0

View File

@ -1,24 +0,0 @@
#!/bin/bash
set -euo pipefail
# Install vector
brew tap vectordotdev/brew && brew install vector
# Configure vector
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i '' "s#OS_NAME#${OS_NAME}#g" /tmp/vector.toml
sed -i '' "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i '' "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i '' "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i '' "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i '' "s#GH_ACTIONS_AXIOM_TOKEN#${GH_ACTIONS_AXIOM_TOKEN}#g" /tmp/vector.toml
# Display settings
echo
echo 'Vector config:'
cat /tmp/vector.toml
echo
# Start in the background
$(brew --prefix)/opt/vector/bin/vector --config /tmp/vector.toml &

View File

@ -1,24 +0,0 @@
#!/bin/bash
set -euo pipefail
# Install vector
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev | bash -s -- -y
# Configure vector
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#OS_NAME#${OS_NAME}#g" /tmp/vector.toml
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${GH_ACTIONS_AXIOM_TOKEN}#g" /tmp/vector.toml
# Display settings
echo
echo 'Vector config:'
cat /tmp/vector.toml
echo
# Start in background
${HOME}/.vector/bin/vector --config /tmp/vector.toml &

View File

@ -1,41 +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"
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 "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

750
.github/dependabot.yml vendored
View File

@ -1,721 +1,35 @@
# DO NOT EDIT THIS FILE. This dependabot file was generated # To get started with Dependabot version updates, you'll need to specify which
# by https://github.com/KittyCAD/ciso Changes to this file should be addressed in # package ecosystems to update and where the package manifests are located.
# the ciso repository. # Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2 version: 2
updates: updates:
- package-ecosystem: github-actions - package-ecosystem: 'npm' # See documentation for possible values
directory: / directory: '/' # Location of package manifests
schedule: schedule:
interval: weekly interval: 'daily'
day: monday reviewers:
time: '03:00' - franknoirot
timezone: America/Los_Angeles - irev-dev
open-pull-requests-limit: 5 - package-ecosystem: 'github-actions' # See documentation for possible values
groups: directory: '/' # Location of package manifests
security: schedule:
applies-to: security-updates interval: 'daily'
update-types: reviewers:
- minor - adamchalmers
- patch - jessfraz
security-major: - package-ecosystem: 'cargo' # See documentation for possible values
applies-to: security-updates directory: '/src/wasm-lib/' # Location of package manifests
update-types: schedule:
- major interval: 'daily'
patch: reviewers:
applies-to: version-updates - adamchalmers
update-types: - jessfraz
- patch - package-ecosystem: 'cargo' # See documentation for possible values
major: directory: '/src-tauri/' # Location of package manifests
applies-to: version-updates schedule:
update-types: interval: 'daily'
- major reviewers:
minor: - adamchalmers
applies-to: version-updates - jessfraz
update-types:
- minor
- patch
- package-ecosystem: cargo
directory: /rust
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-python-bindings
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-to-core
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-language-server-release
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-wasm-lib
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-derive-docs
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-bumper
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-language-server
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-lib
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-lib/fuzz
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-test-server
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: cargo
directory: /rust/kcl-directory-test-macro
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: /
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: /rust/kcl-language-server
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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-lang-kcl
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: /.github/actions/github-release
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: pip
directory: /rust/kcl-python-bindings
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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: docker
directory: /.github/actions/github-release
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:
- minor
- patch
security-major:
applies-to: security-updates
update-types:
- major
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

View File

@ -13,30 +13,21 @@ 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: Setup Rust
shell: bash uses: dtolnay/rust-toolchain@stable
run: | - name: Cache wasm
[ -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 uses: Swatinem/rust-cache@v2
with: with:
workspaces: rust workspaces: './src/wasm-lib'
- 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
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
with: with:
name: wasm-bundle name: wasm-bundle
path: rust/kcl-wasm-lib/pkg path: src/wasm-lib/pkg

View File

@ -1,385 +0,0 @@
name: build-apps
on:
pull_request:
push:
branches:
- main
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
env:
IS_RELEASE: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }}
IS_NIGHTLY: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
prepare-files:
runs-on: ubuntu-22.04 # seperate job on Ubuntu for easy string manipulations (compared to Windows)
outputs:
version: ${{ steps.export_version.outputs.version }}
notes: ${{ steps.export_notes.outputs.notes }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- id: filter
name: Check for Rust changes
uses: dorny/paths-filter@v3
with:
filters: |
rust:
- 'rust/**'
- name: Download Wasm Cache
id: download-wasm
if: ${{ github.event_name == 'pull_request' && steps.filter.outputs.rust == 'false' }}
uses: dawidd6/action-download-artifact@v7
continue-on-error: true
with:
github_token: ${{secrets.GITHUB_TOKEN}}
name: wasm-bundle
workflow: build-and-store-wasm.yml
branch: main
path: rust/kcl-wasm-lib/pkg
- name: Build WASM condition
id: wasm
run: |
set -euox pipefail
# Build wasm if this is a push to main or tag, there are Rust changes, or
# downloading from the wasm cache failed.
if [[ ${{github.event_name}} == 'push' || ${{steps.filter.outputs.rust}} == 'true' || ${{steps.download-wasm.outcome}} == 'failure' ]]; then
echo "should-build-wasm=true" >> $GITHUB_OUTPUT
else
echo "should-build-wasm=false" >> $GITHUB_OUTPUT
fi
- name: Use correct Rust toolchain
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
with:
tool: wasm-pack
- name: Rust Cache
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
uses: Swatinem/rust-cache@v2
with:
workspaces: rust
- name: Run build:wasm
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
run: "npm run build:wasm"
- name: Set nightly version, product name, release notes, and icons
if: ${{ env.IS_NIGHTLY == 'true' }}
run: |
COMMIT=$(git rev-parse --short HEAD)
DATE=$(date +'%-y.%-m.%-d')
export VERSION=$DATE-main.$COMMIT
npm run files:set-version
npm run files:flip-to-nightly
- name: Set release version
if: ${{ env.IS_RELEASE == 'true' }}
run: |
export VERSION=${GITHUB_REF_NAME#v}
npm run files:set-version
- uses: actions/upload-artifact@v4
with:
name: prepared-files
path: |
package.json
electron-builder.yml
rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
release-notes.md
assets/icon.ico
assets/icon.png
- id: export_version
run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT"
- id: export_notes
run: echo "notes=`cat release-notes.md`" >> "$GITHUB_OUTPUT"
build-apps:
needs: [prepare-files]
strategy:
fail-fast: false
matrix:
include:
- os: macos-14
platform: mac
- os: windows-2022
platform: win
- os: ubuntu-22.04
platform: linux
runs-on: ${{ matrix.os }}
env:
VERSION_NO_V: ${{ needs.prepare-files.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
name: prepared-files
- name: Copy prepared files
run: |
ls -R prepared-files
cp prepared-files/package.json package.json
cp prepared-files/electron-builder.yml electron-builder.yml
cp prepared-files/rust/kcl-wasm-lib/pkg/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-files/rust/kcl-wasm-lib/pkg/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
cp prepared-files/release-notes.md release-notes.md
cp prepared-files/assets/icon.ico assets/icon.ico
cp prepared-files/assets/icon.png assets/icon.png
- name: Sync node version and setup cache
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm' # Set this to npm, npm or pnpm.
- run: npm install
- name: Prepare certificate and variables (Windows only)
if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }}
run: |
echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
cat /d/Certificate_pkcs12.p12
echo "::set-output name=version::${GITHUB_REF#refs/tags/v}"
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$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 "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\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH
shell: bash
- name: Setup certicate with SSM KSP (Windows only)
if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }}
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
msiexec /i smtools-windows-x64.msi /quiet /qn
smksp_registrar.exe list
smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe
smctl windows certsync
# This last line `smctl windows certsync` was added after windows codesign failures started happening
# with nightly-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
- name: Build the app (debug)
if: ${{ env.IS_RELEASE == 'false' && env.IS_NIGHTLY == 'false' }}
# 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
run: npm run tronb:package:dev
- name: Build the app (release)
if: ${{ env.IS_RELEASE == 'true' || env.IS_NIGHTLY == '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 }}
run: npm run tronb:package:prod
- name: List artifacts in out/
run: ls -R out
- uses: actions/upload-artifact@v4
with:
name: out-arm64-${{ matrix.platform }}
# first two will pick both Zoo Design Studio-$VERSION-arm64-win.exe and Zoo Design Studio-$VERSION-win.exe
path: |
out/*-${{ env.VERSION_NO_V }}-win.*
out/*-${{ env.VERSION_NO_V }}-arm64-win.*
out/*-arm64-mac.*
out/*-arm64-linux.*
- uses: actions/upload-artifact@v4
with:
name: out-x64-${{ matrix.platform }}
path: |
out/*-x64-win.*
out/*-x64-mac.*
out/*-x86_64-linux.*
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true' }}
with:
name: out-yml-${{ matrix.platform }}
path: |
out/latest*.yml
# TODO: add the 'Build for Mac TestFlight (nightly)' stage back
upload-apps-release:
runs-on: ubuntu-22.04
permissions:
contents: write
# Equivalent to IS_RELEASE || IS_NIGHTLY (but we can't access those env vars here)
if: ${{ (github.ref_type == 'tag' && startsWith(github.ref_name, 'v')) || (github.event_name == 'push' && github.ref == 'refs/heads/main') }}
env:
VERSION_NO_V: ${{ needs.prepare-files.outputs.version }}
VERSION: ${{ format('v{0}', needs.prepare-files.outputs.version) }}
needs: [prepare-files, build-apps]
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: out-arm64-win
path: out
- uses: actions/download-artifact@v4
with:
name: out-x64-win
path: out
- uses: actions/download-artifact@v4
with:
name: out-yml-win
path: out
- uses: actions/download-artifact@v4
with:
name: out-arm64-mac
path: out
- uses: actions/download-artifact@v4
with:
name: out-x64-mac
path: out
- uses: actions/download-artifact@v4
with:
name: out-yml-mac
path: out
- uses: actions/download-artifact@v4
with:
name: out-arm64-linux
path: out
- uses: actions/download-artifact@v4
with:
name: out-x64-linux
path: out
- uses: actions/download-artifact@v4
with:
name: out-yml-linux
path: out
- name: Generate the download static endpoint
env:
NOTES: ${{ needs.prepare-files.outputs.notes }}
PUB_DATE: ${{ github.event.repository.updated_at }}
WEBSITE_DIR: ${{ env.IS_NIGHTLY == 'true' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }}
URL_CODED_NAME: ${{ env.IS_NIGHTLY == 'true' && 'Zoo%20Design%20Studio%20%28Nightly%29' || 'Zoo%20Design%20Studio' }}
run: |
RELEASE_DIR=https://${WEBSITE_DIR}
jq --null-input \
--arg version "${VERSION}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg mac_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-mac.dmg" \
--arg mac_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-mac.dmg" \
--arg windows_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-win.exe" \
--arg windows_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-win.exe" \
--arg linux_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-linux.AppImage" \
--arg linux_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x86_64-linux.AppImage" \
'{
"version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": {
"dmg-arm64": {
"url": $mac_arm64_url
},
"dmg-x64": {
"url": $mac_x64_url
},
"exe-arm64": {
"url": $windows_arm64_url
},
"exe-x64": {
"url": $windows_x64_url
},
"appimage-arm64": {
"url": $linux_arm64_url
},
"appimage-x64": {
"url": $linux_x64_url
}
}
}' > out/last_download.json
cat out/last_download.json
- uses: actions/upload-artifact@v4
with:
name: out-download-json
path: out/last_download.json
- name: List artifacts
run: "ls -R out"
- name: Authenticate to Google Cloud
if: ${{ env.IS_NIGHTLY == 'true' }}
uses: 'google-github-actions/auth@v2.1.8'
with:
credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}'
- name: Set up Google Cloud SDK
if: ${{ env.IS_NIGHTLY == 'true' }}
uses: google-github-actions/setup-gcloud@v2.1.4
with:
project_id: ${{ env.GOOGLE_CLOUD_PROJECT_ID }}
- name: Upload nightly files to public bucket
if: ${{ env.IS_NIGHTLY == 'true' }}
uses: google-github-actions/upload-cloud-storage@v2.2.2
with:
path: out
glob: '*'
parent: false
destination: 'dl.kittycad.io/releases/modeling-app/nightly'
- name: Invalidate bucket cache on latest*.yml and last_download.json files
if: ${{ env.IS_NIGHTLY == 'true' }}
run: npm run 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

@ -16,42 +16,29 @@ on:
- '**/rust-toolchain.toml' - '**/rust-toolchain.toml'
- .github/workflows/cargo-bench.yml - .github/workflows/cargo-bench.yml
workflow_dispatch: workflow_dispatch:
permissions: permissions: read-all
contents: read
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 bench name: cargo bench
jobs: jobs:
cargo-bench: cargo-bench:
name: cargo bench name: Benchmark with iai
runs-on: ubuntu-latest runs-on: ubuntu-latest-8-cores
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use correct Rust toolchain - uses: dtolnay/rust-toolchain@stable
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: rust
- name: Install dependencies - name: Install dependencies
run: | run: |
cargo install cargo-criterion cargo install cargo-criterion
cargo install cargo-codspeed sudo apt update
cd rust/kcl-lib sudo apt install -y valgrind
cargo add --dev codspeed-criterion-compat --rename criterion - name: Rust Cache
- name: Build the benchmark target(s) uses: Swatinem/rust-cache@v2.6.1
run: | - name: Benchmark kcl library
cd rust shell: bash
cargo codspeed build run: |-
- name: Run the benchmarks cd src/wasm-lib/kcl; cargo bench --all-features -- iai
uses: CodSpeedHQ/action@v3
with:
working-directory: rust
run: cargo codspeed run
token: ${{ secrets.CODSPEED_TOKEN }}
env: env:
KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN }} KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}

View File

@ -17,21 +17,24 @@ jobs:
cargocheck: cargocheck:
name: cargo check name: cargo check
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
dir: ['src/wasm-lib']
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use correct Rust toolchain - name: Install latest rust
shell: bash uses: actions-rs/toolchain@v1
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache-workspaces: rust toolchain: stable
override: true
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1
- name: Run check - name: Run check
run: | run: |
cd rust cd "${{ matrix.dir }}"
# We specifically want to test the disable-println feature # We specifically want to test the disable-println feature
# Since it is not enabled by default, we need to specify it # Since it is not enabled by default, we need to specify it
# This is used in kcl-lsp # This is used in kcl-lsp
cargo check --workspace --features disable-println --features pyo3 --features cli cargo check --all --features disable-println --features pyo3

View File

@ -23,23 +23,43 @@ jobs:
cargoclippy: cargoclippy:
name: cargo clippy name: cargo clippy
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
dir: ['src/wasm-lib', 'src-tauri']
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: taiki-e/install-action@just - name: Install latest rust
- name: Use correct Rust toolchain uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
components: clippy
- name: install dependencies
if: matrix.dir == 'src-tauri'
shell: bash shell: bash
run: | run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./ sudo apt-get update
- name: Install rust sudo apt-get install -y \
uses: actions-rust-lang/setup-rust-toolchain@v1 libgtk-3-dev \
with: libayatana-appindicator3-dev \
cache-workspaces: rust webkit2gtk-driver \
components: clippy libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev \
libwebkit2gtk-4.1-dev \
at-spi2-core \
xvfb
yarn install
yarn build:wasm
yarn build:local
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1
- name: Run clippy - name: Run clippy
run: | run: |
cd rust cd "${{ matrix.dir }}"
just lint cargo clippy --all --tests --benches -- -D warnings
# If this fails, run "cargo check" to update Cargo.lock, # If this fails, run "cargo check" to update Cargo.lock,
# then add Cargo.lock to the PR. # then add Cargo.lock to the PR.
- name: Check Cargo.lock doesn't need updating - name: Check Cargo.lock doesn't need updating

View File

@ -26,20 +26,23 @@ jobs:
cargofmt: cargofmt:
name: cargo fmt name: cargo fmt
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
dir: ['src/wasm-lib', 'src-tauri']
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use correct Rust toolchain - name: Install latest rust
shell: bash uses: actions-rs/toolchain@v1
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache-workspaces: rust toolchain: stable
components: rustfmt override: true
components: rustfmt
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1
- name: Run cargo fmt - name: Run cargo fmt
run: | run: |
cd rust cd "${{ matrix.dir }}"
cargo fmt -- --check cargo fmt -- --check
shell: bash shell: bash

57
.github/workflows/cargo-test-tauri.yml vendored Normal file
View File

@ -0,0 +1,57 @@
on:
push:
branches:
- main
paths:
- 'src-tauri/**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-test-tauri.yml
pull_request:
paths:
- 'src-tauri/**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-test-tauri.yml
workflow_dispatch:
permissions: read-all
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
name: cargo test of tauri
jobs:
cargotest:
name: cargo test
runs-on: ubuntu-latest-8-cores
strategy:
matrix:
dir: ['src-tauri']
steps:
- uses: actions/checkout@v4
- name: Install latest rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: install dependencies
if: matrix.dir == 'src-tauri'
run: |
sudo apt-get update
sudo apt-get install -y \
libgtk-3-dev \
libayatana-appindicator3-dev \
webkit2gtk-driver \
libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev \
libwebkit2gtk-4.1-dev \
at-spi2-core \
xvfb
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1
- name: cargo test
shell: bash
run: |-
cd "${{ matrix.dir }}"
cargo test --all

View File

@ -2,276 +2,77 @@ on:
push: push:
branches: branches:
- main - main
paths:
- 'src/wasm-lib/**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-test.yml
pull_request: pull_request:
paths:
- 'src/wasm-lib/**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-test.yml
workflow_dispatch: workflow_dispatch:
permissions: permissions: read-all
contents: read
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 name: cargo test of wasm-lib
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:
- uses: runs-on/action@v1
- 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: 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: Install just
uses: taiki-e/install-action@just
- name: Install cargo-insta
shell: bash
run: |
cargo install cargo-insta
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: rust
- 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 "outside-kcl-samples=true" >> $GITHUB_OUTPUT
exit 0
fi
changed_files=$(git diff --name-only origin/${{ github.base_ref }})
echo "$changed_files"
if grep -Evq '^public/kcl-samples/|^rust/kcl-lib/tests/kcl_samples/' <<< "$changed_files" ; then
echo "outside-kcl-samples=true" >> $GITHUB_OUTPUT
else
echo "outside-kcl-samples=false" >> $GITHUB_OUTPUT
fi
- name: cargo test only kcl-samples
id: cargo-test-kcl-samples
if: steps.path-changes.outputs.outside-kcl-samples == 'false'
continue-on-error: true
shell: bash
run: |
set -euo pipefail
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
env:
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
ZOO_HOST: https://api.dev.zoo.dev
RUST_BACKTRACE: full
- name: Commit differences
if: steps.path-changes.outputs.outside-kcl-samples == 'false' && steps.cargo-test-kcl-samples.outcome == 'failure'
shell: bash
run: |
set -euo pipefail
pushd rust
just overwrite-sim-test kcl_samples
popd
git add \
rust/kcl-lib/tests \
public/kcl-samples
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 }}
if ! git commit -m "Update kcl-samples simulation test output" ; then
echo "No changes to commit"
# This only runs if tests failed, so we should fail the step.
exit 1
fi
git push origin ${{ github.head_ref }}
env:
# The default is auto, and insta behaves differently in CI vs. not.
INSTA_UPDATE: always
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
ZOO_HOST: https://api.dev.zoo.dev
# Configure nextest when it's run by insta (via just).
NEXTEST_PROFILE: ci
RUST_BACKTRACE: full
- name: Build and archive tests
run: |
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@v1
- 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: 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
run: |-
cp nextest-archive.tar.zst rust/nextest-archive.tar.zst
ls -lah
cd rust
cargo nextest run \
--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:
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
ZOO_HOST: https://api.dev.zoo.dev
- name: Upload results
if: always()
run: .github/ci-cd-scripts/upload-results.sh
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 }}
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@v1
- 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: 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}}
run-wasm-tests:
name: Run wasm tests
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest] dir: ['src/wasm-lib']
fail-fast: false
runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use correct Rust toolchain - name: Install latest rust
shell: bash uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: install dependencies
if: matrix.dir == 'src-tauri'
run: | run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./ sudo apt-get update
- name: Install rust sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
uses: actions-rust-lang/setup-rust-toolchain@v1 - name: Install vector
with: run: |
cache: false # Configured below. curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc chmod +x /tmp/vector.sh
with: /tmp/vector.sh -y -no-modify-path
tool: wasm-pack mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
cat /tmp/vector.toml
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
- uses: taiki-e/install-action@cargo-llvm-cov
- uses: taiki-e/install-action@nextest
- name: Rust Cache - name: Rust Cache
uses: Swatinem/rust-cache@v2 uses: Swatinem/rust-cache@v2.6.1
with: - name: cargo test
workspaces: './rust'
- name: Build Wasm
shell: bash shell: bash
run: | run: |-
npm install cd "${{ matrix.dir }}"
npm run build:wasm cargo llvm-cov nextest --all --lcov --output-path lcov.info --test-threads=1 --no-fail-fast -P ci 2>&1 | tee /tmp/github-actions.log
- name: Run wasm tests
run: |
cd rust
cd kcl-wasm-lib
#wasm-pack test --headless --chrome
env: env:
KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
NODE_ENV: development RUST_MIN_STACK: 10485760000
- name: Upload to codecov.io
uses: codecov/codecov-action@v4
with:
token: ${{secrets.CODECOV_TOKEN}}
fail_ci_if_error: true
flags: wasm-lib
verbose: true
files: lcov.info

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

@ -0,0 +1,36 @@
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;
// Post a comment on the PR
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body: message,
});

View File

@ -1,48 +0,0 @@
name: Check kcl-samples files for proper header structure
on:
pull_request:
paths:
- 'public/kcl-samples/**/*.kcl'
- .github/workflows/check-kcl-header.yml
branches:
- main
push:
paths:
- 'public/kcl-samples/**/*.kcl'
- .github/workflows/check-kcl-header.yml
branches:
- main
permissions:
contents: read
jobs:
check-kcl-header:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check KCL files for header comment block and blank line
run: |
files=$(find public/kcl-samples -type f -name '*.kcl')
failed_files=()
for file in $files; do
if ! awk '
NR == 1 && $0 !~ /^\/\// { exit 1 }
BEGIN { in_comment = 1 }
NF == 0 && in_comment == 1 { in_comment = 0; next }
$1 !~ /^\/\// && in_comment == 1 { exit 1 }
in_comment == 0 && NF > 0 { exit 0 }
END { if (in_comment == 1) exit 1 }
' "$file"; then
failed_files+=("$file")
fi
done
if [ ${#failed_files[@]} -ne 0 ]; then
echo "One or more KCL files do not begin with a header comment block followed by a blank line:"
printf '%s\n' "${failed_files[@]}"
exit 1
fi

546
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,546 @@
name: CI
on:
pull_request:
push:
branches:
- main
release:
types: [published]
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)
env:
CUT_RELEASE_PR: ${{ github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
BUILD_RELEASE: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
check-format:
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- run: yarn fmt-check
check-types:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- run: yarn build:wasm
- run: yarn xstate:typegen
- run: yarn tsc
check-typos:
runs-on: ubuntu-latest
steps:
- name: Checkout
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
run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration.
build-test-web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- run: yarn build:wasm
- run: yarn simpleserver:ci
- run: yarn test:nowatch
prepare-json-files:
runs-on: ubuntu-latest # seperate job on Ubuntu for easy string manipulations (compared to Windows)
outputs:
version: ${{ steps.export_version.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Set nightly version
if: github.event_name == 'schedule'
run: |
VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons
echo "$(jq --arg url 'https://dl.zoo.dev/releases/modeling-app/nightly/last_update.json' \
'.plugins.updater.endpoints[]=$url' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
echo "$(jq --arg id 'dev.zoo.modeling-app-nightly' \
'.identifier=$id' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
echo "$(jq --arg name 'Zoo Modeling App (Nightly)' \
'.productName=$name' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
- name: Set updater test version
if: ${{ env.CUT_RELEASE_PR == 'true' }}
run: |
echo "$(jq --arg url 'https://dl.zoo.dev/releases/modeling-app/test/last_update.json' \
'.plugins.updater.endpoints[]=$url' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
- uses: actions/upload-artifact@v3
if: ${{ github.event_name == 'schedule' || env.CUT_RELEASE_PR == 'true' }}
with:
path: |
package.json
src-tauri/tauri.conf.json
src-tauri/tauri.release.conf.json
- id: export_version
run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT"
build-test-apps:
needs: [prepare-json-files]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-14, ubuntu-latest, windows-latest]
env:
# Specific Apple Universal target for macos
TAURI_ARGS_MACOS: ${{ matrix.os == 'macos-14' && '--target universal-apple-darwin' || '' }}
# Only build executable on linux (no appimage or deb)
TAURI_ARGS_UBUNTU: ${{ matrix.os == 'ubuntu-latest' && '--bundles' || '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v3
if: github.event_name == 'schedule'
- name: Copy updated .json files
if: github.event_name == 'schedule'
run: |
ls -l artifact
cp artifact/package.json package.json
cp artifact/src-tauri/tauri.conf.json src-tauri/tauri.conf.json
cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json
- name: Update WebView2 on Windows
if: matrix.os == 'windows-latest'
# Workaround needed to build the tauri windows app with matching edge version.
# From https://github.com/actions/runner-images/issues/9538
run: |
Invoke-WebRequest -Uri 'https://go.microsoft.com/fwlink/p/?LinkId=2124703' -OutFile 'setup.exe'
Start-Process -FilePath setup.exe -Verb RunAs -Wait
- name: Install ubuntu system dependencies
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y \
libgtk-3-dev \
libayatana-appindicator3-dev \
webkit2gtk-driver \
libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev \
libwebkit2gtk-4.1-dev \
at-spi2-core \
xvfb
- name: Sync node version and setup cache
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn' # Set this to npm, yarn or pnpm.
- run: yarn install
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Setup Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: './src-tauri -> target'
- uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: Run build:wasm manually
shell: bash
env:
MODE: ${{ env.BUILD_RELEASE == 'true' && '--release' || '--debug' }}
run: |
mkdir src/wasm-lib/pkg; cd src/wasm-lib
echo "building with ${{ env.MODE }}"
npx wasm-pack build --target web --out-dir pkg ${{ env.MODE }}
cd ../../
cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
- name: Run vite build (build:both)
run: yarn vite build --mode ${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }}
- name: Fix format
run: yarn fmt
- name: Install x86 target for Universal builds (MacOS only)
if: matrix.os == 'macos-14'
run: |
rustup target add x86_64-apple-darwin
- name: Prepare certificate and variables (Windows only)
if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }}
run: |
echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
cat /d/Certificate_pkcs12.p12
echo "::set-output name=version::${GITHUB_REF#refs/tags/v}"
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$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 "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\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH
shell: bash
- name: Setup certicate with SSM KSP (Windows only)
if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }}
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
msiexec /i smtools-windows-x64.msi /quiet /qn
smksp_registrar.exe list
smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe
shell: cmd
- name: Build the app (debug)
if: ${{ env.BUILD_RELEASE == 'false' }}
run: "yarn tauri build --debug ${{ env.TAURI_ARGS_MACOS }} ${{ env.TAURI_ARGS_UBUNTU }}"
- name: Build for Mac TestFlight (nightly)
if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }}
shell: bash
run: |
unset APPLE_SIGNING_IDENTITY
unset APPLE_CERTIFICATE
sign_app="3rd Party Mac Developer Application: KittyCAD Inc (${APPLE_TEAM_ID})"
sign_install="3rd Party Mac Developer Installer: KittyCAD Inc (${APPLE_TEAM_ID})"
profile="src-tauri/entitlements/Mac_App_Distribution.provisionprofile"
mkdir -p src-tauri/entitlements
echo -n "${APPLE_STORE_PROVISIONING_PROFILE}" | base64 --decode -o "${profile}"
echo -n "${APPLE_STORE_DISTRIBUTION_CERT}" | base64 --decode -o "dist.cer"
echo -n "${APPLE_STORE_INSTALLER_CERT}" | base64 --decode -o "installer.cer"
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
KEYCHAIN_PASSWORD="password"
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import "dist.cer" -P "$APPLE_STORE_P12_PASSWORD" -k $KEYCHAIN_PATH -f pkcs12 -t cert -A
security import "installer.cer" -P "$APPLE_STORE_P12_PASSWORD" -k $KEYCHAIN_PATH -f pkcs12 -t cert -A
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
target="universal-apple-darwin"
# Turn off the default target
# We don't want to install the updater for the apple store build
sed -i.bu "s/default =/# default =/" src-tauri/Cargo.toml
rm src-tauri/Cargo.toml.bu
git diff src-tauri/Cargo.toml
yarn tauri build --target "${target}" --verbose --config src-tauri/tauri.app-store.conf.json
app_path="src-tauri/target/${target}/release/bundle/macos/Zoo Modeling App.app"
build_name="src-tauri/target/${target}/release/bundle/macos/Zoo Modeling App.pkg"
cp_dir="src-tauri/target/${target}/release/bundle/macos/Zoo Modeling App.app/Contents/embedded.provisionprofile"
entitlements="src-tauri/entitlements/app-store.entitlements"
cp "${profile}" "${cp_dir}"
codesign --deep --force -s "${sign_app}" --entitlements "${entitlements}" "${app_path}"
productbuild --component "${app_path}" /Applications/ --sign "${sign_install}" "${build_name}"
# Undo the changes to the Cargo.toml
git checkout src-tauri/Cargo.toml
env:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_STORE_PROVISIONING_PROFILE: ${{ secrets.APPLE_STORE_PROVISIONING_PROFILE }}
APPLE_STORE_DISTRIBUTION_CERT: ${{ secrets.APPLE_STORE_DISTRIBUTION_CERT }}
APPLE_STORE_INSTALLER_CERT: ${{ secrets.APPLE_STORE_INSTALLER_CERT }}
APPLE_STORE_P12_PASSWORD: ${{ secrets.APPLE_STORE_P12_PASSWORD }}
- name: 'Upload to Mac TestFlight (nightly)'
uses: apple-actions/upload-testflight-build@v1
if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }}
with:
app-path: 'src-tauri/target/universal-apple-darwin/release/bundle/macos/Zoo Modeling App.pkg'
issuer-id: ${{ secrets.APPLE_STORE_ISSUER_ID }}
api-key-id: ${{ secrets.APPLE_STORE_API_KEY_ID }}
api-private-key: ${{ secrets.APPLE_STORE_API_PRIVATE_KEY }}
app-type: osx
- name: Clean up after Mac TestFlight (nightly)
if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }}
shell: bash
run: |
git status
# remove our target builds because we want to make sure the later build
# includes the updater, and that anything we changed with the target
# does not persist
rm -rf src-tauri/target
# Lets get rid of the info.plist for the normal mac builds since its
# being sketchy.
rm src-tauri/Info.plist
# We do this after the apple store because the apple store build is
# specific and we want to overwrite it with the this new build after and
# not upload the apple store build to the public bucket
- name: Build the app (release) and sign
if: ${{ env.BUILD_RELEASE == 'true' }}
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
TAURI_CONF_ARGS: "--config ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}"
run: "yarn tauri build ${{ env.TAURI_CONF_ARGS }} ${{ env.TAURI_ARGS_MACOS }} ${{ env.TAURI_ARGS_UBUNTU }}"
- uses: actions/upload-artifact@v3
if: matrix.os != 'ubuntu-latest'
env:
PREFIX: ${{ matrix.os == 'macos-14' && 'src-tauri/target/universal-apple-darwin' || 'src-tauri/target' }}
MODE: ${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}
with:
path: "${{ env.PREFIX }}/${{ env.MODE }}/bundle/*/*"
- name: Run e2e tests (linux only)
if: ${{ matrix.os == 'ubuntu-latest' && github.event_name != 'release' && github.event_name != 'schedule' }}
run: |
cargo install tauri-driver --force
source .env.${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }}
export VITE_KC_API_BASE_URL
xvfb-run yarn test:e2e:tauri
env:
E2E_APPLICATION: "./src-tauri/target/${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}/zoo-modeling-app"
KITTYCAD_API_TOKEN: ${{ env.BUILD_RELEASE == 'true' && secrets.KITTYCAD_API_TOKEN || secrets.KITTYCAD_API_TOKEN_DEV }}
- name: Run e2e tests (windows only)
if: ${{ matrix.os == 'windows-latest' && github.event_name != 'release' && github.event_name != 'schedule' }}
run: |
cargo install tauri-driver --force
yarn wdio run wdio.conf.ts
env:
E2E_APPLICATION: ".\\src-tauri\\target\\${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}\\Zoo Modeling App.exe"
KITTYCAD_API_TOKEN: ${{ env.BUILD_RELEASE == 'true' && secrets.KITTYCAD_API_TOKEN || secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_API_BASE_URL: ${{ env.BUILD_RELEASE == 'true' && 'https://api.zoo.dev' || 'https://api.dev.zoo.dev' }}
E2E_TAURI_ENABLED: true
TS_NODE_COMPILER_OPTIONS: '{"module": "commonjs"}'
- uses: actions/download-artifact@v3
if: ${{ env.CUT_RELEASE_PR == 'true' }}
- name: Copy updated .json file for updater test
if: ${{ env.CUT_RELEASE_PR == 'true' }}
run: |
ls -l artifact
cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json
cat src-tauri/tauri.release.conf.json
- name: Build the app (release, updater test)
if: ${{ env.CUT_RELEASE_PR == 'true' && matrix.os != 'ubuntu-latest' }}
env:
TAURI_CONF_ARGS: "-c ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}"
TAURI_BUNDLE_ARGS: "-b ${{ matrix.os == 'windows-latest' && 'msi' || 'dmg' }}"
run: "yarn tauri build ${{ env.TAURI_CONF_ARGS }} ${{ env.TAURI_BUNDLE_ARGS }} ${{ env.TAURI_ARGS_MACOS }}"
- uses: actions/upload-artifact@v3
if: ${{ env.CUT_RELEASE_PR == 'true' && matrix.os != 'ubuntu-latest' }}
with:
path: "${{ matrix.os == 'macos-14' && 'src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg' || 'src-tauri/target/release/bundle/msi/*.msi' }}"
name: updater-test
publish-apps-release:
permissions:
contents: write
runs-on: ubuntu-latest
if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }}
needs: [check-format, check-types, check-typos, build-test-web, prepare-json-files, build-test-apps]
env:
VERSION_NO_V: ${{ needs.prepare-json-files.outputs.version }}
VERSION: ${{ github.event_name == 'release' && format('v{0}', needs.prepare-json-files.outputs.version) || needs.prepare-json-files.outputs.version }}
PUB_DATE: ${{ github.event_name == 'release' && github.event.release.created_at || github.event.repository.updated_at }}
NOTES: ${{ github.event_name == 'release' && github.event.release.body || format('Nightly build, commit {0}', github.sha) }}
BUCKET_DIR: ${{ github.event_name == 'release' && 'dl.kittycad.io/releases/modeling-app' || 'dl.kittycad.io/releases/modeling-app/nightly' }}
WEBSITE_DIR: ${{ github.event_name == 'release' && 'dl.zoo.dev/releases/modeling-app' || 'dl.zoo.dev/releases/modeling-app/nightly' }}
URL_CODED_NAME: ${{ github.event_name == 'schedule' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }}
steps:
- uses: actions/download-artifact@v3
- name: Generate the update static endpoint
run: |
ls -l artifact/*/*oo*
DARWIN_SIG=`cat artifact/macos/*.app.tar.gz.sig`
WINDOWS_SIG=`cat artifact/msi/*.msi.zip.sig`
RELEASE_DIR=https://${WEBSITE_DIR}/${VERSION}
jq --null-input \
--arg version "${VERSION}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg darwin_sig "$DARWIN_SIG" \
--arg darwin_url "$RELEASE_DIR/macos/${{ env.URL_CODED_NAME }}.app.tar.gz" \
--arg windows_sig "$WINDOWS_SIG" \
--arg windows_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64_en-US.msi.zip" \
'{
"version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": {
"darwin-x86_64": {
"signature": $darwin_sig,
"url": $darwin_url
},
"darwin-aarch64": {
"signature": $darwin_sig,
"url": $darwin_url
},
"windows-x86_64": {
"signature": $windows_sig,
"url": $windows_url
}
}
}' > last_update.json
cat last_update.json
- name: Generate the download static endpoint
run: |
RELEASE_DIR=https://${WEBSITE_DIR}/${VERSION}
jq --null-input \
--arg version "${VERSION}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg darwin_url "$RELEASE_DIR/dmg/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_universal.dmg" \
--arg windows_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64_en-US.msi" \
'{
"version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": {
"dmg-universal": {
"url": $darwin_url
},
"msi-x86_64": {
"url": $windows_url
}
}
}' > last_download.json
cat last_download.json
- name: Authenticate to Google Cloud
uses: 'google-github-actions/auth@v2.1.3'
with:
credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}'
- name: Set up Google Cloud SDK
uses: google-github-actions/setup-gcloud@v2.1.0
with:
project_id: kittycadapi
- name: Upload release files to public bucket
uses: google-github-actions/upload-cloud-storage@v2.1.0
with:
path: artifact
glob: '*/Zoo*'
parent: false
destination: ${{ env.BUCKET_DIR }}/${{ env.VERSION }}
- name: Upload update endpoint to public bucket
uses: google-github-actions/upload-cloud-storage@v2.1.0
with:
path: last_update.json
destination: ${{ env.BUCKET_DIR }}
- name: Upload download endpoint to public bucket
uses: google-github-actions/upload-cloud-storage@v2.1.0
with:
path: last_download.json
destination: ${{ env.BUCKET_DIR }}
- name: Upload release files to Github
if: ${{ github.event_name == 'release' }}
uses: softprops/action-gh-release@v2
with:
files: 'artifact/*/Zoo*'
announce_release:
needs: [publish-apps-release]
runs-on: ubuntu-latest
if: github.event_name == 'release'
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests
- name: Announce Release
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
RELEASE_VERSION: ${{ github.event.release.tag_name }}
RELEASE_BODY: ${{ github.event.release.body}}
run: python public/announce_release.py

View File

@ -1,29 +0,0 @@
name: CodeMirror Lang KCL
on:
pull_request:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
npm-unit-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- run: npm run tsc --workspace=packages/codemirror-lang-kcl
- name: run unit tests
run: npm run test --workspace=packages/codemirror-lang-kcl

37
.github/workflows/create-release.yml vendored Normal file
View File

@ -0,0 +1,37 @@
name: Create Release
on:
push:
branches:
- main
jobs:
create-release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: read
if: contains(github.event.head_commit.message, 'Cut release v')
steps:
- uses: actions/github-script@v7
name: Read Cut release PR info and create release
with:
script: |
const { owner, repo } = context.repo
const pulls = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner,
repo,
commit_sha: context.sha,
})
const { title, body } = pulls.data[0]
const version = title.split('Cut release ')[1]
const result = await github.rest.repos.createRelease({
owner,
repo,
body,
tag_name: version,
name: version,
draft: true,
})
console.log(result)

View File

@ -1,327 +0,0 @@
name: E2E Tests
on:
push:
branches:
- main
pull_request:
schedule:
- cron: 0 * * * * # hourly
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
actions: read
jobs:
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
steps:
- uses: actions/checkout@v4
- id: filter
name: Check for Rust changes
uses: dorny/paths-filter@v3
with:
filters: |
rust:
- 'rust/**'
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
run: npm install
- name: Download Wasm cache
id: download-wasm
if: ${{ github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }}
uses: dawidd6/action-download-artifact@v7
continue-on-error: true
with:
github_token: ${{secrets.GITHUB_TOKEN}}
name: wasm-bundle
workflow: build-and-store-wasm.yml
branch: main
path: rust/kcl-wasm-lib/pkg
- name: Build Wasm condition
id: wasm
run: |
set -euox pipefail
# Build wasm if this is a scheduled run, there are Rust changes, or
# downloading from the wasm cache failed.
if [[ ${{github.event_name}} == 'schedule' || ${{steps.filter.outputs.rust}} == 'true' || ${{steps.download-wasm.outcome}} == 'failure' ]]; then
echo "should-build-wasm=true" >> $GITHUB_OUTPUT
else
echo "should-build-wasm=false" >> $GITHUB_OUTPUT
fi
- name: Use correct Rust toolchain
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install Rust
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
with:
tool: wasm-pack
- name: Use Rust cache
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
uses: Swatinem/rust-cache@v2
with:
workspaces: './rust'
- name: Build Wasm
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
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*
snapshots:
name: playwright:snapshots:ubuntu
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
needs: [prepare-wasm]
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/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
id: deps-install
run: npm install
- name: Cache browsers
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: Capture snapshots
uses: nick-fields/retry@v3.0.2
with:
shell: bash
command: npm run test:snapshots
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 }}
TARGET: web
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
with:
name: playwright-report-ubuntu-snapshot-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
overwrite: true
- name: Check diff
if: ${{ github.ref != 'refs/heads/main' }}
shell: bash
id: git-check
run: |
git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots
if git status | grep -q "Changes to be committed"
then echo "modified=true" >> $GITHUB_OUTPUT
else echo "modified=false" >> $GITHUB_OUTPUT
fi
- name: Commit changes
if: ${{ steps.git-check.outputs.modified == 'true' }}
shell: bash
run: |
git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots
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 }}
git commit --message "Update snapshots" || true
git push
git push origin ${{ github.head_ref }}
electron:
needs: [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') }} (shard ${{ matrix.shardIndex }})
strategy:
fail-fast: false
matrix:
# TODO: enable namespace-profile-windows-latest once available
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: windows-latest-8-cores
shardIndex: 1
shardTotal: 2
- os: windows-latest-8-cores
shardIndex: 2
shardTotal: 2
runs-on: ${{ matrix.os }}
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
id: deps-install
run: npm install
- name: Cache Playwright Browsers
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
- name: Install Playwright Browsers
run: npm run playwright install --with-deps
- name: Build web
run: npm run tronb:vite:dev
- 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 }}
- uses: actions/download-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
continue-on-error: true
with:
name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
- name: Run playwright/electron flow (with retries)
id: retry
if: ${{ !cancelled() && steps.deps-install.outcome == 'success' }}
uses: nick-fields/retry@v3.0.2
with:
shell: bash
command: .github/ci-cd-scripts/playwright-electron.sh ${{matrix.shardIndex}} ${{matrix.shardTotal}} ${{ env.OS_NAME }}
timeout_minutes: 30
max_attempts: 9
env:
FAIL_ON_CONSOLE_ERRORS: true
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 }}
TARGET: desktop
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
include-hidden-files: true
retention-days: 30
overwrite: true
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
overwrite: true

View File

@ -1,49 +0,0 @@
name: generate machine-api types
on:
pull_request:
paths:
- 'openapi/machine-api.json'
- '.github/workflows/generate-machine-api-types.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: write
jobs:
generate:
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- run: npm run generate:machine-api
- run: npm run fmt || true
- name: check for changes
id: git-check
run: |
git add .
if git status | 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: steps.git-check.outputs.modified == 'true'
run: |
git add .
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 }}
git commit -am "New machine-api types" || true
git push
git push origin ${{ github.head_ref }}

View File

@ -5,7 +5,6 @@ on:
paths: paths:
- .github/workflows/generate-website-docs.yml - .github/workflows/generate-website-docs.yml
- 'docs/**' - 'docs/**'
- 'public/kcl-samples/**'
pull_request: pull_request:
paths: paths:
- .github/workflows/generate-website-docs.yml - .github/workflows/generate-website-docs.yml
@ -38,21 +37,9 @@ 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
# 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
# We don't need the README
rm documentation/content/pages/docs/kcl-std/README.md
- name: move kcl-samples
shell: bash
run: |
mkdir -p documentation/content/pages/docs/kcl-samples
# cleanup old
rm -rf documentation/content/pages/docs/kcl-samples/*
# move new
mv -f public/kcl-samples/* documentation/content/pages/docs/kcl-samples/
- name: commit the changes in the docs repo - name: commit the changes in the docs repo
shell: bash shell: bash
run: | run: |

View File

@ -1,354 +0,0 @@
name: kcl-language-server
on:
push:
branches:
- main
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- 'rust/kcl-language-server/**'
- '**.rs'
- .github/workflows/kcl-language-server.yml
tags:
- 'kcl-*'
pull_request:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- 'rust/kcl-language-server/**'
- '**.rs'
- .github/workflows/kcl-language-server.yml
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
RUSTFLAGS: ""
RUSTUP_MAX_RETRIES: 10
FETCH_DEPTH: 0 # pull in the tags for the version string
MACOSX_DEPLOYMENT_TARGET: 10.15
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
jobs:
test:
name: kcl-language-server (vscode tests)
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
- name: Install dependencies
run: |
npm install
- name: Run tests
run: |
cd rust/kcl-language-server
npm run build
npm run test-compile
ls -la dist
xvfb-run -a npm run test
if: runner.os == 'Linux'
- name: Run tests
run: |
cd rust/kcl-language-server
npm run test
if: runner.os != 'Linux'
build-release:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
target: x86_64-pc-windows-msvc
code-target: win32-x64
#- os: windows-latest
#target: i686-pc-windows-msvc
#code-target:
#win32-ia32
#- os: windows-latest
#target: aarch64-pc-windows-msvc
#code-target: win32-arm64
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
code-target: linux-x64
#- os: ubuntu-latest
#target: aarch64-unknown-linux-musl
#code-target: linux-arm64
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
code-target: linux-arm64
- os: ubuntu-latest
target: arm-unknown-linux-gnueabihf
code-target: linux-armhf
- os: macos-latest
target: x86_64-apple-darwin
code-target: darwin-x64
- os: macos-latest
target: aarch64-apple-darwin
code-target: darwin-arm64
name: kcl-language-server build-release (${{ matrix.target }})
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
env:
RA_TARGET: ${{ matrix.target }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: ${{ env.FETCH_DEPTH }}
- name: Use correct Rust toolchain
shell: bash
run: |
rm rust/rust-toolchain.toml
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: rust
components: rust-src
target: ${{ matrix.target }}
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
- name: Update apt repositories
if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf' || matrix.os == 'ubuntu-latest'
run: sudo apt-get update
- if: ${{ matrix.os == 'ubuntu-latest' }}
name: Install deps
shell: bash
run: |
sudo apt install -y \
ca-certificates \
clang \
cmake \
curl \
g++ \
gcc \
gcc-mingw-w64-i686 \
gcc-mingw-w64 \
jq \
libmpc-dev \
libmpfr-dev \
libgmp-dev \
libssl-dev \
libxml2-dev \
mingw-w64 \
wget \
zlib1g-dev
cargo install cross
- name: Install AArch64 target toolchain
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: sudo apt-get install gcc-aarch64-linux-gnu
- name: Install ARM target toolchain
if: matrix.target == 'arm-unknown-linux-gnueabihf'
run: sudo apt-get install gcc-arm-linux-gnueabihf
- name: build
run: |
cd rust
cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }}
- name: Install dependencies
run: |
cd rust/kcl-language-server
# npm will symlink which will cause issues w tarballing later
yarn install
- name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/')
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }}
- name: Package Extension (nightly)
if: startsWith(github.event.ref, 'refs/tags/') == false
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release
- name: remove server
if: matrix.target == 'x86_64-unknown-linux-gnu'
run: |
cd rust/kcl-language-server
rm -rf server
- name: Package Extension (no server, release)
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/')
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix
- name: Package Extension (no server, nightly)
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/') == false
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix --pre-release
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: release-${{ matrix.target }}
path: ./rust/build
build-release-x86_64-unknown-linux-musl:
name: kcl-language-server build-release (x86_64-unknown-linux-musl)
runs-on: ubuntu-latest
env:
RA_TARGET: x86_64-unknown-linux-musl
# For some reason `-crt-static` is not working for clang without lld
RUSTFLAGS: "-C link-arg=-fuse-ld=lld -C target-feature=-crt-static"
container:
image: alpine:latest
volumes:
- /usr/local/cargo/registry:/usr/local/cargo/registry
steps:
- name: Install dependencies
run: |
apk add --no-cache \
bash \
curl \
git \
clang \
lld \
musl-dev \
nodejs \
npm \
yarn
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: ${{ env.FETCH_DEPTH }}
- name: Use correct Rust toolchain
shell: bash
run: |
rm rust/rust-toolchain.toml
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: rust
components: rust-src
target: ${{ matrix.target }}
- name: build
run: |
cd rust
cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }}
- name: Install dependencies
run: |
cd rust/kcl-language-server
# npm will symlink which will cause issues w tarballing later
yarn install
- name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/')
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64
- name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/') == false
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64 --pre-release
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: release-x86_64-unknown-linux-musl
path: ./rust/build
publish:
name: kcl-language-server (publish)
runs-on: ubuntu-latest
needs: ["build-release", "build-release-x86_64-unknown-linux-musl"]
if: startsWith(github.event.ref, 'refs/tags')
permissions:
contents: write
steps:
- run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- run: 'echo "TAG: $TAG"'
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: ${{ env.FETCH_DEPTH }}
- name: Install Nodejs
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
- run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
- run: 'echo "HEAD_SHA: $HEAD_SHA"'
- uses: actions/download-artifact@v4
with:
name: release-aarch64-apple-darwin
path: rust/build
- uses: actions/download-artifact@v4
with:
name: release-x86_64-apple-darwin
path: rust/build
- uses: actions/download-artifact@v4
with:
name: release-x86_64-unknown-linux-gnu
path: rust/build
- uses: actions/download-artifact@v4
with:
name: release-x86_64-unknown-linux-musl
path: rust/build
- uses: actions/download-artifact@v4
with:
name: release-aarch64-unknown-linux-gnu
path: rust/build
- uses: actions/download-artifact@v4
with:
name: release-arm-unknown-linux-gnueabihf
path: rust/build
- uses: actions/download-artifact@v4
with:
name: release-x86_64-pc-windows-msvc
path: rust/build
#- uses: actions/download-artifact@v4
#with:
#name: release-i686-pc-windows-msvc
#path:
#build
#- uses: actions/download-artifact@v4
#with:
#name: release-aarch64-pc-windows-msvc
#path: rust/build
- run: ls -al ./rust/build
- name: Publish Release
uses: ./.github/actions/github-release
with:
files: "rust/build/*"
name: ${{ env.TAG }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: move files to dir for upload
shell: bash
run: |
cd rust
mkdir -p releases/language-server/${{ env.TAG }}
cp -r build/* releases/language-server/${{ env.TAG }}
- name: "Authenticate to Google Cloud"
uses: "google-github-actions/auth@v2.1.8"
with:
credentials_json: "${{ secrets.GOOGLE_CLOUD_DL_SA }}"
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2.1.4
with:
project_id: kittycadapi
- name: "upload files to gcp"
id: upload-files
uses: google-github-actions/upload-cloud-storage@v2.2.2
with:
path: rust/releases
destination: dl.kittycad.io
- run: rm rust/build/kcl-language-server-no-server.vsix
- name: Publish Extension (Code Marketplace, release)
# token from https://dev.azure.com/kcl-language-server/
run: |
cd rust/kcl-language-server
npx vsce publish --pat ${{ secrets.VSCE_PAT }} --packagePath ../build/kcl-language-server-*.vsix
- name: Publish Extension (OpenVSX, release)
run: |
cd rust/kcl-language-server
npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../build/kcl-language-server-*.vsix
timeout-minutes: 2

View File

@ -1,179 +0,0 @@
# This file is autogenerated by maturin v1.6.0 and then modified
# To update, run
#
# maturin generate-ci github
#
name: kcl-python-bindings
on:
push:
branches:
- main
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- 'rust/kcl-python-bindings/**'
- '**.rs'
- .github/workflows/kcl-python-bindings.yml
tags:
- 'kcl-*'
pull_request:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- 'rust/kcl-python-bindings/**'
- '**.rs'
- .github/workflows/kcl-python-bindings.yml
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
linux-x86_64:
name: kcl-python-bindings (linux-x86_64)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
working-directory: rust/kcl-python-bindings
target: x86_64
args: --release --out dist --find-interpreter
sccache: 'true'
manylinux: auto
before-script-linux: |
yum install openssl-devel -y
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-linux-x86_64
path: rust/kcl-python-bindings/dist
windows:
name: kcl-python-bindings (windows)
runs-on: windows-16-cores
strategy:
matrix:
target:
- x64
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
architecture: ${{ matrix.target }}
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
working-directory: rust/kcl-python-bindings
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-windows-${{ matrix.target }}
path: rust/kcl-python-bindings/dist
macos:
name: kcl-python-bindings (macos)
runs-on: macos-latest
strategy:
matrix:
target:
- x86_64
- aarch64
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
working-directory: rust/kcl-python-bindings
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-macos-${{ matrix.target }}
path: rust/kcl-python-bindings/dist
test:
name: kcl-python-bindings (test)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
- uses: taiki-e/install-action@just
- name: Run tests
run: |
cd rust/kcl-python-bindings
just setup-uv
just test
env:
KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
ZOO_HOST: https://api.dev.zoo.dev
sdist:
name: kcl-python-bindings (sdist)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v5
- name: Install codespell
run: |
uv venv .venv
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
echo "$PWD/.venv/bin" >> $GITHUB_PATH
uv pip install pip --upgrade
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
working-directory: rust/kcl-python-bindings
command: sdist
args: --out dist
- name: Upload sdist
uses: actions/upload-artifact@v4
with:
name: wheels-sdist
path: rust/kcl-python-bindings/dist
release:
name: Release
runs-on: ubuntu-latest
permissions:
contents: write
if: startsWith(github.ref, 'refs/tags/')
needs: [linux-x86_64, windows, macos, sdist]
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
path: rust/kcl-python-bindings
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v5
- name: do uv things
run: |
cd rust/kcl-python-bindings
uv venv .venv
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
echo "$PWD/.venv/bin" >> $GITHUB_PATH
uv pip install pip --upgrade
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:
working-directory: rust/kcl-python-bindings
command: upload
args: --non-interactive --skip-existing wheels-*/*

View File

@ -1,31 +0,0 @@
name: Label Issues
on:
issues:
types: [opened]
permissions:
issues: write
jobs:
label:
runs-on: ubuntu-latest
steps:
- name: Check if issue opener is ZooSpiritWolf
id: check_opener
uses: actions/github-script@v7
with:
script: |
const issueOpener = context.payload.issue.user.login;
return issueOpener === 'ZooSpiritWolf';
- name: Add labels
if: steps.check_opener.outputs.result == 'true'
uses: actions/github-script@v7
with:
script: |
github.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
labels: ['bug', 'regression', 'high-priority']
});

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 .

368
.github/workflows/playwright.yml vendored Normal file
View File

@ -0,0 +1,368 @@
name: Playwright Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
actions: read
jobs:
check-rust-changes:
runs-on: ubuntu-latest
outputs:
rust-changed: ${{ steps.filter.outputs.rust }}
steps:
- uses: actions/checkout@v4
- id: filter
name: Check for Rust changes
uses: dorny/paths-filter@v3
with:
filters: |
rust:
- 'src/wasm-lib/**'
playwright-ubuntu:
timeout-minutes: 60
runs-on: ubuntu-latest-8-cores
needs: check-rust-changes
steps:
- name: Tune GitHub-hosted runner network
uses: smorimoto/tune-github-hosted-runner-network@v1
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- uses: KittyCAD/action-install-cli@main
- name: Install dependencies
run: yarn
- name: Cache Playwright Browsers
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Browsers
run: yarn playwright install --with-deps
- name: Download Wasm Cache
id: download-wasm
if: needs.check-rust-changes.outputs.rust-changed == 'false'
uses: dawidd6/action-download-artifact@v6
continue-on-error: true
with:
github_token: ${{secrets.GITHUB_TOKEN}}
name: wasm-bundle
workflow: build-and-store-wasm.yml
branch: main
path: src/wasm-lib/pkg
- name: copy wasm blob
if: needs.check-rust-changes.outputs.rust-changed == 'false'
run: cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
continue-on-error: true
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Wasm (because rust diff)
if: needs.check-rust-changes.outputs.rust-changed == 'true'
uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: OR Cache Wasm (because wasm cache failed)
if: steps.download-wasm.outcome == 'failure'
uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: Install vector
run: |
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
chmod +x /tmp/vector.sh
/tmp/vector.sh -y -no-modify-path
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
cat /tmp/vector.toml
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
- name: Build Wasm (because rust diff)
if: needs.check-rust-changes.outputs.rust-changed == 'true'
run: yarn build:wasm
- name: OR Build Wasm (because wasm cache failed)
if: steps.download-wasm.outcome == 'failure'
run: yarn build:wasm
- name: build web
run: yarn build:local
- name: Run ubuntu/chrome snapshots
continue-on-error: true
run: |
yarn playwright test --project="Google Chrome" --update-snapshots e2e/playwright/snapshot-tests.spec.ts
env:
CI: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
- name: Clean up test-results
if: always()
continue-on-error: true
run: rm -r test-results
- name: check for changes
id: git-check
run: |
git add .
if git status | 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: steps.git-check.outputs.modified == 'true'
run: |
git add .
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 "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" || true
git push
git push origin ${{ github.head_ref }}
# only upload artifacts if there's actually changes
- uses: actions/upload-artifact@v4
if: steps.git-check.outputs.modified == 'true'
with:
name: playwright-report-ubuntu-${{ github.sha }}
path: playwright-report/
retention-days: 30
# if have previous run results, use them
- uses: actions/download-artifact@v4
if: always()
continue-on-error: true
with:
name: test-results-ubuntu-${{ github.sha }}
path: test-results/
- name: Run ubuntu/chrome flow (with retries)
id: retry
if: always()
run: |
if [[ ! -f "test-results/.last-run.json" ]]; then
# if no last run artifact, than run plawright normally
echo "run playwright normally"
yarn playwright test --project="Google Chrome" e2e/playwright/flow-tests.spec.ts || true
# # send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
fi
retry=1
max_retrys=4
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues
while [[ $retry -le $max_retrys ]]; do
if [[ -f "test-results/.last-run.json" ]]; then
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ $failed_tests -gt 0 ]]; then
echo "retried=true" >>$GITHUB_OUTPUT
echo "run playwright with last failed tests and retry $retry"
yarn playwright test --project="Google Chrome" --last-failed e2e/playwright/flow-tests.spec.ts || true
# send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
retry=$((retry + 1))
else
echo "retried=false" >>$GITHUB_OUTPUT
exit 0
fi
else
echo "retried=false" >>$GITHUB_OUTPUT
exit 0
fi
done
echo "retried=false" >>$GITHUB_OUTPUT
if [[ -f "test-results/.last-run.json" ]]; then
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ $failed_tests -gt 0 ]]; then
# if it still fails after 3 retrys, then fail the job
exit 1
fi
fi
exit 0
env:
CI: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- name: send to axiom
if: always()
shell: bash
run: |
node playwrightProcess.mjs | tee /tmp/github-actions.log
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-ubuntu-${{ github.sha }}
path: test-results/
retention-days: 30
overwrite: true
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-ubuntu-${{ github.sha }}
path: playwright-report/
retention-days: 30
overwrite: true
playwright-macos:
timeout-minutes: 60
runs-on: macos-14-large
needs: check-rust-changes
steps:
- name: Tune GitHub-hosted runner network
uses: smorimoto/tune-github-hosted-runner-network@v1
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Install dependencies
run: yarn
- name: Cache Playwright Browsers
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install Playwright Browsers
run: yarn playwright install --with-deps
- name: Download Wasm Cache
id: download-wasm
if: needs.check-rust-changes.outputs.rust-changed == 'false'
uses: dawidd6/action-download-artifact@v6
continue-on-error: true
with:
github_token: ${{secrets.GITHUB_TOKEN}}
name: wasm-bundle
workflow: build-and-store-wasm.yml
branch: main
path: src/wasm-lib/pkg
- name: copy wasm blob
if: needs.check-rust-changes.outputs.rust-changed == 'false'
run: cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
continue-on-error: true
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Wasm (because rust diff)
if: needs.check-rust-changes.outputs.rust-changed == 'true'
uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: OR Cache Wasm (because wasm cache failed)
if: steps.download-wasm.outcome == 'failure'
uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: Install vector
run: |
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
chmod +x /tmp/vector.sh
/tmp/vector.sh -y -no-modify-path
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "" "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "" "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "" "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "" "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "" "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
cat /tmp/vector.toml
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
- name: Build Wasm (because rust diff)
if: needs.check-rust-changes.outputs.rust-changed == 'true'
run: yarn build:wasm
- name: OR Build Wasm (because wasm cache failed)
if: steps.download-wasm.outcome == 'failure'
run: yarn build:wasm
- name: build web
run: yarn build:local
# if have previous run results, use them
- uses: actions/download-artifact@v4
if: ${{ always() }}
continue-on-error: true
with:
name: test-results-macos-${{ github.sha }}
path: test-results/
- name: Run macos/safari flow (with retries)
id: retry
if: always()
run: |
if [[ ! -f "test-results/.last-run.json" ]]; then
# if no last run artifact, than run plawright normally
echo "run playwright normally"
yarn playwright test --project="webkit" e2e/playwright/flow-tests.spec.ts || true
# # send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
fi
retry=1
max_retrys=4
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues
while [[ $retry -le $max_retrys ]]; do
if [[ -f "test-results/.last-run.json" ]]; then
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ $failed_tests -gt 0 ]]; then
echo "retried=true" >>$GITHUB_OUTPUT
echo "run playwright with last failed tests and retry $retry"
yarn playwright test --project="webkit" --last-failed e2e/playwright/flow-tests.spec.ts || true
# send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
retry=$((retry + 1))
else
echo "retried=false" >>$GITHUB_OUTPUT
exit 0
fi
else
echo "retried=false" >>$GITHUB_OUTPUT
exit 0
fi
done
echo "retried=false" >>$GITHUB_OUTPUT
if [[ -f "test-results/.last-run.json" ]]; then
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ $failed_tests -gt 0 ]]; then
# if it still fails after 3 retrys, then fail the job
exit 1
fi
fi
exit 0
env:
CI: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- uses: actions/upload-artifact@v4
if: ${{ always() }}
with:
name: test-results-macos-${{ github.sha }}
path: test-results/
retention-days: 30
overwrite: true
- uses: actions/upload-artifact@v4
if: ${{ always() }}
with:
name: playwright-report-macos-${{ github.sha }}
path: playwright-report/
retention-days: 30
overwrite: true

View File

@ -1,160 +0,0 @@
name: publish-apps-release
on:
release:
types: [published]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
publish-apps-release:
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Find tag workflow id
id: tag_workflow_id
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
id=$(gh run ls --repo kittycad/modeling-app -w build-apps.yml --branch ${{ github.event.release.tag_name }} --json databaseId | jq '.[0].databaseId')
echo "id=$id" >> "$GITHUB_OUTPUT"
- uses: actions/download-artifact@v4
with:
name: out-arm64-win
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: out-x64-win
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: out-yml-win
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: out-arm64-mac
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: out-x64-mac
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: out-yml-mac
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: out-arm64-linux
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: out-x64-linux
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: out-yml-linux
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: out-download-json
path: out
run-id: ${{ steps.tag_workflow_id.outputs.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: List artifacts
run: ls -R out
- name: Override release notes
env:
NOTES: ${{ github.event.release.body }}
run: npm run files:set-notes
- name: Authenticate to Google Cloud
uses: 'google-github-actions/auth@v2.1.8'
with:
credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}'
- name: Set up Google Cloud SDK
uses: google-github-actions/setup-gcloud@v2.1.4
with:
project_id: ${{ env.GOOGLE_CLOUD_PROJECT_ID }}
- name: Upload release files to public bucket
uses: google-github-actions/upload-cloud-storage@v2.2.2
with:
path: out
glob: '*'
parent: false
destination: 'dl.kittycad.io/releases/modeling-app'
- name: Invalidate bucket cache on latest*.yml and last_download.json files
run: npm run files:invalidate-bucket
- name: Upload release files to Github
if: ${{ github.event_name == 'release' }}
uses: softprops/action-gh-release@v2
with:
files: 'out/Zoo*'
announce_release:
needs: [publish-apps-release]
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests
- name: Announce Release
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
RELEASE_VERSION: ${{ github.event.release.tag_name }}
RELEASE_BODY: ${{ github.event.release.body }}
run: python public/announce_release.py

View File

@ -1,24 +0,0 @@
name: ruff
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
push:
branches: main
paths:
- '**.py'
- .github/workflows/ruff.yml
pull_request:
paths:
- '**.py'
- .github/workflows/ruff.yml
permissions:
contents: read
pull-requests: write
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/ruff-action@v3

View File

@ -1,129 +0,0 @@
name: Static Analysis
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-fmt-check:
runs-on: 'ubuntu-22.04'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- run: npm run fmt:check
npm-build-wasm:
uses: ./.github/workflows/build-wasm.yml
npm-tsc:
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 tsc
npm-lint:
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 lint
npm-circular-dependencies:
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 circular-deps:diff
python-codespell:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run codespell
uses: crate-ci/typos@v1.32.0

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

View File

@ -1,8 +1,5 @@
name: update-dev-branch name: update-dev-branch
# This is used to sync the `dev` branch with the `main` branch to continuously
# deploy a second instance of the app to Vercel: https://app.dev.zoo.dev
on: on:
push: push:
branches: branches:
@ -29,4 +26,4 @@ jobs:
# reset to main # reset to main
git reset --hard origin/main git reset --hard origin/main
# force push it # force push it
git push --force origin dev git push -f origin dev

View File

@ -8,7 +8,6 @@ include = ["/tmp/github-actions.log"]
type = "remap" type = "remap"
inputs = [ "github-actions-file" ] inputs = [ "github-actions-file" ]
source = ''' source = '''
.platform = "OS_NAME"
.action = "GITHUB_WORKFLOW" .action = "GITHUB_WORKFLOW"
.repo = "GITHUB_REPOSITORY" .repo = "GITHUB_REPOSITORY"
.sha = "GITHUB_SHA" .sha = "GITHUB_SHA"

56
.gitignore vendored
View File

@ -1,7 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies # dependencies
node_modules /node_modules
/.pnp /.pnp
.pnp.js .pnp.js
@ -9,7 +9,7 @@ node_modules
/coverage /coverage
# production # production
build /build
# misc # misc
.DS_Store .DS_Store
@ -25,66 +25,38 @@ yarn-error.log*
.idea .idea
.vscode .vscode
.helix src/wasm-lib/.idea
result src/wasm-lib/.vscode
# rust # rust
rust/target src/wasm-lib/target
rust/kcl-lib/bindings src/wasm-lib/bindings
rust/kcl-language-server/server src/wasm-lib/kcl/bindings
public/kcl_wasm_lib_bg.wasm public/wasm_lib_bg.wasm
rust/lcov.info src/wasm-lib/lcov.info
rust/kcl-wasm-lib/pkg src/wasm-lib/grackle/test_json_output
*.snap.new
rust/kcl-lib/fuzz/Cargo.lock
rust/kcl-language-server-release/Cargo.lock
# kcl language server package
rust/kcl-language-server/dist/
e2e/playwright/playwright-secrets.env e2e/playwright/playwright-secrets.env
e2e/playwright/temp1.png e2e/playwright/temp1.png
e2e/playwright/temp2.png e2e/playwright/temp2.png
e2e/playwright/temp3.png
# this will be overridden for specific directories
e2e/playwright/**/*.png
# exports from snapshot-tests.spec.ts "exports of each format should work" # exports from snapshot-tests.spec.ts "exports of each format should work"
e2e/playwright/export-snapshots/* e2e/playwright/export-snapshots/*
!e2e/playwright/export-snapshots/*.png !e2e/playwright/export-snapshots/*.png
!e2e/playwright/snapshot-tests.spec.ts-snapshots/*.png
trace.zip
/public/kcl-samples.zip
/public/kcl-samples/.github
/public/kcl-samples/screenshots/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/
/playwright/.cache/ /playwright/.cache/
/src/lang/std/artifactMapCache
## generated files ## generated files
src/**/*.typegen.ts src/**/*.typegen.ts
src-tauri/gen
src/wasm-lib/grackle/stdlib_cube_partial.json
Mac_App_Distribution.provisionprofile Mac_App_Distribution.provisionprofile
*.tsbuildinfo *.tsbuildinfo
.eslintcache
.vite/
# electron
out/
# python
__pycache__/
uv.lock
dist
venv venv
.vscode-test
.biome/
.million

View File

@ -1,2 +0,0 @@
[editor]
auto-format = true

View File

@ -1,10 +0,0 @@
[language-server.eslint]
args = ["--stdio"]
command = "vscode-eslint-language-server"
[[language]]
name = "typescript"
auto-format = true
formatter = { command = "./node_modules/@biomejs/biome/bin/biome", args = ["format", "--write", "--stdin-file-path=foo.ts"] }
# 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

2
.nvmrc
View File

@ -1 +1 @@
v22.12.0 v21.7.1

View File

@ -5,12 +5,11 @@ coverage
# Ignore Rust projects: # Ignore Rust projects:
*.rs *.rs
*.hbs
target target
src/wasm-lib/pkg
src/wasm-lib/kcl/bindings
e2e/playwright/export-snapshots e2e/playwright/export-snapshots
e2e/playwright/snapshots/prompt-to-edit
# XState generated files # XState generated files
src/machines/**.typegen.ts src/machines/**.typegen.ts
.vscode-test

View File

@ -1,309 +0,0 @@
# Contributor Guide
## 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:
```
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
```
Then 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".
## Desktop
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).
## 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
npm install
npm run build:wasm
npm start
```
## 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:
- `npm run fmt`
- `npm run tsc`
- `npm run test`
- Here they are all together: `npm run fmt && npm run tsc && npm run 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.
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.
A prompt should show up asking for a downgrade to the last release version. Running through that at the end of testing
and making sure the current release candidate has the ability to be updated to what electron-updater points to is critical,
but what is actually being downloaded and installed isn't.
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.
```
# 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
Prepare these system dependencies:
- Set $token from https://zoo.dev/account/api-tokens
#### Snapshot tests (Google Chrome on Ubuntu only)
Only Ubunu 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.
#### Electron flow tests (Chromium on Ubuntu, macOS, Windows)
```
npm run playwright -- install chromium
npm run test:playwright:electron:local
```
You may use `-- -g "my test"` to match specific test titles, or `-- path/to/file.spec.ts` for a test file.
#### 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
```
### 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,43 +0,0 @@
# Setting Up Zoo Design Studio
Compared to other CAD software, getting Zoo Design Studio up and running is quick and straightforward across platforms. It's about 100MB to download and is quick to install.
## Windows
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.
3. The installation happens at `C:\Program Files\Zoo Design Studio`. A shortcut in the start menu is also created so you can run the app easily by clicking on it.
## macOS
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.
3. You can then open your `Applications` directory and double-click on `Zoo Design Studio` to open.
## Linux
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/).
- On Ubuntu, install the FUSE library with these commands in a terminal.
```bash
sudo apt update
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.
- 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:
```bash
chmod a+x ~/Applications/Zoo\ Modeling\ App-{version}-{arch}-linux.AppImage
```
3. You can double-click on the AppImage to run it, or in a terminal with this command:
```bash
~/Applications/Zoo\ Modeling\ App-{version}-{arch}-linux.AppImage
```

178
Makefile
View File

@ -1,171 +1,17 @@
.PHONY: all .PHONY: dev
all: install check build
############################################################################### WASM_LIB_FILES := $(wildcard src/wasm-lib/**/*.rs)
# INSTALL TS_SRC := $(wildcard src/**/*.tsx) $(wildcard src/**/*.ts)
XSTATE_TYPEGENS := $(wildcard src/machines/*.typegen.ts)
ifeq ($(OS),Windows_NT) dev: node_modules public/wasm_lib_bg.wasm $(XSTATE_TYPEGENS)
export WINDOWS := true yarn start
ifndef MSYSTEM
export POWERSHELL := true
endif
endif
ifdef WINDOWS $(XSTATE_TYPEGENS): $(TS_SRC)
CARGO ?= $(USERPROFILE)/.cargo/bin/cargo.exe yarn xstate typegen 'src/**/*.ts?(x)'
WASM_PACK ?= $(USERPROFILE)/.cargo/bin/wasm-pack.exe
else
CARGO ?= $(shell which cargo || echo ~/.cargo/bin/cargo)
WASM_PACK ?= $(shell which wasm-pack || echo ~/.cargo/bin/wasm-pack)
endif
.PHONY: install public/wasm_lib_bg.wasm: $(WASM_LIB_FILES)
install: node_modules/.package-lock.json $(CARGO) $(WASM_PACK) ## Install dependencies yarn build:wasm-dev
node_modules/.package-lock.json: package.json package-lock.json node_modules: package.json yarn.lock
npm prune yarn install
npm install
$(CARGO):
ifdef WINDOWS
npm run install:rust:windows
else
npm run install:rust
endif
$(WASM_PACK):
ifdef WINDOWS
npm run install:wasm-pack:cargo
else
npm run install:wasm-pack:sh
endif
###############################################################################
# BUILD
CARGO_SOURCES := rust/.cargo/config.toml $(wildcard rust/Cargo.*) $(wildcard rust/**/Cargo.*)
KCL_SOURCES := $(wildcard public/kcl-samples/**/*.kcl)
RUST_SOURCES := $(wildcard rust/**/*.rs)
REACT_SOURCES := $(wildcard src/*.tsx) $(wildcard src/**/*.tsx)
TYPESCRIPT_SOURCES := tsconfig.* $(wildcard src/*.ts) $(wildcard src/**/*.ts)
VITE_SOURCES := $(wildcard vite.*) $(wildcard vite/**/*.tsx)
.PHONY: build
build: install public/kcl_wasm_lib_bg.wasm public/kcl-samples/manifest.json .vite/build/main.js
public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES)
ifdef WINDOWS
npm run build:wasm:dev:windows
else
npm run build:wasm:dev
endif
public/kcl-samples/manifest.json: $(KCL_SOURCES)
cd rust/kcl-lib && EXPECTORATE=overwrite cargo test generate_manifest
.vite/build/main.js: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES)
npm run tronb:vite:dev
###############################################################################
# CHECK
.PHONY: check
check: format lint
.PHONY: format
format: install ## Format the code
npm run fmt
.PHONY: lint
lint: install ## Lint the code
npm run tsc
npm run lint
###############################################################################
# RUN
TARGET ?= desktop
.PHONY: run
run: run-$(TARGET)
.PHONY: run-web
run-web: install build ## Start the web app
npm run start
.PHONY: run-desktop
run-desktop: install build ## Start the desktop app
npm run tron:start
###############################################################################
# TEST
E2E_GREP ?=
E2E_WORKERS ?=
E2E_FAILURES ?= 1
.PHONY: test
test: test-unit test-e2e
.PHONY: test-unit
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 )
npm run test:unit
.PHONY: test-e2e
test-e2e: test-e2e-$(TARGET)
.PHONY: test-e2e-web
test-e2e-web: install build ## 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
npm run chrome:test -- --headed --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
else
npm run chrome:test -- --headed --workers='100%'
endif
.PHONY: test-e2e-desktop
test-e2e-desktop: install build ## Run the desktop e2e tests
ifdef E2E_GREP
npm run test:playwright:electron -- --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
else
npm run test:playwright:electron -- --workers='100%'
endif
###############################################################################
# CLEAN
.PHONY: clean
clean: ## Delete all artifacts
ifdef POWERSHELL
git clean --force -d -x --exclude=.env* --exclude=**/*.env
else
rm -rf .vite/ build/
rm -rf trace.zip playwright-report/ test-results/
rm -rf public/kcl_wasm_lib_bg.wasm
rm -rf rust/*/bindings/ rust/*/pkg/ rust/target/
rm -rf node_modules/ rust/*/node_modules/
endif
.PHONY: help
help: install
ifdef POWERSHELL
@ 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
@ grep -E '^[^[:space:]]+:.*## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
endif
.DEFAULT_GOAL := help
###############################################################################
# I'm sorry this is so specific to my setup you may as well ignore this.
# This is so you don't have to deal with electron windows popping up constantly.
# It should work for you other Linux users.
lee-electron-test:
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"
killall Xephyr

332
README.md
View File

@ -1,17 +1,17 @@
![Zoo Design Studio](/public/zma-logomark-outlined.png) ![Zoo Modeling App](/public/zma-logomark-outlined.png)
# Zoo Design Studio ## Zoo Modeling App
[zoo.dev/modeling-app](https://zoo.dev/modeling-app) live at [app.zoo.dev](https://app.zoo.dev/)
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).
Design Studio is our take on what a modern modelling experience can be. It is applying several lessons learned in the decades since most major CAD tools came into existence: Modeling App is our take on what a modern modelling experience can be. It is applying several lessons learned in the decades since most major CAD tools came into existence:
- All artifacts—including parts and assemblies—should be represented as human-readable code. At the end of the day, your CAD project should be "plain text" - All artifacts—including parts and assemblies—should be represented as human-readable code. At the end of the day, your CAD project should be "plain text"
- This makes version control—which is a solved problem in software engineering—trivial for CAD - This makes version control—which is a solved problem in software engineering—trivial for CAD
- All GUI (or point-and-click) interactions should be actions performed on this code representation under the hood - All GUI (or point-and-click) interactions should be actions performed on this code representation under the hood
- This unlocks a hybrid approach to modeling. Whether you point-and-click as you always have or you write your own KCL code, you are performing the same action in Design Studio - This unlocks a hybrid approach to modeling. Whether you point-and-click as you always have or you write your own KCL code, you are performing the same action in Modeling App
- Everything graphics _has_ to be built for the GPU - Everything graphics _has_ to be built for the GPU
- Most CAD applications have had to retrofit support for GPUs, but our geometry engine is made for GPUs (primarily Nvidia's Vulkan), getting the order of magnitude rendering performance boost with it - Most CAD applications have had to retrofit support for GPUs, but our geometry engine is made for GPUs (primarily Nvidia's Vulkan), getting the order of magnitude rendering performance boost with it
- Make the resource-intensive pieces of an application auto-scaling - Make the resource-intensive pieces of an application auto-scaling
@ -19,11 +19,11 @@ Design Studio is our take on what a modern modelling experience can be. It is ap
We are excited about what a small team of people could build in a short time with our API. We welcome you to try our API, build your own applications, or contribute to ours! We are excited about what a small team of people could build in a short time with our API. We welcome you to try our API, build your own applications, or contribute to ours!
Design Studio is a _hybrid_ user interface for CAD modeling. You can point-and-click to design parts (and soon assemblies), but everything you make is really just [`kcl` code](https://github.com/KittyCAD/kcl-experiments) under the hood. All of your CAD models can be checked into source control such as GitHub and responsibly versioned, rolled back, and more. Modeling App is a _hybrid_ user interface for CAD modeling. You can point-and-click to design parts (and soon assemblies), but everything you make is really just [`kcl` code](https://github.com/KittyCAD/kcl-experiments) under the hood. All of your CAD models can be checked into source control such as GitHub and responsibly versioned, rolled back, and more.
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 Modeling App 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,20 +34,322 @@ 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 [releases](https://github.com/KittyCAD/modeling-app/releases) page. If you don't see your platform or architecture supported there, please file an issue. [Original demo slides](https://github.com/KittyCAD/Eng/files/10398178/demo.pdf)
If you'd like to try out upcoming changes sooner, you can also download those from our [nightly releases](https://zoo.dev/modeling-app/download/nightly) page. ## Get started
## Developing 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.
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. ## Running a development build
First, [install Rust via `rustup`](https://www.rust-lang.org/tools/install). This project uses a lot of Rust compiled to [WASM](https://webassembly.org/) within it. We always use the latest stable version of Rust, so you may need to run `rustup update stable`. Then, run:
```
yarn install
```
followed by:
```
yarn build:wasm-dev
```
or if you have the gh cli installed
```
./get-latest-wasm-bundle.sh # this will download the latest main wasm bundle
```
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 an KittyCAD employee you won't be able to access the dev environment, you should copy everything from `.env.production` to `.env.development` 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 ofcourse, 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".
## Tauri
To spin up up tauri dev, `yarn install` and `yarn build:wasm-dev` need to have been done before hand then
```
yarn tauri dev
```
Will spin up the web app before opening up the tauri dev desktop app. Note that it's probably a good idea to close the browser tab that gets opened since at the time of writing they can conflict.
The dev instance automatically opens up the browser devtools which can be disabled by [commenting it out](https://github.com/KittyCAD/modeling-app/blob/main/src-tauri/src/main.rs#L92.)
To build, run `yarn tauri build`, or `yarn tauri build --debug` to keep access to the devtools.
Note that these became separate apps on Macos, so make sure you open the right one after a build 😉
![image](https://github.com/KittyCAD/modeling-app/assets/29681384/a08762c5-8d16-42d8-a02f-a5efc9ae5551)
<img width="1232" alt="image" src="https://user-images.githubusercontent.com/29681384/211947063-46164bb4-7bdd-45cb-9a76-2f40c71a24aa.png">
<img width="1232" alt="image (1)" src="https://user-images.githubusercontent.com/29681384/211947073-e76b4933-bef5-4636-bc4d-e930ac8e290f.png">
## 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. Bump the versions by running `./make-release.sh` and create a Cut Release PR
That will create the branch with the updated json files for you:
- run `./make-release.sh` or `./make-release.sh patch` for a patch update;
- run `./make-release.sh minor` for minor; or
- run `./make-release.sh major` for major.
After it runs you should just need the push the branch and open a PR.
**Important:** It needs to be prefixed with `Cut release v` to build in release mode and a few other things to test in the best context possible, the intent would be for instance to have `Cut release v1.2.3` for the `v1.2.3` release candidate.
The PR may then serve as a place to discuss the human-readable changelog and extra QA. The `make-release.sh` tool suggests a changelog for you too to be used as PR description, just make sure to delete lines that are not user facing.
#### 2. Smoke test artifacts from the Cut Release PR
The release builds can be find under the `artifact` zip, at the very bottom of the `ci` action page for each commit on this branch.
We don't have a strict process, but click around and check for anything obvious, posting results as comments in the Cut Release PR.
The other `ci` output in Cut Release PRs is `updater-test`, because we don't have a way to test this fully automated, we have a semi-automated process. Download updater-test zip file, install the app, run it, expect an updater prompt to a dummy v0.99.99, install it and check that the app comes back at that version (on both macOS and Windows).
#### 3. Merge the Cut Release PR
This will kick the `create-release` action, that creates a _Draft_ release out of this Cut Release PR merge after less than a minute, with the new version as title and Cut Release PR as description.
#### 4. Publish the release
Head over to https://github.com/KittyCAD/modeling-app/releases, the draft release corresponding to the merged Cut Release PR should show up at the top as _Draft_. Click on it, verify the content, and hit _Publish_.
#### 5. Profit
A new Action kicks in at https://github.com/KittyCAD/modeling-app/actions, which can be found under `release` event filter.
## Fuzzing the parser
Make sure you install cargo fuzz:
```bash
$ cargo install cargo-fuzz
```
```bash
$ cd src/wasm-lib/kcl
# 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
For a portable way to run Playwright you'll need Docker.
After that, open a terminal and run:
```bash
docker run --network host --rm --init -it playwright/chrome:playwright-1.43.1
```
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>
```
An example of a `<test suite>` is: `e2e/playwright/flow-tests.spec.ts`
YOU WILL NEED A PLAYWRIGHT-SECRETS.ENV FILE:
```bash
# ./e2e/playwright/playwright-secrets.env
token=<your-token>
snapshottoken=<your-snapshot-token>
```
then replace "your-token" with a dev token from dev.zoo.dev/account/api-tokens
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)
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:nowatch
```
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
```bash
cd src/wasm-lib
cargo test
```
#### 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>
### Tauri e2e tests
#### Windows (local only until the CI edge version mismatch is fixed)
```
yarn install
yarn build:wasm-dev
cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
yarn vite build --mode development
yarn tauri build --debug -b
$env:KITTYCAD_API_TOKEN="<YOUR_KITTYCAD_API_TOKEN>"
$env:VITE_KC_API_BASE_URL="https://api.dev.zoo.dev"
$env:E2E_TAURI_ENABLED="true"
$env:TS_NODE_COMPILER_OPTIONS='{"module": "commonjs"}'
$env:E2E_APPLICATION=".\src-tauri\target\debug\Zoo Modeling App.exe"
Stop-Process -Name msedgedriver
yarn wdio run wdio.conf.ts
```
## KCL ## KCL
To contribute to the KittyCAD Language, see the [README](https://github.com/KittyCAD/modeling-app/tree/main/rust/kcl-lib) for KCL. For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl).

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 .*",
]

BIN
app-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 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,32 +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; 1+]` denotes an array whose length is at least one (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. Examples:
```kcl,norun
[0..3] // [0, 1, 2, 3]
[3..10] // [3, 4, 5, 6, 7, 8, 9, 10]
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]() 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,20 +0,0 @@
---
title: "Known Issues"
excerpt: "Known issues with the KCL standard library for the Zoo Design Studio."
layout: manual
---
The following are bugs that are not in modeling-app or kcl itself. These bugs
once fixed in engine will just start working here with no language changes.
- **Sketch on Face**: If your sketch is outside the edges of the face (on which you
are sketching) you will get multiple models returned instead of one single
model for that sketch and its underlying 3D object.
If you see a red line around your model, it means this is happening.
- **Import**: Right now you can import a file, even if that file has brep data
you cannot edit it, after v1, the engine will account for this.
- **Appearance**: Changing the appearance on a loft does not work.
- **CSG Booleans**: Coplanar (bodies that share a plane) unions, subtractions, and intersections are not currently supported.

View File

@ -1,266 +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)
```
Imported files _must_ be in the same project so that units are uniform across
modules. This means that it must be in the same directory.
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"
```
---
## 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 "tests/inputs/cube.kcl" as cube
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.
---
## 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 "tests/inputs/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" as cube
cube
|> translate(x=10)
clone(cube)
|> translate(x=20)
```

View File

@ -1,48 +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.

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,45 +0,0 @@
---
title: "Settings"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
# KCL Settings
There are three levels of settings available in Zoo Design Studio:
1. [User Settings](/docs/kcl-lang/settings/user): Global settings that apply to all projects, stored in `user.toml`
2. [Project Settings](/docs/kcl-lang/settings/project): Settings specific to a project, stored in `project.toml`
3. Per-file Settings: Settings that apply to a single KCL file, specified using the `@settings` attribute
## Configuration Files
Zoo Design Studio uses TOML files for configuration:
* **User Settings**: `user.toml` - See [complete documentation](/docs/kcl-lang/settings/user)
* **Project Settings**: `project.toml` - See [complete documentation](/docs/kcl-lang/settings/project)
## Per-file settings
Settings which affect a single file are configured using the settings attribute.
This must be at the top of the KCL file (comments before the attribute are permitted).
For example:
```kcl
// The settings attribute.
@settings(defaultLengthUnit = in)
// The rest of your KCL code goes below...
x = 42 // Represents 42 inches.
```
The settings attribute may contain multiple properties separated by commas.
Valid properties are:
- `defaultLengthUnit`: the default length unit to use for numbers declared in this file.
- Accepted values: `mm`, `cm`, `m`, `in` (inches), `ft` (feet), `yd` (yards).
- `defaultAngleUnit`: the default angle unit to use for numbers declared in this file.
- Accepted values: `deg` (degrees), `rad` (radians).
These settings override any project-wide settings (configured in project.toml or via the UI).

View File

@ -1,187 +0,0 @@
---
title: "Project Settings"
excerpt: "Project specific settings for the app. These live in `project.toml` in the base of the project directory. Updating the settings for the project in the app will update this file automatically. Do not edit this file manually, as it may be overwritten by the app. Manual edits can cause corruption of the settings file."
layout: manual
---
# Project Settings
Project specific settings for the app. These live in `project.toml` in the base of the project directory. Updating the settings for the project in the app will update this file automatically. Do not edit this file manually, as it may be overwritten by the app. Manual edits can cause corruption of the settings file.
## Project Configuration Structure
```toml
[settings.app]
# Set the appearance of the application
name = "My Awesome Project"
[settings.app.appearance]
# Use dark mode theme
theme = "dark"
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
color = 240.0
[settings.modeling]
# Use inches as the default measurement unit
base_unit = "in"
```
## Available Settings
### settings
#### app
The settings for the Design Studio.
**Default:** None
This setting has the following nested options:
##### appearance
The settings for the appearance of the app.
**Default:** None
This setting has further nested options. See the schema for full details.
##### onboarding_status
The onboarding status of the app.
**Default:** None
##### dismiss_web_banner
Permanently dismiss the banner warning to download the desktop app. This setting only applies to the web app. And is temporary until we have Linux support.
**Default:** None
##### stream_idle_mode
When the user is idle, and this is true, the stream will be torn down.
**Default:** None
##### allow_orbit_in_sketch_mode
When the user is idle, and this is true, the stream will be torn down.
**Default:** None
##### show_debug_panel
Whether to show the debug panel, which lets you see various states of the app to aid in development.
**Default:** None
##### named_views
Settings that affect the behavior of the command bar.
**Default:** None
#### modeling
Settings that affect the behavior while modeling.
**Default:** None
This setting has the following nested options:
##### base_unit
The default unit to use in modeling dimensions.
**Default:** None
##### highlight_edges
Highlight edges of 3D objects?
**Default:** None
##### enable_ssao
Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
**Default:** None
#### text_editor
Settings that affect the behavior of the KCL text editor.
**Default:** None
This setting has the following nested options:
##### text_wrapping
Whether to wrap text in the editor or overflow with scroll.
**Default:** None
##### blinking_cursor
Whether to make the cursor blink in the editor.
**Default:** None
#### command_bar
Settings that affect the behavior of the command bar.
**Default:** None
This setting has the following nested options:
##### include_settings
Whether to include settings in the command bar.
**Default:** None
## Complete Example
```toml
[settings.app]
# Set the appearance of the application
name = "My Awesome Project"
[settings.app.appearance]
# Use dark mode theme
theme = "dark"
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
color = 240.0
[settings.modeling]
# Use inches as the default measurement unit
base_unit = "in"
```

View File

@ -1,237 +0,0 @@
---
title: "User Settings"
excerpt: "User specific settings for the app. These live in `user.toml` in the app's configuration directory. Updating the settings in the app will update this file automatically. Do not edit this file manually, as it may be overwritten by the app. Manual edits can cause corruption of the settings file."
layout: manual
---
# User Settings
User specific settings for the app. These live in `user.toml` in the app's configuration directory. Updating the settings in the app will update this file automatically. Do not edit this file manually, as it may be overwritten by the app. Manual edits can cause corruption of the settings file.
## User Configuration Structure
```toml
[settings.app]
# Set the appearance of the application
[settings.app.appearance]
# Use dark mode theme
theme = "dark"
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
color = 240.0
[settings.modeling]
# Use millimeters as the default measurement unit
base_unit = "mm"
[settings.text_editor]
# Disable text wrapping in the editor
text_wrapping = false
```
## Available Settings
### settings
#### app
The settings for the Design Studio.
**Default:** None
This setting has the following nested options:
##### appearance
The settings for the appearance of the app.
**Default:** None
This setting has further nested options. See the schema for full details.
##### onboarding_status
The onboarding status of the app.
**Default:** None
##### dismiss_web_banner
Permanently dismiss the banner warning to download the desktop app. This setting only applies to the web app. And is temporary until we have Linux support.
**Default:** None
##### stream_idle_mode
When the user is idle, teardown the stream after some time.
**Default:** None
##### allow_orbit_in_sketch_mode
Allow orbiting in sketch mode.
**Default:** None
##### show_debug_panel
Whether to show the debug panel, which lets you see various states of the app to aid in development.
**Default:** None
#### modeling
Settings that affect the behavior while modeling.
**Default:** None
This setting has the following nested options:
##### base_unit
The default unit to use in modeling dimensions.
**Default:** None
##### camera_projection
The projection mode the camera should use while modeling.
**Default:** None
##### camera_orbit
The methodology the camera should use to orbit around the model.
**Default:** None
##### mouse_controls
The controls for how to navigate the 3D view.
**Possible values:** `zoo`, `onshape`, `trackpad_friendly`, `solidworks`, `nx`, `creo`, `autocad`
**Default:** None
##### highlight_edges
Highlight edges of 3D objects?
**Default:** None
##### enable_ssao
Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
**Default:** None
##### show_scale_grid
Whether or not to show a scale grid in the 3D modeling view
**Default:** None
#### text_editor
Settings that affect the behavior of the KCL text editor.
**Default:** None
This setting has the following nested options:
##### text_wrapping
Whether to wrap text in the editor or overflow with scroll.
**Default:** None
##### blinking_cursor
Whether to make the cursor blink in the editor.
**Default:** None
#### project
Settings that affect the behavior of project management.
**Default:** None
This setting has the following nested options:
##### directory
The directory to save and load projects from.
**Default:** None
##### default_project_name
The default project name to use when creating a new project.
**Default:** None
#### command_bar
Settings that affect the behavior of the command bar.
**Default:** None
This setting has the following nested options:
##### include_settings
Whether to include settings in the command bar.
**Default:** None
## Complete Example
```toml
[settings.app]
# Set the appearance of the application
[settings.app.appearance]
# Use dark mode theme
theme = "dark"
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
color = 240.0
[settings.modeling]
# Use millimeters as the default measurement unit
base_unit = "mm"
[settings.text_editor]
# Disable text wrapping in the editor
text_wrapping = false
```

View File

@ -1,161 +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.
### `TagDeclarator`
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()
```
### `TagIdentifier`
As per the example above you can use the tag identifier to get a reference to the
tagged object. The syntax for this is `myTag`.
In the example above we use the tag identifier to get the angle of the segment
`segAng(rectangleSegmentA001)`.
### `Start`
There is a special tag, `START` (with type `Start`, although under the cover, it's a string)
for identifying the face of a solid which was the start of an extrusion (i.e., the surface which
is extruded).
### `End`
There is a special tag, `END` (with type `End`, although under the cover, it's a string)
for identifying the face of a solid which was finishes an extrusion.
### 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`.

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

View File

@ -1,33 +0,0 @@
---
title: "KCL Constants"
excerpt: "Documentation for the KCL constants."
layout: manual
---
## Table of Contents
### `std`
- [`END`](/docs/kcl/consts/std-END)
- [`START`](/docs/kcl/consts/std-START)
- [`X`](/docs/kcl/consts/std-X)
- [`XY`](/docs/kcl/consts/std-XY)
- [`XZ`](/docs/kcl/consts/std-XZ)
- [`Y`](/docs/kcl/consts/std-Y)
- [`YZ`](/docs/kcl/consts/std-YZ)
- [`Z`](/docs/kcl/consts/std-Z)
### `std::math`
- [`E`](/docs/kcl/consts/std-math-E)
- [`PI`](/docs/kcl/consts/std-math-PI)
- [`TAU`](/docs/kcl/consts/std-math-TAU)
### `std::turns`
- [`HALF_TURN`](/docs/kcl/consts/std-turns-HALF_TURN)
- [`QUARTER_TURN`](/docs/kcl/consts/std-turns-QUARTER_TURN)
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-turns-THREE_QUARTER_TURN)
- [`ZERO`](/docs/kcl/consts/std-turns-ZERO)

View File

@ -1,16 +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: string = 'end'
```

View File

@ -1,16 +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: string = 'start'
```

View File

@ -1,16 +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
```

View File

@ -1,16 +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
```

View File

@ -1,16 +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
```

View File

@ -1,16 +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
```

View File

@ -1,16 +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
```

View File

@ -1,16 +0,0 @@
---
title: "Z"
subtitle: "Constant in std"
excerpt: "The 3D Z-axis."
layout: manual
---
The 3D Z-axis.
```kcl
Z
```

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