Skip to content

Commit 3a2d7d7

Browse files
markomanninenclaude
andcommitted
feat: Add automated release script
Add comprehensive release automation script that: - Validates environment and dependencies - Runs full test suite - Formats code with Black - Bumps version (patch/minor/major) - Creates git tag - Pushes to GitHub - Creates GitHub release with changelog Usage: ./scripts/release.sh [patch|minor|major] 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 03bcf5c commit 3a2d7d7

1 file changed

Lines changed: 186 additions & 0 deletions

File tree

scripts/release.sh

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# Release automation script for mcp-debugpy
5+
# Usage: ./scripts/release.sh [patch|minor|major]
6+
7+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
9+
VENV_DIR="$ROOT_DIR/.venv"
10+
11+
# Colors for output
12+
RED='\033[0;31m'
13+
GREEN='\033[0;32m'
14+
YELLOW='\033[1;33m'
15+
NC='\033[0m' # No Color
16+
17+
# Print colored message
18+
print_msg() {
19+
local color=$1
20+
shift
21+
echo -e "${color}$*${NC}"
22+
}
23+
24+
print_error() { print_msg "$RED" "ERROR: $*"; }
25+
print_success() { print_msg "$GREEN" "$*"; }
26+
print_info() { print_msg "$YELLOW" "$*"; }
27+
28+
# Check if we're in the right directory
29+
if [[ ! -f "$ROOT_DIR/pyproject.toml" ]]; then
30+
print_error "Must be run from mcp-debugpy repository root or scripts directory"
31+
exit 1
32+
fi
33+
34+
cd "$ROOT_DIR"
35+
36+
# Detect Python and ensure venv exists
37+
if [[ ! -d "$VENV_DIR" ]]; then
38+
print_error "Virtual environment not found at $VENV_DIR"
39+
print_info "Run: python -m venv .venv && .venv/bin/pip install -e '.[dev]'"
40+
exit 1
41+
fi
42+
43+
PYTHON="$VENV_DIR/bin/python"
44+
PIP="$VENV_DIR/bin/pip"
45+
46+
if [[ ! -x "$PYTHON" ]]; then
47+
print_error "Python executable not found: $PYTHON"
48+
exit 1
49+
fi
50+
51+
# Ensure required packages are installed
52+
print_info "Checking required packages..."
53+
for pkg in black pytest; do
54+
if ! "$PYTHON" -c "import $pkg" 2>/dev/null; then
55+
print_info "Installing $pkg..."
56+
"$PIP" install -q "$pkg"
57+
fi
58+
done
59+
print_success "Required packages available"
60+
61+
# Get version bump type (default: patch)
62+
BUMP_TYPE="${1:-patch}"
63+
if [[ ! "$BUMP_TYPE" =~ ^(patch|minor|major)$ ]]; then
64+
print_error "Invalid version bump type: $BUMP_TYPE"
65+
print_info "Usage: $0 [patch|minor|major]"
66+
exit 1
67+
fi
68+
69+
# Get current version from pyproject.toml
70+
CURRENT_VERSION=$(grep '^version = ' pyproject.toml | cut -d'"' -f2)
71+
print_info "Current version: $CURRENT_VERSION"
72+
73+
# Calculate new version
74+
IFS='.' read -r major minor patch <<< "$CURRENT_VERSION"
75+
case "$BUMP_TYPE" in
76+
major) NEW_VERSION="$((major + 1)).0.0" ;;
77+
minor) NEW_VERSION="${major}.$((minor + 1)).0" ;;
78+
patch) NEW_VERSION="${major}.${minor}.$((patch + 1))" ;;
79+
esac
80+
81+
print_info "New version will be: $NEW_VERSION"
82+
read -p "Continue? [y/N] " -n 1 -r
83+
echo
84+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
85+
print_info "Cancelled"
86+
exit 0
87+
fi
88+
89+
# Check git status
90+
if [[ -n $(git status --porcelain) ]]; then
91+
print_error "Working directory is not clean. Commit or stash changes first."
92+
git status --short
93+
exit 1
94+
fi
95+
print_success "Working directory is clean"
96+
97+
# Ensure we're on main branch
98+
CURRENT_BRANCH=$(git branch --show-current)
99+
if [[ "$CURRENT_BRANCH" != "main" ]]; then
100+
print_error "Must be on main branch (currently on: $CURRENT_BRANCH)"
101+
exit 1
102+
fi
103+
print_success "On main branch"
104+
105+
# Pull latest changes
106+
print_info "Pulling latest changes..."
107+
git pull origin main
108+
print_success "Up to date with origin"
109+
110+
# Run tests
111+
print_info "Running tests..."
112+
export PYTHONPATH="$ROOT_DIR:$ROOT_DIR/src:${PYTHONPATH:-}"
113+
if ! "$PYTHON" -m pytest tests/ -v --tb=short; then
114+
print_error "Tests failed!"
115+
exit 1
116+
fi
117+
print_success "All tests passed"
118+
119+
# Format code with Black
120+
print_info "Formatting code with Black..."
121+
"$PYTHON" -m black src/ tests/ scripts/ || true
122+
print_success "Code formatted"
123+
124+
# Update version in pyproject.toml
125+
print_info "Updating version to $NEW_VERSION..."
126+
sed -i.bak "s/^version = \".*\"/version = \"$NEW_VERSION\"/" pyproject.toml
127+
rm -f pyproject.toml.bak
128+
print_success "Version updated in pyproject.toml"
129+
130+
# Commit version bump
131+
git add pyproject.toml
132+
if [[ -n $(git status --porcelain) ]]; then
133+
git add -A
134+
git commit -m "chore: Bump version to $NEW_VERSION
135+
136+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
137+
138+
Co-Authored-By: Claude <noreply@anthropic.com>"
139+
print_success "Version bump committed"
140+
else
141+
print_info "No changes to commit"
142+
fi
143+
144+
# Create and push tag
145+
print_info "Creating tag v$NEW_VERSION..."
146+
git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION"
147+
print_success "Tag created"
148+
149+
# Push changes and tag
150+
print_info "Pushing to origin..."
151+
git push origin main
152+
git push origin "v$NEW_VERSION"
153+
print_success "Pushed to origin"
154+
155+
# Create GitHub release (if gh is available)
156+
if command -v gh &> /dev/null; then
157+
print_info "Creating GitHub release..."
158+
159+
# Generate release notes
160+
PREV_TAG=$(git describe --tags --abbrev=0 "v$NEW_VERSION^" 2>/dev/null || echo "")
161+
if [[ -n "$PREV_TAG" ]]; then
162+
CHANGELOG_URL="https://github.com/markomanninen/mcp-debugpy/compare/${PREV_TAG}...v${NEW_VERSION}"
163+
else
164+
CHANGELOG_URL="https://github.com/markomanninen/mcp-debugpy/commits/v${NEW_VERSION}"
165+
fi
166+
167+
RELEASE_NOTES="## v$NEW_VERSION
168+
169+
$(git log "${PREV_TAG}..HEAD" --pretty=format:"- %s" 2>/dev/null | grep -v "^- chore: Bump version" || echo "- Release v$NEW_VERSION")
170+
171+
**Full Changelog**: $CHANGELOG_URL"
172+
173+
gh release create "v$NEW_VERSION" \
174+
--title "v$NEW_VERSION" \
175+
--notes "$RELEASE_NOTES"
176+
177+
print_success "GitHub release created: https://github.com/markomanninen/mcp-debugpy/releases/tag/v$NEW_VERSION"
178+
else
179+
print_info "gh CLI not found - skipping GitHub release creation"
180+
print_info "Create release manually at: https://github.com/markomanninen/mcp-debugpy/releases/new?tag=v$NEW_VERSION"
181+
fi
182+
183+
print_success "Release v$NEW_VERSION completed!"
184+
print_info "Next steps:"
185+
print_info " 1. Verify release at: https://github.com/markomanninen/mcp-debugpy/releases"
186+
print_info " 2. Monitor CI: https://github.com/markomanninen/mcp-debugpy/actions"

0 commit comments

Comments
 (0)