# 发布 Python 包到 PyPI

本指南介绍如何将 agentcenter 项目发布到 PyPI（Python Package Index），让其他用户可以通过 `pip install agentcenter` 安装。

---

## 📋 发布前检查清单

在发布之前，确保完成以下检查：

### 1. 代码质量检查

```bash
# 运行所有测试
uv run pytest --cov=agentcenter --cov-report=term-missing

# 代码格式检查
uv run black src/ tests/ --check
uv run ruff check src/ tests/

# 类型检查
uv run mypy src/
```

### 2. 文档完整性检查

- ✓ README.md 完整且准确
- ✓ CHANGELOG.md 已更新
- ✓ LICENSE 文件存在
- ✓ 所有配置字段有文档说明
- ✓ 示例代码可以运行

### 3. 版本管理检查

- ✓ 版本号遵循语义化版本 (SemVer)
- ✓ pyproject.toml 中的版本号已更新
- ✓ CHANGELOG.md 记录了本版本的更新
- ✓ Git tag 已创建

---

## 🔢 版本号管理

### 语义化版本 (Semantic Versioning)

格式：`MAJOR.MINOR.PATCH` (例如：`1.2.3`)

- **MAJOR**: 不兼容的 API 变更
- **MINOR**: 向后兼容的功能新增
- **PATCH**: 向后兼容的问题修正

**示例：**
```
0.1.0  - 初始开发版本
0.2.0  - 新增功能（向后兼容）
0.2.1  - Bug 修复
1.0.0  - 第一个稳定版本
1.1.0  - 新增功能
2.0.0  - 破坏性更新
```

### 更新版本号

1. 编辑 `pyproject.toml`:

```toml
[project]
version = "0.1.0"  # 修改这里
```

2. 更新 `CHANGELOG.md`:

```markdown
## [0.1.0] - 2025-01-27

### Added
- 初始版本发布
- 基本 Agent 功能
- CLI 接口
- 配置管理

### Changed
- 无

### Fixed
- 无
```

3. 创建 Git tag:

```bash
git tag -a v0.1.0 -m "Release version 0.1.0"
git push origin v0.1.0
```

---

## 📦 构建 Python 包

### 方法 1：使用 uv（推荐）

uv 已经集成了构建功能：

```bash
# 构建源码包和 wheel
uv build

# 输出文件在 dist/ 目录：
# dist/agentcenter-0.1.0.tar.gz
# dist/agentcenter-0.1.0-py3-none-any.whl
```

### 方法 2：使用 build

```bash
# 安装 build 工具
uv add --dev build

# 构建包
uv run python -m build

# 或使用传统方式
python -m build
```

### 验证构建的包

```bash
# 检查包内容
tar -tzf dist/agentcenter-0.1.0.tar.gz

# 或查看 wheel 内容
unzip -l dist/agentcenter-0.1.0-py3-none-any.whl

# 检查包元数据
uv run python -m tarfile -l dist/agentcenter-0.1.0.tar.gz
```

---

## 🚀 发布到 PyPI

### 准备工作

1. **注册 PyPI 账号**
   - 生产环境: https://pypi.org/account/register/
   - 测试环境: https://test.pypi.org/account/register/

2. **创建 API Token**
   - 访问: https://pypi.org/manage/account/token/
   - 创建新 token，选择作用域为"整个账户"或"特定项目"
   - 保存 token（只显示一次）

3. **配置凭证**

创建 `~/.pypirc` 文件：

```ini
[distutils]
index-servers =
    pypi
    testpypi

[pypi]
username = __token__
password = pypi-AgEIcHlwaS5vcmcC...  # 你的 PyPI token

[testpypi]
username = __token__
password = pypi-AgENdGVzdC5weXBp...  # 你的 TestPyPI token
```

或使用环境变量：

```bash
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=pypi-AgEIcHlwaS5vcmcC...
```

### 步骤 1：发布到 TestPyPI（测试）

**强烈建议先发布到测试环境！**

```bash
# 安装 twine
uv add --dev twine

# 上传到 TestPyPI
uv run twine upload --repository testpypi dist/*

# 或指定文件
uv run twine upload --repository testpypi dist/agentcenter-0.1.0*
```

验证测试环境的包：

```bash
# 从 TestPyPI 安装
pip install --index-url https://test.pypi.org/simple/ agentcenter

# 测试安装的包
python -c "from agentcenter import AgentCenter; print('Success!')"
```

### 步骤 2：发布到 PyPI（正式）

确认测试环境没问题后，发布到正式环境：

```bash
# 上传到 PyPI
uv run twine upload dist/*

# 成功后会显示：
# Uploading agentcenter-0.1.0.tar.gz
# Uploading agentcenter-0.1.0-py3-none-any.whl
# View at: https://pypi.org/project/agentcenter/0.1.0/
```

