Files
freecad-robust-mcp-fc111/docs/development/releasing.md
T
8c338f6da7 feat: MCP Bridge Workbench, just command cleanup, testing, etc. (#24)
* fix: lots of fixes and name refactoring

* feat: Add workbench preferences

* fix: MCP bridge status widget and just command fixes

* fix(tests): Use the correct mesa-glx package

* fix(ci): Add fontconfig to GUI test dependencies

FreeCAD GUI was failing to start with:
"Fontconfig error: Cannot load default config file: No such file"

Added fontconfig and fonts-dejavu-core packages to the GUI test job
dependencies to resolve the font configuration issue.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(addon): Extract path utilities into shared module

Create path_utils.py module that consolidates duplicated path-finding
logic from commands.py and InitGui.py:
- get_addon_path(): Find addon directory with caching and fallbacks
- get_icon_path(): Get full path to an icon file
- get_icons_dir(): Get path to icons directory
- get_workbench_icon(): Get path to workbench main icon

This removes ~100 lines of duplicated code while preserving the same
behavior including _addon_path_cache and all fallback methods.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(addon): Prevent stale plugin state on startup failure

The StartMCPBridgeCommand.Activated method could leave _mcp_plugin in
a partially initialized state if FreecadMCPPlugin.start() failed after
the plugin was instantiated.

Changes:
- Create plugin in a local variable first
- Only assign to _mcp_plugin after start() succeeds
- Explicitly clear _mcp_plugin and _running_config in exception
  handlers to ensure clean state for subsequent retry attempts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Lot of broad improvements

* fix(ci): Use blocking headless_server.py for GUI tests

The GUI test was using startup_bridge.py which is non-blocking
(designed for interactive use). For CI, even in GUI mode, we need
the blocking headless_server.py that calls run_forever() to keep
FreeCAD running. GUI features are still available since we use
the 'freecad' executable instead of 'freecadcmd'.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(addon): Rename headless_server.py to blocking_bridge.py

The old name was misleading because:
- It works with both GUI (freecad) and headless (freecadcmd) modes
- The key characteristic is that it BLOCKS with run_forever()

New naming convention clarifies the difference:
- blocking_bridge.py: Starts bridge and blocks (for CI, servers)
- startup_bridge.py: Starts bridge and returns (for interactive GUI)

Updated all references across:
- GitHub workflow (macro-test.yaml)
- Just commands (freecad.just)
- Unit tests (test_addon_structure.py)
- Documentation (5 files)
- CLAUDE.md

Also improved the script to detect GUI mode dynamically using
FreeCAD.GuiUp and display the appropriate status message.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(just): Remove erroneous rm of startup_bridge.py on error

The startup script is now a permanent source file in the repository,
not a generated temporary file. The rm -f would have deleted source
code if FreeCAD wasn't found.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: General improvements

* fix: Lots of general fixes and only stable to PyPi

* fix: small cleanup

* fix: Small fixes and hopefully fixes the GUI tests

* fix: Add proper library paths for FreeCAD GUI in CI

- Create wrapper scripts instead of symlinks for AppImage binaries
- Set LD_LIBRARY_PATH, QT_PLUGIN_PATH for GUI mode
- Add diagnostic output to identify startup failures

* fix: Use apprun for GUI tests in CI

* fix: Improving Xvfb tests

* fix: GUI tests worlk

* chore: remove invalid --no-splash comments

* fix: ARM64 architecture support and other fixes

* fix: cleanup

* test: just commands test suite

* test: improve just command tests

* fix: more general improvements

* fix: more cleanup

* fix: more updates

* fix: small tweaks

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 15:26:33 -08:00

16 KiB

Release Process

This project uses component-specific versioning. Each component (MCP Server, Workbench, Macros) has its own version and release cycle, allowing independent updates without affecting other components.

Quick Start

The complete release workflow in order:

# 1. Pre-release checks
just release::status                        # Check which components have unreleased changes
just release::changes-since mcp-server      # View specific changes (or workbench, macro-magnets, macro-export)
just all                                    # Run all quality checks (must pass)

# 2. Update changelog
just release::draft-notes mcp-server        # Generate draft notes from commits
# Then manually edit CHANGELOG.md with appropriate section header

# 3. Version bump (workbench & macros only - MCP Server uses setuptools-scm)
just release::bump-workbench 1.0.0          # or bump-macro-magnets, bump-macro-export

# 4. Commit changes
git add -A
git commit -m "chore: bump workbench to 1.0.0"  # or appropriate component/message

# 5. Create & push tag (triggers CI/CD automatically)
just release::tag-workbench 1.0.0           # or tag-mcp-server, tag-macro-magnets, tag-macro-export

# 6. Monitor release at GitHub Actions, then verify
just release::list-tags
just release::latest-versions

# 7. Update FreeCAD wiki (macros only)
just release::wiki-update macro-magnets     # Copies content to clipboard & opens wiki edit page
Component Bump Command Tag Command
MCP Server (none - uses setuptools-scm) just release::tag-mcp-server X.Y.Z
Workbench just release::bump-workbench X.Y.Z just release::tag-workbench X.Y.Z
Magnets Macro just release::bump-macro-magnets X.Y.Z just release::tag-macro-magnets X.Y.Z
Export Macro just release::bump-macro-export X.Y.Z just release::tag-macro-export X.Y.Z

Components and Their Release Targets

Component Tag Format Releases To
MCP Server robust-mcp-server-vX.Y.Z PyPI/TestPyPI*, Docker Hub, GitHub Release
Robust MCP Bridge Workbench robust-mcp-workbench-vX.Y.Z GitHub Release (archive)
Cut Object for Magnets Macro macro-cut-object-for-magnets-vX.Y.Z GitHub Release (archive)
Multi Export Macro macro-multi-export-vX.Y.Z GitHub Release (archive)

*Stable releases (X.Y.Z) publish to PyPI; non-stable releases (alpha, beta, rc) publish to TestPyPI only.

Version Format

All versions follow Semantic Versioning 2.0:

  • X.Y.Z - Stable release (published to PyPI only)
  • X.Y.Z-alpha or X.Y.Z-alpha.N - Alpha pre-release (published to TestPyPI only)
  • X.Y.Z-beta or X.Y.Z-beta.N - Beta pre-release (published to TestPyPI only)
  • X.Y.Z-rc.N - Release candidate (published to TestPyPI only)

Release Workflow Overview

Releases follow a two-step process:

  1. Bump: Update version in all source files locally, then commit
  2. Tag: Create and push the git tag (triggers CI/CD)

This ensures the version in source files matches the git tag on the same commit.

┌─────────────────────────────────────────────────────────────────┐
│  1. just release::bump-<component> X.Y.Z                        │
│     └── Updates version in all relevant files                   │
│                                                                 │
│  2. git add -A && git commit -m "chore: bump ... to X.Y.Z"      │
│     └── Commit the version changes                              │
│                                                                 │
│  3. just release::tag-<component> X.Y.Z                         │
│     └── Verifies versions match, then creates & pushes tag      │
│                                                                 │
│  4. GitHub Actions workflow runs automatically                  │
│     └── Verifies versions, builds, and publishes release        │
└─────────────────────────────────────────────────────────────────┘

Pre-Release Checklist

Before creating any release, complete these steps:

1. Check Release Status

See which components have unreleased changes:

just release::status

This shows the number of commits since the last release for each component.

2. Review Changes

View the specific changes for the component you're releasing:

# For MCP Server
just release::changes-since mcp-server

# For Workbench
just release::changes-since workbench

# For Macros
just release::changes-since macro-magnets
just release::changes-since macro-export

3. Run All Quality Checks

Ensure all tests and checks pass:

just all

For a more thorough check including integration tests:

just all-with-integration

4. Update CHANGELOG.md

The changelog uses a multi-component structure. Each release date section contains entries for each component that was released.

Draft Release Notes

Use the draft-notes command to generate a starting point from conventional commits:

# Generate draft notes for a component
just release::draft-notes mcp-server
just release::draft-notes workbench
just release::draft-notes macro-magnets
just release::draft-notes macro-export

This categorizes commits by type (feat, fix, refactor, etc.) to help you write the changelog entry.

Changelog Structure

Add entries under the appropriate component section in CHANGELOG.md:

## YYYY-MM-DD - Release Title (optional)

### MCP Server vX.Y.Z

Brief description of the release.

#### Added
- New feature description

#### Changed
- Changed behavior description

#### Fixed
- Bug fix description

---

### Robust MCP Bridge Workbench vX.Y.Z

...

Important: The changelog section header format must match exactly for the GitHub Release workflow to extract it:

  • MCP Server: ### MCP Server vX.Y.Z
  • Workbench: ### Robust MCP Bridge Workbench vX.Y.Z
  • Magnets Macro: ### Cut Object for Magnets Macro vX.Y.Z
  • Export Macro: ### Multi Export Macro vX.Y.Z

The release workflows automatically extract the changelog section and include it in the GitHub Release body.

Releasing Each Component

MCP Server Release

The MCP Server is the main Python package. It uses setuptools-scm to derive version from git tags at build time, so there's no version bump step needed.

# 1. Ensure all changes are committed
git status  # Should show clean working tree

# 2. Update CHANGELOG.md and commit
git add CHANGELOG.md
git commit -m "docs: update changelog for MCP Server v1.0.0"

# 3. Create and push the release tag
just release::tag-mcp-server 1.0.0

What happens automatically:

  1. GitHub Actions validates the tag format
  2. Builds Python wheel and source distribution (version from tag)
  3. Tests installation on Ubuntu and macOS
  4. Publishes to PyPI (or TestPyPI for alpha, beta, and rc versions)
  5. Builds multi-architecture Docker image (amd64 + arm64)
  6. Pushes to Docker Hub as spkane/freecad-robust-mcp:1.0.0
  7. Creates GitHub Release with wheel and tar.gz artifacts

Pre-release versions:

# Alpha (goes to TestPyPI only)
just release::tag-mcp-server 1.0.0-alpha.1

# Beta (goes to TestPyPI only)
just release::tag-mcp-server 1.0.0-beta.1

# Release candidate (goes to TestPyPI only)
just release::tag-mcp-server 1.0.0-rc.1

Robust MCP Bridge Workbench Release

The workbench is a FreeCAD addon that provides the Robust MCP Bridge GUI.

# 1. Bump version in source files
just release::bump-workbench 1.0.0

# 2. Review and commit the changes
git diff  # Review changes
git add -A
git commit -m "chore: bump workbench to 1.0.0"

# 3. Create and push the release tag
just release::tag-workbench 1.0.0

Files updated by bump-workbench:

  • addon/FreecadRobustMCP/freecad_mcp_bridge/__init__.py (__version__)
  • package.xml (workbench section: <version> and <date>)

What happens automatically:

  1. GitHub Actions validates the tag format
  2. Verifies version in source files matches tag
  3. Creates archive (tar.gz and zip)
  4. Creates GitHub Release with the archives

Macro Releases

Each macro can be released independently.

Cut Object for Magnets Macro:

# 1. Bump version in source files
just release::bump-macro-magnets 1.0.0

# 2. Review and commit the changes
git diff  # Review changes
git add -A
git commit -m "chore: bump Cut Object for Magnets macro to 1.0.0"

# 3. Create and push the release tag
just release::tag-macro-magnets 1.0.0

Multi Export Macro:

# 1. Bump version in source files
just release::bump-macro-export 1.0.0

# 2. Review and commit the changes
git diff  # Review changes
git add -A
git commit -m "chore: bump Multi Export macro to 1.0.0"

# 3. Create and push the release tag
just release::tag-macro-export 1.0.0

Files updated by macro bump commands:

  • macros/<MacroDir>/<Macro>.FCMacro (__Version__ and __Date__)
  • macros/<MacroDir>/README-<Macro>.md (**Version:**)
  • macros/<MacroDir>/wiki-source.txt (|Version= and |Date=)
  • package.xml (macro section: <version> and <date>)

What happens automatically:

  1. GitHub Actions validates the tag format
  2. Verifies version in source files matches tag
  3. Creates archive (tar.gz and zip)
  4. Creates GitHub Release with the archives

Verifying a Release

Check GitHub Actions

After pushing a tag, monitor the release workflow:

  1. Go to GitHub Actions
  2. Find the workflow run triggered by your tag
  3. Verify all steps complete successfully

Verify Published Artifacts

For MCP Server:

# Check PyPI
pip index versions freecad-robust-mcp

# Check Docker Hub
docker pull spkane/freecad-robust-mcp:1.0.0

For Workbench/Macros:

  • Check the GitHub Releases page for the archive downloads
  • Verify the package.xml version was updated

Managing Release Tags

List All Tags

# All tags grouped by component
just release::list-tags

# Latest version of each component
just release::latest-versions

Delete a Tag (If Needed)

If a release has issues and needs to be removed:

just release::delete-tag robust-mcp-server-v1.0.0

!!! warning "Deleting Published Releases" Deleting a tag does not unpublish from PyPI or Docker Hub. Contact the respective registries to remove published artifacts if necessary.

Preview a Release (Dry Run)

To see what a release tag would look like without creating it:

just release::dry-run-tag mcp-server 1.0.0
just release::dry-run-tag workbench 1.0.0
just release::dry-run-tag macro-magnets 1.0.0

Troubleshooting

Release Workflow Failed

  1. Check the GitHub Actions logs for the specific error
  2. Common issues:
    • Invalid version format (must be semver)
    • Version mismatch between source files and tag
    • Missing secrets (PyPI token, Docker credentials)
    • Tests failing during the release build

Version Mismatch Error

If the workflow fails with "Version mismatch":

# You forgot to bump the version before tagging
# Delete the tag
just release::delete-tag <full-tag-name>

# Bump the version
just release::bump-<component> X.Y.Z

# Commit the changes
git add -A && git commit -m "chore: bump <component> to X.Y.Z"

# Create the tag again
just release::tag-<component> X.Y.Z

Tag Already Exists

If you try to create a tag that already exists:

# Delete the existing tag first
just release::delete-tag robust-mcp-server-v1.0.0

# Then create the new tag
just release::tag-mcp-server 1.0.0

Wrong Version Released

  1. Delete the tag: just release::delete-tag <tag>
  2. Create a new release with the correct version
  3. For PyPI: you cannot re-upload the same version; increment the patch version instead

Release Cadence Recommendations

  • MCP Server: Release when there are significant new features or important bug fixes
  • Workbench: Release in sync with server changes that affect the bridge protocol
  • Macros: Release independently when macro functionality changes

Updating the FreeCAD Wiki

After releasing a macro, you should update its FreeCAD wiki page. The wiki-source.txt files are automatically updated by the bump-macro-* commands with the new version and date.

Wiki Update Commands

# Check differences between local and live wiki
just release::wiki-diff macro-magnets
just release::wiki-diff macro-export

# View the wiki source content locally
just release::wiki-show macro-magnets
just release::wiki-show macro-export

# Update the wiki (copies to clipboard and opens edit page)
just release::wiki-update macro-magnets
just release::wiki-update macro-export

Wiki Update Workflow

The wiki-update command provides a safe, assisted workflow:

  1. Copies the updated wiki-source.txt content to your clipboard
  2. Opens the FreeCAD wiki edit page in your browser
  3. Displays step-by-step instructions

Manual steps after running the command:

  1. Log in to your FreeCAD wiki account if prompted
  2. Select all content in the edit box (Ctrl+A / Cmd+A)
  3. Paste the new content (Ctrl+V / Cmd+V)
  4. Add an edit summary like "Update to version X.Y.Z"
  5. Click "Show preview" to verify changes
  6. Click "Save changes" when satisfied

!!! note "Wiki Account Required" You need a FreeCAD wiki account to edit pages. Register at wiki.freecad.org if you don't have one.

Macro Shortcuts

The wiki commands accept multiple aliases for convenience:

Macro Aliases
Cut Object for Magnets macro-magnets, magnets, cut
Multi Export macro-export, export, multi

Quick Reference

# Check what needs releasing
just release::status

# View changes for a component
just release::changes-since mcp-server

# Draft changelog entries from commits
just release::draft-notes mcp-server
just release::draft-notes workbench
just release::draft-notes macro-magnets
just release::draft-notes macro-export

# Bump versions (for workbench and macros)
just release::bump-workbench 1.0.0
just release::bump-macro-magnets 1.0.0
just release::bump-macro-export 1.0.0

# Commit version changes
git add -A && git commit -m "chore: bump <component> to X.Y.Z"

# Create releases (verifies versions, creates and pushes tag)
just release::tag-mcp-server 1.0.0
just release::tag-workbench 1.0.0
just release::tag-macro-magnets 1.0.0
just release::tag-macro-export 1.0.0

# List existing releases
just release::list-tags
just release::latest-versions

# Extract changelog for a version (used by CI)
just release::extract-changelog mcp-server 1.0.0

# Update FreeCAD wiki for macros (after release)
just release::wiki-diff macro-magnets   # Check differences
just release::wiki-update macro-magnets # Copy to clipboard & open edit page
just release::wiki-update macro-export

# Delete a tag if needed
just release::delete-tag <full-tag-name>