# Releasing a new version

Releases are published to PyPI automatically when a GitHub Release is created.
The workflow is defined in [`.github/workflows/publish.yml`](../.github/workflows/publish.yml).

---

## Steps

### 1. Bump the version

Update the version in **both** files — they must match:

- [`pyproject.toml`](../pyproject.toml) → `version = "X.Y.Z"`
- [`src/semantic_model/__init__.py`](../src/semantic_model/__init__.py) → `__version__ = "X.Y.Z"`

#### Versioning policy

| Change type                               | Bump            |
| ----------------------------------------- | --------------- |
| Breaking change (removed/renamed exports) | Minor — `0.Y.0` |
| New feature, backwards-compatible         | Patch — `0.Y.Z` |
| Bug fix                                   | Patch — `0.Y.Z` |

### 2. Commit the version bump

```bash
git add pyproject.toml src/semantic_model/__init__.py
git commit -m "chore: bump version to X.Y.Z"
git push
```

### 3. Merge to main

The release tag must point to a commit on `main`. Either merge your branch via a PR
or push directly if you have access.

### 4. Verify the version is on main

Before creating the release, confirm the version bump commit is on `main`:

```bash
git log main --oneline -3
```

The top commit must contain the version bump. **If the release tag points to an old
commit, the build will package the old version number and PyPI will reject it.**

### 5. Create the GitHub Release

```bash
gh release create vX.Y.Z \
  --title "vX.Y.Z" \
  --notes "Short description of what changed"
```

This single command:

- Creates and pushes the `vX.Y.Z` tag
- Publishes a GitHub Release
- Triggers the publish workflow → PyPI

> **Note:** `gh release create` must be run from the `main` branch, or point at the
> correct commit with `--target <sha>` if run from another branch.

### 6. Verify

- Check the Actions tab on GitHub — the `Publish to PyPI` workflow should be running.
- Once complete, confirm the new version is live: [pypi.org/project/nomox-semantic-model](https://pypi.org/project/nomox-semantic-model/)

---

## Fixing a bad release

### Release tag pointed to wrong commit (version mismatch)

Symptom: PyPI rejects the upload with `File already exists` for an older version number.
This happens when the release tag was created before the version bump was committed.

```bash
# 1. Delete the release and tag
gh release delete vX.Y.Z --yes
git push origin --delete vX.Y.Z
git tag -d vX.Y.Z

# 2. Commit the version bump if not already done
git add pyproject.toml src/semantic_model/__init__.py
git commit -m "chore: bump version to X.Y.Z"
git push

# 3. Recreate the release from the correct commit
gh release create vX.Y.Z --title "vX.Y.Z" --notes "..."
```

### PyPI already has this version (failed build that partially uploaded)

PyPI does not allow re-uploading the same version number even if the upload failed.
You must bump to the next patch version and start over.

```bash
# Bump version to X.Y.(Z+1) in pyproject.toml and __init__.py, then:
git add pyproject.toml src/semantic_model/__init__.py
git commit -m "chore: bump version to X.Y.(Z+1)"
git push
gh release create vX.Y.(Z+1) --title "vX.Y.(Z+1)" --notes "..."
```
