# PUBLISH.md — PyPI Publication Guide

Complete guide to publish `openclaw-installer` to PyPI.

---

## 📋 Prerequisites

### Accounts Required

1. **PyPI Account**: https://pypi.org/account/register/
2. **TestPyPI Account**: https://test.pypi.org/account/register/ (separate!)

### Tools Installation

```bash
pipx install build
pipx install twine
pip install hatchling
```

Or with pip (for build tools only):
```bash
pip install build twine hatchling
```

---

## 🔑 API Token Setup (Recommended)

### 1. Create PyPI API Token

1. Go to https://pypi.org/manage/account/token/
2. Click **Add API token**
3. Name: `openclaw-installer-release`
4. Scope: **Entire account** (or limit to project after first upload)
5. Copy the token (starts with `pypi-`)

### 2. Configure Locally

**Option A: Keyring (Secure)**

```bash
pip install keyring
keyring set https://upload.pypi.org/legacy/ __token__
# Enter: pypi-your-token-here
```

**Option B: Environment Variable**

```bash
export PYPI_API_TOKEN=pypi-your-token-here
```

**Option C: .pypirc File**

Create `~/.pypirc`:

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

[pypi]
username = __token__
password = pypi-your-token-here

[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = pypi-your-test-token-here
```

---

## 🧪 TestPyPI Upload (ALWAYS DO THIS FIRST)

### Step 1: Clean Build Artifacts

```bash
cd /path/to/openclaw-installer
rm -rf build/ dist/ *.egg-info/
```

### Step 2: Build Package

```bash
python -m build
```

Output:
```
Successfully built openclaw-installer-1.0.0.tar.gz and openclaw_installer-1.0.0-py3-none-any.whl
```

### Step 3: Verify Build

```bash
twine check dist/*
```

Should show: `PASSED`

### Step 4: Upload to TestPyPI

```bash
twine upload --repository testpypi dist/*
```

Or with token:
```bash
twine upload --repository testpypi dist/* -u __token__ -p $TESTPYPI_TOKEN
```

### Step 5: Verify TestPyPI Upload

1. Visit: https://test.pypi.org/project/openclaw-installer/
2. Check version appears
3. Read rendering looks correct

### Step 6: Test Install from TestPyPI

```bash
# Install from TestPyPI using pipx
pipx install --index-url https://test.pypi.org/simple/     --pip-args="--extra-index-url https://pypi.org/simple/"     openclaw-installer

# Test it works
openclaw-installer --help

# Uninstall test version
pipx uninstall openclaw-installer
```

---

## 🚀 Production PyPI Upload

### Final Checks

```bash
# Version correct in pyproject.toml?
grep version pyproject.toml

# README renders?
twine check dist/*

# Git committed?
git status
```

### Upload to Production PyPI

```bash
twine upload dist/*
```

Or with explicit auth:
```bash
twine upload dist/* -u __token__ -p $PYPI_API_TOKEN
```

### Verify Production Upload

1. Visit: https://pypi.org/project/openclaw-installer/
2. Check version, description, classifiers
3. Copy install command:
   ```bash
   pipx install openclaw-installer
   ```

---

## 🔄 Version Updates

### Semantic Versioning

| Version | When to Use |
|---------|-------------|
| `1.0.0` → `1.0.1` | Bug fixes, patches |
| `1.0.1` → `1.1.0` | New features, backward compatible |
| `1.1.0` → `2.0.0` | Breaking changes |

### Release Checklist

```bash
# 1. Update version in pyproject.toml
# 2. Update __version__ in __init__.py
# 3. Update CHANGELOG.md
# 4. Commit changes
git add .
git commit -m "Release v1.0.1"
git tag v1.0.1
git push origin main --tags

# 5. Clean and rebuild
rm -rf build/ dist/
python -m build

# 6. Upload
twine upload dist/*
```

---

## 🐛 Troubleshooting

### Error: "File already exists"

PyPI doesn't allow overwriting files. Must increment version.

```bash
# Can't re-upload 1.0.0, must use:
# 1.0.0.post1  (post-release)
# or 1.0.1     (patch)
```

### Error: "Invalid API Token"

- Check token hasn't expired
- Verify `__token__` username (literal string)
- Ensure token scope includes upload

### Error: "README long_description has syntax errors"

```bash
pip install readme_renderer
twine check dist/*
# Fix README.md issues
```

### Error: "nodejs-bin not found"

This error should no longer occur as of v1.0.1+. The `nodejs-bin` dependency has been removed. Node.js is now downloaded automatically by the installer.

If you still see this error with an older version, upgrade to the latest:
```bash
pipx upgrade openclaw-installer
```

---

## 📦 Alternative: Automated CI/CD

### GitHub Actions Workflow

Create `.github/workflows/publish.yml`:

```yaml
name: Publish to PyPI

on:
  release:
    types: [created]

jobs:
  pypi-publish:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - name: Build
        run: |
          pip install build
          python -m build
      - name: Publish
        uses: pypa/gh-action-pypi-publish@release/v1
```

Then create GitHub release → auto-publishes to PyPI.

---

## ✅ Pre-Publish Final Checklist

- [ ] Version updated in `pyproject.toml`
- [ ] `__version__` matches in `__init__.py`
- [ ] README.md renders correctly
- [ ] All files committed to git
- [ ] TestPyPI upload successful
- [ ] Test install from TestPyPI works
- [ ] `twine check` passes
- [ ] API token configured

---

**Ready to publish! 🚀**
