Skip to content

Release Process

This repository uses monorepo semantic-release to independently version and release two packages:

  1. katana-openapi-client - The main Python API client
  2. katana-mcp-server - The Model Context Protocol server

Each package is released independently based on commit scopes, allowing them to evolve at their own pace.

Quick Reference

For Client Package Releases

git commit -m "feat(client): add new domain helper classes"
git commit -m "fix(client): resolve pagination edge case"

For MCP Server Releases

git commit -m "feat(mcp): add inventory tools"
git commit -m "fix(mcp): correct stock level calculation"

No Release Needed

git commit -m "docs: update contributing guide"
git commit -m "chore: update dependencies"
git commit -m "test: add integration tests"

How Releases Work

Automated Release Workflow

When a PR is merged to main, the .github/workflows/release.yml workflow runs two independent semantic-release jobs:

  1. Client Release (release-client job):

  2. Checks for commits with feat(client):, fix(client):, or no scope

  3. Calculates next version based on conventional commits
  4. Creates tag: client-v{version} (e.g., client-v0.24.0)
  5. Updates pyproject.toml and __init__.py versions
  6. Generates docs/CHANGELOG.md from commits
  7. Builds and publishes to PyPI as katana-openapi-client

  8. MCP Server Release (release-mcp job):

  9. Checks for commits with feat(mcp): or fix(mcp):

  10. Calculates next version based on conventional commits
  11. Creates tag: mcp-v{version} (e.g., mcp-v0.1.0)
  12. Updates katana_mcp_server/pyproject.toml version
  13. Generates katana_mcp_server/CHANGELOG.md from commits
  14. Builds and publishes to PyPI as katana-mcp-server

Both jobs run in parallel and are completely independent.

Version Bumps

Commit Type Example Version Bump
feat(scope): feat(mcp): add search tool MINOR (0.1.0 → 0.2.0)
fix(scope): fix(client): resolve auth bug PATCH (0.1.0 → 0.1.1)
perf(scope): perf(mcp): optimize queries PATCH (0.1.0 → 0.1.1)
feat(scope)!: or Breaking feat(client)!: redesign API MAJOR (0.1.0 → 1.0.0)
Other (docs:, chore:, test) docs(mcp): update README NO BUMP
feat: (no scope) feat: add pagination Client MINOR (0.23.0 → 0.24.0)

Commit Message Format

Follow Conventional Commits with scopes:

Structure

<type>(<scope>): <description>

[optional body]

[optional footer]

Examples

Client Package Release:

feat(client): add Products domain helper class

- Implement CRUD operations
- Add search and filtering methods
- Full test coverage

MCP Server Release:

feat(mcp): implement check_inventory tool

- Add CheckInventoryRequest and StockInfo models
- Implement tool using Products domain helper
- Add comprehensive unit tests

Closes #35

Breaking Change (Major Version):

feat(client)!: redesign authentication flow

BREAKING CHANGE: Removed legacy BasicAuth class. Use KatanaClient with API key instead.

Documentation (No Release):

docs: update monorepo release documentation

Added comprehensive guide for semantic-release with scopes.

For Contributors

You don't need to do anything special! Just:

  1. Write good commit messages following conventional commits with scopes
  2. Use (client) scope for client changes, (mcp) scope for MCP server changes
  3. Merge your PR to main
  4. The release workflow automatically handles versioning and publishing

Which Scope Should I Use?

  • Changed files in katana_public_api_client/? → Use (client) scope
  • Changed files in katana_mcp_server/? → Use (mcp) scope
  • Changed both? → Make two separate commits, one for each scope
  • Changed only docs or CI? → Use docs: or ci: (no scope, no release)

Release Workflow Steps

1. CI Tests Run

All tests must pass before release:

  • Code quality checks (ruff, ty)
  • Unit and integration tests
  • Security scans (CodeQL, Semgrep, Trivy)

2. Semantic-Release Analysis (Per Package)

For each package, semantic-release:

  • Analyzes commits since last release for that package
  • Determines if a release is needed
  • Calculates the next version number

3. Version Updates (If Releasing)

For each package being released:

  • Updates version in pyproject.toml
  • Updates version variables (__init__.py for client)
  • Generates/updates changelog
  • Creates release commit
  • Creates version tag

4. Build and Publish

For each package being released:

  • Builds Python wheel and source distribution
  • Publishes to PyPI using Trusted Publisher (OIDC, no API tokens)
  • Creates GitHub release with auto-generated notes

Current Versions

  • katana-openapi-client: See PyPI
  • katana-mcp-server: See PyPI

Tag Format

  • Client tags: client-v0.23.0, client-v0.24.0, etc.
  • MCP tags: mcp-v0.1.0, mcp-v0.2.0, etc.

This prevents tag conflicts and makes it clear which package each tag refers to.

Manual Release (Emergency Only)

If the automated workflow fails or you need to force a release:

Option 1: Trigger Workflow Manually

gh workflow run release.yml

This will analyze commits and release any packages with releasable changes.

Option 2: Manual Tag (Advanced)

For MCP Server only (there's a backup workflow):

git tag mcp-v0.1.1
git push origin mcp-v0.1.1

This triggers .github/workflows/release-mcp.yml which builds and publishes the MCP package directly.

Troubleshooting

"No release will be made"

Cause: No commits with feat:, fix:, or perf: since last release for that package.

Solution: Ensure your commits follow conventional commit format with appropriate scopes:

  • Use feat(client): or fix(client): for client releases
  • Use feat(mcp): or fix(mcp): for MCP releases

Release not triggered?

Check:

  • Are there feat: or fix: commits with the correct scope?
  • Did the test job pass? (release only runs after tests pass)
  • Check Actions tab for workflow run details

Wrong package released?

Cause: Missing or incorrect commit scope.

Solution:

  • Use feat(client): or fix(client): for client releases
  • Use feat(mcp): or fix(mcp): for MCP releases
  • Commits without scope default to client package

Release created but PyPI publish failed?

Check:

  • Verify PyPI Trusted Publisher is configured for the repository
  • Ensure workflow has id-token: write permission
  • Check PyPI status page for outages

Protected branch error?**

Check:

  • Verify SEMANTIC_RELEASE_TOKEN secret is set:
    gh secret list --repo dougborg/katana-openapi-client
    
  • Ensure PAT has correct permissions (Contents: write, PRs: write)
  • Verify PAT hasn't expired

Version conflict?

Cause: PyPI version already exists (can happen if manual release conflicts with automated).

Solution: Semantic-release will skip the publish step. Wait for next release cycle.

Technical Details

Protected Branch Setup

The main branch is protected with required status checks. The release workflow uses a Personal Access Token (SEMANTIC_RELEASE_TOKEN) to bypass protection and push release commits.

Workflow Configuration

See .github/workflows/release.yml for the complete workflow configuration.

PyPI Trusted Publishers

Both packages use PyPI Trusted Publishers for secure, tokenless authentication:

  • katana-openapi-client: Published from release-client job
  • katana-mcp-server: Published from release-mcp job

Configuration: PyPI Project Settings → Publishing → Trusted Publishers

Semantic-Release Configuration

Each package has its own semantic-release configuration:

  • Client: pyproject.toml (root) - [tool.semantic_release]
  • MCP Server: katana_mcp_server/pyproject.toml - [tool.semantic_release]

Configuration includes:

  • Version file locations
  • Tag format
  • Commit message format
  • Changelog generation
  • Build commands

Further Reading