From 3b9a975299ed6fc6813593e10036f8a00f6a4d8c Mon Sep 17 00:00:00 2001 From: bherbruck Date: Fri, 9 Oct 2026 14:41:42 +0000 Subject: [PATCH] Release workflow: Linux tar.gz and AppImage, Windows zip, universal macOS app, web zip, SHA256SUMS .github/workflows/release.yml builds on a pushed v* tag (or by hand) and attaches everything to a GitHub release, a pre-release while the version is 0.x, with .github/release-notes.md. The packaging lives in .github/release/package-{linux,macos}.sh so it can be run locally; the AppImage icon is rendered by solvecraft-cli from the bracket example. Fixes #32 Co-Authored-By: Claude Opus 5.5 --- .github/release-notes.md | 62 ++++++++++++++ .github/release/package-linux.sh | 39 +++++++++ .github/release/package-macos.sh | 35 ++++++++ .github/workflows/release.yml | 136 +++++++++++++++++++++++++++++++ 4 files changed, 272 insertions(+) create mode 100644 .github/release-notes.md create mode 100755 .github/release/package-linux.sh create mode 100755 .github/release/package-macos.sh create mode 100644 .github/workflows/release.yml diff --git a/.github/release-notes.md b/.github/release-notes.md new file mode 100644 index 00000000..76e95bff --- /dev/null +++ b/.github/release-notes.md @@ -0,0 +1,62 @@ +SolveCraft is an open-source parametric 3D CAD application in pure Rust: sketch on a plane, +constrain and dimension the sketch, turn profiles into solids on a feature timeline, and change a +parameter to watch the timeline rebuild. This is the first public build, a **pre-release**: it is +early, and we'd like your bug reports. + +- **Documentation:** https://bherbruck.github.io/solvecraft/ +- **Try it in the browser:** https://bherbruck.github.io/solvecraft/app/ (`?sample` opens a sample part) +- **Contributing:** [CONTRIBUTING.md](https://github.com/bherbruck/solvecraft/blob/main/CONTRIBUTING.md) +- **Bugs and ideas:** [issues](https://github.com/bherbruck/solvecraft/issues) + +## What works + +- Sketches with SolveCraft's own constraint solver: lines, rectangles, circles, arcs, polygons, + slots, splines, text; constraints and parameter-driven dimensions; automatic profiles. +- Solid features on a parametric timeline that rebuilds incrementally: extrude, revolve, sweep, + loft, fillet and chamfer, shell, draft, holes and threads, patterns, mirror, combine, split, + primitives. Faces and edges are referenced by persistent names, so upstream edits don't + scramble downstream features. +- Parameters with unit-aware expressions, and configurations. +- Components, joints, motion studies, sheet metal with flat patterns, and a plastic-enclosure + subset (bosses, lips, snap fits). +- Files: `.solvecraft` designs; STEP (AP203/214/242) and IGES import and export; 3MF, STL and OBJ; + DXF. Atomic saves, autosave and crash recovery. +- 76 of 76 reference parts built in Fusion rebuild in SolveCraft with the same volume, area and + topology. + +## Built for AI agents + +Everything the UI does is a command with JSON parameters, so an agent can do it too. +`solvecraft-cli mcp` is a Model Context Protocol server: headless, or bridged to the running app +(`solvecraft --control 7878`, then `solvecraft-cli mcp --connect 127.0.0.1:7878`) so you can +watch the agent model. In Claude Code: `claude mcp add solvecraft -- solvecraft-cli mcp`. The +attached video shows an agent building an enclosure through the UI and MCP. + +## Downloads + +| File | What | +|---|---| +| `solvecraft-v0.1.0-windows-x86_64.zip` | Windows 10/11: `solvecraft.exe` (the app) and `solvecraft-cli.exe` | +| `solvecraft-v0.1.0-linux-x86_64.tar.gz` | Linux x86_64 (glibc 2.35 or newer): `solvecraft` and `solvecraft-cli` | +| `SolveCraft-v0.1.0-x86_64.AppImage` | Linux, the app as one file: `chmod +x` and run it | +| `solvecraft-v0.1.0-macos-universal.zip` | macOS 11 or newer, Apple silicon and Intel: `SolveCraft.app` and `solvecraft-cli` | +| `solvecraft-v0.1.0-web.zip` | the web app, to host yourself (any static server; HTTPS or localhost for saving files) | +| `SHA256SUMS` | checksums: `sha256sum -c SHA256SUMS` | + +### The binaries are not signed + +- **macOS:** the first time, right-click (or Control-click) `SolveCraft.app` and choose **Open**, + then **Open** again in the dialog. If macOS says the app is damaged, run + `xattr -dr com.apple.quarantine SolveCraft.app`. Do the same for `solvecraft-cli`. +- **Windows:** SmartScreen may say "Windows protected your PC". Click **More info**, then + **Run anyway**. + +## Known limitations + +SolveCraft is early. Some fillet, chamfer and boolean configurations still fail (with an error, +never a crash); surfaces, drawings, CAM, mesh tools and simulation are out of scope for now; the +model is Z-up only, so STEP files from Y-up tools open lying on their backs. The full list is in +[ROADMAP.md](https://github.com/bherbruck/solvecraft/blob/main/ROADMAP.md#known-limitations). + +SolveCraft is MIT OR Apache-2.0. It is a clean-room implementation and is not affiliated with +Autodesk; Fusion is a trademark of Autodesk, Inc. diff --git a/.github/release/package-linux.sh b/.github/release/package-linux.sh new file mode 100755 index 00000000..8d94cb81 --- /dev/null +++ b/.github/release/package-linux.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Package the Linux release build: a tar.gz with both binaries, and an AppImage of the desktop app. +# Usage: .github/release/package-linux.sh (from the repository root, after +# `cargo build --release -p solvecraft -p solvecraft-cli`). Writes out/. +set -euo pipefail +tag=${1:?usage: package-linux.sh } +bin=${CARGO_TARGET_DIR:-target}/release +name="solvecraft-$tag-linux-x86_64" +rm -rf stage out && mkdir -p "stage/$name" out +cp "$bin/solvecraft" "$bin/solvecraft-cli" README.md LICENSE-MIT LICENSE-APACHE NOTICE ATTRIBUTION.md "stage/$name/" +tar -C stage -czf "out/$name.tar.gz" "$name" + +# AppImage. The icon is rendered by SolveCraft itself from the bracket example, so no image file +# is committed. +app=stage/SolveCraft.AppDir +mkdir -p "$app/usr/bin" +cp "$bin/solvecraft" "$bin/solvecraft-cli" "$app/usr/bin/" +"$bin/solvecraft-cli" snapshot examples/bracket.json --out "$app/solvecraft.png" --width 256 --height 256 >/dev/null +cat > "$app/solvecraft.desktop" <<'DESKTOP' +[Desktop Entry] +Type=Application +Name=SolveCraft +Comment=Parametric 3D CAD +Exec=solvecraft %f +Icon=solvecraft +Categories=Graphics;Engineering; +MimeType=model/step; +DESKTOP +cat > "$app/AppRun" <<'APPRUN' +#!/bin/sh +here="$(dirname "$(readlink -f "$0")")" +exec "$here/usr/bin/solvecraft" "$@" +APPRUN +chmod +x "$app/AppRun" +tool=stage/appimagetool +curl -sSfL -o "$tool" https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage +chmod +x "$tool" +APPIMAGE_EXTRACT_AND_RUN=1 ARCH=x86_64 "$tool" --no-appstream "$app" "out/SolveCraft-$tag-x86_64.AppImage" +ls -l out diff --git a/.github/release/package-macos.sh b/.github/release/package-macos.sh new file mode 100755 index 00000000..df9d5e95 --- /dev/null +++ b/.github/release/package-macos.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Package the macOS release build: a universal (arm64 + x86_64) SolveCraft.app and CLI in one zip. +# Usage: .github/release/package-macos.sh (from the repository root, after building both +# aarch64-apple-darwin and x86_64-apple-darwin). Writes out/. The app is not signed. +set -euo pipefail +tag=${1:?usage: package-macos.sh } +version=${tag#v} +t=${CARGO_TARGET_DIR:-target} +name="solvecraft-$tag-macos-universal" +rm -rf stage out && mkdir -p "stage/$name" out +app="stage/$name/SolveCraft.app" +mkdir -p "$app/Contents/MacOS" +lipo -create -output "$app/Contents/MacOS/solvecraft" "$t/aarch64-apple-darwin/release/solvecraft" "$t/x86_64-apple-darwin/release/solvecraft" +lipo -create -output "stage/$name/solvecraft-cli" "$t/aarch64-apple-darwin/release/solvecraft-cli" "$t/x86_64-apple-darwin/release/solvecraft-cli" +cat > "$app/Contents/Info.plist" < + + + + CFBundleNameSolveCraft + CFBundleDisplayNameSolveCraft + CFBundleIdentifierio.github.bherbruck.solvecraft + CFBundleExecutablesolvecraft + CFBundlePackageTypeAPPL + CFBundleVersion$version + CFBundleShortVersionString$version + LSMinimumSystemVersion11.0 + NSHighResolutionCapable + + +PLIST +cp README.md LICENSE-MIT LICENSE-APACHE NOTICE ATTRIBUTION.md "stage/$name/" +lipo -info "$app/Contents/MacOS/solvecraft" +(cd stage && ditto -c -k --keepParent "$name" "../out/$name.zip") +ls -l out diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..dd480585 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,136 @@ +# Release builds: push a tag `v*` (or run it by hand with a tag name) and this builds the desktop +# app and the CLI for Linux, Windows and macOS plus the web app, and attaches them to a GitHub +# release (a pre-release while the version is 0.x) with SHA256SUMS. Notes: +# .github/release-notes.md. +name: Release + +on: + push: + tags: ["v*"] + workflow_dispatch: + inputs: + tag: + description: "Tag to release (must exist), e.g. v0.1.0" + required: true + +permissions: + contents: write + +env: + CARGO_TERM_COLOR: always + TAG: ${{ inputs.tag || github.ref_name }} + TRUNK_VERSION: v0.21.14 + +jobs: + linux: + runs-on: ubuntu-22.04 # an older glibc, so the binaries run on older distributions + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.TAG }} + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo build --release --locked -p solvecraft -p solvecraft-cli + - name: Package + run: .github/release/package-linux.sh "$TAG" + - uses: actions/upload-artifact@v4 + with: + name: linux + path: out/* + + windows: + runs-on: windows-latest + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.TAG }} + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo build --release --locked -p solvecraft -p solvecraft-cli + - name: Package + shell: pwsh + run: | + $name = "solvecraft-$env:TAG-windows-x86_64" + New-Item -ItemType Directory -Force -Path "stage/$name", out | Out-Null + Copy-Item target/release/solvecraft.exe, target/release/solvecraft-cli.exe, README.md, LICENSE-MIT, LICENSE-APACHE, NOTICE, ATTRIBUTION.md "stage/$name/" + Compress-Archive -Path "stage/$name" -DestinationPath "out/$name.zip" + - uses: actions/upload-artifact@v4 + with: + name: windows + path: out/* + + macos: + # One universal build: arm64 natively, x86_64 cross-compiled on the same runner, joined by lipo. + runs-on: macos-14 + timeout-minutes: 90 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.TAG }} + - uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-apple-darwin, x86_64-apple-darwin + - uses: Swatinem/rust-cache@v2 + - run: | + cargo build --release --locked -p solvecraft -p solvecraft-cli --target aarch64-apple-darwin + cargo build --release --locked -p solvecraft -p solvecraft-cli --target x86_64-apple-darwin + - name: Package + run: .github/release/package-macos.sh "$TAG" + - uses: actions/upload-artifact@v4 + with: + name: macos + path: out/* + + web: + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.TAG }} + - uses: dtolnay/rust-toolchain@stable + with: + targets: wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 + - name: Install trunk + run: | + mkdir -p "$HOME/.local/bin" + curl -sSfL "https://github.com/trunk-rs/trunk/releases/download/${TRUNK_VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz" | tar -xz -C "$HOME/.local/bin" + echo "$HOME/.local/bin" >> "$GITHUB_PATH" + - name: Build (relative public URL, so it can be served from any path) + working-directory: apps/solvecraft-web + run: trunk build --release + - name: Package + run: | + name="solvecraft-$TAG-web" + mkdir -p out && cp -r dist/web "$name" + cp LICENSE-MIT LICENSE-APACHE NOTICE "$name/" + zip -qr "out/$name.zip" "$name" + - uses: actions/upload-artifact@v4 + with: + name: web + path: out/* + + release: + needs: [linux, windows, macos, web] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.TAG }} + - uses: actions/download-artifact@v4 + with: + path: assets + merge-multiple: true + - name: Checksums + working-directory: assets + run: sha256sum * > SHA256SUMS && cat SHA256SUMS + - uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ env.TAG }} + name: SolveCraft ${{ env.TAG }} + body_path: .github/release-notes.md + prerelease: ${{ startsWith(env.TAG, 'v0.') }} + files: assets/*