Some checks failed
Build and Test / build (push) Has been cancelled
- Update .gitmodules: ztools, silo, and OndselSolver now reference public git.kindred-systems.com URLs instead of internal Gitea - Merge OndselSolver numerical solver with ML solver scaffolding into unified kindred/solver repository - Rewrite README.md for conciseness - Add docs/CI_CD.md with full pipeline documentation - Rework CI/CD workflows for public dockerized runners - Add multi-platform release builds (Linux, macOS, Windows) - Release workflow triggers on v* tags only - Update docs/REPOSITORY_STATE.md and docs/INTEGRATION_PLAN.md
274 lines
9.4 KiB
Markdown
274 lines
9.4 KiB
Markdown
# CI/CD
|
|
|
|
Kindred Create uses Gitea Actions for continuous integration and release builds. Workflows are defined in `.gitea/workflows/`.
|
|
|
|
## Overview
|
|
|
|
| Workflow | Trigger | Purpose | Artifacts |
|
|
|----------|---------|---------|-----------|
|
|
| `build.yml` | Push to `main`, pull requests | Build + test | Linux tarball |
|
|
| `release.yml` | Tags matching `v*` | Multi-platform release | AppImage, .deb, .dmg, .exe, .7z |
|
|
|
|
All builds run on public runners in dockerized mode. No host-mode or internal infrastructure is required.
|
|
|
|
---
|
|
|
|
## Build workflow (`build.yml`)
|
|
|
|
Runs on every push to `main` and on pull requests. Builds the project in an Ubuntu 24.04 container and runs the test suite.
|
|
|
|
### Steps
|
|
|
|
1. Install system prerequisites (GL, X11, fontconfig headers)
|
|
2. Checkout with recursive submodules
|
|
3. Install pixi
|
|
4. Restore ccache from prior builds
|
|
5. Configure via `pixi run cmake --preset conda-linux-release`
|
|
6. Build with `pixi run cmake --build build/release -j$(nproc)`
|
|
7. Run C++ unit tests under xvfb (Assembly_tests excluded due to discovery timeouts)
|
|
8. Install to `build/release/install`
|
|
9. Run Python CLI tests (`FreeCADCmd -t 0`)
|
|
10. Run GUI tests headless (`xvfb-run FreeCAD -t 0`)
|
|
11. Package as `.tar.xz` with SHA256 checksum
|
|
12. Upload artifact (14-day retention)
|
|
|
|
### Caching
|
|
|
|
ccache is persisted between builds using `actions/cache`. Cache keys are scoped by branch and commit SHA, with fallback to the branch key then `main`.
|
|
|
|
```
|
|
Key: ccache-build-{branch}-{sha}
|
|
Fallback: ccache-build-{branch}-
|
|
Fallback: ccache-build-main-
|
|
```
|
|
|
|
ccache configuration: 4 GB max, zlib compression level 6, sloppy mode for include timestamps and PCH.
|
|
|
|
---
|
|
|
|
## Release workflow (`release.yml`)
|
|
|
|
Triggered by pushing a tag matching `v*` (e.g., `v0.1.0`, `v1.0.0-rc1`). Builds release packages for all platforms in parallel, then creates a Gitea release with all artifacts.
|
|
|
|
### Triggering a release
|
|
|
|
```bash
|
|
git tag v0.1.0
|
|
git push origin v0.1.0
|
|
```
|
|
|
|
Or manually via `workflow_dispatch` with a tag input.
|
|
|
|
Tags containing `rc`, `beta`, or `alpha` are marked as pre-releases.
|
|
|
|
### Platform matrix
|
|
|
|
| Job | Runner | Container | Preset | Output |
|
|
|-----|--------|-----------|--------|--------|
|
|
| `build-linux` | `ubuntu-latest` | `ubuntu:24.04` | `conda-linux-release` | AppImage, .deb |
|
|
| `build-macos` (Intel) | `macos-13` | native | `conda-macos-release` | .dmg (x86_64) |
|
|
| `build-macos` (Apple Silicon) | `macos-14` | native | `conda-macos-release` | .dmg (arm64) |
|
|
| `build-windows` | `windows-latest` | native | `conda-windows-release` | .exe (NSIS), .7z |
|
|
|
|
All four jobs run concurrently. After all succeed, `publish-release` collects artifacts and creates the Gitea release.
|
|
|
|
### Linux build
|
|
|
|
Uses the rattler-build packaging pipeline:
|
|
|
|
1. `pixi install` in `package/rattler-build/`
|
|
2. `pixi run -e package create_bundle` -- invokes `linux/create_bundle.sh`
|
|
3. The bundle script:
|
|
- Copies the pixi conda environment to an AppDir
|
|
- Strips unnecessary files (includes, static libs, cmake files, `__pycache__`)
|
|
- Downloads `appimagetool` and creates a squashfs AppImage (zstd compressed)
|
|
- Generates SHA256 checksums
|
|
4. `package/debian/build-deb.sh` builds a .deb from the AppDir
|
|
- Installs to `/opt/kindred-create/` with wrapper scripts in `/usr/bin/`
|
|
- Sets up LD_LIBRARY_PATH, QT_PLUGIN_PATH, PYTHONPATH in wrappers
|
|
- Creates desktop entry, MIME types, AppStream metainfo
|
|
|
|
### macOS build
|
|
|
|
Builds natively on macOS runners (Intel via `macos-13`, Apple Silicon via `macos-14`):
|
|
|
|
1. `pixi run -e package create_bundle` invokes `osx/create_bundle.sh`
|
|
2. The bundle script:
|
|
- Creates `FreeCAD.app` bundle with conda environment in `Contents/Resources/`
|
|
- Runs `fix_macos_lib_paths.py` to convert absolute rpaths to `@loader_path`
|
|
- Builds native macOS launcher from `launcher/CMakeLists.txt`
|
|
- Patches `Info.plist` with version info
|
|
- Creates DMG via `dmgbuild`
|
|
- If `SIGN_RELEASE=true`: signs and notarizes via `macos_sign_and_notarize.zsh`
|
|
|
|
### Windows build
|
|
|
|
Builds natively on Windows runner:
|
|
|
|
1. `pixi run -e package create_bundle` invokes `windows/create_bundle.sh` (bash via Git for Windows)
|
|
2. The bundle script:
|
|
- Copies conda environment DLLs, Python, and FreeCAD binaries to `FreeCAD_Windows/`
|
|
- Applies SSL certificate patch (`ssl-patch.py`)
|
|
- Creates `qt6.conf` for Qt6 plugin paths
|
|
- Creates `.exe` wrapper shims via Chocolatey `shimgen`
|
|
- Compresses to `.7z` (compression level 9)
|
|
- If `MAKE_INSTALLER=true` and NSIS available: builds NSIS installer
|
|
3. NSIS installer (`package/WindowsInstaller/`):
|
|
- Multi-language support (28 languages)
|
|
- File associations for `.FCStd`
|
|
- Start menu and desktop shortcuts
|
|
- LZMA compression
|
|
|
|
### Publish step
|
|
|
|
`publish-release` runs after all platform builds succeed:
|
|
|
|
1. Downloads all artifacts from `build-linux`, `build-macos`, `build-windows`
|
|
2. Collects release files (AppImage, .deb, .dmg, .7z, .exe, checksums)
|
|
3. Creates a Gitea release via `gitea.com/actions/release-action`
|
|
4. Requires `RELEASE_TOKEN` secret with repository write permissions
|
|
|
|
---
|
|
|
|
## Runner configuration
|
|
|
|
### Public runner setup
|
|
|
|
Workflows target public Gitea-compatible runners. The Linux build job runs inside a Docker container (`ubuntu:24.04`) for isolation and reproducibility. macOS and Windows jobs run directly on hosted runners.
|
|
|
|
**Required runner labels:**
|
|
- `ubuntu-latest` -- Linux builds (dockerized)
|
|
- `macos-13` -- macOS Intel builds
|
|
- `macos-14` -- macOS Apple Silicon builds
|
|
- `windows-latest` -- Windows builds
|
|
|
|
### Registering a self-hosted runner
|
|
|
|
If using self-hosted runners instead of hosted:
|
|
|
|
```bash
|
|
# Download the Gitea runner binary
|
|
curl -fsSL -o act_runner https://gitea.com/gitea/act_runner/releases/latest/download/act_runner-linux-amd64
|
|
chmod +x act_runner
|
|
|
|
# Register with your Gitea instance
|
|
./act_runner register \
|
|
--instance https://git.kindred-systems.com \
|
|
--token <RUNNER_REGISTRATION_TOKEN> \
|
|
--labels ubuntu-latest:docker://ubuntu:24.04
|
|
|
|
# Start the runner
|
|
./act_runner daemon
|
|
```
|
|
|
|
For dockerized mode, the runner executes jobs inside containers. Ensure Docker is installed on the runner host.
|
|
|
|
The runner config file (`config.yaml`) should set:
|
|
|
|
```yaml
|
|
runner:
|
|
labels:
|
|
- "ubuntu-latest:docker://ubuntu:24.04"
|
|
container:
|
|
privileged: false
|
|
network: bridge
|
|
```
|
|
|
|
---
|
|
|
|
## Secrets
|
|
|
|
| Secret | Used by | Purpose |
|
|
|--------|---------|---------|
|
|
| `RELEASE_TOKEN` | `release.yml` (publish) | Gitea API token for creating releases |
|
|
| `SIGNING_KEY_ID` | macOS build (optional) | Apple Developer signing identity |
|
|
|
|
---
|
|
|
|
## Build tools
|
|
|
|
### pixi
|
|
|
|
[pixi](https://pixi.sh) manages all build dependencies via conda-forge. It ensures consistent toolchains (clang, cmake, Qt6, OpenCASCADE, etc.) across all platforms without relying on system packages.
|
|
|
|
Key pixi tasks (defined in root `pixi.toml`):
|
|
|
|
| Task | Description |
|
|
|------|-------------|
|
|
| `pixi run configure` | CMake configure (defaults to debug) |
|
|
| `pixi run build` | CMake build (defaults to debug) |
|
|
| `pixi run install` | CMake install |
|
|
| `pixi run test` | Run ctest |
|
|
| `pixi run freecad` | Launch built FreeCAD |
|
|
| `pixi run build-release` | CMake build (release) |
|
|
|
|
### CMake presets
|
|
|
|
Defined in `CMakePresets.json`. Release builds use:
|
|
|
|
| Platform | Preset | Compiler | Linker |
|
|
|----------|--------|----------|--------|
|
|
| Linux | `conda-linux-release` | clang/clang++ | mold |
|
|
| macOS | `conda-macos-release` | clang/clang++ | default |
|
|
| Windows | `conda-windows-release` | MSVC | default |
|
|
|
|
### ccache
|
|
|
|
Compiler cache is used across all builds to speed up incremental compilation. Cache is persisted between CI runs via `actions/cache`. Configuration:
|
|
|
|
- Max size: 4 GB
|
|
- Compression: zlib level 6
|
|
- Sloppy mode: include timestamps, PCH defines, time macros
|
|
|
|
---
|
|
|
|
## Adding a new platform or package format
|
|
|
|
1. Create a bundle script at `package/rattler-build/<platform>/create_bundle.sh`
|
|
2. Add the platform to `package/rattler-build/pixi.toml` if needed
|
|
3. Add a new job to `release.yml` following the existing pattern
|
|
4. Add the new artifact pattern to the `publish-release` job's `find` command
|
|
5. Update the release body template with the new download entry
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Build fails with missing system libraries
|
|
|
|
The Docker container installs only minimal dependencies. If a new dependency is needed, add it to the `apt-get install` step in the workflow. Check the pixi environment first -- most dependencies should come from conda-forge, not system packages.
|
|
|
|
### ccache misses are high
|
|
|
|
ccache misses spike when:
|
|
- The compiler version changes (pixi update)
|
|
- CMake presets change configuration flags
|
|
- The cache key doesn't match (new branch, force-pushed SHA)
|
|
|
|
Check `pixi run ccache -s` output for hit/miss ratios.
|
|
|
|
### Submodule checkout fails
|
|
|
|
Submodules pointing to internal Gitea instances require either:
|
|
- Public mirrors of the submodule repositories
|
|
- Runner network access to the Gitea instance
|
|
- Submodule URLs updated to public-facing addresses in `.gitmodules`
|
|
|
|
### macOS signing
|
|
|
|
Code signing and notarization require:
|
|
- `SIGNING_KEY_ID` secret set to the Apple Developer identity
|
|
- `SIGN_RELEASE=true` environment variable
|
|
- Valid Apple Developer account credentials in the runner keychain
|
|
|
|
Without signing, the DMG is created unsigned. Users will see Gatekeeper warnings.
|
|
|
|
### Windows NSIS installer not created
|
|
|
|
The NSIS installer requires:
|
|
- NSIS 3.x installed in the runner environment (available via conda or Chocolatey)
|
|
- `MAKE_INSTALLER=true` environment variable
|
|
- Chocolatey `shimgen.exe` for wrapper executables
|
|
|
|
If NSIS is unavailable, only the `.7z` portable archive is produced.
|