# Dynamic Versioning with setuptools-scm

This project uses **setuptools-scm** for automatic version management based on git tags.

## 🚀 Quick Start

### Check Current Version
```bash
# From git (most accurate)
python -m setuptools_scm

# From installed package
python -c "import rir_generator; print(rir_generator.__version__)"
```

### Create a Release
```bash
# 1. Tag the version (version is automatic from this tag!)
git tag v0.3.0

# 2. Push the tag
git push origin v0.3.0

# That's it! No version file edits needed!
```

## How It Works

Instead of manually updating version numbers in `pyproject.toml`, the version is **automatically determined from git tags**.

### Version Determination

setuptools-scm determines the version based on:
1. **Latest git tag** (e.g., `v0.3.0`)
2. **Commits since tag** (for development versions)
3. **Git repository state** (clean vs. dirty)

### Version Scheme

We use the `post-release` scheme:

| Git State | Example Version | Description |
|-----------|----------------|-------------|
| On tag `v0.3.0` | `0.3.0` | Clean release |
| 5 commits after `v0.3.0` | `0.3.0.post5` | Post-release development |
| No tags | `0.0.0.dev0` | Initial development |

## Creating Releases

### 1. Tag a Release

```bash
# Tag the current commit
git tag v0.3.0

# Push the tag to GitHub
git push origin v0.3.0
```

**Version format:** Always use `vX.Y.Z` format (with the `v` prefix).

### 2. Automatic Version

Once tagged, setuptools-scm will automatically use that version:
- Building: `python -m build` → creates `rir_generator-0.3.0.tar.gz`
- Installing: `pip install .` → version is `0.3.0`
- In Python: `rir_generator.__version__` → returns `"0.3.0"`

### 3. Between Releases

After tagging `v0.3.0`, if you make 3 more commits, the version becomes:
- `0.3.0.post3` (indicating 3 commits after version 0.3.0)

## Semantic Versioning

Follow [Semantic Versioning](https://semver.org/):

- **Major (X.0.0)**: Breaking changes, incompatible API changes
- **Minor (0.X.0)**: New features, backwards compatible
- **Patch (0.0.X)**: Bug fixes, backwards compatible

### Examples

```bash
# Bug fix release
git tag v0.3.1

# New feature release
git tag v0.4.0

# Breaking change release
git tag v1.0.0

# Pre-release versions
git tag v0.4.0-rc1
git tag v0.4.0-beta1
git tag v0.4.0-alpha1
```

## Checking Version

### In Python

```python
import rir_generator
print(rir_generator.__version__)
```

### From Command Line

```bash
# After installation
python -c "import rir_generator; print(rir_generator.__version__)"

# During development
python -m setuptools_scm
```

### In Git Repository

```bash
# Show current version based on git state
python -m setuptools_scm

# Show all tags
git tag -l
```

## Version File

setuptools-scm automatically generates `src/rir_generator/_version.py`:

```python
# This file is auto-generated by setuptools-scm
__version__ = "0.3.0"
__version_tuple__ = (0, 3, 0)
```

**Important:** This file is:
- ✅ Auto-generated on build/install
- ✅ Added to `.gitignore`
- ❌ Never committed to git

## Development Installation

When installing in development mode:

```bash
pip install -e .
```

setuptools-scm will:
1. Read git tags and commits
2. Generate `_version.py`
3. Make version available in Python

## Troubleshooting

### "No version found" Error

**Problem:** setuptools-scm can't find git tags

**Solutions:**

1. **Create an initial tag:**
   ```bash
   git tag v0.1.0
   ```

2. **Ensure you're in a git repository:**
   ```bash
   git status  # Should work
   ```

3. **Check for tags:**
   ```bash
   git tag -l  # Should show at least one tag
   ```

### Version Shows as "0.0.0.dev0"

**Problem:** No git tags exist

**Solution:**
```bash
# Create your first version tag
git tag v0.3.0
git push origin v0.3.0
```

### Building Outside Git Repository

**Problem:** Building from tarball without git

**Solution:** The fallback version `0.0.0.dev0` is used. This is expected behavior for source distributions.

### Shallow Clone Issues (CI/CD)

**Problem:** Error like `"path" is shallow and may cause errors` or invalid version `0.0.0.dev0.post1`

**Solution:** Ensure full git history is fetched in CI:
```yaml
- uses: actions/checkout@v4
  with:
    fetch-depth: 0  # Fetch all history for setuptools-scm
```

This is already configured in the project's GitHub Actions workflows.

### Version Doesn't Update

**Problem:** Version seems stale after creating new tag

**Solutions:**

1. **Reinstall the package:**
   ```bash
   pip install -e . --force-reinstall --no-deps
   ```

2. **Clear build artifacts:**
   ```bash
   rm -rf build/ dist/ *.egg-info src/*.egg-info
   pip install -e .
   ```

3. **Regenerate version file:**
   ```bash
   rm -f src/rir_generator/_version.py
   pip install -e .
   ```

## Configuration

The setuptools-scm configuration is in `pyproject.toml`:

```toml
[tool.setuptools_scm]
version_scheme = "post-release"
local_scheme = "no-local-version"
write_to = "src/rir_generator/_version.py"
fallback_version = "0.0.0.dev0"
```

### Options Explained

- **`version_scheme = "post-release"`**
  - Versions after a tag are marked as `X.Y.Z.postN`
  - Alternative: `"guess-next-dev"` would create `X.Y.(Z+1).devN`

- **`local_scheme = "no-local-version"`**
  - Don't add local version identifiers (like git commit hash)
  - Cleaner versions for PyPI uploads

- **`write_to = "src/rir_generator/_version.py"`**
  - Generate a Python file with version information
  - Allows version access without setuptools-scm at runtime

- **`fallback_version = "0.0.0.dev0"`**
  - Version to use when git is not available
  - Useful for building from source archives

## Best Practices

### ✅ DO
- Use `v` prefix for tags: `v0.3.0` ✓
- Follow semantic versioning: `MAJOR.MINOR.PATCH`
- Push tags to GitHub: `git push origin v0.3.0`
- Let setuptools-scm handle the version
- Check version before release: `python -m setuptools_scm`

### ❌ DON'T
- Don't manually edit version in code or pyproject.toml
- Don't commit `_version.py` to git (it's auto-generated)
- Don't use tags without `v` prefix
- Don't create duplicate tags
- Don't delete tags after pushing (breaks history)

## Complete Example: Making a Release

```bash
# 1. Make your changes
git commit -am "Implement feature X"
git commit -am "Fix bug Y"
git commit -am "Update docs"

# 2. Check everything works
pytest
python -m build

# 3. Tag the release (version comes from this!)
git tag v0.3.0

# 4. Push everything
git push origin master
git push origin v0.3.0

# 5. Create GitHub Release (or GitHub Actions handles it)
# - Go to releases page
# - Select tag v0.3.0
# - Add release notes
# - Publish

# Done! GitHub Actions publishes to PyPI automatically
```

## Integration with CI/CD

The release workflow automatically handles versioning:

1. You create a release with tag `v0.3.0`
2. GitHub Actions checks out the code
3. setuptools-scm reads the tag
4. Build uses version `0.3.0`
5. Package is published to PyPI with correct version

**No manual version updates needed!**

## References

- [setuptools-scm Documentation](https://setuptools-scm.readthedocs.io/)
- [Semantic Versioning](https://semver.org/)
- [PEP 440 - Version Identification](https://peps.python.org/pep-0440/)
- [Git Tagging Guide](https://git-scm.com/book/en/v2/Git-Basics-Tagging)

