Skip to content

v2.3.0 — ZAP CloudClient + Security Fixes #84

v2.3.0 — ZAP CloudClient + Security Fixes

v2.3.0 — ZAP CloudClient + Security Fixes #84

Workflow file for this run

# This workflow is triggered when a tag is pushed or a GitHub release is created.
# It can also be run manually to re-publish to PyPI in case it failed for some reason.
# You can run this workflow by navigating to https://www.github.com/hanzoai/python-sdk/actions/workflows/publish-pypi.yml
name: Publish PyPI
on:
workflow_dispatch:
inputs:
packages:
description: 'Packages to publish (space-separated, or "all" for everything)'
required: false
default: 'all'
push:
tags:
- 'v*'
- 'hanzo-*'
- 'hanzoai-*'
- 'hanzo-tools-*'
release:
types: [published]
jobs:
# Run tests first to ensure code quality
test:
name: Run Tests
uses: ./.github/workflows/test.yml
publish-all-packages:
name: Publish All Python Packages
runs-on: hanzo-build-linux-amd64
needs: test # Only publish if tests pass
if: always() && !cancelled()
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all tags
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install build tools
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Get tag name
id: get_tag
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Determine packages to publish
id: determine_packages
run: |
TAG="${{ steps.get_tag.outputs.TAG }}"
MANUAL_INPUT="${{ github.event.inputs.packages }}"
PACKAGES=""
# All hanzo-tools packages
TOOLS_PACKAGES="hanzo-tools-core hanzo-tools-fs hanzo-tools-shell hanzo-tools-browser hanzo-tools-memory hanzo-tools-todo hanzo-tools-reasoning hanzo-tools-lsp hanzo-tools-refactor hanzo-tools-database hanzo-tools-agent hanzo-tools-jupyter hanzo-tools-editor hanzo-tools-llm hanzo-tools-vector hanzo-tools-config hanzo-tools-mcp hanzo-tools-computer hanzo-tools"
# Main packages
MAIN_PACKAGES="hanzoai hanzo hanzo-cli hanzo-kms hanzo-iam hanzo-consensus hanzo-network hanzo-mcp hanzo-memory hanzo-aci hanzo-repl"
# Handle manual workflow dispatch
if [ -n "$MANUAL_INPUT" ]; then
if [ "$MANUAL_INPUT" = "all" ]; then
PACKAGES="$MAIN_PACKAGES $TOOLS_PACKAGES"
else
PACKAGES="$MANUAL_INPUT"
fi
# Handle specific package tags
elif [[ $TAG == hanzo-tools-core-* ]]; then
PACKAGES="hanzo-tools-core"
elif [[ $TAG == hanzo-tools-fs-* ]]; then
PACKAGES="hanzo-tools-fs"
elif [[ $TAG == hanzo-tools-shell-* ]]; then
PACKAGES="hanzo-tools-shell"
elif [[ $TAG == hanzo-tools-browser-* ]]; then
PACKAGES="hanzo-tools-browser"
elif [[ $TAG == hanzo-tools-memory-* ]]; then
PACKAGES="hanzo-tools-memory"
elif [[ $TAG == hanzo-tools-todo-* ]]; then
PACKAGES="hanzo-tools-todo"
elif [[ $TAG == hanzo-tools-reasoning-* ]]; then
PACKAGES="hanzo-tools-reasoning"
elif [[ $TAG == hanzo-tools-lsp-* ]]; then
PACKAGES="hanzo-tools-lsp"
elif [[ $TAG == hanzo-tools-refactor-* ]]; then
PACKAGES="hanzo-tools-refactor"
elif [[ $TAG == hanzo-tools-database-* ]]; then
PACKAGES="hanzo-tools-database"
elif [[ $TAG == hanzo-tools-agent-* ]]; then
PACKAGES="hanzo-tools-agent"
elif [[ $TAG == hanzo-tools-jupyter-* ]]; then
PACKAGES="hanzo-tools-jupyter"
elif [[ $TAG == hanzo-tools-editor-* ]]; then
PACKAGES="hanzo-tools-editor"
elif [[ $TAG == hanzo-tools-llm-* ]]; then
PACKAGES="hanzo-tools-llm"
elif [[ $TAG == hanzo-tools-vector-* ]]; then
PACKAGES="hanzo-tools-vector"
elif [[ $TAG == hanzo-tools-config-* ]]; then
PACKAGES="hanzo-tools-config"
elif [[ $TAG == hanzo-tools-mcp-* ]]; then
PACKAGES="hanzo-tools-mcp"
elif [[ $TAG == hanzo-tools-computer-* ]]; then
PACKAGES="hanzo-tools-computer"
elif [[ $TAG == hanzo-tools-* ]]; then
# All tools packages
PACKAGES="$TOOLS_PACKAGES"
elif [[ $TAG == hanzo-cli-* ]]; then
PACKAGES="hanzo-cli"
elif [[ $TAG == hanzo-kms-* ]]; then
PACKAGES="hanzo-kms"
elif [[ $TAG == hanzo-iam-* ]]; then
PACKAGES="hanzo-iam"
elif [[ $TAG == hanzo-consensus-* ]]; then
PACKAGES="hanzo-consensus"
elif [[ $TAG == hanzo-network-* ]]; then
PACKAGES="hanzo-network"
elif [[ $TAG == hanzo-mcp-* ]]; then
PACKAGES="hanzo-mcp"
elif [[ $TAG == hanzo-memory-* ]]; then
PACKAGES="hanzo-memory"
elif [[ $TAG == hanzo-aci-* ]]; then
PACKAGES="hanzo-aci"
elif [[ $TAG == hanzo-repl-* ]]; then
PACKAGES="hanzo-repl"
elif [[ $TAG == hanzoai-* ]]; then
PACKAGES="hanzoai"
elif [[ $TAG == hanzo-* ]]; then
PACKAGES="hanzo"
elif [[ $TAG == v* ]]; then
# For general version tags, publish all packages
PACKAGES="$MAIN_PACKAGES $TOOLS_PACKAGES"
fi
echo "PACKAGES=$PACKAGES" >> $GITHUB_OUTPUT
echo "Publishing packages: $PACKAGES"
- name: Build and publish packages
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.HANZO_PYPI_TOKEN || secrets.PYPI_TOKEN }}
run: |
PACKAGES="${{ steps.determine_packages.outputs.PACKAGES }}"
if [ -z "$PACKAGES" ]; then
echo "No packages to publish for tag ${{ steps.get_tag.outputs.TAG }}"
exit 0
fi
for package in $PACKAGES; do
echo "=========================================="
echo "Building and publishing $package..."
echo "=========================================="
# hanzoai is the root package, all others live under pkg/
if [ "$package" = "hanzoai" ]; then
PKG_DIR="."
elif [ -d "pkg/$package" ]; then
PKG_DIR="pkg/$package"
else
echo "Warning: Package directory pkg/$package does not exist, skipping"
continue
fi
# Clean any previous builds
rm -rf "$PKG_DIR/dist/" "$PKG_DIR/build/"
# Build from repo root to avoid stdlib shadowing (hanzoai/types vs types)
python -m build "$PKG_DIR" --outdir "$PKG_DIR/dist"
# Upload to PyPI
python -m twine upload "$PKG_DIR/dist/"* --skip-existing || echo "Warning: Failed to upload $package (may already exist)"
done
- name: Create GitHub Release Notes
if: startsWith(github.ref, 'refs/tags/v')
uses: actions/github-script@v7
with:
script: |
const tag = '${{ steps.get_tag.outputs.TAG }}';
const packages = '${{ steps.determine_packages.outputs.PACKAGES }}'.split(' ').filter(p => p);
let body = `## 🚀 Published Python Packages\n\n`;
body += `The following packages have been published to PyPI:\n\n`;
for (const pkg of packages) {
body += `- ✅ **${pkg}** - [View on PyPI](https://pypi.org/project/${pkg}/)\n`;
}
body += `\n### Installation\n\n`;
body += `\`\`\`bash\n`;
body += `# Install main SDK\n`;
body += `pip install hanzo\n\n`;
body += `# Install MCP tools\n`;
body += `pip install hanzo-mcp\n\n`;
body += `# Install individual tool packages\n`;
body += `pip install hanzo-tools # All tools\n`;
body += `pip install hanzo-tools-core # Core only\n`;
body += `\`\`\`\n`;
// Update release if it exists
try {
const releases = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
});
const release = releases.data.find(r => r.tag_name === tag);
if (release) {
await github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release.id,
body: release.body + '\n\n' + body,
});
}
} catch (error) {
console.log('Could not update release notes:', error);
}