Skip to content

Commit 48336a2

Browse files
committed
feat: add automated release pipeline with release-please
- Configure release-please for automated changelog and version bumps - Single-source version via importlib.metadata (pyproject.toml only) - Add conventional commits guide to CLAUDE.md - Update CLAUDE.md for src layout and new CLI entry points https://claude.ai/code/session_01KvtJxwu7mCzSWEwX8wANCL
1 parent a467012 commit 48336a2

6 files changed

Lines changed: 125 additions & 10 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
".": "0.1.1"
3+
}

.github/release-please-config.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
3+
"packages": {
4+
".": {
5+
"release-type": "python",
6+
"package-name": "webex-bot-mcp",
7+
"changelog-path": "CHANGELOG.md"
8+
}
9+
}
10+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Release Please
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
jobs:
13+
release-please:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: googleapis/release-please-action@v4
17+
with:
18+
config-file: .github/release-please-config.json
19+
manifest-file: .github/.release-please-manifest.json

CLAUDE.md

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,17 @@ guides) and prompt templates for common workflows.
99
## Repository Layout
1010

1111
```
12+
pyproject.toml — Project metadata, version (single source of truth), and dependencies (uv)
13+
Dockerfile — Multi-stage build; non-root user, health checks
14+
docker-compose.yml — Compose stack with optional Prometheus + Grafana
15+
1216
src/webex_bot_mcp/
17+
__init__.py — Package init; reads __version__ from importlib.metadata
18+
__main__.py — Enables `python -m webex_bot_mcp`
1319
main.py — MCP server entry point; registers all tools/resources/prompts
1420
config.py — WebexConfig dataclass; loaded via get_config() or WebexConfig.from_env()
1521
health_check.py — Standalone diagnostic script; validates env and API connectivity
22+
1623
tools/
1724
__init__.py — Re-exports every tool function
1825
common.py — Shared: WebexAPI client, create_error_response, create_success_response,
@@ -23,12 +30,15 @@ src/webex_bot_mcp/
2330
memberships.py — Membership CRUD (list, add, update, delete) + space aliases
2431
people.py — get_webex_me, list_webex_people
2532
26-
pyproject.toml — Project metadata and dependencies (uses uv, src layout)
27-
Dockerfile — Multi-stage build; non-root user, health checks
28-
docker-compose.yml — Compose stack with optional Prometheus + Grafana
29-
3033
tests/
3134
test_messages.py — Unit tests (85 cases); mocks webexpythonsdk at sys.modules level
35+
36+
.github/
37+
workflows/
38+
publish.yml — Builds + publishes to TestPyPI then PyPI on tag/workflow_dispatch
39+
release-please.yml — Creates release PRs and tags from conventional commits
40+
release-please-config.json — release-please package config
41+
.release-please-manifest.json — Tracks current released version
3242
```
3343

3444
## Key Conventions
@@ -74,18 +84,25 @@ params['files'] = [files] if isinstance(files, str) else files
7484
## Running the Server
7585

7686
```bash
77-
# stdio (default — for Claude Desktop / MCP clients)
87+
# If installed from PyPI (pip install webex-bot-mcp)
88+
webex-bot-mcp # stdio (default)
89+
webex-bot-mcp --transport streamable-http --port 8000 # HTTP transport
90+
91+
# From source checkout (development)
7892
uv run webex-bot-mcp
93+
uv run python -m webex_bot_mcp --transport streamable-http --host 0.0.0.0 --port 8000
7994

80-
# HTTP transport
81-
uv run webex-bot-mcp --transport streamable-http --host 0.0.0.0 --port 8000
95+
# Health check
96+
webex-bot-mcp-health
8297
```
8398

8499
Required environment variable: `WEBEX_ACCESS_TOKEN`
85100

86101
## Running Tests
87102

88103
```bash
104+
python -m unittest discover -s tests -v
105+
# or, from a source checkout with uv:
89106
uv run python -m unittest discover -s tests -v
90107
```
91108

