phase 1: copy Kindred-only files onto upstream/main (FreeCAD 1.2.0-dev)

Wholesale copy of all Kindred Create additions that don't conflict with
upstream FreeCAD code:

- kindred-icons/ (1444 Catppuccin Mocha SVG icon overrides)
- src/Mod/Create/ (Kindred Create workbench)
- src/Gui/ Kindred source files (FileOrigin, OriginManager,
  OriginSelectorWidget, CommandOrigin, BreadcrumbToolBar, EditingContext)
- src/Gui/Icons/ (Kindred branding and silo icons)
- src/Gui/PreferencePacks/KindredCreate/
- src/Gui/Stylesheets/ (KindredCreate.qss, images_dark-light/)
- package/ (rattler-build recipe)
- docs/ (architecture, guides, specifications)
- .gitea/ (CI workflows, issue templates)
- mods/silo, mods/ztools submodules
- .gitmodules (Kindred submodule URLs)
- resources/ (kindred-create.desktop, kindred-create.xml)
- banner-logo-light.png, CONTRIBUTING.md
This commit is contained in:
forbes
2026-02-13 14:03:58 -06:00
parent 5d81f8ac16
commit 87a0af0b0f
1566 changed files with 32071 additions and 6155 deletions

View File

@@ -0,0 +1,82 @@
name: Bug Report
about: Report a bug or unexpected behavior in Kindred Create
labels:
- bug
body:
- type: textarea
id: description
attributes:
label: Description
description: A clear description of the bug.
placeholder: What happened? What did you expect instead?
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to Reproduce
description: Minimal steps to reproduce the behavior.
placeholder: |
1. Open a new file
2. Switch to the PartDesign workbench
3. ...
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: What should have happened?
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual Behavior
description: What actually happened? Include error messages, console output, or screenshots.
validations:
required: true
- type: dropdown
id: component
attributes:
label: Component
description: Which part of Kindred Create is affected?
options:
- General / Core
- ztools Workbench
- Silo (Parts Database)
- Theme / QSS
- Assembly
- PartDesign
- CI/CD
- Documentation
- Other
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment
description: |
OS, Kindred Create version, and any relevant details.
Find the version under Help > About Kindred Create.
placeholder: |
- OS: Ubuntu 24.04
- Kindred Create: v0.2.0 (AppImage)
- GPU: NVIDIA RTX 3060
validations:
required: false
- type: textarea
id: logs
attributes:
label: Log Output
description: Paste any relevant log output (View > Panels > Report View).
render: shell
validations:
required: false

View File

@@ -0,0 +1,42 @@
name: Documentation
about: Report missing, incorrect, or unclear documentation
labels:
- documentation
body:
- type: textarea
id: description
attributes:
label: Description
description: What needs to be documented, updated, or corrected?
validations:
required: true
- type: dropdown
id: type
attributes:
label: Type
description: What kind of documentation change is needed?
options:
- Missing documentation
- Incorrect / outdated content
- Unclear or confusing
- New guide or tutorial
validations:
required: true
- type: textarea
id: location
attributes:
label: Location
description: Where should this documentation live? Link to existing pages if applicable.
placeholder: e.g. docs/src/guide/ztools.md, or "new page under Reference"
validations:
required: false
- type: textarea
id: context
attributes:
label: Additional Context
description: Any other details, screenshots, or references that would help.
validations:
required: false

View File

@@ -0,0 +1,55 @@
name: Feature Request
about: Suggest a new feature or enhancement for Kindred Create
labels:
- enhancement
body:
- type: textarea
id: description
attributes:
label: Description
description: A clear description of the feature you'd like.
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Use Case
description: Why is this feature needed? What problem does it solve?
placeholder: As a user, I want to... so that...
validations:
required: true
- type: dropdown
id: component
attributes:
label: Component
description: Which part of Kindred Create does this relate to?
options:
- General / Core
- ztools Workbench
- Silo (Parts Database)
- Theme / QSS
- Assembly
- PartDesign
- CI/CD
- Documentation
- Other
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposed Implementation
description: If you have ideas on how this could be implemented, describe them here.
validations:
required: false
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: Any alternative approaches or workarounds you've considered.
validations:
required: false

View File

@@ -0,0 +1,18 @@
## Summary
<!-- Brief description of what this PR does -->
## Changes
<!-- List the key changes made -->
## Related Issues
<!-- Link related issues: Closes #123, Fixes #456 -->
## Checklist
- [ ] Commit messages follow [conventional commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `chore:`, `docs:`, `art:`)
- [ ] Code follows project style (clang-format for C++, black for Python)
- [ ] Changes are tested locally
- [ ] Documentation updated (if applicable)

