Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 73 additions & 117 deletions .github/workflows/create-release.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# .github/workflows/create-release.yml
name: Create GitHub Release and Publish to PyPI
name: Create GitHub Release and Publish SDKs
on:
push:
branches: [main] # Trigger on ANY push to main (including PR merges)
pull_request:
types: [closed] # Also trigger when PRs are merged
branches: [main]
jobs:
detect-and-release:
detect-release:
runs-on: ubuntu-latest
if: github.event_name == 'push' || (github.event.pull_request.merged == true)
outputs:
latest_tag: ${{ steps.find-tags.outputs.latest_tag }}
version: ${{ steps.find-tags.outputs.version }}
should_release: ${{ steps.check-release.outputs.should_release }}
permissions:
contents: write
pull-requests: read
Expand Down Expand Up @@ -81,118 +85,70 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# NEW: Set up Python for PyPI publishing
- name: Set up Python
if: steps.check-release.outputs.should_release == 'true'
uses: actions/setup-python@v5
with:
python-version: '3.11'

# NEW: Install build dependencies
- name: Install build dependencies
if: steps.check-release.outputs.should_release == 'true'
run: |
python -m pip install --upgrade pip
python -m pip install build twine

# NEW: Verify version matches tag
- name: Verify package version matches tag
if: steps.check-release.outputs.should_release == 'true'
run: |
TAG_VERSION="${{ steps.find-tags.outputs.version }}"

# Check if setup.py exists
if [ -f "setup.py" ]; then
PACKAGE_VERSION=$(python setup.py --version)
# Check if pyproject.toml exists
elif [ -f "pyproject.toml" ]; then
# Extract version from pyproject.toml
PACKAGE_VERSION=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['version'])")
else
echo "❌ Neither setup.py nor pyproject.toml found!"
exit 1
fi

echo "Tag version: $TAG_VERSION"
echo "Package version: $PACKAGE_VERSION"

if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then
echo "❌ Version mismatch! Tag: $TAG_VERSION, Package: $PACKAGE_VERSION"
exit 1
else
echo "✅ Version match confirmed: $TAG_VERSION"
fi

# NEW: Build Python package
- name: Build package
if: steps.check-release.outputs.should_release == 'true'
run: python -m build

# NEW: Check if package already exists on PyPI
- name: Check if package exists on PyPI
if: steps.check-release.outputs.should_release == 'true'
id: check-pypi
run: |
VERSION="${{ steps.find-tags.outputs.version }}"

# Get package name from setup.py or pyproject.toml
if [ -f "pyproject.toml" ]; then
PACKAGE_NAME=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['name'])")
elif [ -f "setup.py" ]; then
PACKAGE_NAME=$(python setup.py --name)
else
echo "❌ Cannot determine package name"
exit 1
fi

echo "Checking if $PACKAGE_NAME version $VERSION exists on PyPI..."

# Check if this version already exists on PyPI
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/$PACKAGE_NAME/$VERSION/json/")

if [ "$HTTP_CODE" = "200" ]; then
echo "⚠️ Package $PACKAGE_NAME v$VERSION already exists on PyPI, skipping upload"
echo "should_publish_pypi=false" >> $GITHUB_OUTPUT
else
echo "✅ Package $PACKAGE_NAME v$VERSION not found on PyPI, proceeding with upload"
echo "should_publish_pypi=true" >> $GITHUB_OUTPUT
fi

# NEW: Publish to PyPI using API token
- name: Publish package to PyPI
if: steps.check-release.outputs.should_release == 'true' && steps.check-pypi.outputs.should_publish_pypi == 'true'
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
print-hash: true

- name: Create main GitHub Release
if: steps.check-release.outputs.should_release == 'true'
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.find-tags.outputs.latest_tag }}
name: RunAgent v${{ steps.find-tags.outputs.version }}
body: |
# 🚀 RunAgent v${{ steps.find-tags.outputs.version }}

**Universal AI Agent Platform - All SDKs synchronized at v${{ steps.find-tags.outputs.version }}**

## 📋 What's New

For detailed changes in this release, see [CHANGELOG.md](./CHANGELOG.md).

This release synchronizes all RunAgent SDKs (Python, JavaScript, Rust, Go) to version ${{ steps.find-tags.outputs.version }}.

## 📦 Installation

```bash
pip install runagent==${{ steps.find-tags.outputs.version }}
```

draft: false
prerelease: false
generate_release_notes: true # Let GitHub add commit-based notes
files: |
CHANGELOG.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-python:
name: Publish Python SDK
needs: detect-release
if: needs.detect-release.outputs.should_release == 'true'
uses: ./.github/workflows/reusable-sdk-release.yml
with:
sdk: python
working-directory: .
tag: ${{ needs.detect-release.outputs.latest_tag }}
version: ${{ needs.detect-release.outputs.version }}
secrets: inherit

