Metadata-Version: 2.4
Name: hatch-calvar-sample-gitlab
Version: 2026.1.20.7
Summary: Sample project demonstrating CalVer (YYYY.MM.DD.MICRO) with hatch
Project-URL: Documentation, https://gitlab.com/QAToolist/hatch-calvar-sample-gitlab#readme
Project-URL: Issues, https://gitlab.com/QAToolist/hatch-calvar-sample-gitlab/-/issues
Project-URL: Source, https://gitlab.com/QAToolist/hatch-calvar-sample-gitlab
Author-email: QAToolist <qatoolist@gmail.com>
License-Expression: MIT
License-File: LICENSE.txt
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Requires-Python: >=3.8
Provides-Extra: dev
Requires-Dist: bandit[sarif]>=1.7.0; extra == 'dev'
Requires-Dist: black>=24.1.0; extra == 'dev'
Requires-Dist: interrogate>=1.5.0; extra == 'dev'
Requires-Dist: isort>=5.13.0; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pip-audit>=2.6.0; extra == 'dev'
Requires-Dist: pip-licenses>=4.0.0; extra == 'dev'
Requires-Dist: pre-commit>=3.0.0; extra == 'dev'
Requires-Dist: pydocstyle>=6.3.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: radon>=6.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: safety>=2.3.0; extra == 'dev'
Requires-Dist: xenon>=0.9.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: interrogate>=1.5.0; extra == 'docs'
Requires-Dist: pydocstyle>=6.3.0; extra == 'docs'
Provides-Extra: lint
Requires-Dist: bandit>=1.7.0; extra == 'lint'
Requires-Dist: black>=24.1.0; extra == 'lint'
Requires-Dist: isort>=5.13.0; extra == 'lint'
Requires-Dist: mypy>=1.0.0; extra == 'lint'
Requires-Dist: pre-commit>=3.0.0; extra == 'lint'
Requires-Dist: ruff>=0.1.0; extra == 'lint'
Provides-Extra: quality
Requires-Dist: radon>=6.0.0; extra == 'quality'
Requires-Dist: xenon>=0.9.0; extra == 'quality'
Provides-Extra: security
Requires-Dist: bandit[sarif]>=1.7.0; extra == 'security'
Requires-Dist: pip-audit>=2.6.0; extra == 'security'
Requires-Dist: safety>=2.3.0; extra == 'security'
Provides-Extra: test
Requires-Dist: pytest-cov>=4.0.0; extra == 'test'
Requires-Dist: pytest>=7.0.0; extra == 'test'
Description-Content-Type: text/markdown

# hatch-calvar-sample-gitlab