验证正式发布：

```bash
# 等待几分钟让 PyPI 索引更新

# 安装
pip install agentcenter

# 或使用 uv
uv add agentcenter

# 验证
python -c "from agentcenter import AgentCenter; print('Success!')"
```

---

## 🔄 完整发布流程

### 标准发布流程

```bash
# 1. 确保代码最新
git pull origin main

# 2. 运行所有测试
uv run pytest --cov=agentcenter --cov-fail-under=80

# 3. 运行代码质量检查
uv run black src/ tests/
uv run ruff check src/ tests/ --fix
uv run mypy src/

# 4. 更新版本号 (编辑 pyproject.toml)
# version = "0.1.0" -> "0.2.0"

# 5. 更新 CHANGELOG.md
# 添加本版本的更新内容

# 6. 提交更改
git add .
git commit -m "Release version 0.2.0"
git push origin main

# 7. 创建 Git tag
git tag -a v0.2.0 -m "Release version 0.2.0"
git push origin v0.2.0

# 8. 清理旧构建
rm -rf dist/ build/ *.egg-info

# 9. 构建新版本
uv build

# 10. 检查构建产物
ls -lh dist/

# 11. 上传到 TestPyPI（可选但推荐）
uv run twine upload --repository testpypi dist/*

# 12. 测试 TestPyPI 的包
pip install --index-url https://test.pypi.org/simple/ agentcenter==0.2.0

# 13. 上传到正式 PyPI
uv run twine upload dist/*

# 14. 验证安装
pip install --upgrade agentcenter

# 15. 创建 GitHub Release（可选）
gh release create v0.2.0 --title "Release v0.2.0" --notes "$(cat CHANGELOG.md)"
```

### 使用脚本自动化

创建 `scripts/release.sh`:

```bash
#!/bin/bash
# Release script for agentcenter

set -e

# 颜色输出
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color

echo -e "${GREEN}Starting release process...${NC}"

# 1. 检查工作目录是否干净
if [[ -n $(git status -s) ]]; then
    echo -e "${RED}Error: Working directory is not clean${NC}"
    git status -s
    exit 1
fi

# 2. 运行测试
echo -e "${YELLOW}Running tests...${NC}"
uv run pytest --cov=agentcenter --cov-fail-under=80

# 3. 运行代码质量检查
echo -e "${YELLOW}Running code quality checks...${NC}"
uv run black src/ tests/ --check
uv run ruff check src/ tests/
uv run mypy src/

# 4. 获取版本号
VERSION=$(grep '^version = ' pyproject.toml | cut -d'"' -f2)
echo -e "${GREEN}Building version: ${VERSION}${NC}"

# 5. 清理旧构建
echo -e "${YELLOW}Cleaning old builds...${NC}"
rm -rf dist/ build/ *.egg-info

# 6. 构建
echo -e "${YELLOW}Building package...${NC}"
uv build

# 7. 检查构建产物
echo -e "${YELLOW}Build artifacts:${NC}"
ls -lh dist/

# 8. 询问是否继续
read -p "Upload to TestPyPI? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    uv run twine upload --repository testpypi dist/*
fi

read -p "Upload to PyPI? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    uv run twine upload dist/*
    echo -e "${GREEN}Successfully released version ${VERSION}!${NC}"
    echo -e "${GREEN}View at: https://pypi.org/project/agentcenter/${VERSION}/${NC}"
else
    echo -e "${YELLOW}Upload cancelled${NC}"
fi
```

使用脚本：

```bash
chmod +x scripts/release.sh
./scripts/release.sh
```

---

## 🔐 安全最佳实践

### 1. 保护 API Token

**不要**：
- ❌ 将 token 提交到 Git
- ❌ 将 token 写在脚本中
- ❌ 分享 token 给他人

**应该**：
- ✓ 使用环境变量
- ✓ 使用 `.pypirc` 并添加到 `.gitignore`
- ✓ 使用项目级别的 token（而非账户级别）
- ✓ 定期轮换 token

### 2. 验证包内容

发布前检查：

```bash
# 检查包含的文件
tar -tzf dist/agentcenter-0.1.0.tar.gz

# 确保没有包含敏感信息：
# - .env 文件
# - API keys
# - 私钥
# - 数据库凭证
```

### 3. 使用 .gitignore 和 MANIFEST.in

确保 `.gitignore` 包含：

```gitignore
# 构建产物
dist/
build/
*.egg-info/

# 敏感信息
.env
.env.local
*.key
*.pem
credentials.json

# PyPI 配置
.pypirc
```

---

## 🏷️ GitHub Release

