diff --git a/CHANGELOG.md b/CHANGELOG.md index e442bee..86c0543 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Better support for week numbering. - Better support for optional parts. - New: Start `BUILD` parts at `1000` to avoid leading zero truncation. + - New: Add `INC0` (0-based) and `INC1` (1-based) parts that do auto increment and rollover. - New: `MAJOR`/`MINOR`/`PATCH`/`INC` will roll over when a date part changes to their left. - New gitlab #2: Added `grep` subcommand to find and debug patterns. - New: Added better error messages to debug regular expressions. diff --git a/README.md b/README.md index 14f0383..1904398 100644 --- a/README.md +++ b/README.md @@ -229,14 +229,16 @@ These patterns are closely based on https://calver.org/ | `0D` | 01, 02, 03..31 | `%d` | | `JJJ` | 1,2,3..366 | `int(%j)` | | `00J` | 001, 002..366 | `%j` | -| `BUILD` | 0011, 1001, 1002, .. | build number (lexid) | -| `BLD` | 11, 1001, 1002, .. | zero truncated `BUILD` | | `MAJOR` | 0..9, 10..99, 100.. | `--major` | | `MINOR` | 0..9, 10..99, 100.. | `-m/--minor` | | `PATCH` | 0..9, 10..99, 100.. | `-p/--patch` | -| `NUM` | 0, 1, 2... | `-r/--release-num` | +| `INC0` | 0, 1, 2... | | +| `INC1` | 1, 2... | | +| `BUILD` | 0011, 1001, 1002, .. | build number (lexid) | +| `BLD` | 11, 1001, 1002, .. | zero truncated `BUILD` | | `RELEASE` | alpha, beta, rc | `--release=` | | `PYTAG` | a, b, rc | `--release=` | +| `NUM` | 0, 1, 2... | `-r/--release-num` | ### Week Numbering diff --git a/setup.cfg b/setup.cfg index 8a41aca..37d1964 100644 --- a/setup.cfg +++ b/setup.cfg @@ -126,7 +126,8 @@ README.md = score = no reports = no -jobs = 4 +# pylint spams the same message multiple times if jobs > 1 +jobs = 1 # Set the output format. Available formats are text, parseable, colorized, # msvs (visual studio) and html. You can also give a reporter class, eg @@ -134,7 +135,7 @@ jobs = 4 output-format = colorized # Maximum number of locals for function / method body -max-locals = 21 +max-locals = 25 # Maximum number of arguments for function / method max-args = 12 diff --git a/src/pycalver/v2patterns.py b/src/pycalver/v2patterns.py index 3336dce..3d85c9f 100644 --- a/src/pycalver/v2patterns.py +++ b/src/pycalver/v2patterns.py @@ -86,6 +86,8 @@ PART_PATTERNS = { 'RELEASE': r"preview|final|alpha|beta|post|rc", 'PYTAG' : r"post|rc|a|b", 'NUM' : r"[0-9]+", + 'INC0' : r"[0-9]+", + 'INC1' : r"[1-9][0-9]*", } @@ -111,6 +113,8 @@ PATTERN_PART_FIELDS = { 'RELEASE': 'tag', 'PYTAG' : 'pytag', 'NUM' : 'num', + 'INC0' : 'inc0', + 'INC1' : 'inc1', 'WW' : 'week_w', '0W' : 'week_w', 'UU' : 'week_u', @@ -183,7 +187,10 @@ def _fmt_0v(week_v: FieldValue) -> str: return "{0:02}".format(int(week_v)) -PART_FORMATS: typ.Dict[str, typ.Callable[[FieldValue], str]] = { +FormatterFunc = typ.Callable[[FieldValue], str] + + +PART_FORMATS: typ.Dict[str, FormatterFunc] = { 'YYYY' : _fmt_num, 'YY' : _fmt_yy, '0Y' : _fmt_0y, @@ -205,6 +212,8 @@ PART_FORMATS: typ.Dict[str, typ.Callable[[FieldValue], str]] = { 'RELEASE': _fmt_num, 'PYTAG' : _fmt_num, 'NUM' : _fmt_num, + 'INC0' : _fmt_num, + 'INC1' : _fmt_num, 'WW' : _fmt_num, '0W' : _fmt_0w, 'UU' : _fmt_num, diff --git a/src/pycalver/v2version.py b/src/pycalver/v2version.py index d0773eb..57f966a 100644 --- a/src/pycalver/v2version.py +++ b/src/pycalver/v2version.py @@ -201,6 +201,8 @@ def _parse_version_info(field_values: FieldValues) -> version.V2VersionInfo: patch = int(fvals.get('patch') or 0) num = int(fvals.get('num' ) or 0) bid = fvals['bid'] if 'bid' in fvals else "1000" + inc0 = int(fvals.get('inc0') or 0) + inc1 = int(fvals.get('inc1') or 1) vinfo = version.V2VersionInfo( year_y=year_y, @@ -219,6 +221,8 @@ def _parse_version_info(field_values: FieldValues) -> version.V2VersionInfo: bid=bid, tag=tag, pytag=pytag, + inc0=inc0, + inc1=inc1, ) return vinfo @@ -567,9 +571,9 @@ def _iter_reset_field_items( # Any field to the left of another can reset all to the right has_reset = False for field in fields: - zero_val = version.V2_FIELD_ZERO_VALUES.get(field) - if has_reset and zero_val is not None: - yield field, zero_val + initial_val = version.V2_FIELD_INITIAL_VALUES.get(field) + if has_reset and initial_val is not None: + yield field, initial_val elif getattr(old_vinfo, field) != getattr(cur_vinfo, field): has_reset = True @@ -598,6 +602,16 @@ def _incr_numeric( cur_vinfo = cur_vinfo._replace(bid=lexid.next_id(cur_vinfo.bid)) + if 'inc0' in reset_fields: + cur_vinfo = cur_vinfo._replace(inc0=0) + else: + cur_vinfo = cur_vinfo._replace(inc0=cur_vinfo.inc0 + 1) + + if 'inc1' in reset_fields: + cur_vinfo = cur_vinfo._replace(inc1=1) + else: + cur_vinfo = cur_vinfo._replace(inc1=cur_vinfo.inc1 + 1) + if major and 'major' not in reset_fields: cur_vinfo = cur_vinfo._replace(major=cur_vinfo.major + 1, minor=0, patch=0) if minor and 'minor' not in reset_fields: diff --git a/src/pycalver/version.py b/src/pycalver/version.py index fb42532..afa4a20 100644 --- a/src/pycalver/version.py +++ b/src/pycalver/version.py @@ -73,6 +73,8 @@ class V2VersionInfo(typ.NamedTuple): bid : str tag : str pytag : str + inc0 : int + inc1 : int # The test suite may replace this. @@ -116,18 +118,19 @@ PART_ZERO_VALUES = { 'RELEASE': "final", 'PYTAG' : "", 'NUM' : "0", - 'INC' : "0", + 'INC0' : "0", } -V2_FIELD_ZERO_VALUES = { +V2_FIELD_INITIAL_VALUES = { 'major': "0", 'minor': "0", 'patch': "0", 'tag' : "final", 'pytag': "", 'num' : "0", - 'inc' : "0", + 'inc0' : "0", + 'inc1' : "1", } diff --git a/test/test_cli.py b/test/test_cli.py index a9b15be..5f361db 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -768,23 +768,31 @@ def test_multimatch_file_patterns(runner): assert "[aka. 202010.1003b0 !]" in readme_text -def _kwargs(month, minor): - return {'date': dt.date(2020, month, 1), 'minor': minor} +def _kwargs(year, month, minor=False): + return {'date': dt.date(year, month, 1), 'minor': minor} ROLLOVER_TEST_CASES = [ # v1 cases - ["{year}.{month}.{MINOR}", "2020.10.3", "2020.10.4", _kwargs(10, True)], - ["{year}.{month}.{MINOR}", "2020.10.3", None, _kwargs(10, False)], - ["{year}.{month}.{MINOR}", "2020.10.3", "2020.11.4", _kwargs(11, True)], - ["{year}.{month}.{MINOR}", "2020.10.3", "2020.11.3", _kwargs(11, False)], + ["{year}.{month}.{MINOR}", "2020.10.3", "2020.10.4", _kwargs(2020, 10, True)], + ["{year}.{month}.{MINOR}", "2020.10.3", None, _kwargs(2020, 10, False)], + ["{year}.{month}.{MINOR}", "2020.10.3", "2020.11.4", _kwargs(2020, 11, True)], + ["{year}.{month}.{MINOR}", "2020.10.3", "2020.11.3", _kwargs(2020, 11, False)], # v2 cases - ["YYYY.MM.MINOR" , "2020.10.3", "2020.10.4", _kwargs(10, True)], - ["YYYY.MM.MINOR" , "2020.10.3", None, _kwargs(10, False)], - ["YYYY.MM.MINOR" , "2020.10.3", "2020.11.0", _kwargs(11, True)], - ["YYYY.MM.MINOR" , "2020.10.3", "2020.11.0", _kwargs(11, False)], - ["YYYY.MM[.MINOR]", "2020.10.3", "2020.10.4", _kwargs(10, True)], - ["YYYY.MM[.MINOR]", "2020.10.3", "2020.11", _kwargs(11, False)], + ["YYYY.MM.MINOR" , "2020.10.3", "2020.10.4", _kwargs(2020, 10, True)], + ["YYYY.MM.MINOR" , "2020.10.3", None, _kwargs(2020, 10, False)], + ["YYYY.MM.MINOR" , "2020.10.3", "2020.11.0", _kwargs(2020, 11, True)], + ["YYYY.MM.MINOR" , "2020.10.3", "2020.11.0", _kwargs(2020, 11, False)], + ["YYYY.MM[.MINOR]", "2020.10.3", "2020.10.4", _kwargs(2020, 10, True)], + ["YYYY.MM[.MINOR]", "2020.10.3", "2020.11", _kwargs(2020, 11, False)], + ["YYYY.MM.MINOR" , "2020.10.3", "2021.10.0", _kwargs(2021, 10, False)], + # incr0/incr1 part + ["YYYY.MM.INC0", "2020.10.3", "2020.10.4", _kwargs(2020, 10)], + ["YYYY.MM.INC0", "2020.10.3", "2020.11.0", _kwargs(2020, 11)], + ["YYYY.MM.INC0", "2020.10.3", "2021.10.0", _kwargs(2021, 10)], + ["YYYY.MM.INC1", "2020.10.3", "2020.10.4", _kwargs(2020, 10)], + ["YYYY.MM.INC1", "2020.10.3", "2020.11.1", _kwargs(2020, 11)], + ["YYYY.MM.INC1", "2020.10.3", "2021.10.1", _kwargs(2021, 10)], ]