-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit dfcd910
Showing
11 changed files
with
478 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: | ||
- master | ||
pull_request: | ||
|
||
jobs: | ||
Test: | ||
runs-on: "${{ matrix.os }}" | ||
strategy: | ||
matrix: | ||
os: | ||
- ubuntu-latest | ||
python-version: | ||
- "3.9" | ||
- "3.x" | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: "Set up Python ${{ matrix.python-version }}" | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: "${{ matrix.python-version }}" | ||
cache: pip | ||
- run: "pip install -e .[dev]" | ||
- run: py.test -vvv --cov . | ||
|
||
Lint: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: pre-commit/action@v3.0.1 | ||
|
||
Build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- run: pip install -U build | ||
- run: python -m build . | ||
- name: Upload artifact | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: dist | ||
path: dist | ||
|
||
Publish: | ||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') | ||
needs: | ||
- Build | ||
name: Upload release to PyPI | ||
runs-on: ubuntu-latest | ||
environment: | ||
name: release | ||
url: https://pypi.org/p/hatch-calver/ | ||
permissions: | ||
id-token: write | ||
steps: | ||
- uses: actions/download-artifact@v4 | ||
with: | ||
name: dist | ||
path: dist/ | ||
- name: Publish package distributions to PyPI | ||
uses: pypa/gh-action-pypi-publish@release/v1 | ||
with: | ||
verbose: true | ||
print-hash: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
*.py[cod] | ||
.coverage | ||
/htmlcov | ||
build | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
repos: | ||
- repo: https://github.com/astral-sh/ruff-pre-commit | ||
rev: v0.6.5 | ||
hooks: | ||
- id: ruff | ||
args: | ||
- --fix | ||
- id: ruff-format | ||
|
||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
rev: v4.6.0 | ||
hooks: | ||
- id: debug-statements | ||
- id: end-of-file-fixer | ||
- id: trailing-whitespace | ||
exclude: .*ambr | ||
|
||
- repo: https://github.com/pre-commit/mirrors-prettier | ||
rev: v3.1.0 | ||
hooks: | ||
- id: prettier |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2024 Aarni Koskela <akx@iki.fi> | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# hatch-calver | ||
|
||
A plugin for [hatch][hatch] to support [calendar versioning][calver]. | ||
|
||
## Setup | ||
|
||
Add `hatch-calver` as a build dependency to your project. | ||
|
||
```toml | ||
[build-system] | ||
requires = [ | ||
"hatchling", | ||
"hatch-calver", | ||
] | ||
build-backend = "hatchling.build" | ||
``` | ||
|
||
Then, set `tool.hatch.version.scheme` to `"calver"`. | ||
|
||
```toml | ||
[tool.hatch.version] | ||
scheme = "calver" | ||
``` | ||
|
||
### Configuring the CalVer scheme | ||
|
||
You can optionally set `calver-scheme` to a dot-separated string | ||
of parts specified in the [calver scheme][calver_scheme] specification. | ||
It defaults to `YYYY.MM.DD`. | ||
|
||
```toml | ||
[tool.hatch.version] | ||
scheme = "calver" | ||
calver-scheme = "YY.MM" | ||
``` | ||
|
||
Note that your project's versions should conform to the scheme you specify; | ||
otherwise, determining where to put e.g. patch versions will be quite ambiguous. | ||
|
||
## Usage | ||
|
||
You can use Hatch's [standard versioning][hatch_version_updating] commands. | ||
|
||
To update your project's version to the current date, run `hatch version release` | ||
(or `hatch version date`). | ||
|
||
As with the regular versioning scheme, you can chain multiple segment updates. | ||
The date part of the version will _not_ be updated unless you explicitly specify it. | ||
|
||
The CalVer scheme specified for your project specifies which segment of the | ||
PEP 440 "release" segments are automatically determined; for instance, for a `YYYY.MM.DD` | ||
scheme, the 4th field of the release segment will be considered the `patch` field. | ||
|
||
In other words, if you specify `YYYY.MM.DD` as your scheme, and it's the 16th of September 2024: | ||
|
||
| Original version | Command | New version | | ||
| ---------------- | ----------------------- | --------------- | | ||
| `2024.07.22` | `hatch version release` | `2024.09.16` | | ||
| `2024.07.22` | `hatch version date,a` | `2024.09.16a0` | | ||
| `2021.01.01` | `hatch version rc` | `2021.01.01rc0` | | ||
| `2024.7.22` | `hatch version patch` | `2024.07.22.1` | | ||
|
||
[hatch]: https://hatch.pypa.io/ | ||
[hatch_version_updating]: https://hatch.pypa.io/latest/version/#updating | ||
[hatch_version_segments]: https://hatch.pypa.io/latest/version/#supported-segments | ||
[calver]: https://calver.org/ | ||
[calver_scheme]: https://calver.org/#scheme |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
[build-system] | ||
requires = ["hatchling"] | ||
build-backend = "hatchling.build" | ||
|
||
[project] | ||
name = "hatch-calver" | ||
description = "Hatch plugin for CalVer versioning" | ||
readme = "README.md" | ||
license = "MIT" | ||
requires-python = ">=3.9" | ||
dependencies = ["hatchling"] | ||
dynamic = ["version"] | ||
|
||
authors = [ | ||
{ name = "Aarni Koskela", email = "akx@iki.fi" }, | ||
] | ||
|
||
classifiers = [ | ||
"Development Status :: 4 - Beta", | ||
"Framework :: Hatch", | ||
"Intended Audience :: Developers", | ||
"License :: OSI Approved :: MIT License", | ||
"Natural Language :: English", | ||
"Operating System :: MacOS :: MacOS X", | ||
"Operating System :: Microsoft :: Windows", | ||
"Operating System :: OS Independent", | ||
"Operating System :: POSIX :: Linux", | ||
"Programming Language :: Python :: 3.9", | ||
"Topic :: Software Development", | ||
] | ||
|
||
[project.urls] | ||
Repository = "https://github.com/akx/hatch-calver" | ||
Issues = "https://github.com/akx/hatch-calver/issues" | ||
PyPI = "https://pypi.org/project/hatch-calver/" | ||
|
||
[project.entry-points.hatch] | ||
calver = "hatch_calver.hatch_hooks" | ||
|
||
[project.optional-dependencies] | ||
dev = ["pytest", "pytest-cov"] | ||
|
||
[tool.hatch.version] | ||
path = "src/hatch_calver/__init__.py" | ||
scheme = "calver" | ||
calver-scheme = "YYYY.MM.DD" | ||
|
||
[tool.coverage.report] | ||
exclude_lines = [ | ||
"if __name__ == .__main__.:", | ||
"if TYPE_CHECKING:", | ||
] | ||
|
||
[tool.ruff] | ||
line-length = 110 | ||
|
||
[tool.ruff.lint] | ||
select = [ | ||
"B", | ||
"COM812", | ||
"D", | ||
"E", | ||
"EM", | ||
"F", | ||
"I", | ||
"PT", | ||
"S", | ||
"W", | ||
] | ||
ignore = [ | ||
"D100", | ||
"D101", | ||
"D104", | ||
"D211", | ||
"D213", | ||
"E501", | ||
"TRY003", | ||
] | ||
[tool.ruff.lint.extend-per-file-ignores] | ||
"tests/*" = [ | ||
"D", | ||
"ANN", | ||
"S101", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
__version__ = "2024.9.16rc0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
# Parts of this code has been adapted from the Hatchling project's | ||
# `hatchling.version.scheme.standard` module, which is licensed under | ||
# the MIT License (Copyright (c) 2017-present Ofek Lev <oss@ofek.dev>). | ||
|
||
from __future__ import annotations | ||
|
||
import datetime | ||
from typing import TYPE_CHECKING, Any | ||
|
||
if TYPE_CHECKING: | ||
from packaging.version import Version | ||
|
||
SCHEME_PART_TO_FORMATTER = { | ||
# See https://calver.org/#scheme | ||
"YYYY": lambda d: d.year, | ||
"YY": lambda d: d.year - 2000, | ||
"0Y": lambda d: f"{d.year % 100:02}", | ||
"MM": lambda d: d.month, | ||
"0M": lambda d: f"{d.month:02}", | ||
"WW": lambda d: d.isocalendar()[1], | ||
"0W": lambda d: f"{d.isocalendar()[1]:02}", | ||
"DD": lambda d: d.day, | ||
"0D": lambda d: f"{d.day:02}", | ||
} | ||
|
||
SCHEME_PART_MIN_LENGTHS = { | ||
"YYYY": 4, | ||
"YY": 2, | ||
"0D": 2, | ||
"0M": 2, | ||
"0W": 2, | ||
"0Y": 2, | ||
} | ||
|
||
|
||
def _map_scheme_part(part: str, dt: datetime.datetime) -> str: | ||
formatter = SCHEME_PART_TO_FORMATTER.get(part) | ||
if formatter is None: | ||
err = f"Unknown calver-scheme part: {part} (expected one of {', '.join(SCHEME_PART_TO_FORMATTER)})" | ||
raise ValueError(err) | ||
|
||
return str(formatter(dt)) | ||
|
||
|
||
def _update_version(version: Version, **kwargs: Any) -> None: | ||
parts = {} | ||
for part_name in ("epoch", "release", "pre", "post", "dev", "local"): | ||
if part_name in kwargs: | ||
parts[part_name] = kwargs[part_name] | ||
elif parts: # We've set a part, so clear out the following ones | ||
parts[part_name] = None | ||
|
||
version._version = version._version._replace(**parts) | ||
|
||
|
||
def bump_calver( | ||
original_version: str, | ||
desired_version: str, | ||
*, | ||
calver_scheme_string: str = "YYYY.MM.DD", | ||
version_date: datetime.datetime | None = None, | ||
) -> str: | ||
"""Bumps a CalVer version according to the given instructions.""" | ||
from packaging.version import Version | ||
from packaging.version import _parse_letter_version as parse_letter_version | ||
|
||
if not version_date: | ||
version_date = datetime.datetime.now(tz=datetime.timezone.utc) | ||
|
||
scheme_parts = str(calver_scheme_string).split(".") | ||
v = Version(original_version) | ||
instructions = desired_version.split(",") | ||
for inst in instructions: | ||
if inst in {"date", "release"}: | ||
# Update the prefix of the current `release`, | ||
# but keep the remaining (non-specified) parts as-is. | ||
release = ( | ||
*(_map_scheme_part(part, version_date) for part in scheme_parts), | ||
*v.release[len(scheme_parts) :], | ||
) | ||
v._version = v._version._replace(release=release) | ||
_update_version(v, release=release) | ||
elif inst in {"micro", "patch", "fix"}: | ||
# We'll assume the first part after any part specified by the calver scheme is the micro/patch/fix part. | ||
old_micro = v.release[len(scheme_parts)] if len(v.release) > len(scheme_parts) else 0 | ||
new_release = (*v.release[: len(scheme_parts)], old_micro + 1) | ||
_update_version(v, release=new_release) | ||
elif inst in {"a", "b", "c", "rc", "alpha", "beta", "pre", "preview"}: | ||
phase, number = parse_letter_version(inst, 0) | ||
if v.pre: | ||
current_phase, current_number = parse_letter_version(*v.pre) | ||
if phase == current_phase: | ||
number = current_number + 1 | ||
|
||
_update_version(v, pre=(phase, number)) | ||
elif inst in {"post", "rev", "r"}: | ||
number = 0 if v.post is None else v.post + 1 | ||
_update_version(v, post=parse_letter_version(inst, number)) | ||
elif inst == "dev": | ||
number = 0 if v.dev is None else v.dev + 1 | ||
_update_version(v, dev=(inst, number)) | ||
else: | ||
if len(instructions) > 1: | ||
msg = "Cannot specify multiple update operations with an explicit version" | ||
raise ValueError(msg) | ||
return str(inst) | ||
# Small hack – `packaging.Version` strips leading zeroes from the release part, so | ||
# check if we need to pad any of them. This technically breaks the type annotations of | ||
# `packaging._Version`, but `Version.__str__()` doesn't mind... | ||
v._version = v._version._replace( | ||
release=( | ||
tuple( | ||
str(val).zfill(SCHEME_PART_MIN_LENGTHS.get(scheme_parts[i], 1)) | ||
if i < len(scheme_parts) | ||
else val | ||
for (i, val) in enumerate(v._version.release) | ||
) | ||
), | ||
) | ||
return str(v) |
Oops, something went wrong.