Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/auto-merge-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Auto-merge release-please PRs
# Automatically merges release-please PRs once CI passes

name: Auto-merge Release PRs

on:
pull_request:
branches: [releases]
types: [opened, synchronize, reopened]

jobs:
auto-merge:
name: Auto-merge release-please PR
runs-on: ubuntu-latest
# Only run for release-please PRs
if: startsWith(github.head_ref, 'release-please--')

permissions:
contents: write
pull-requests: write

steps:
- name: Enable auto-merge
uses: peter-evans/enable-pull-request-automerge@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
pull-request-number: ${{ github.event.pull_request.number }}
merge-method: squash
69 changes: 56 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# CI - runs on PRs to releases branch
# Full test matrix, linting, and build validation
# Separated jobs for faster feedback and clearer results

name: CI

Expand All @@ -23,13 +23,13 @@ jobs:
run: pip install black flake8

- name: Check formatting with black
run: black --check --diff microfinity/ tests/
run: black --check --diff microfinity/ meshcutter/ tests/

- name: Lint with flake8
run: flake8 microfinity/ tests/ --max-line-length=120 --extend-ignore=E203,W503,F401,F403,F405,E402,F821,W293,W605,F841
run: flake8 microfinity/ meshcutter/ tests/ --max-line-length=120 --extend-ignore=E203,W503,F401,F403,F405,E402,F821,W293,W605,F841