### 创建 GitHub Release

```bash
# 使用 gh CLI
gh release create v0.1.0 \
  --title "Release v0.1.0" \
  --notes "Initial release with basic agent functionality" \
  dist/*

# 或从 CHANGELOG 读取
gh release create v0.1.0 \
  --title "Release v0.1.0" \
  --notes-file CHANGELOG.md \
  dist/*
```

### 自动化 GitHub Release

创建 `.github/workflows/release.yml`:

```yaml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - uses: actions/setup-python@v4
        with:
          python-version: '3.12'

      - name: Install uv
        run: curl -LsSf https://astral.sh/uv/install.sh | sh

      - name: Install dependencies
        run: uv sync --group dev

      - name: Run tests
        run: uv run pytest --cov=agentcenter --cov-fail-under=80

      - name: Build package
        run: uv build

      - name: Publish to PyPI
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
        run: uv run twine upload dist/*

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v1
        with:
          files: dist/*
          generate_release_notes: true
```

需要在 GitHub 仓库设置中添加 Secret：
- `PYPI_API_TOKEN`: 你的 PyPI API token

---

## 📊 发布后检查

### 1. 验证 PyPI 页面

访问 https://pypi.org/project/agentcenter/ 检查：
- ✓ 项目描述正确显示
- ✓ README 渲染正常
- ✓ 版本号正确
- ✓ 依赖列表正确
- ✓ 链接有效

### 2. 测试安装

```bash
# 在新的虚拟环境测试
python -m venv test_env
source test_env/bin/activate

pip install agentcenter
python -c "from agentcenter import AgentCenter; a = AgentCenter(); print('OK')"

deactivate
rm -rf test_env
```

### 3. 监控下载量

- 访问 https://pypistats.org/packages/agentcenter
- 查看下载统计和趋势

---

## 🔄 更新已发布的包

### 发布补丁版本

```bash
# 修复 bug 后
# 1. 更新版本: 0.1.0 -> 0.1.1
# 2. 更新 CHANGELOG
# 3. 提交并打 tag
git commit -am "Fix: bug description"
git tag v0.1.1
git push origin main --tags

# 4. 构建并发布
uv build
uv run twine upload dist/*
```

### 发布新功能版本

```bash
# 添加新功能后
# 1. 更新版本: 0.1.1 -> 0.2.0
# 2. 更新 CHANGELOG
# 3. 提交并打 tag
git commit -am "Feature: new feature description"
git tag v0.2.0
git push origin main --tags

# 4. 构建并发布
uv build
uv run twine upload dist/*
```

---

## ❗ 常见问题

### Q1: 如何撤回已发布的版本？

**不能撤回！** PyPI 不允许删除已发布的版本。只能：
- 发布新的修复版本
- 如果版本有严重问题，可以 yank（标记为不推荐）

```bash
# Yank 一个版本（不推荐安装，但已安装的不受影响）
twine upload --skip-existing dist/*
# 然后在 PyPI 网站上手动 yank
```

### Q2: 版本号写错了怎么办？

发布新版本，版本号+1。例如错误发布了 0.2.0，发布 0.2.1 作为修正。

### Q3: 如何发布 alpha/beta 版本？

```toml
# pyproject.toml
version = "0.2.0a1"  # alpha
version = "0.2.0b1"  # beta
version = "0.2.0rc1" # release candidate
```

安装时：
```bash
pip install agentcenter==0.2.0a1
# 或安装最新的预发布版本
pip install --pre agentcenter
```

### Q4: 上传失败：HTTPError: 403 Forbidden

检查：
- Token 是否正确
- Token 权限是否足够
- 包名是否已被占用
- `.pypirc` 配置是否正确

---

## 📚 参考资源

- [Python Packaging User Guide](https://packaging.python.org/)
- [PyPI 官方文档](https://pypi.org/help/)
- [Twine 文档](https://twine.readthedocs.io/)
- [Semantic Versioning](https://semver.org/)
- [uv 文档](https://docs.astral.sh/uv/)

---

## ✅ 快速参考

```bash
# 完整发布流程（一键复制）
uv run pytest --cov=agentcenter --cov-fail-under=80 && \
uv run black src/ tests/ && \
uv run ruff check src/ tests/ && \
rm -rf dist/ && \
uv build && \
uv run twine upload --repository testpypi dist/* && \
echo "Test at: pip install --index-url https://test.pypi.org/simple/ agentcenter" && \
read -p "Upload to PyPI? (y/n) " -n 1 -r && \
[[ $REPLY =~ ^[Yy]$ ]] && uv run twine upload dist/*
```

---

**记住：** 发布到 PyPI 是永久的，无法撤销。发布前务必仔细检查！