publish-typescript:
name: Publish TypeScript SDK
needs: detect-release
if: needs.detect-release.outputs.should_release == 'true'
uses: ./.github/workflows/reusable-sdk-release.yml
with:
sdk: typescript
working-directory: runagent-ts
tag: ${{ needs.detect-release.outputs.latest_tag }}
version: ${{ needs.detect-release.outputs.version }}
secrets: inherit

create-release:
name: Create GitHub Release
needs:
- detect-release
- publish-python
- publish-typescript
if: needs.detect-release.outputs.should_release == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create main GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ needs.detect-release.outputs.latest_tag }}
name: RunAgent v${{ needs.detect-release.outputs.version }}
body: |
# 🚀 RunAgent v${{ needs.detect-release.outputs.version }}

**Universal AI Agent Platform - All SDKs synchronized at v${{ needs.detect-release.outputs.version }}**

## 📋 What's New

For detailed changes in this release, see [CHANGELOG.md](./CHANGELOG.md).

This release synchronizes all RunAgent SDKs (Python, JavaScript, Rust, Go) to version ${{ needs.detect-release.outputs.version }}.

## 📦 Installation

```bash
pip install runagent==${{ needs.detect-release.outputs.version }}
```

draft: false
prerelease: false
generate_release_notes: true # Let GitHub add commit-based notes
files: |
CHANGELOG.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
99 changes: 99 additions & 0 deletions .github/workflows/python-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Python SDK Release

on:
workflow_call:
inputs:
working-directory:
description: Path where build commands should run
required: true
type: string
tag:
description: Git tag for this release (e.g., v0.1.0)
required: true
type: string
version:
description: Package version without the leading v (e.g., 0.1.0)
required: true
type: string
python-version:
description: Python version used to build the package
required: false
type: string
default: "3.11"
secrets:
PYPI_API_TOKEN:
required: true

jobs:
publish:
name: Publish Python SDK
runs-on: ubuntu-latest
if: inputs.version != ''
defaults:
run:
shell: bash
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Show release context
run: |
echo "Tag: ${{ inputs.tag }}"
echo "Version: ${{ inputs.version }}"
echo "Working directory: ${{ inputs.working-directory }}"

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}

- name: Upgrade pip and install build dependencies
run: |
python -m pip install --upgrade pip
python -m pip install build twine

- name: Verify package version matches tag
id: verify-python-version
run: |
TAG_VERSION="${{ inputs.version }}"
PACKAGE_VERSION=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['version'])")
echo "Detected package version: $PACKAGE_VERSION"
if [ "$PACKAGE_VERSION" != "$TAG_VERSION" ]; then
echo "❌ Version mismatch! Tag: $TAG_VERSION, Package: $PACKAGE_VERSION"
exit 1
fi
echo "✅ Python version matches tag"

- name: Build package
run: python -m build

- name: Check if package version already exists on PyPI
id: check-python
run: |
VERSION="${{ inputs.version }}"
PACKAGE_NAME=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['name'])")
echo "Package name: $PACKAGE_NAME"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/$PACKAGE_NAME/$VERSION/json/")
if [ "$HTTP_CODE" = "200" ]; then
echo "⚠️ $PACKAGE_NAME v$VERSION already exists on PyPI"
echo "should_publish=false" >> "$GITHUB_OUTPUT"
else
echo "✅ $PACKAGE_NAME v$VERSION not found on PyPI"
echo "should_publish=true" >> "$GITHUB_OUTPUT"
fi
echo "package_name=$PACKAGE_NAME" >> "$GITHUB_OUTPUT"

- name: Publish package to PyPI
if: steps.check-python.outputs.should_publish == 'true'
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
print-hash: true

- name: Skip publish (already exists)
if: steps.check-python.outputs.should_publish != 'true'
run: echo "Skipping PyPI publish because version already exists."

58 changes: 58 additions & 0 deletions .github/workflows/reusable-sdk-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: SDK Release Router

on:
workflow_call:
inputs:
sdk:
description: Identifier for the SDK (e.g., python, typescript)
required: true
type: string
working-directory:
description: Path where build commands should run
required: true
type: string
tag:
description: Git tag for this release (e.g., v0.1.0)
required: true
type: string
version:
description: Package version without the leading v (e.g., 0.1.0)
required: true
type: string
python-version:
description: Python version to use when sdk == python
required: false
type: string
default: "3.11"
node-version:
description: Node.js version to use when sdk == typescript
required: false
type: string
default: "20"
secrets:
PYPI_API_TOKEN:
required: false
NPM_TOKEN:
required: false

jobs:
python:
if: inputs.sdk == 'python' && inputs.version != ''
uses: ./.github/workflows/python-release.yml
with:
working-directory: ${{ inputs.working-directory }}
tag: ${{ inputs.tag }}
version: ${{ inputs.version }}
python-version: ${{ inputs.python-version }}
secrets: inherit

typescript:
if: inputs.sdk == 'typescript' && inputs.version != ''
uses: ./.github/workflows/typescript-release.yml
with:
working-directory: ${{ inputs.working-directory }}
tag: ${{ inputs.tag }}
version: ${{ inputs.version }}
node-version: ${{ inputs.node-version }}
secrets: inherit

Loading