test:
name: Test (Python ${{ matrix.python-version }})
test-microfinity:
name: Test microfinity (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -48,18 +48,61 @@ jobs:
run: |
pip install --upgrade pip
pip install cadquery-ocp cadquery cqkit
pip install pytest pytest-cov
pip install pytest
pip install -e .

- name: Run full test suite
run: pytest -v --cov=microfinity --cov-report=xml
- name: Run microfinity tests
run: pytest tests/ --ignore=tests/test_meshcutter -v

- name: Upload coverage
uses: codecov/codecov-action@v4
if: matrix.python-version == '3.11'
test-meshcutter-unit:
name: Test meshcutter unit (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
pip install --upgrade pip
pip install cadquery-ocp cadquery cqkit
pip install manifold3d
pip install pytest
pip install -e .

- name: Run meshcutter unit tests
run: pytest tests/test_meshcutter -m "not integration" -v

test-meshcutter-integration:
name: Test meshcutter integration
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
files: ./coverage.xml
fail_ci_if_error: false
python-version: "3.11"

- name: Install dependencies
run: |
pip install --upgrade pip
pip install cadquery-ocp cadquery cqkit
pip install manifold3d
pip install pytest
pip install -e .

- name: Run meshcutter integration tests
run: pytest tests/test_meshcutter -m "integration" -v

build:
name: Build Package
Expand Down
54 changes: 54 additions & 0 deletions .github/workflows/sync-to-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Sync releases back to dev after release-please creates a release
# This ensures dev stays up-to-date with version bumps and changelog updates

name: Sync to Dev

on:
push:
branches: [releases]
paths:
- 'pyproject.toml'
- 'microfinity/__init__.py'
- 'CHANGELOG.md'

jobs:
sync:
name: Sync releases to dev
runs-on: ubuntu-latest
# Only run if this looks like a release-please commit
if: contains(github.event.head_commit.message, 'chore(releases)') || contains(github.event.head_commit.message, 'chore(main)')

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Sync version files to dev
run: |
# Get the version from releases branch
VERSION=$(grep -m1 'version = ' pyproject.toml | cut -d'"' -f2)
echo "Syncing version $VERSION to dev"

# Checkout dev branch
git checkout dev

# Cherry-pick the version bump changes (if they apply cleanly)
# Or directly update the version files
git checkout releases -- pyproject.toml microfinity/__init__.py CHANGELOG.md

# Check if there are changes
if git diff --quiet; then
echo "No changes to sync"
exit 0
fi

# Commit and push
git add pyproject.toml microfinity/__init__.py CHANGELOG.md
git commit -m "chore: sync version $VERSION from releases"
git push origin dev
105 changes: 105 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Claude Project Context: Microfinity

This file provides context for Claude when working on this project.

## Project Overview

**Microfinity** is a Python library for creating Gridfinity-compatible objects using CadQuery. It includes:

1. **microfinity/** - CadQuery-based generator for boxes, baseplates, and spacers
2. **meshcutter/** - Mesh-based tool to convert 1U Gridfinity boxes to micro-divided feet

## Key Architecture Decisions

### Meshcutter: Replace-Base Approach

The meshcutter uses a **replace-base pipeline** (not boolean subtraction) to convert 1U feet to micro-feet:

1. **Trim** the input mesh above z=5mm (keeps walls and interior)
2. **Generate** fresh micro-feet base using microfinity's construction path
3. **Union** the trimmed top with the new base

This produces geometry **identical** to natively-generated micro boxes (<1mm³ difference).

**Important**: The legacy boolean subtraction approach has been deprecated and removed.

### Gridfinity Constants

All Gridfinity constants should come from `meshcutter/core/constants.py`, which re-exports from `microfinity.core.constants`.

Key values:
- `GRU = 42.0` - 1U pitch (mm)
- `GR_TOL = 0.5` - Clearance between feet
- `GR_BASE_HEIGHT = 4.75` - Foot height
- `GR_BASE_CLR = 0.25` - Clearance above foot
- `Z_SPLIT_HEIGHT = 5.0` - Where we cut between top and base

## Important Files

### Core Modules
- `meshcutter/core/replace_base.py` - Main replace-base pipeline
- `meshcutter/core/constants.py` - Centralized constants
- `meshcutter/core/mesh_utils.py` - Mesh conversion utilities
- `meshcutter/core/cq_utils.py` - CadQuery utilities
- `meshcutter/core/grid_utils.py` - Grid/offset calculations

### CLI
- `meshcutter/cli/meshcut.py` - Command-line interface

### Tests
- `tests/test_meshcutter/test_golden.py` - Golden comparison tests
- `tests/test_meshcutter/golden_utils.py` - Test utilities

## Refactoring Tracking

**IMPORTANT**: When completing refactoring tasks, update `REFACTOR_TODO.md` to mark items as complete.

The refactoring TODO file tracks:
- DRY elimination (utility modules)
- Module updates
- Test creation
- CI setup

## Testing

### Golden Tests
Golden tests compare meshcutter output against microfinity-generated references:
- Reference meshes are generated on-demand (not stored)
- Acceptance threshold: <1mm³ total geometric difference
- Test configurations: 1x1x1, 2x3x2, 1x1x3, 3x3x1

### Running Tests
```bash
# All meshcutter tests
pytest tests/test_meshcutter/ -v

# Just golden tests
pytest tests/test_meshcutter/test_golden.py -v

# Quick unit tests (skip slow golden tests)
pytest tests/test_meshcutter/ -v -m "not golden"
```

## Code Style

- **Line length**: 120 characters (configured in pyproject.toml)
- **Formatter**: Black
- **Type hints**: Use throughout, especially for public APIs
- **Docstrings**: Google style

## Common Tasks

### Adding a New Micro-Division Size
1. Update `meshcutter/core/grid_utils.py` if offset calculations change
2. Add test configuration to `tests/test_meshcutter/test_golden.py`
3. Update `docs/TODO_FUTURE_DIVISIONS.md`

### Updating Constants
1. Check if constant exists in `microfinity.core.constants`
2. If yes, re-export in `meshcutter/core/constants.py`
3. If no, add to meshcutter-specific section

### Debugging Mesh Issues
1. Use `mesh_utils.get_mesh_diagnostics()` for mesh info
2. Export intermediate meshes with `mesh.export('/tmp/debug.stl')`
3. View in external tool (MeshLab, Blender)
Loading