# Publishing `sales-model` via GitHub Actions (recommended)

This repo includes a workflow at `.github/workflows/pypi-publish.yml` that builds the package in `model/` and publishes using **Trusted Publishing** (OIDC).

## 1) Decide your release trigger

- **TestPyPI**: push a tag like `model-v0.1.0` (or `v0.1.0`). Tag pushes publish to TestPyPI by default.
- **PyPI**: run the workflow manually (workflow_dispatch) and choose `pypi`

## 2) Enable Trusted Publishing

You must configure this once on each index you want to publish to:

### TestPyPI
1. Go to https://test.pypi.org/ and create your account.
2. Create the project (or let the first publish create it, depending on index settings).
3. In the project settings, add a **Trusted Publisher**:
   - Owner: your GitHub org/user
   - Repository: this repo name
   - Workflow: `pypi-publish.yml`
   - Environment: `testpypi`

### PyPI
1. Go to https://pypi.org/ and create your account.
2. Create the project (first publish typically requires ownership).
3. Add a **Trusted Publisher** with:
   - Workflow: `pypi-publish.yml`
   - Environment: `pypi`

Notes:
- Trusted publishing avoids storing `PYPI_API_TOKEN` secrets in GitHub.
- The workflow uses Python 3.12 on CI even if you develop locally on newer versions.

## 3) Releasing

### Publish to TestPyPI via tag

1. Bump `version` in `model/pyproject.toml`.
2. Create and push a tag:
   - `git tag model-v0.1.1` (or `git tag v0.1.1`)
   - `git push --tags`

### Publish to TestPyPI locally (no GitHub Actions)

If GitHub Actions is unavailable (billing, policy, or offline builds), you can publish from your dev machine using an API token.

1. Bump `version` in `model/pyproject.toml` (TestPyPI rejects re-uploading the same version).
2. Build:

```bash
cd model
python -m pip install -U build twine
python -m build
python -m twine check dist/*
```

3. Upload to **TestPyPI** (token-based auth):

```bash
cd model
python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
```

Twine will prompt for credentials:
- Username: `__token__`
- Password: your TestPyPI API token (starts with `pypi-...`)

4. Install from TestPyPI to verify:

```bash
python -m pip install -U pip
python -m pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple sales-model==<version>
```

### Publish to PyPI via manual dispatch

1. Go to GitHub → Actions → "Publish Python package".
2. Click "Run workflow" and choose `pypi`.

### Publish to PyPI locally (no GitHub Actions)

Same steps as TestPyPI, but upload to the default PyPI repository:

```bash
cd model
python -m pip install -U build twine
python -m build
python -m twine check dist/*
python -m twine upload dist/*
```

## Troubleshooting

- If you see `403 Forbidden`, it’s usually one of:
  - trusted publisher not configured (or wrong workflow/environment name)
  - you don’t own the project name on that index
  - you’re publishing a version that already exists