@@ -116,6 +133,63 @@ Must run via `uv run` so the `src/webex_bot_mcp` package is on the Python path.
116133
| `METRICS_ENABLED` | | `false` | Enable metrics endpoint |
117134
| `METRICS_ENDPOINT` | || Prometheus push endpoint |
118135

136+
## Releases & Conventional Commits
137+
138+
Releases are fully automated via **release-please** + **GitHub Actions**. No manual version
139+
bumping or tagging is needed for normal releases.
140+
141+
### How it works
142+
143+
1. Merge commits to `main` using the **conventional commit** format (see below).
144+
2. release-please watches `main` and maintains a "Release PR" that accumulates unreleased
145+
changes, updating `CHANGELOG.md` and `pyproject.toml` version automatically.
146+
3. When you're ready to release, **merge the Release PR** — release-please creates a GitHub
147+
tag + release automatically.
148+
4. The `publish.yml` workflow fires on the new tag, builds the wheel, publishes to TestPyPI
149+
(requires approval from the `testpypi` environment), then publishes to PyPI (requires
150+
approval from the `pypi` environment).
151+
152+
You can also trigger a publish manually from the GitHub Actions tab via `workflow_dispatch`
153+
(useful if you need to republish without a new tag).
154+
155+
### Conventional commit format
156+
157+
```
158+
<type>(<scope>): <short description>
159+
160+
[optional body]
161+
162+
[optional footer(s)]
163+
```
164+
165+
| Type | Version bump | Use for |
166+
|---|---|---|
167+
| `feat:` | minor | New tool, resource, or user-visible feature |
168+
| `fix:` | patch | Bug fix |
169+
| `feat!:` or `BREAKING CHANGE:` footer | major | Breaking API change |
170+
| `chore:` | none | Build, CI, dependency updates |
171+
| `docs:` | none | Documentation only |
172+
| `refactor:` | none | Code restructure, no behavior change |
173+
| `test:` | none | Test additions or fixes |
174+
| `perf:` | patch | Performance improvement |
175+
176+
**Examples:**
177+
```
178+
feat(messages): add markdown formatting support
179+
fix(rooms): handle 404 when room already deleted
180+
chore(deps): update fastmcp to 2.5.0
181+
docs: add conventional commits guide to CLAUDE.md
182+
feat!: rename list_webex_rooms to list_rooms
183+
184+
BREAKING CHANGE: tool name changed for consistency
185+
```
186+
187+
### Version source of truth
188+
189+
Version lives **only** in `pyproject.toml`. Code reads it at runtime via
190+
`importlib.metadata.version("webex-bot-mcp")`. Never hard-code a version string anywhere
191+
else in the source.
192+
119193
## Dependency Management
120194

121195
Uses `uv`. The declared runtime dependency for dotenv is `python-dotenv>=1.0.0`

src/webex_bot_mcp/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
"""Webex Bot MCP — Model Context Protocol server for Webex Teams."""
22

3-
__version__ = "0.1.1"
3+
from importlib.metadata import version, PackageNotFoundError
4+
5+
try:
6+
__version__ = version("webex-bot-mcp")
7+
except PackageNotFoundError:
8+
__version__ = "unknown"

src/webex_bot_mcp/tools/common.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44
import os
55
from datetime import datetime, timezone
66
from typing import Dict, Any
7+
from importlib.metadata import version, PackageNotFoundError
78
from webexpythonsdk import WebexAPI
89

9-
# Server version information
10-
MCP_SERVER_VERSION = "0.1.1"
10+
# Server version information — single source of truth is pyproject.toml
11+
try:
12+
MCP_SERVER_VERSION = version("webex-bot-mcp")
13+
except PackageNotFoundError:
14+
MCP_SERVER_VERSION = "unknown"
1115
MCP_SPEC_VERSION = "2024-11-05"
1216

1317
# Error codes for structured error handling

0 commit comments

Comments
 (0)