Files

357 lines
14 KiB
YAML

name: plugins
# Rebuild and test the plugins whenever something they use changes. Orca bundles
# the site's engine (web/*.js) at build time, so a site change only reaches Orca
# users through a rebuild: this makes that rebuild automatic, and makes a site
# change that breaks a plugin fail the PR that made it.
#
# PR: build + test
# push to main: build + test, then publish the builds to the rolling
# `plugins-latest` pre-release (printfins.com's Plugins menu links here)
#
# The Fusion add-in runs the engine in Fusion's own browser (a hidden palette), so
# its zip has nothing native in it and serves Windows and macOS alike. It has been
# run in Fusion on Windows and on an Apple-silicon Mac.
#
# Not here: the shared engine's Deno tests (plugins/shared/tests) already run in
# test.yml. Onshape is published from its Onshape document, so there is nothing
# to build.
on:
pull_request:
paths:
- 'web/**'
- 'plugins/**'
- '.github/workflows/plugins.yml'
push:
branches: [main]
paths:
- 'web/**'
- 'plugins/**'
- '.github/workflows/plugins.yml'
workflow_dispatch:
permissions:
contents: read
jobs:
orca:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-node@v4 # npx fetches the pinned esbuild (plugins/shared/bundle.py)
with:
node-version: '22'
- name: Install test dependencies
# mini-racer pinned to the version the plugin's PEP 723 header asks Orca for
run: pip install pytest numpy trimesh scipy shapely rtree networkx mini-racer==0.14.1
- name: Build
run: python plugins/orca/build.py
- name: Test
run: python -m pytest -q plugins/orca/tests/
- name: Test the shared Python modules (host, slicer)
run: python -m pytest -q plugins/shared/py/tests/
- uses: actions/upload-artifact@v4
with:
name: orca
path: plugins/orca/build/support_fins_orca.py
if-no-files-found: error
fusion:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-node@v4 # esbuild via npx, and Node runs the engine in the tests
with:
node-version: '22'
- name: Build (engine bundle + SupportFins.zip)
run: python plugins/fusion/build.py --zip
- name: Test
run: python -m unittest discover -s plugins/fusion/tests -v
- uses: actions/upload-artifact@v4
with:
name: fusion
path: plugins/fusion/build/SupportFins.zip
if-no-files-found: error
cura:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-node@v4 # npx fetches the pinned esbuild (plugins/shared/bundle.py)
with:
node-version: '22'
- name: Install test dependencies
run: pip install pytest numpy mini-racer==0.14.1
- name: Build a .curapackage per platform
# pip fetches each platform's mini-racer wheel, so one Linux runner builds all five;
# this runner's own (linux-x64) is built last and is what the tests run against
run: python plugins/cura/build.py --all
- name: Test
run: python -m pytest -q plugins/cura/tests/
- uses: actions/upload-artifact@v4
with:
name: cura
path: plugins/cura/build/*.curapackage
if-no-files-found: error
freecad:
# The add-on's settings mapping, then a zip per platform (engine bundle + that
# platform's mini-racer). FreeCAD itself isn't installable here:
# plugins/freecad/tests/smoke.py runs the real thing locally.
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-node@v4 # npx fetches the pinned esbuild (plugins/shared/bundle.py)
with:
node-version: '22'
- name: Install test dependencies
run: pip install pytest
- name: Test
run: python -m pytest -q plugins/freecad/tests/test_props.py
- name: Build a zip per platform
run: python plugins/freecad/build.py --all
- uses: actions/upload-artifact@v4
with:
name: freecad
path: plugins/freecad/build/support-fins-freecad-*.zip
if-no-files-found: error
cli:
# The command line as one file (its tests run with the rest in test.yml's deno test):
# bundled, then run on Node from outside the checkout, so a missed import fails here.
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-node@v4 # npx fetches the pinned esbuild (plugins/shared/bundle.py)
with:
node-version: '22'
- name: Build
run: python plugins/cli/build.py
- name: Run it outside the checkout
run: |
mkdir -p "$RUNNER_TEMP/cli" && cp plugins/cli/build/support-fins.mjs prototype/stress/models/lowledge.stl "$RUNNER_TEMP/cli/"
cd "$RUNNER_TEMP/cli" && node support-fins.mjs lowledge.stl && test -s lowledge-fins.3mf
- uses: actions/upload-artifact@v4
with:
name: cli
path: plugins/cli/build/support-fins.mjs
if-no-files-found: error
mcp:
# The MCP server as one file (its tests run with the rest in test.yml's deno test):
# bundled, then driven over stdio on Node from outside the checkout -- initialize,
# then fin a part -- so a missed import or a stray stdout line fails here.
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-node@v4 # npx fetches the pinned esbuild (plugins/shared/bundle.py)
with:
node-version: '22'
- name: Build
run: python plugins/mcp/build.py
- name: Run it outside the checkout
run: |
mkdir -p "$RUNNER_TEMP/mcp" && cp plugins/mcp/build/support-fins-mcp.mjs prototype/stress/models/lowledge.stl "$RUNNER_TEMP/mcp/"
cd "$RUNNER_TEMP/mcp"
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"ci","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"fin_part","arguments":{"path":"lowledge.stl"}}}' \
| node support-fins-mcp.mjs > replies.jsonl
cat replies.jsonl
node -e 'const l=require("fs").readFileSync("replies.jsonl","utf8").trim().split("\n").map(JSON.parse); if (l.length!==2||l[1].result.isError!==false) process.exit(1)'
test -s lowledge-fins.3mf
- uses: actions/upload-artifact@v4
with:
name: mcp
path: plugins/mcp/build/support-fins-mcp.mjs
if-no-files-found: error
blender:
# The extension's settings mapping + 3MF writer, then a zip per platform (engine
# bundle + that platform's mini-racer wheel, which Blender installs itself).
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-node@v4 # npx fetches the pinned esbuild (plugins/shared/bundle.py)
with:
node-version: '22'
- name: Install test dependencies
run: pip install pytest mini-racer==0.14.1
- name: Test
run: python -m pytest -q plugins/blender/tests/
- name: Build
run: python plugins/blender/build.py --all
- uses: actions/upload-artifact@v4
with:
name: blender
path: plugins/blender/build/support_fins-*.zip
if-no-files-found: error
rhino:
# The Rhino 8 plugin's settings mapping, mesh weld and staged project (rhinocode,
# which compiles the .yak, needs Rhino: built locally; rhino_smoke.py runs in Rhino).
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.9' # Rhino 8's CPython
- uses: actions/setup-node@v4 # npx fetches the pinned esbuild (plugins/shared/bundle.py)
with:
node-version: '22'
- name: Install test dependencies
run: pip install pytest numpy mini-racer==0.12.4 # the commands' # r: pin (0.13+ needs 3.10)
- name: Test
run: python -m pytest -q plugins/rhino/tests/
- name: Stage the project
run: python plugins/rhino/build.py
blender-smoke:
# Install the Linux zip into a real headless Blender (the oldest it supports and
# a current one) and use it: Generate, out of date, settings, units, Draw wall, Lay face flat, 3MF, overlays, Clear.
needs: blender
runs-on: ubuntu-24.04
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
version: ['4.2.23', '5.2.2']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/download-artifact@v4
with:
name: blender
path: plugins/blender/build
- name: Install Blender's system libraries
run: sudo apt-get update -q && sudo apt-get install -y -q libx11-6 libxi6 libxrender1 libxfixes3 libxxf86vm1 libgl1 libsm6 libice6 libxkbcommon0
- name: Smoke test in Blender ${{ matrix.version }}
run: python plugins/blender/tests/run_blender.py --version '${{ matrix.version }}' --package plugins/blender/build/support_fins-linux-x64.zip
prusa:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: Install Lua
run: sudo apt-get update -q && sudo apt-get install -y -q lua5.4 && lua -v && luac -v
- name: Test
run: bash plugins/prusa/run-tests.sh
- name: Package
# the slicer loads the bundle folder, so ship the folder zipped
run: cd plugins/prusa && zip -qr "$GITHUB_WORKSPACE/support-fins-prusa.zip" com.printfins.support-fins
- uses: actions/upload-artifact@v4
with:
name: prusa
path: support-fins-prusa.zip
if-no-files-found: error
solidworks:
# The add-in, built on Linux: it targets .NET Framework 4.8 through reference
# assemblies and SolidWorks' interop is compile-time only. Its page's tests run
# with the rest in test.yml's deno test; SolidWorks itself isn't installable here.
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-node@v4 # npx fetches the pinned esbuild (plugins/shared/bundle.py)
with:
node-version: '22'
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Build
run: python plugins/solidworks/build.py --zip
- uses: actions/upload-artifact@v4
with:
name: solidworks
path: plugins/solidworks/build/support-fins-solidworks.zip
if-no-files-found: error
publish:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [orca, fusion, cura, prusa, blender, blender-smoke, freecad, cli, mcp, solidworks]
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: write
concurrency:
group: plugins-publish
cancel-in-progress: false
env:
GH_TOKEN: ${{ github.token }}
TAG: plugins-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5 # release_labels.py needs 3.11+ (tomllib)
with:
python-version: '3.12'
- uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Move the tag to this commit
run: |
git tag -f "$TAG"
git push -f origin "refs/tags/$TAG"
- name: Publish
run: |
notes="Built automatically from ${GITHUB_SHA::7} on main. Replaced on every push that touches web/ or plugins/.
- support_fins_orca.py: OrcaSlicer plugin (2.5 nightly), experimental
- SupportFins.zip: Autodesk Fusion add-in, experimental (run on Windows and macOS)
- SupportFins-<platform>.curapackage: UltiMaker Cura 5 plugin, experimental; pick your computer's (mac-arm64, mac-x64, windows-x64, linux-x64, linux-arm64) and drag it onto Cura
- support-fins-prusa.zip: PrusaSlicer 3.0 plugin bundle, placement by hand
- support_fins-<platform>.zip: Blender 4.2+ extension, experimental; pick your computer's (macos-arm64, macos-x64, windows-x64, linux-x64) and use Install from Disk
- support-fins-freecad-<platform>.zip: FreeCAD 1.0 add-on, experimental; pick your computer's (mac-arm64, mac-x64, windows-x64, linux-x64, linux-arm64) and unzip into FreeCAD's Mod folder
- support-fins-solidworks.zip: SolidWorks add-in (Windows), experimental, not yet run in SolidWorks; unzip, run install.bat as administrator
- support-fins.mjs: command line (Deno or Node 20.10+): node support-fins.mjs part.stl
- support-fins-mcp.mjs: MCP server for AI clients (Claude Code, Claude Desktop; Deno or Node 20.10+): claude mcp add support-fins -- node /full/path/to/support-fins-mcp.mjs
Each file's label names its plugin version and the engine commit it was built from."
if gh release view "$TAG" >/dev/null 2>&1; then
gh release edit "$TAG" --title "Plugins (latest build)" --notes "$notes" --prerelease
else
gh release create "$TAG" --title "Plugins (latest build)" --notes "$notes" --prerelease --verify-tag
fi
# label = plugin version + engine commit; printfins.com's Plugins menu shows it
python3 plugins/shared/release_labels.py dist "$GITHUB_SHA" > labels.txt
cat labels.txt
xargs -d '\n' gh release upload "$TAG" --clobber < labels.txt