View File

@@ -0,0 +1,11 @@
[Unit]
Description=Kindred Create CI runner disk cleanup
After=docker.service
[Service]
Type=oneshot
ExecStart=/opt/runner/cleanup.sh
Environment=CLEANUP_THRESHOLD=85
Environment=CACHE_MAX_AGE_DAYS=7
StandardOutput=append:/var/log/runner-cleanup.log
StandardError=append:/var/log/runner-cleanup.log

220
.gitea/runner/cleanup.sh Executable file
View File

@@ -0,0 +1,220 @@
#!/usr/bin/env bash
# Runner disk cleanup script for Kindred Create CI/CD
#
# Designed to run as a cron job on the pubworker host:
# */30 * * * * /path/to/cleanup.sh >> /var/log/runner-cleanup.log 2>&1
#
# Or install the systemd timer (see cleanup.timer / cleanup.service).
#
# What it cleans:
# 1. Docker: stopped containers, dangling images, build cache
# 2. act_runner action cache: keeps only the newest entry per key prefix
# 3. act_runner workspaces: removes leftover build workspaces
# 4. System: apt cache, old logs
#
# What it preserves:
# - The current runner container and its image
# - The most recent cache entry per prefix (so ccache hits still work)
# - Everything outside of known CI paths
set -euo pipefail
# ---------------------------------------------------------------------------
# Configuration -- adjust these to match your runner setup
# ---------------------------------------------------------------------------
# Disk usage threshold (percent) -- only run aggressive cleanup above this
THRESHOLD=${CLEANUP_THRESHOLD:-85}
# act_runner cache directory (default location)
CACHE_DIR=${CACHE_DIR:-/root/.cache/actcache}
# act_runner workspace directories
WORKSPACES=(
"/root/.cache/act"
"/workspace"
)
# Maximum age (days) for cache entries before unconditional deletion
CACHE_MAX_AGE_DAYS=${CACHE_MAX_AGE_DAYS:-7}
# Maximum age (days) for Docker images not used by running containers
DOCKER_IMAGE_MAX_AGE=${DOCKER_IMAGE_MAX_AGE:-48h}
# Log prefix
LOG_PREFIX="[runner-cleanup]"
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
log() { echo "$(date '+%Y-%m-%d %H:%M:%S') ${LOG_PREFIX} $*"; }
disk_usage_pct() {
df --output=pcent / | tail -1 | tr -dc '0-9'
}
bytes_to_human() {
numfmt --to=iec-i --suffix=B "$1" 2>/dev/null || echo "${1}B"
}
# ---------------------------------------------------------------------------
# Phase 1: Check if cleanup is needed
# ---------------------------------------------------------------------------
usage=$(disk_usage_pct)
log "Disk usage: ${usage}% (threshold: ${THRESHOLD}%)"
if [ "$usage" -lt "$THRESHOLD" ]; then
log "Below threshold, running light cleanup only"
AGGRESSIVE=false
else
log "Above threshold, running aggressive cleanup"
AGGRESSIVE=true
fi
# ---------------------------------------------------------------------------
# Phase 2: Docker cleanup (always runs, safe)
# ---------------------------------------------------------------------------
log "--- Docker cleanup ---"
# Remove stopped containers
stopped=$(docker ps -aq --filter status=exited --filter status=dead 2>/dev/null | wc -l)
if [ "$stopped" -gt 0 ]; then
docker rm $(docker ps -aq --filter status=exited --filter status=dead) 2>/dev/null || true
log "Removed ${stopped} stopped containers"
fi
# Remove dangling images (untagged layers)
dangling=$(docker images -q --filter dangling=true 2>/dev/null | wc -l)
if [ "$dangling" -gt 0 ]; then
docker rmi $(docker images -q --filter dangling=true) 2>/dev/null || true
log "Removed ${dangling} dangling images"
fi
# Prune build cache
docker builder prune -f --filter "until=${DOCKER_IMAGE_MAX_AGE}" 2>/dev/null || true
log "Pruned Docker build cache older than ${DOCKER_IMAGE_MAX_AGE}"
if [ "$AGGRESSIVE" = true ]; then
# Remove all images not used by running containers
running_images=$(docker ps -q 2>/dev/null | xargs -r docker inspect --format='{{.Image}}' | sort -u)
all_images=$(docker images -q 2>/dev/null | sort -u)
for img in $all_images; do
if ! echo "$running_images" | grep -q "$img"; then
docker rmi -f "$img" 2>/dev/null || true
fi
done
log "Removed unused Docker images (aggressive)"
# Prune volumes
docker volume prune -f 2>/dev/null || true
log "Pruned unused Docker volumes"
fi
# ---------------------------------------------------------------------------
# Phase 3: act_runner action cache cleanup
# ---------------------------------------------------------------------------
log "--- Action cache cleanup ---"
if [ -d "$CACHE_DIR" ]; then
before=$(du -sb "$CACHE_DIR" 2>/dev/null | cut -f1)
# Delete cache entries older than max age
find "$CACHE_DIR" -type f -mtime "+${CACHE_MAX_AGE_DAYS}" -delete 2>/dev/null || true
find "$CACHE_DIR" -type d -empty -delete 2>/dev/null || true
after=$(du -sb "$CACHE_DIR" 2>/dev/null | cut -f1)
freed=$((before - after))
log "Cache cleanup freed $(bytes_to_human $freed) (entries older than ${CACHE_MAX_AGE_DAYS}d)"
else
log "Cache directory not found: ${CACHE_DIR}"
# Try common alternative locations
for alt in /var/lib/act_runner/.cache/actcache /home/*/.cache/actcache; do
if [ -d "$alt" ]; then
log "Found cache at: $alt (update CACHE_DIR config)"
CACHE_DIR="$alt"
find "$CACHE_DIR" -type f -mtime "+${CACHE_MAX_AGE_DAYS}" -delete 2>/dev/null || true
find "$CACHE_DIR" -type d -empty -delete 2>/dev/null || true
break
fi
done
fi
# ---------------------------------------------------------------------------
# Phase 4: Workspace cleanup
# ---------------------------------------------------------------------------
log "--- Workspace cleanup ---"
for ws in "${WORKSPACES[@]}"; do
if [ -d "$ws" ]; then
# Remove workspace dirs not modified in the last 2 hours
# (active builds should be touching files continuously)
before=$(du -sb "$ws" 2>/dev/null | cut -f1)
find "$ws" -mindepth 1 -maxdepth 1 -type d -mmin +120 -exec rm -rf {} + 2>/dev/null || true
after=$(du -sb "$ws" 2>/dev/null | cut -f1)
freed=$((before - after))
if [ "$freed" -gt 0 ]; then
log "Workspace $ws: freed $(bytes_to_human $freed)"
fi
fi
done
# ---------------------------------------------------------------------------
# Phase 5: System cleanup
# ---------------------------------------------------------------------------
log "--- System cleanup ---"
# apt cache
apt-get clean 2>/dev/null || true
# Truncate large log files (keep last 1000 lines)
for logfile in /var/log/syslog /var/log/daemon.log /var/log/kern.log; do
if [ -f "$logfile" ] && [ "$(stat -c%s "$logfile" 2>/dev/null)" -gt 104857600 ]; then
tail -1000 "$logfile" > "${logfile}.tmp" && mv "${logfile}.tmp" "$logfile"
log "Truncated $logfile (was >100MB)"
fi
done
# Journal logs older than 3 days
journalctl --vacuum-time=3d 2>/dev/null || true
# ---------------------------------------------------------------------------
# Phase 6: Emergency cleanup (only if still critical)
# ---------------------------------------------------------------------------
usage=$(disk_usage_pct)
if [ "$usage" -gt 95 ]; then
log "CRITICAL: Still at ${usage}% after cleanup"
# Nuclear option: remove ALL docker data except running containers
docker system prune -af --volumes 2>/dev/null || true
log "Ran docker system prune -af --volumes"
# Clear entire action cache
if [ -d "$CACHE_DIR" ]; then
rm -rf "${CACHE_DIR:?}/"*
log "Cleared entire action cache"
fi
usage=$(disk_usage_pct)
log "After emergency cleanup: ${usage}%"
fi
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
usage=$(disk_usage_pct)
log "Cleanup complete. Disk usage: ${usage}%"
# Report top space consumers for diagnostics
log "Top 10 directories under /var:"
du -sh /var/*/ 2>/dev/null | sort -rh | head -10 | while read -r line; do
log " $line"
done

