diff --git a/CHANGELOG.md b/CHANGELOG.md index 34638d4..ba3fa59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Unreleased * Fixed: The `--ignore-untracked` CLI flag was ignored. +* Added: `--commit-length` option. ## v1.21.2 (2024-06-26) diff --git a/dunamai/__init__.py b/dunamai/__init__.py index 07a3296..804f7ef 100644 --- a/dunamai/__init__.py +++ b/dunamai/__init__.py @@ -986,6 +986,7 @@ def from_git( path: Optional[Path] = None, pattern_prefix: Optional[str] = None, ignore_untracked: bool = False, + commit_length: Optional[int] = None, ) -> "Version": r""" Determine a version based on Git tags. @@ -1004,9 +1005,12 @@ def from_git( :param pattern_prefix: Insert this after the pattern's start anchor (`^`). :param ignore_untracked: Ignore untracked files when determining whether the repository is dirty. + :param commit_length: + Use this many characters from the start of the full commit hash. :returns: Detected version. """ vcs = Vcs.Git + full_commit = full_commit or commit_length is not None archival = _find_higher_file(".git_archival.json", path, ".git") if archival is not None: @@ -1019,6 +1023,9 @@ def from_git( else: commit = data.get("hash-short") + if commit is not None: + commit = commit[:commit_length] + timestamp = None raw_timestamp = data.get("timestamp") if raw_timestamp: @@ -1118,7 +1125,7 @@ def from_git( ) if code == 128: return cls._fallback(strict, distance=0, dirty=True, branch=branch, concerns=concerns, vcs=vcs) - commit = msg + commit = msg[:commit_length] timestamp = None if git_version < [2, 2]: @@ -1243,6 +1250,7 @@ def from_mercurial( strict: bool = False, path: Optional[Path] = None, pattern_prefix: Optional[str] = None, + commit_length: Optional[int] = None, ) -> "Version": r""" Determine a version based on Mercurial tags. @@ -1257,9 +1265,12 @@ def from_mercurial( When there are no tags, fail instead of falling back to 0.0.0. :param path: Directory to inspect, if not the current working directory. :param pattern_prefix: Insert this after the pattern's start anchor (`^`). + :param commit_length: + Use this many characters from the start of the full commit hash. :returns: Detected version. """ vcs = Vcs.Mercurial + full_commit = full_commit or commit_length is not None archival = _find_higher_file(".hg_archival.txt", path, ".hg") if archival is not None: @@ -1275,6 +1286,8 @@ def from_mercurial( # The distance is 1 on a new repo or on a tagged commit. distance = int(data.get("latesttagdistance", 1)) - 1 commit = data.get("node") + if commit is not None: + commit = commit[:commit_length] branch = data.get("branch") if tag is None or tag == "null": @@ -1326,7 +1339,7 @@ def from_mercurial( branch = msg code, msg = _run_cmd('hg id --template "{}"'.format("{id}" if full_commit else "{id|short}"), path) - commit = msg if set(msg) != {"0"} else None + commit = msg[:commit_length] if set(msg) != {"0"} else None code, msg = _run_cmd('hg log --limit 1 --template "{date|rfc3339date}"', path) timestamp = _parse_git_timestamp_iso_strict(msg) if msg != "" else None @@ -1395,6 +1408,7 @@ def from_darcs( strict: bool = False, path: Optional[Path] = None, pattern_prefix: Optional[str] = None, + commit_length: Optional[int] = None, ) -> "Version": r""" Determine a version based on Darcs tags. @@ -1408,6 +1422,8 @@ def from_darcs( When there are no tags, fail instead of falling back to 0.0.0. :param path: Directory to inspect, if not the current working directory. :param pattern_prefix: Insert this after the pattern's start anchor (`^`). + :param commit_length: + Use this many characters from the start of the full commit hash. :returns: Detected version. """ vcs = Vcs.Darcs @@ -1423,6 +1439,8 @@ def from_darcs( timestamp = None else: commit = root[0].attrib["hash"] + if commit is not None: + commit = commit[:commit_length] timestamp = dt.datetime.strptime(root[0].attrib["date"] + "+0000", "%Y%m%d%H%M%S%z") code, msg = _run_cmd("darcs show tags", path) @@ -1475,6 +1493,7 @@ def from_subversion( strict: bool = False, path: Optional[Path] = None, pattern_prefix: Optional[str] = None, + commit_length: Optional[int] = None, ) -> "Version": r""" Determine a version based on Subversion tags. @@ -1489,6 +1508,8 @@ def from_subversion( When there are no tags, fail instead of falling back to 0.0.0. :param path: Directory to inspect, if not the current working directory. :param pattern_prefix: Insert this after the pattern's start anchor (`^`). + :param commit_length: + Use this many characters from the start of the full commit hash. :returns: Detected version. """ vcs = Vcs.Subversion @@ -1506,7 +1527,7 @@ def from_subversion( if not msg or msg == "0": commit = None else: - commit = msg + commit = msg[:commit_length] timestamp = None if commit: @@ -1573,6 +1594,7 @@ def from_bazaar( strict: bool = False, path: Optional[Path] = None, pattern_prefix: Optional[str] = None, + commit_length: Optional[int] = None, ) -> "Version": r""" Determine a version based on Bazaar tags. @@ -1586,6 +1608,8 @@ def from_bazaar( When there are no tags, fail instead of falling back to 0.0.0. :param path: Directory to inspect, if not the current working directory. :param pattern_prefix: Insert this after the pattern's start anchor (`^`). + :param commit_length: + Use this many characters from the start of the full commit hash. :returns: Detected version. """ vcs = Vcs.Bazaar @@ -1601,7 +1625,7 @@ def from_bazaar( for line in msg.splitlines(): info = line.split("revno: ", maxsplit=1) if len(info) == 2: - commit = info[1] + commit = info[1][:commit_length] info = line.split("branch nick: ", maxsplit=1) if len(info) == 2: @@ -1668,6 +1692,7 @@ def from_fossil( strict: bool = False, path: Optional[Path] = None, pattern_prefix: Optional[str] = None, + commit_length: Optional[int] = None, ) -> "Version": r""" Determine a version based on Fossil tags. @@ -1680,6 +1705,8 @@ def from_fossil( When there are no tags, fail instead of falling back to 0.0.0. :param path: Directory to inspect, if not the current working directory. :param pattern_prefix: Insert this after the pattern's start anchor (`^`). + :param commit_length: + Use this many characters from the start of the full commit hash. :returns: Detected version. """ vcs = Vcs.Fossil @@ -1692,7 +1719,7 @@ def from_fossil( branch = msg code, msg = _run_cmd("fossil sql \"SELECT value FROM vvar WHERE name = 'checkout-hash' LIMIT 1\"", path) - commit = msg.strip("'") + commit = msg.strip("'")[:commit_length] code, msg = _run_cmd( 'fossil sql "' @@ -1802,6 +1829,7 @@ def from_pijul( strict: bool = False, path: Optional[Path] = None, pattern_prefix: Optional[str] = None, + commit_length: Optional[int] = None, ) -> "Version": r""" Determine a version based on Pijul tags. @@ -1815,6 +1843,8 @@ def from_pijul( When there are no tags, fail instead of falling back to 0.0.0. :param path: Directory to inspect, if not the current working directory. :param pattern_prefix: Insert this after the pattern's start anchor (`^`). + :param commit_length: + Use this many characters from the start of the full commit hash. :returns: Detected version. """ vcs = Vcs.Pijul @@ -1835,7 +1865,7 @@ def from_pijul( if len(limited_commits) == 0: return cls._fallback(strict, dirty=dirty, branch=branch, vcs=vcs) - commit = limited_commits[0]["hash"] + commit = limited_commits[0]["hash"][:commit_length] timestamp = _parse_timestamp(limited_commits[0]["timestamp"]) code, msg = _run_cmd("pijul log --output-format json", path) @@ -1951,6 +1981,7 @@ def from_any_vcs( path: Optional[Path] = None, pattern_prefix: Optional[str] = None, ignore_untracked: bool = False, + commit_length: Optional[int] = None, ) -> "Version": r""" Determine a version based on a detected version control system. @@ -1983,6 +2014,8 @@ def from_any_vcs( :param ignore_untracked: Ignore untracked files when determining whether the repository is dirty. This is only used for Git currently. + :param commit_length: + Use this many characters from the start of the full commit hash. :returns: Detected version. """ vcs = _detect_vcs_from_archival(path) @@ -1999,6 +2032,7 @@ def from_any_vcs( path, pattern_prefix, ignore_untracked, + commit_length, ) @classmethod @@ -2014,6 +2048,7 @@ def from_vcs( path: Optional[Path] = None, pattern_prefix: Optional[str] = None, ignore_untracked: bool = False, + commit_length: Optional[int] = None, ) -> "Version": r""" Determine a version based on a specific VCS setting. @@ -2040,6 +2075,8 @@ def from_vcs( :param ignore_untracked: Ignore untracked files when determining whether the repository is dirty. This is only used for Git currently. + :param commit_length: + Use this many characters from the start of the full commit hash. :returns: Detected version. """ return cls._do_vcs_callback( @@ -2053,6 +2090,7 @@ def from_vcs( path, pattern_prefix, ignore_untracked, + commit_length, ) @classmethod @@ -2068,6 +2106,7 @@ def _do_vcs_callback( path: Optional[Path], pattern_prefix: Optional[str] = None, ignore_untracked: bool = False, + commit_length: Optional[int] = None, ) -> "Version": mapping = { Vcs.Any: cls.from_any_vcs, @@ -2091,6 +2130,7 @@ def _do_vcs_callback( ("path", path), ("pattern_prefix", pattern_prefix), ("ignore_untracked", ignore_untracked), + ("commit_length", commit_length), ]: if kwarg in inspect.getfullargspec(callback).args: kwargs[kwarg] = value diff --git a/dunamai/__main__.py b/dunamai/__main__.py index 64f78b5..0efbb93 100644 --- a/dunamai/__main__.py +++ b/dunamai/__main__.py @@ -124,6 +124,12 @@ "default": False, "help": "Get the full commit hash instead of the short form", }, + { + "triggers": ["--commit-length"], + "dest": "commit_length", + "type": int, + "help": "Use this many characters from the start of the full commit hash", + }, { "vcs": [Vcs.Git], "triggers": ["--tag-branch"], @@ -270,9 +276,20 @@ def from_vcs( path: Optional[Path], pattern_prefix: Optional[str], ignore_untracked: bool, + commit_length: Optional[int], ) -> None: version = Version.from_vcs( - vcs, pattern, latest_tag, tag_dir, tag_branch, full_commit, strict, path, pattern_prefix, ignore_untracked + vcs, + pattern, + latest_tag, + tag_dir, + tag_branch, + full_commit, + strict, + path, + pattern_prefix, + ignore_untracked, + commit_length, ) for concern in version.concerns: @@ -293,6 +310,7 @@ def main() -> None: tag_branch = getattr(args, "tag_branch", None) full_commit = getattr(args, "full_commit", False) ignore_untracked = getattr(args, "ignore_untracked", False) + commit_length = getattr(args, "commit_length", None) from_vcs( Vcs(args.vcs), args.pattern, @@ -311,6 +329,7 @@ def main() -> None: Path(args.path) if args.path is not None else None, args.pattern_prefix, ignore_untracked, + commit_length, ) elif args.command == "check": version = from_stdin(args.version) diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index 1ab04ee..a41b799 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -26,6 +26,7 @@ def test__parse_args__from(): path=None, pattern_prefix=None, ignore_untracked=False, + commit_length=None, ) assert parse_args(["from", "git"]).vcs == "git" assert parse_args(["from", "git", "--tag-branch", "foo"]).tag_branch == "foo" @@ -55,6 +56,7 @@ def test__parse_args__from(): assert parse_args(["from", "any", "--path", "/tmp"]).path == "/tmp" assert parse_args(["from", "any", "--pattern-prefix", "foo-"]).pattern_prefix == "foo-" assert parse_args(["from", "any", "--ignore-untracked"]).ignore_untracked is True + assert parse_args(["from", "any", "--commit-length", "10"]).commit_length == 10 assert parse_args(["from", "subversion", "--tag-dir", "foo"]).tag_dir == "foo" with pytest.raises(SystemExit):