chore: Prepare for 0.6.1 release (#29)

* fix: version in wiki-source.txt fix

* chore: small release-fixes

* chore: prep for 0.6.1 release
This commit is contained in:
Sean P. Kane
2026-01-12 12:06:11 -08:00
committed by GitHub
parent a24189b07c
commit 75726329c7
11 changed files with 477 additions and 43 deletions
@@ -9,5 +9,5 @@ It is bundled with the workbench addon for self-contained installation.
from .server import FreecadMCPPlugin from .server import FreecadMCPPlugin
__version__ = "0.6.0" # Updated by release workflow __version__ = "0.6.1" # Updated by release workflow
__all__ = ["FreecadMCPPlugin", "__version__"] __all__ = ["FreecadMCPPlugin", "__version__"]
+1 -1
View File
@@ -10,7 +10,7 @@
|Icon=FreecadRobustMCPBridge.svg |Icon=FreecadRobustMCPBridge.svg
|Description=Bridge workbench designed to provide an interface between FreeCAD and the Robust MCP Server to enable AI assistants (like Claude) to control FreeCAD via the Model Context Protocol (MCP). It provides XML-RPC and JSON-RPC interfaces for external automation. |Description=Bridge workbench designed to provide an interface between FreeCAD and the Robust MCP Server to enable AI assistants (like Claude) to control FreeCAD via the Model Context Protocol (MCP). It provides XML-RPC and JSON-RPC interfaces for external automation.
|Author=Sean P. Kane |Author=Sean P. Kane
|Version=0.6.0 |Version=0.6.1
|Date=2026-01-12 |Date=2026-01-12
|FCVersion=0.21+ |FCVersion=0.21+
|Download=[https://github.com/spkane/freecad-robust-mcp-and-more/releases Latest Release] |Download=[https://github.com/spkane/freecad-robust-mcp-and-more/releases Latest Release]
+376 -32
View File
@@ -208,19 +208,14 @@ bump-macro-export version: (_bump-macro "Multi_Export" "Multi Export" "MultiExpo
tag-mcp-server version: tag-mcp-server version:
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# Source shared release helper functions
. "{{project_root}}/scripts/release-helpers.sh"
TAG="robust-mcp-server-v{{version}}" TAG="robust-mcp-server-v{{version}}"
# Validate version format # Run all pre-release checks (version format, main branch, up-to-date, clean tree)
if [[ ! "{{version}}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then pre_release_checks "{{version}}" || exit 1
echo "ERROR: Version '{{version}}' is not valid semver (X.Y.Z or X.Y.Z-prerelease)"
exit 1
fi
# Check for uncommitted changes
if ! git diff --quiet HEAD; then
echo "ERROR: You have uncommitted changes. Please commit or stash them first."
exit 1
fi
echo "Creating tag: $TAG" echo "Creating tag: $TAG"
echo "" echo ""
@@ -246,19 +241,15 @@ tag-mcp-server version:
tag-workbench version: tag-workbench version:
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# Source shared release helper functions
. "{{project_root}}/scripts/release-helpers.sh"
TAG="robust-mcp-workbench-v{{version}}" TAG="robust-mcp-workbench-v{{version}}"
VERSION="{{version}}" VERSION="{{version}}"
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then # Run all pre-release checks (version format, main branch, up-to-date, clean tree)
echo "ERROR: Version '$VERSION' is not valid semver" pre_release_checks "$VERSION" || exit 1
exit 1
fi
# Check for uncommitted changes
if ! git diff --quiet HEAD; then
echo "ERROR: You have uncommitted changes. Please commit or stash them first."
exit 1
fi
# Verify version in source files matches tag version # Verify version in source files matches tag version
echo "Verifying version in source files..." echo "Verifying version in source files..."
@@ -332,22 +323,16 @@ _tag-macro macro_dir macro_name macro_file_basename tag_prefix bump_command tag_
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# Source shared release helper functions
. "{{project_root}}/scripts/release-helpers.sh"
VERSION="{{version}}" VERSION="{{version}}"
TAG="{{tag_prefix}}v{{version}}" TAG="{{tag_prefix}}v{{version}}"
MACRO_DIR="{{project_root}}/macros/{{macro_dir}}" MACRO_DIR="{{project_root}}/macros/{{macro_dir}}"
MACRO_NAME="{{macro_name}}" MACRO_NAME="{{macro_name}}"
# Validate version format (SemVer 2.0) # Run all pre-release checks (version format, main branch, up-to-date, clean tree)
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then pre_release_checks "$VERSION" || exit 1
echo "ERROR: Version '$VERSION' is not valid semver"
exit 1
fi
# Check for uncommitted changes
if ! git diff --quiet HEAD; then
echo "ERROR: You have uncommitted changes. Please commit or stash them first."
exit 1
fi
# Verify version in source files matches tag version # Verify version in source files matches tag version
echo "Verifying version in source files..." echo "Verifying version in source files..."
@@ -536,6 +521,365 @@ delete-tag tag:
echo "" echo ""
echo "Tag '{{tag}}' deleted." echo "Tag '{{tag}}' deleted."
# Show information about a release (useful before rollback)
show-release-info tag:
#!/usr/bin/env bash
set -euo pipefail
TAG="{{tag}}"
echo "=========================================="
echo "Release Information: $TAG"
echo "=========================================="
echo ""
# Check if tag exists locally
if git tag -l "$TAG" | grep -qF "$TAG"; then
echo "Local tag: EXISTS"
COMMIT=$(git rev-parse "$TAG" 2>/dev/null)
echo " Commit: $COMMIT"
echo " Date: $(git log -1 --format=%ai "$TAG")"
echo " Author: $(git log -1 --format='%an <%ae>' "$TAG")"
else
echo "Local tag: NOT FOUND"
fi
# Check if tag exists on remote
if git ls-remote --tags origin | grep -qF "refs/tags/$TAG"; then
echo "Remote tag: EXISTS"
else
echo "Remote tag: NOT FOUND"
fi
echo ""
# Check which branches contain the tag
echo "Branches containing this tag:"
BRANCHES=$(git branch -a --contains "$TAG" 2>/dev/null || true)
if [ -n "$BRANCHES" ]; then
echo "$BRANCHES" | sed 's/^/ /'
else
echo " (none or tag not found)"
fi
echo ""
# Check if GitHub Release exists
echo "GitHub Release:"
if command -v gh &> /dev/null; then
if gh release view "$TAG" --json tagName,name,isDraft,isPrerelease,createdAt &>/dev/null; then
gh release view "$TAG" --json tagName,name,isDraft,isPrerelease,createdAt | \
jq -r '" Name: \(.name)\n Draft: \(.isDraft)\n Prerelease: \(.isPrerelease)\n Created: \(.createdAt)"'
echo ""
echo " Assets:"
gh release view "$TAG" --json assets | jq -r '.assets[].name' | sed 's/^/ - /'
else
echo " NOT FOUND (no GitHub Release for this tag)"
fi
else
echo " (gh CLI not installed - cannot check)"
fi
echo ""
# Determine component type and show additional info
case "$TAG" in
robust-mcp-server-v*)
VERSION="${TAG#robust-mcp-server-v}"
echo "Component: Robust MCP Server"
echo "Version: $VERSION"
echo ""
echo "Published to:"
echo " - PyPI: https://pypi.org/project/freecad-robust-mcp/$VERSION/"
echo " - Docker Hub: spkane/freecad-robust-mcp:$VERSION"
echo ""
echo "NOTE: PyPI packages cannot be fully deleted, only yanked."
echo " Docker tags can be deleted from Docker Hub."
;;
robust-mcp-workbench-v*)
VERSION="${TAG#robust-mcp-workbench-v}"
echo "Component: Robust MCP Bridge Workbench"
echo "Version: $VERSION"
;;
macro-cut-object-for-magnets-v*)
VERSION="${TAG#macro-cut-object-for-magnets-v}"
echo "Component: Cut Object for Magnets Macro"
echo "Version: $VERSION"
;;
macro-multi-export-v*)
VERSION="${TAG#macro-multi-export-v}"
echo "Component: Multi Export Macro"
echo "Version: $VERSION"
;;
*)
echo "Component: Unknown (not a recognized release tag format)"
;;
esac
# Rollback a release (delete tag and GitHub Release)
rollback-release tag:
#!/usr/bin/env bash
set -euo pipefail
TAG="{{tag}}"
echo "=========================================="
echo "ROLLBACK RELEASE: $TAG"
echo "=========================================="
echo ""
# Determine component type and version
COMPONENT=""
VERSION=""
case "$TAG" in
robust-mcp-server-v*)
COMPONENT="mcp-server"
VERSION="${TAG#robust-mcp-server-v}"
;;
robust-mcp-workbench-v*)
COMPONENT="workbench"
VERSION="${TAG#robust-mcp-workbench-v}"
;;
macro-cut-object-for-magnets-v*)
COMPONENT="macro-magnets"
VERSION="${TAG#macro-cut-object-for-magnets-v}"
;;
macro-multi-export-v*)
COMPONENT="macro-export"
VERSION="${TAG#macro-multi-export-v}"
;;
*)
COMPONENT="unknown"
;;
esac
# Show what will be affected
echo "This will:"
echo " 1. Delete the GitHub Release (if exists)"
echo " 2. Delete the git tag (local and remote)"
if [ "$COMPONENT" = "mcp-server" ]; then
echo " 3. Optionally yank from PyPI"
echo " 4. Provide Docker Hub cleanup instructions"
fi
echo ""
# Check what exists
LOCAL_TAG_EXISTS=false
REMOTE_TAG_EXISTS=false
GH_RELEASE_EXISTS=false
if git tag -l "$TAG" | grep -qF "$TAG"; then
LOCAL_TAG_EXISTS=true
echo " Local tag: WILL BE DELETED"
else
echo " Local tag: not found (already deleted?)"
fi
if git ls-remote --tags origin | grep -qF "refs/tags/$TAG"; then
REMOTE_TAG_EXISTS=true
echo " Remote tag: WILL BE DELETED"
else
echo " Remote tag: not found (already deleted?)"
fi
if command -v gh &> /dev/null; then
if gh release view "$TAG" &>/dev/null; then
GH_RELEASE_EXISTS=true
echo " GitHub Release: WILL BE DELETED"
else
echo " GitHub Release: not found (already deleted?)"
fi
else
echo " GitHub Release: (gh CLI not installed - cannot check/delete)"
fi
echo ""
# Component-specific info
case "$COMPONENT" in
mcp-server)
echo "Component: Robust MCP Server v$VERSION"
echo ""
echo "IMPORTANT: MCP Server releases publish to multiple registries:"
echo " - PyPI: Package cannot be deleted, only yanked (hidden from pip install)"
echo " - Docker Hub: Tags can be deleted via web UI or API"
echo ""
;;
workbench)
echo "Component: Robust MCP Bridge Workbench v$VERSION"
echo ""
echo "This release only creates a GitHub Release with archive files."
echo "Rollback will fully clean up this release."
echo ""
;;
macro-magnets)
echo "Component: Cut Object for Magnets Macro v$VERSION"
echo ""
echo "This release only creates a GitHub Release with archive files."
echo "Rollback will fully clean up this release."
echo ""
;;
macro-export)
echo "Component: Multi Export Macro v$VERSION"
echo ""
echo "This release only creates a GitHub Release with archive files."
echo "Rollback will fully clean up this release."
echo ""
;;
*)
echo "WARNING: Unrecognized tag format. Proceeding with generic rollback."
echo ""
;;
esac
# Nothing to do?
if [ "$LOCAL_TAG_EXISTS" = false ] && [ "$REMOTE_TAG_EXISTS" = false ] && [ "$GH_RELEASE_EXISTS" = false ]; then
echo "Nothing to rollback - tag and release not found."
exit 0
fi
read -p "Proceed with rollback? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 1
fi
echo ""
# Delete GitHub Release first (before tag, since release references tag)
if [ "$GH_RELEASE_EXISTS" = true ]; then
echo "Deleting GitHub Release..."
if gh release delete "$TAG" --yes; then
echo " ✓ GitHub Release deleted."
else
echo " WARNING: Failed to delete GitHub Release."
fi
fi
# Delete remote tag
if [ "$REMOTE_TAG_EXISTS" = true ]; then
echo "Deleting remote tag..."
if git push origin --delete "$TAG"; then
echo " ✓ Remote tag deleted."
else
echo " WARNING: Failed to delete remote tag."
fi
fi
# Delete local tag
if [ "$LOCAL_TAG_EXISTS" = true ]; then
echo "Deleting local tag..."
if git tag -d "$TAG"; then
echo " ✓ Local tag deleted."
else
echo " WARNING: Failed to delete local tag."
fi
fi
echo ""
echo "=========================================="
echo "Git/GitHub Rollback complete!"
echo "=========================================="
# MCP Server: Offer to yank from PyPI and provide Docker cleanup info
if [ "$COMPONENT" = "mcp-server" ]; then
echo ""
echo "--- PyPI Cleanup ---"
echo ""
echo "Would you like to yank version $VERSION from PyPI?"
echo " - Yanking hides the version from 'pip install freecad-robust-mcp'"
echo " - Users who pin to this version can still install it"
echo " - This can be undone later with 'twine yank --undo'"
echo ""
read -p "Yank from PyPI? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo ""
echo "Attempting to yank from PyPI..."
echo "(This requires PyPI authentication - you may be prompted to login)"
echo ""
if command -v twine &> /dev/null || uv run twine --version &>/dev/null; then
if uv run twine yank freecad-robust-mcp "$VERSION" 2>&1; then
echo " ✓ Version $VERSION yanked from PyPI."
else
echo ""
echo " Yank failed. You can try manually:"
echo " uv run twine yank freecad-robust-mcp $VERSION"
echo ""
echo " Or use the PyPI web interface:"
echo " https://pypi.org/manage/project/freecad-robust-mcp/release/$VERSION/"
fi
else
echo " twine not available. Install with: uv add twine"
echo ""
echo " Or use the PyPI web interface:"
echo " https://pypi.org/manage/project/freecad-robust-mcp/release/$VERSION/"
fi
else
echo ""
echo "Skipped PyPI yank. You can do this later with:"
echo " uv run twine yank freecad-robust-mcp $VERSION"
echo ""
echo "Or via web interface:"
echo " https://pypi.org/manage/project/freecad-robust-mcp/release/$VERSION/"
fi
echo ""
echo "--- Docker Hub Cleanup ---"
echo ""
echo "Docker Hub tags must be deleted manually."
echo "Tags to delete: $VERSION, latest (if this was the latest release)"
echo ""
echo "Web interface:"
echo " https://hub.docker.com/r/spkane/freecad-robust-mcp/tags"
echo ""
echo "Or via API (requires DOCKER_HUB_TOKEN):"
echo " curl -X DELETE -H \"Authorization: Bearer \$DOCKER_HUB_TOKEN\" \\"
echo " https://hub.docker.com/v2/repositories/spkane/freecad-robust-mcp/tags/$VERSION/"
fi
echo ""
echo "=========================================="
echo "Rollback process complete!"
echo "=========================================="
# Delete only the GitHub Release (keep tag)
delete-github-release tag:
#!/usr/bin/env bash
set -euo pipefail
TAG="{{tag}}"
if ! command -v gh &> /dev/null; then
echo "ERROR: gh CLI is required but not installed."
echo "Install: https://cli.github.com/"
exit 1
fi
if ! gh release view "$TAG" &>/dev/null; then
echo "No GitHub Release found for tag: $TAG"
exit 0
fi
echo "This will delete the GitHub Release for: $TAG"
echo "(The git tag will be preserved)"
echo ""
gh release view "$TAG" --json name,createdAt,assets | \
jq -r '"Release: \(.name)\nCreated: \(.createdAt)\nAssets: \(.assets | length)"'
echo ""
read -p "Delete this release? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 1
fi
gh release delete "$TAG" --yes
echo "GitHub Release deleted. Tag '$TAG' preserved."
# ============================================================================= # =============================================================================
# Release Status # Release Status
# ============================================================================= # =============================================================================
@@ -21,7 +21,7 @@ Usage:
__Name__ = "Cut Object for Magnets" __Name__ = "Cut Object for Magnets"
__Comment__ = "Cut an object along a plane and add aligned magnet holes with surface collision detection" __Comment__ = "Cut an object along a plane and add aligned magnet holes with surface collision detection"
__Author__ = "Sean P. Kane" __Author__ = "Sean P. Kane"
__Version__ = "0.6.0" __Version__ = "0.6.1"
__Date__ = "2026-01-12" __Date__ = "2026-01-12"
__License__ = "MIT" __License__ = "MIT"
__Web__ = "https://github.com/spkane/freecad-robust-mcp-and-more" __Web__ = "https://github.com/spkane/freecad-robust-mcp-and-more"
@@ -2,7 +2,7 @@
![Macro Icon](CutObjectForMagnets.svg) ![Macro Icon](CutObjectForMagnets.svg)
**Version:** 0.6.0 **Version:** 0.6.1
**FreeCAD Version:** 0.19 or later **FreeCAD Version:** 0.19 or later
**License:** MIT **License:** MIT
@@ -7,7 +7,7 @@
|Icon=Macro_Cut_Object_For_Magnets.png |Icon=Macro_Cut_Object_For_Magnets.png
|Description=Cut an object along a plane and add aligned magnet holes with surface collision detection. Creates two parts with perfectly aligned holes for embedding magnets that allow the parts to snap together. |Description=Cut an object along a plane and add aligned magnet holes with surface collision detection. Creates two parts with perfectly aligned holes for embedding magnets that allow the parts to snap together.
|Author=Sean P. Kane |Author=Sean P. Kane
|Version=0.6.0 |Version=0.6.1
|Date=2026-01-12 |Date=2026-01-12
|FCVersion=0.19+ |FCVersion=0.19+
|Download=[https://wiki.freecad.org/images/thumb/e/e3/Macro_Cut_Object_For_Magnets.png/48px-Macro_Cut_Object_For_Magnets.png ToolBar Icon] |Download=[https://wiki.freecad.org/images/thumb/e/e3/Macro_Cut_Object_For_Magnets.png/48px-Macro_Cut_Object_For_Magnets.png ToolBar Icon]
+1 -1
View File
@@ -22,7 +22,7 @@ Usage:
__Name__ = "Multi Export" __Name__ = "Multi Export"
__Comment__ = "Export selected bodies to multiple file formats (STL, STEP, 3MF, OBJ, IGES, BREP, PLY, AMF) simultaneously" __Comment__ = "Export selected bodies to multiple file formats (STL, STEP, 3MF, OBJ, IGES, BREP, PLY, AMF) simultaneously"
__Author__ = "Sean P. Kane" __Author__ = "Sean P. Kane"
__Version__ = "0.6.0" __Version__ = "0.6.1"
__Date__ = "2026-01-12" __Date__ = "2026-01-12"
__License__ = "MIT" __License__ = "MIT"
__Web__ = "https://github.com/spkane/freecad-robust-mcp-and-more" __Web__ = "https://github.com/spkane/freecad-robust-mcp-and-more"
+1 -1
View File
@@ -2,7 +2,7 @@
![Macro Icon](MultiExport.svg) ![Macro Icon](MultiExport.svg)
**Version:** 0.6.0 **Version:** 0.6.1
**FreeCAD Version:** 0.19 or later **FreeCAD Version:** 0.19 or later
**License:** MIT **License:** MIT
+1 -1
View File
@@ -7,7 +7,7 @@
|Icon=Macro_Multi_Export.png |Icon=Macro_Multi_Export.png
|Description=Export selected bodies to multiple file formats (STL, STEP, 3MF, OBJ, IGES, BREP, PLY, AMF) simultaneously with a user-friendly dialog for format selection and output configuration. |Description=Export selected bodies to multiple file formats (STL, STEP, 3MF, OBJ, IGES, BREP, PLY, AMF) simultaneously with a user-friendly dialog for format selection and output configuration.
|Author=Sean P. Kane |Author=Sean P. Kane
|Version=0.6.0 |Version=0.6.1
|Date=2026-01-12 |Date=2026-01-12
|FCVersion=0.21+ |FCVersion=0.21+
|Download=[https://wiki.freecad.org/images/thumb/1/19/Macro_Multi_Export.png/48px-Macro_Multi_Export.png ToolBar Icon] |Download=[https://wiki.freecad.org/images/thumb/1/19/Macro_Multi_Export.png/48px-Macro_Multi_Export.png ToolBar Icon]
+3 -3
View File
@@ -37,7 +37,7 @@
<workbench> <workbench>
<name>Robust MCP Bridge</name> <name>Robust MCP Bridge</name>
<version>0.6.0</version> <version>0.6.1</version>
<date>2026-01-12</date> <date>2026-01-12</date>
<description>Robust MCP Bridge workbench for AI assistant integration with FreeCAD. Uses the Model Context Protocol (MCP) to connect AI assistants like Claude Code and Cursor to FreeCAD. Works in both GUI mode (with full visual features including screenshots, colors, and camera control) and headless mode (for automation and CI/CD). Provides toolbar commands to start, stop, and monitor the MCP bridge server. Supports XML-RPC and JSON-RPC protocols with 82+ CAD tools.</description> <description>Robust MCP Bridge workbench for AI assistant integration with FreeCAD. Uses the Model Context Protocol (MCP) to connect AI assistants like Claude Code and Cursor to FreeCAD. Works in both GUI mode (with full visual features including screenshots, colors, and camera control) and headless mode (for automation and CI/CD). Provides toolbar commands to start, stop, and monitor the MCP bridge server. Supports XML-RPC and JSON-RPC protocols with 82+ CAD tools.</description>
<classname>FreecadRobustMCPBridgeWorkbench</classname> <classname>FreecadRobustMCPBridgeWorkbench</classname>
@@ -48,7 +48,7 @@
<macro> <macro>
<name>Multi Export</name> <name>Multi Export</name>
<version>0.6.0</version> <version>0.6.1</version>
<date>2026-01-12</date> <date>2026-01-12</date>
<description>Export selected bodies to multiple file formats (STL, STEP, 3MF, OBJ, IGES, BREP, PLY, AMF) simultaneously with configurable mesh options.</description> <description>Export selected bodies to multiple file formats (STL, STEP, 3MF, OBJ, IGES, BREP, PLY, AMF) simultaneously with configurable mesh options.</description>
<subdirectory>./macros/Multi_Export/</subdirectory> <subdirectory>./macros/Multi_Export/</subdirectory>
@@ -58,7 +58,7 @@
<macro> <macro>
<name>Cut Object for Magnets</name> <name>Cut Object for Magnets</name>
<version>0.6.0</version> <version>0.6.1</version>
<date>2026-01-12</date> <date>2026-01-12</date>
<description>Cut an object along a plane and add aligned magnet holes with surface collision detection. Perfect for creating 3D printed parts that snap together with embedded magnets.</description> <description>Cut an object along a plane and add aligned magnet holes with surface collision detection. Perfect for creating 3D printed parts that snap together with embedded magnets.</description>
<subdirectory>./macros/Cut_Object_for_Magnets/</subdirectory> <subdirectory>./macros/Cut_Object_for_Magnets/</subdirectory>
+90
View File
@@ -0,0 +1,90 @@
#!/usr/bin/env bash
# Shared helper functions for release management
# Source this file in Just recipes: . ./scripts/release-helpers.sh
# Validate semver version format
# Usage: validate_semver "1.0.0" || exit 1
validate_semver() {
local version="$1"
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "ERROR: Version '$version' is not valid semver (X.Y.Z or X.Y.Z-prerelease)"
echo "Examples: 1.0.0, 1.0.0-alpha, 1.0.0-beta.1, 1.0.0-rc.1"
return 1
fi
return 0
}
# Verify we're on the main branch
# Usage: require_main_branch || exit 1
require_main_branch() {
local current_branch
current_branch=$(git rev-parse --abbrev-ref HEAD)
if [[ "$current_branch" != "main" ]]; then
echo "ERROR: Release tags must be created from the 'main' branch."
echo " Current branch: $current_branch"
echo ""
echo "Please merge your changes to main first, then run this command from main."
return 1
fi
return 0
}
# Verify local main is up to date with origin/main
# Usage: require_up_to_date || exit 1
require_up_to_date() {
# Fetch latest from origin (quietly)
git fetch origin main --quiet 2>/dev/null || {
echo "WARNING: Could not fetch from origin. Continuing with local state."
return 0
}
local local_sha remote_sha base_sha
local_sha=$(git rev-parse HEAD)
remote_sha=$(git rev-parse origin/main 2>/dev/null) || {
echo "WARNING: Could not find origin/main. Continuing with local state."
return 0
}
if [[ "$local_sha" != "$remote_sha" ]]; then
# Check if we're behind, ahead, or diverged
base_sha=$(git merge-base HEAD origin/main 2>/dev/null)
if [[ "$base_sha" == "$local_sha" ]]; then
echo "ERROR: Local main is behind origin/main."
echo " Please run: git pull origin main"
return 1
elif [[ "$base_sha" == "$remote_sha" ]]; then
echo "ERROR: Local main is ahead of origin/main."
echo " Please push your changes first: git push origin main"
return 1
else
echo "ERROR: Local main has diverged from origin/main."
echo " Please reconcile the branches before releasing."
return 1
fi
fi
return 0
}
# Check for uncommitted changes
# Usage: require_clean_tree || exit 1
require_clean_tree() {
if ! git diff --quiet HEAD 2>/dev/null; then
echo "ERROR: You have uncommitted changes. Please commit or stash them first."
return 1
fi
return 0
}
# Run all pre-release checks
# Usage: pre_release_checks "1.0.0" || exit 1
pre_release_checks() {
local version="$1"
validate_semver "$version" || return 1
require_main_branch || return 1
require_up_to_date || return 1
require_clean_tree || return 1
return 0
}