View File

@@ -0,0 +1,10 @@
[Unit]
Description=Run CI runner cleanup every 30 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=30min
Persistent=true
[Install]
WantedBy=timers.target

146
.gitea/workflows/build.yml Normal file
View File

@@ -0,0 +1,146 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
name: Build and Test
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
env:
CCACHE_DIR: /tmp/ccache-kindred-create
CCACHE_COMPRESS: "true"
CCACHE_COMPRESSLEVEL: "6"
CCACHE_MAXSIZE: "4G"
CCACHE_SLOPPINESS: "include_file_ctime,include_file_mtime,pch_defines,time_macros"
CCACHE_COMPILERCHECK: "content"
CCACHE_BASEDIR: ${{ github.workspace }}
DEBIAN_FRONTEND: noninteractive
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/ca-certificates.crt
steps:
- name: Trust Cloudflare origin CA
run: |
apt-get update -qq
apt-get install -y --no-install-recommends ca-certificates
update-ca-certificates
- name: Free disk space
run: |
echo "=== Disk usage before cleanup ==="
df -h /
rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache 2>/dev/null || true
rm -rf /usr/local/share/boost /usr/share/swift 2>/dev/null || true
apt-get autoremove -y 2>/dev/null || true
apt-get clean 2>/dev/null || true
echo "=== Disk usage after cleanup ==="
df -h /
- name: Install system prerequisites
run: |
apt-get update -qq
apt-get install -y --no-install-recommends \
ca-certificates curl git xvfb xauth openssl sudo \
libgl1-mesa-dev libglu1-mesa-dev libx11-dev libxkbcommon-dev \
libxcb-xkb-dev libfontconfig1-dev
- name: Checkout repository
uses: https://git.kindred-systems.com/actions/checkout.git@v4
with:
submodules: recursive
fetch-depth: 1
- name: Fetch latest tag (for git describe)
run: |
latest_tag=$(git ls-remote --tags --sort=-v:refname origin 'refs/tags/v*' | grep -v '\^{}' | head -n1 | awk '{print $2}')
if [ -n "$latest_tag" ]; then
git fetch --no-recurse-submodules --force --depth=1 origin "+${latest_tag}:${latest_tag}"
fi
- name: Install pixi
run: |
curl -fsSL https://pixi.sh/install.sh | bash
echo "$HOME/.pixi/bin" >> $GITHUB_PATH
export PATH="$HOME/.pixi/bin:$PATH"
pixi --version
- name: Run Kindred addon tests (pure logic, no build needed)
timeout-minutes: 2
run: python3 tests/run_kindred_tests.py
- name: Restore ccache
id: ccache-restore
uses: https://git.kindred-systems.com/actions/cache.git/restore@v4
with:
path: /tmp/ccache-kindred-create
key: ccache-build-${{ github.ref_name }}-${{ github.run_id }}
restore-keys: |
ccache-build-${{ github.ref_name }}-
ccache-build-main-
- name: Prepare ccache
run: |
mkdir -p $CCACHE_DIR
pixi run ccache -z
pixi run ccache -p
- name: Configure (CMake)
run: pixi run cmake --preset conda-linux-release
- name: Build
run: pixi run cmake --build build/release -j$(nproc)
- name: Show ccache statistics
run: pixi run ccache -s
- name: Save ccache
if: always()
uses: https://git.kindred-systems.com/actions/cache.git/save@v4
with:
path: /tmp/ccache-kindred-create
key: ccache-build-${{ github.ref_name }}-${{ github.run_id }}
- name: Run C++ unit tests
continue-on-error: true
timeout-minutes: 15
run: |
export CTEST_DISCOVERY_TIMEOUT=60
pixi run xvfb-run -a ctest --test-dir build/release \
--output-on-failure \
--timeout 120 \
--exclude-regex "Assembly_tests" \
2>&1 || true
- name: Install
run: pixi run cmake --install build/release --prefix build/release/install
- name: Run Python CLI tests
timeout-minutes: 10
run: pixi run timeout 300 build/release/bin/FreeCADCmd -t 0 || true
- name: Run GUI tests (headless)
timeout-minutes: 10
run: pixi run timeout 300 xvfb-run -a build/release/bin/FreeCAD -t 0 || true
- name: Package build artifacts
run: |
ARTIFACT_NAME="kindred-create-$(git describe --tags --always)-linux-x86_64"
cd build/release
cp -a install "${ARTIFACT_NAME}"
tar -cJf "${ARTIFACT_NAME}.tar.xz" "${ARTIFACT_NAME}"
sha256sum "${ARTIFACT_NAME}.tar.xz" > "${ARTIFACT_NAME}.tar.xz.sha256"
echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV
- name: Upload build artifact
uses: https://git.kindred-systems.com/actions/upload-artifact.git@v3
with:
name: ${{ env.ARTIFACT_NAME }}
path: |
build/release/*.tar.xz
build/release/*.sha256
retention-days: 14

51
.gitea/workflows/docs.yml Normal file
View File

@@ -0,0 +1,51 @@
name: Deploy Docs
on:
push:
branches: [main]
paths:
- "docs/**"
- ".gitea/workflows/docs.yml"
- ".gitea/workflows/sync-silo-docs.yml"
jobs:
build-and-deploy:
runs-on: docs
steps:
- name: Checkout
run: |
REPO_URL="http://gitea:3000/kindred/create.git"
if [ -d .git ]; then
git fetch "$REPO_URL" main
git checkout -f FETCH_HEAD
else
git clone --depth 1 --branch main "$REPO_URL" .
fi
- name: Install mdBook
run: |
if ! command -v mdbook &>/dev/null; then
MDBOOK_VERSION="v0.5.2"
wget -q -O mdbook.tar.gz "https://github.com/rust-lang/mdBook/releases/download/${MDBOOK_VERSION}/mdbook-${MDBOOK_VERSION}-x86_64-unknown-linux-musl.tar.gz"
tar -xzf mdbook.tar.gz -C /usr/local/bin
rm mdbook.tar.gz
fi
- name: Fetch Silo server docs
run: |
rm -rf /tmp/silo
git clone --depth 1 http://gitea:3000/kindred/silo.git /tmp/silo
mkdir -p docs/src/silo-server
cp /tmp/silo/docs/*.md docs/src/silo-server/
cp /tmp/silo/README.md docs/src/silo-server/overview.md
cp /tmp/silo/ROADMAP.md docs/src/silo-server/ROADMAP.md 2>/dev/null || true
cp /tmp/silo/frontend-spec.md docs/src/silo-server/frontend-spec.md 2>/dev/null || true
rm -rf /tmp/silo
- name: Build mdBook
run: mdbook build docs/
- name: Deploy
run: |
rm -rf /opt/git/docs/book/*
cp -r docs/book/* /opt/git/docs/book/

View File

@@ -0,0 +1,438 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
name: Release Build
on:
push:
tags: ["v*", "latest"]
workflow_dispatch:
inputs:
tag:
description: "Release tag (e.g., v0.1.0)"
required: true
type: string
jobs:
# ---------------------------------------------------------------------------
# Linux: AppImage + .deb
# ---------------------------------------------------------------------------
build-linux:
runs-on: ubuntu-latest
env:
CCACHE_DIR: /tmp/ccache-kindred-create
CCACHE_COMPRESS: "true"
CCACHE_COMPRESSLEVEL: "6"
CCACHE_MAXSIZE: "4G"
CCACHE_SLOPPINESS: "include_file_ctime,include_file_mtime,pch_defines,time_macros"
CCACHE_COMPILERCHECK: "content"
CCACHE_BASEDIR: ${{ github.workspace }}
BUILD_TAG: ${{ github.ref_name || inputs.tag }}
CFLAGS: "-O3"
CXXFLAGS: "-O3"
DEBIAN_FRONTEND: noninteractive
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/ca-certificates.crt
steps:
- name: Trust Cloudflare origin CA
run: |
apt-get update -qq
apt-get install -y --no-install-recommends ca-certificates
update-ca-certificates
- name: Free disk space
run: |
echo "=== Disk usage before cleanup ==="
df -h /
# Remove pre-installed bloat common in runner images
rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache 2>/dev/null || true
rm -rf /usr/local/share/boost /usr/share/swift 2>/dev/null || true
apt-get autoremove -y 2>/dev/null || true
apt-get clean 2>/dev/null || true
echo "=== Disk usage after cleanup ==="
df -h /
- name: Install system prerequisites
run: |
apt-get update -qq
apt-get install -y --no-install-recommends \
ca-certificates curl git file fuse3 xvfb xauth openssl sudo dpkg-dev \
libgl1-mesa-dev libglu1-mesa-dev libx11-dev libxkbcommon-dev \
libxcb-xkb-dev libfontconfig1-dev
- name: Checkout repository
uses: https://git.kindred-systems.com/actions/checkout.git@v4
with:
submodules: recursive
fetch-depth: 1
- name: Fetch latest tag (for git describe)
run: |
latest_tag=$(git ls-remote --tags --sort=-v:refname origin 'refs/tags/v*' | grep -v '\^{}' | head -n1 | awk '{print $2}')
if [ -n "$latest_tag" ]; then
git fetch --no-recurse-submodules --force --depth=1 origin "+${latest_tag}:${latest_tag}"
fi
- name: Install pixi
run: |
curl -fsSL https://pixi.sh/install.sh | bash
echo "$HOME/.pixi/bin" >> $GITHUB_PATH
export PATH="$HOME/.pixi/bin:$PATH"
pixi --version
- name: Restore ccache
id: ccache-restore
uses: https://git.kindred-systems.com/actions/cache.git/restore@v4
with:
path: /tmp/ccache-kindred-create
key: ccache-release-linux-${{ github.run_id }}
restore-keys: |
ccache-release-linux-
ccache-build-main-
- name: Prepare ccache
run: |
mkdir -p $CCACHE_DIR
# Ensure ccache is accessible to rattler-build's subprocess
export PATH="$(pixi run bash -c 'echo $PATH')"
pixi run ccache -z
pixi run ccache -p
- name: Build release package (AppImage)
working-directory: package/rattler-build
run: |
pixi install
pixi run -e package create_bundle
- name: Show ccache statistics
run: pixi run ccache -s
- name: Save ccache
if: always()
uses: https://git.kindred-systems.com/actions/cache.git/save@v4
with:
path: /tmp/ccache-kindred-create
key: ccache-release-linux-${{ github.run_id }}
- name: Clean up intermediate build files
run: |
# Remove pixi package cache and build work dirs to free space for .deb
rm -rf package/rattler-build/.pixi/build 2>/dev/null || true
find /root/.cache/rattler -type f -delete 2>/dev/null || true
echo "=== Disk usage after cleanup ==="
df -h /
- name: Build .deb package
run: |
./package/debian/build-deb.sh \
package/rattler-build/linux/AppDir/usr \
package/rattler-build/linux \
"${BUILD_TAG}"
- name: List built artifacts
run: |
echo "=== Linux release artifacts ==="
ls -lah package/rattler-build/linux/*.AppImage* 2>/dev/null || true
ls -lah package/rattler-build/linux/*.deb* 2>/dev/null || true
ls -lah package/rattler-build/linux/*-SHA256.txt 2>/dev/null || true
- name: Upload Linux artifacts
uses: https://git.kindred-systems.com/actions/upload-artifact.git@v3
with:
name: release-linux
path: |
package/rattler-build/linux/FreeCAD_*.AppImage
package/rattler-build/linux/*.deb
package/rattler-build/linux/*-SHA256.txt
package/rattler-build/linux/*.sha256
if-no-files-found: error
# ---------------------------------------------------------------------------
# macOS: DMG (Intel + Apple Silicon)
# TODO: Re-enable when macOS runners are available or cross-compilation is set up
# ---------------------------------------------------------------------------
# build-macos:
# strategy:
# fail-fast: false
# matrix:
# include:
# - runner: macos-13
# arch: x86_64
# - runner: macos-14
# arch: arm64
#
# runs-on: ${{ matrix.runner }}
#
# env:
# CCACHE_DIR: /tmp/ccache-kindred-create
# CCACHE_COMPRESS: "true"
# CCACHE_COMPRESSLEVEL: "6"
# CCACHE_MAXSIZE: "4G"
# CCACHE_SLOPPINESS: "include_file_ctime,include_file_mtime,pch_defines,time_macros"
# CCACHE_BASEDIR: ${{ github.workspace }}
# BUILD_TAG: ${{ github.ref_name || inputs.tag }}
# CFLAGS: "-O3"
# CXXFLAGS: "-O3"
#
# steps:
# - name: Checkout repository
# uses: https://git.kindred-systems.com/actions/checkout.git@v4
# with:
# submodules: recursive
# fetch-depth: 1
#
# - name: Fetch tags
# run: git fetch --tags --force --no-recurse-submodules origin
#
# - name: Install pixi
# run: |
# curl -fsSL https://pixi.sh/install.sh | bash
# echo "$HOME/.pixi/bin" >> $GITHUB_PATH
# export PATH="$HOME/.pixi/bin:$PATH"
# pixi --version
#
# - name: Restore ccache
# id: ccache-restore
# uses: https://git.kindred-systems.com/actions/cache.git/restore@v4
# with:
# path: /tmp/ccache-kindred-create
# key: ccache-release-macos-${{ matrix.arch }}-${{ github.sha }}
# restore-keys: |
# ccache-release-macos-${{ matrix.arch }}-
#
# - name: Prepare ccache
# run: |
# mkdir -p $CCACHE_DIR
# pixi run ccache -z
#
# - name: Build release package (DMG)
# working-directory: package/rattler-build
# run: |
# pixi install
# pixi run -e package create_bundle
#
# - name: Show ccache statistics
# run: pixi run ccache -s
#
# - name: Save ccache
# if: always()
# uses: https://git.kindred-systems.com/actions/cache.git/save@v4
# with:
# path: /tmp/ccache-kindred-create
# key: ccache-release-macos-${{ matrix.arch }}-${{ github.sha }}
#
# - name: List built artifacts
# run: |
# echo "=== macOS ${{ matrix.arch }} release artifacts ==="
# ls -lah package/rattler-build/osx/*.dmg* 2>/dev/null || true
#
# - name: Upload macOS artifacts
# uses: https://git.kindred-systems.com/actions/upload-artifact.git@v3
# with:
# name: release-macos-${{ matrix.arch }}
# path: |
# package/rattler-build/osx/*.dmg
# package/rattler-build/osx/*-SHA256.txt
# if-no-files-found: error
# ---------------------------------------------------------------------------
# Windows: .exe installer + .7z archive
# TODO: Re-enable when Windows runners are available or cross-compilation is set up
# ---------------------------------------------------------------------------
# build-windows:
# runs-on: windows-latest
#
# env:
# CCACHE_DIR: C:\ccache-kindred-create
# CCACHE_COMPRESS: "true"
# CCACHE_COMPRESSLEVEL: "6"
# CCACHE_MAXSIZE: "4G"
# CCACHE_SLOPPINESS: "include_file_ctime,include_file_mtime,pch_defines,time_macros"
# CCACHE_BASEDIR: ${{ github.workspace }}
# BUILD_TAG: ${{ github.ref_name || inputs.tag }}
# CFLAGS: "/O2"
# CXXFLAGS: "/O2"
# MAKE_INSTALLER: "true"
#
# steps:
# - name: Checkout repository
# uses: https://git.kindred-systems.com/actions/checkout.git@v4
# with:
# submodules: recursive
# fetch-depth: 1
#
# - name: Fetch tags
# shell: bash
# run: git fetch --tags --force --no-recurse-submodules origin
#
# - name: Install pixi
# shell: bash
# run: |
# curl -fsSL https://pixi.sh/install.sh | bash
# echo "$HOME/.pixi/bin" >> $GITHUB_PATH
# export PATH="$HOME/.pixi/bin:$PATH"
# pixi --version
#
# - name: Restore ccache
# id: ccache-restore
# uses: https://git.kindred-systems.com/actions/cache.git/restore@v4
# with:
# path: C:\ccache-kindred-create
# key: ccache-release-windows-${{ github.sha }}
# restore-keys: |
# ccache-release-windows-
#
# - name: Build release package
# shell: bash
# working-directory: package/rattler-build
# run: |
# pixi install
# pixi run -e package create_bundle
#
# - name: Save ccache
# if: always()
# uses: https://git.kindred-systems.com/actions/cache.git/save@v4
# with:
# path: C:\ccache-kindred-create
# key: ccache-release-windows-${{ github.sha }}
#
# - name: List built artifacts
# shell: bash
# run: |
# echo "=== Windows release artifacts ==="
# ls -lah package/rattler-build/windows/*.7z* 2>/dev/null || true
# ls -lah package/rattler-build/windows/*.exe 2>/dev/null || true
# ls -lah package/rattler-build/windows/*-SHA256.txt 2>/dev/null || true
#
# - name: Upload Windows artifacts
# uses: https://git.kindred-systems.com/actions/upload-artifact.git@v3
# with:
# name: release-windows
# path: |
# package/rattler-build/windows/*.7z
# package/rattler-build/windows/*.exe
# package/rattler-build/windows/*-SHA256.txt
# if-no-files-found: error
# ---------------------------------------------------------------------------
# Create Gitea release from all platform artifacts
# ---------------------------------------------------------------------------
publish-release:
needs: [build-linux] # TODO: Add build-macos, build-windows when runners are available
runs-on: ubuntu-latest
env:
BUILD_TAG: ${{ github.ref_name || inputs.tag }}
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/ca-certificates.crt
steps:
- name: Trust Cloudflare origin CA
run: |
apt-get update -qq
apt-get install -y --no-install-recommends ca-certificates
update-ca-certificates
- name: Download all artifacts
uses: https://git.kindred-systems.com/actions/download-artifact.git@v3
with:
path: artifacts
- name: List all release artifacts
run: |
echo "=== All release artifacts ==="
find artifacts -type f | sort
- name: Collect release files
run: |
mkdir -p release
find artifacts -type f \( \
-name "*.AppImage" -o \
-name "*.deb" -o \
-name "*.dmg" -o \
-name "*.7z" -o \
-name "*.exe" -o \
-name "*SHA256*" -o \
-name "*.sha256" \
\) -exec cp {} release/ \;
echo "=== Release files ==="
ls -lah release/
- name: Create release
env:
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
GITEA_URL: ${{ github.server_url }}
REPO: ${{ github.repository }}
run: |
TAG="${BUILD_TAG}"
# Build JSON payload entirely in Python to avoid shell/Python type mismatches
PAYLOAD=$(python3 -c "
import json, re
tag = '${TAG}'
prerelease = bool(re.search(r'(rc|beta|alpha)', tag))
body = '''## Kindred Create {tag}
### Downloads
| Platform | File |
|----------|------|
| Linux (AppImage) | \`KindredCreate-*-Linux-x86_64.AppImage\` |
| Linux (Debian/Ubuntu) | \`kindred-create_*.deb\` |
*macOS and Windows builds are not yet available.*
SHA256 checksums are provided alongside each artifact.'''.format(tag=tag)
print(json.dumps({
'tag_name': tag,
'name': f'Kindred Create {tag}',
'body': body,
'prerelease': prerelease,
}))
")
# Delete existing release for this tag (if any) so we can recreate
existing=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}")
if [ "$existing" = "200" ]; then
release_id=$(curl -s \
-H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}" | \
python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
curl -s -X DELETE \
-H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${release_id}"
echo "Deleted existing release ${release_id} for tag ${TAG}"
fi
# Create release
response=$(curl -s -w "\n%{http_code}" -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases")
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | sed '$d')
if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then
echo "::error::Failed to create release (HTTP ${http_code}): ${body}"
exit 1
fi
release_id=$(echo "$body" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
echo "Created release ${release_id}"
# Upload assets
for file in release/*; do
filename=$(basename "$file")
echo "Uploading ${filename}..."
upload_resp=$(curl -s -w "\n%{http_code}" -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-F "attachment=@${file}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${release_id}/assets?name=${filename}")
upload_code=$(echo "$upload_resp" | tail -1)
if [ "$upload_code" -lt 200 ] || [ "$upload_code" -ge 300 ]; then
echo "::warning::Failed to upload ${filename} (HTTP ${upload_code})"
else
echo " done."
fi
done

View File

@@ -0,0 +1,53 @@
name: Sync Silo Server Docs
on:
workflow_dispatch:
schedule:
- cron: "0 6 * * *" # Daily at 06:00 UTC as fallback
jobs:
sync:
runs-on: docs
steps:
- name: Checkout create repo
run: |
REPO_URL="http://gitea:3000/kindred/create.git"
if [ -d .git ]; then
git fetch "$REPO_URL" main
git checkout -f FETCH_HEAD
else
git clone --depth 1 --branch main "$REPO_URL" .
fi
- name: Clone Silo server docs
run: |
rm -rf /tmp/silo
git clone --depth 1 http://gitea:3000/kindred/silo.git /tmp/silo
mkdir -p docs/src/silo-server
cp /tmp/silo/docs/*.md docs/src/silo-server/
cp /tmp/silo/README.md docs/src/silo-server/overview.md
cp /tmp/silo/ROADMAP.md docs/src/silo-server/ROADMAP.md 2>/dev/null || true
cp /tmp/silo/frontend-spec.md docs/src/silo-server/frontend-spec.md 2>/dev/null || true
rm -rf /tmp/silo
- name: Check for changes
id: diff
run: |
git add docs/src/silo-server/
if git diff --cached --quiet; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Commit and push
if: steps.diff.outputs.changed == 'true'
run: |
git config user.name "Kindred Bot"
git config user.email "bot@kindred-systems.com"
git commit -m "docs: sync Silo server documentation
Auto-synced from kindred/silo main branch."
PUSH_URL="http://kindred-bot:${{ secrets.RELEASE_TOKEN }}@gitea:3000/kindred/create.git"
git push "$PUSH_URL" HEAD:main