[![PyPI - Version](https://img.shields.io/pypi/v/hatch-calvar-sample-gitlab.svg)](https://pypi.org/project/hatch-calvar-sample-gitlab)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/hatch-calvar-sample-gitlab.svg)](https://pypi.org/project/hatch-calvar-sample-gitlab)

Sample hatch-based Python project demonstrating **Calendar Versioning (CalVer)** with format `YYYY.MM.DD.MICRO` and automated PyPI release workflows.

## Overview

This project serves as a proof-of-concept for implementing CalVer versioning with the hatch build system. It demonstrates:

- **Calendar Versioning (YYYY.MM.DD.MICRO)** calculated from git tags
- **Dynamic versioning** with hatch build system
- **Version checking CLI tool** with multiple commands
- **Automated PyPI release** via GitLab CI/CD
- **Complete release workflow** automation

### Version Format

The project uses CalVer format: `YYYY.MM.DD.MICRO`

- `YYYY` - 4-digit year (e.g., 2024)
- `MM` - 2-digit month (01-12)
- `DD` - 2-digit day (01-31)
- `MICRO` - Sequential number for releases on the same day (1, 2, 3, ...)

Examples: `2024.01.18.1`, `2024.01.18.2`, `2024.03.15.1`

## Installation

```console
pip install hatch-calvar-sample-gitlab
```

## Features

### Version Calculation

The project includes a script that automatically calculates the next CalVer version based on:
- Current UTC date
- Existing git tags matching the CalVer pattern
- Automatic MICRO increment for same-day releases

### CLI Tool

The `calver-check` CLI provides multiple commands for version management:

```bash
# Calculate next version
calver-check calc

# Check current version from different sources
calver-check check

# Validate version format
calver-check validate 2024.01.18.1

# Compare two versions
calver-check compare 2024.01.18.1 2024.01.18.2

# Show version information
calver-check info
```

All commands support `--json` flag for machine-readable output:

```bash
calver-check calc --json
```

## Usage Examples

### Calculating Next Version

```bash
# Using the script directly
python scripts/calc_version.py

# Using the CLI tool
calver-check calc

# With validation
python scripts/calc_version.py --validate --pep440
```

### Checking Current Version

```bash
# Check version from package metadata
calver-check check

# Check with JSON output
calver-check check --json
```

### Validating Version Format

```bash
# Validate a version string
calver-check validate 2024.01.18.1

# Invalid version will exit with error
calver-check validate 2024.1.18.1
```

### Comparing Versions

```bash
# Compare two versions
calver-check compare 2024.01.18.1 2024.01.18.2
# Output: 2024.01.18.1 < 2024.01.18.2
```

## Release Process

### Fully Automated Release Workflow

The project uses GitLab CI/CD for **fully automated** PyPI releases. **No manual tagging required!** The workflow consists of two stages:

#### Stage 1: Auto-tag on Merge

When code is merged to `main` or `master`:

1. Automatically calculates next CalVer version using `scripts/calc_version.py`
2. Creates a git tag with format `vYYYY.MM.DD.MICRO`
3. Pushes the tag to the repository

#### Stage 2: Build and Publish

When a git tag matching `v*` is pushed:

1. Extracts version from tag (strips `v` prefix)
2. Validates CalVer format
3. Builds package with hatch
4. Validates distributions with twine
5. Publishes to PyPI using API token authentication

### Automated Release Steps

1. **Open a merge request** with your changes
2. **Merge the merge request** to `main`/`master`
3. **GitLab CI/CD automatically:**
   - Calculates next CalVer version (e.g., `2024.01.18.1`)
   - Creates tag `v2024.01.18.1`
   - Builds the package
   - Validates version format
   - Publishes to PyPI

No manual tagging required! The release happens automatically when merge requests are merged.

### GitLab CI/CD Configuration

The project includes a comprehensive `.gitlab-ci.yml` with the following jobs:

- **test**: Runs tests across multiple Python versions (3.8-3.12) with coverage reporting
- **build-verify**: Builds and verifies package installation across Python 3.9 and 3.11
- **license-check**: Checks license compliance and generates license reports
- **auto-tag**: Automatically creates release tags when code is merged to main/master
- **release**: Builds and publishes packages to PyPI when tags are pushed

To enable PyPI publishing, configure the `PYPI_API_TOKEN` variable in GitLab CI/CD settings (Settings → CI/CD → Variables).

### Manual Release (Optional)

If you need to manually create a release tag (for hotfixes, etc.):

1. **Calculate next version:**
   ```bash
   calver-check calc
   # Output: 2024.01.18.1
   ```

2. **Create and push git tag:**
   ```bash
   git tag v2024.01.18.1 -m "Release 2024.01.18.1"
   git push origin v2024.01.18.1
   ```

The tag push will trigger the same build and publish workflow.

### Using Makefile

For convenience, use the Makefile targets:

```bash
# Calculate next version
make version-calc

# Check current version
make version-check

# Validate version format
make version-validate VERSION=2024.01.18.1

# Create and push release tag
make release-tag

# Build package for testing
make build-test
```

## Project Structure

```
hatch-calvar-sample-gitlab/
├── pyproject.toml              # Hatch configuration with dynamic versioning
├── README.md                   # This file
├── CHANGELOG.md                # Changelog with CalVer format
├── LICENSE.txt                 # MIT license
├── Makefile                    # Convenient make targets
├── .gitlab-ci.yml              # GitLab CI/CD pipeline configuration
│                               # Includes: test, build-verify, license-check, auto-tag, release
├── scripts/
│   └── calc_version.py         # Version calculation script
├── src/
│   └── hatch_calvar_sample/
│       ├── __init__.py         # Package with __version__
│       ├── __about__.py        # Version metadata
│       ├── VERSION             # Version file (generated during build)
│       └── cli.py              # Version checking CLI implementation
└── tests/
    ├── test_version_calc.py    # Tests for version calculation
    └── test_version_cli.py     # Tests for CLI tool
```

## Configuration

### Dynamic Versioning

The project uses hatch's dynamic versioning feature configured in `pyproject.toml`:

```toml
[tool.hatch.version]
path = "src/hatch_calvar_sample/VERSION"
```

The VERSION file is created during the release workflow with the version extracted from the git tag.

### Version Metadata in Code

The package reads version from `importlib.metadata` when installed, with fallbacks:

1. Package metadata (when installed)
2. VERSION file (for development builds)
3. Environment variable `HATCH_CALVER_VERSION`

Access version programmatically:

```python
from hatch_calvar_sample import __version__

print(__version__)  # Output: 2024.01.18.1
```

## Development

### Setting Up Development Environment

```bash
# Clone the repository
git clone https://gitlab.com/QAToolist/hatch-calvar-sample-gitlab.git
cd hatch-calvar-sample-gitlab

# Install in development mode
pip install -e .

# Install development dependencies
pip install pytest
```

### Running Tests

```bash
# Run all tests
pytest

# Run specific test file
pytest tests/test_version_calc.py

# Run with coverage
pytest --cov=hatch_calvar_sample --cov=scripts
```

### Local Testing

1. **Test version calculation:**
   ```bash
   python scripts/calc_version.py
   ```

2. **Test build process:**
   ```bash
   # Create VERSION file manually
   echo "2024.01.18.1" > src/hatch_calvar_sample/VERSION

   # Build package
   hatch build

   # Check built package
   twine check dist/*
   ```

3. **Test installation:**
   ```bash
   pip install -e .
   python -c "import hatch_calvar_sample; print(hatch_calvar_sample.__version__)"
   ```

## Version Calculation Logic

The version calculation script:

1. Gets current UTC date → `YYYY.MM.DD`
2. Fetches all git tags (`git fetch --tags`)
3. Parses tags matching CalVer pattern (`YYYY.MM.DD.MICRO` or `vYYYY.MM.DD.MICRO`)
4. Filters tags with the same date
5. Extracts MICRO numbers
6. Calculates next MICRO = `max(existing) + 1` or `1` if none exist
7. Returns: `YYYY.MM.DD.MICRO`

### Edge Cases Handled

- No tags → Returns `YYYY.MM.DD.1`
- Multiple tags same date → Increments MICRO correctly
- Date boundary crossing → Resets MICRO to 1 for new date
- Invalid tag formats → Skipped gracefully
- Timezone handling → Uses UTC for consistency

## PEP 440 Compliance

CalVer format `YYYY.MM.DD.MICRO` is PEP 440 compliant as a release segment. The format:

- Uses numeric components
- Follows semantic ordering (newer dates > older dates)
- Valid for PyPI distribution

Validate PEP 440 compliance:

```bash
calver-check validate 2024.01.18.1
python scripts/calc_version.py --pep440
```

## Troubleshooting

### GitLab CI/CD Issues

For common GitLab CI/CD configuration issues, build problems, and PyPI publishing issues, see the comprehensive [GitLab CI/CD Troubleshooting Guide](GITLAB_CI_TROUBLESHOOTING.md).

Common issues covered:
- CI/CD variable configuration (Protected flags, environment scope)
- Build and package directory issues
- Tag creation and auto-tagging problems
- PyPI publishing failures
- Pipeline configuration errors

### Version Not Found

If `__version__` is not available:

1. Ensure package is installed: `pip install -e .`
2. Check VERSION file exists: `ls src/hatch_calvar_sample/VERSION`
3. Verify git tags: `git tag`

### Build Errors

If build fails:

1. Verify VERSION file exists with valid format
2. Check `pyproject.toml` dynamic version configuration
3. Ensure hatch is installed: `pip install hatchling`
4. See [GitLab CI/CD Troubleshooting Guide](GITLAB_CI_TROUBLESHOOTING.md) for package directory issues

### CLI Not Found

If `calver-check` command is not available:

1. Reinstall package: `pip install -e .`
2. Check entry point in `pyproject.toml`
3. Verify PATH includes Python scripts directory

## Contributing

This is a sample project for demonstration purposes. If you find it useful or want to adapt it for your project:

1. Review the implementation details in scripts and source code
2. Check the GitLab CI/CD pipeline (`.gitlab-ci.yml`) for CI/CD patterns
3. Adapt the configuration for your project structure

## License

`hatch-calvar-sample-gitlab` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.

## References

- [Hatch Documentation](https://hatch.pypa.io/)
- [Calendar Versioning (CalVer)](https://calver.org/)
- [PEP 440 - Version Identification](https://peps.python.org/pep-0440/)
- [GitLab CI/CD Documentation](https://docs.gitlab.com/ee/ci/)


## Demo Change
