Skip to content

Commit

Permalink
Add vcs field to Version class
Browse files Browse the repository at this point in the history
  • Loading branch information
mtkennerly committed Jul 10, 2023
1 parent 1220017 commit 74bd4a4
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Unreleased

* Added a `vcs` attribute to `Version` to indicate which VCS was detected.

## v1.17.0 (2023-05-19)

* The `from` command will print a warning for shallow Git repositories.
Expand Down
73 changes: 57 additions & 16 deletions dunamai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ class Version:
:vartype timestamp: Optional[dt.datetime]
:ivar concerns: Any concerns regarding the version.
:vartype concerns: Optional[Set[Concern]]
:ivar vcs: Version control system from which the version was detected.
:vartype vcs: Vcs
"""

def __init__(
Expand All @@ -545,8 +547,9 @@ def __init__(
epoch: Optional[int] = None,
branch: Optional[str] = None,
timestamp: Optional[dt.datetime] = None,
concerns: Optional[Set[Concern]] = None,
# fmt: off
concerns: Optional[Set[Concern]] = None
vcs: Vcs = Vcs.Any,
# fmt: on
) -> None:
"""
Expand Down Expand Up @@ -578,6 +581,7 @@ def __init__(
# Will fail for naive timestamps before Python 3.6.
self.timestamp = timestamp
self.concerns = concerns or set()
self.vcs = vcs

self._matched_tag = None # type: Optional[str]
self._newer_unmatched_tags = None # type: Optional[Sequence[str]]
Expand Down Expand Up @@ -936,8 +940,9 @@ def _fallback(
epoch: Optional[int] = None,
branch: Optional[str] = None,
timestamp: Optional[dt.datetime] = None,
concerns: Optional[Set[Concern]] = None,
# fmt: off
concerns: Optional[Set[Concern]] = None
vcs: Vcs = Vcs.Any,
# fmt: on
):
if strict:
Expand All @@ -953,6 +958,7 @@ def _fallback(
branch=branch,
timestamp=timestamp,
concerns=concerns,
vcs=vcs,
)

@classmethod
Expand All @@ -979,6 +985,8 @@ def from_git(
When there are no tags, fail instead of falling back to 0.0.0.
:returns: Detected version.
"""
vcs = Vcs.Git

archival = _find_higher_file(".git_archival.json", ".git")
if archival is not None:
content = archival.read_text("utf8")
Expand Down Expand Up @@ -1025,6 +1033,7 @@ def from_git(
dirty=dirty,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)

tag, base, stage, unmatched, tagged_metadata, epoch = _match_version_pattern(
Expand All @@ -1040,12 +1049,13 @@ def from_git(
epoch=epoch,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)
version._matched_tag = tag
version._newer_unmatched_tags = unmatched
return version

_detect_vcs(Vcs.Git)
_detect_vcs(vcs)
concerns = set() # type: Set[Concern]
if tag_branch is None:
tag_branch = "HEAD"
Expand Down Expand Up @@ -1075,7 +1085,9 @@ def from_git(
codes=[0, 128],
)
if code == 128:
return cls._fallback(strict, distance=0, dirty=True, branch=branch, concerns=concerns)
return cls._fallback(
strict, distance=0, dirty=True, branch=branch, concerns=concerns, vcs=vcs
)
commit = msg

timestamp = None
Expand Down Expand Up @@ -1112,6 +1124,7 @@ def from_git(
branch=branch,
timestamp=timestamp,
concerns=concerns,
vcs=vcs,
)
tags = [line.replace("refs/tags/", "") for line in msg.splitlines()]
tag, base, stage, unmatched, tagged_metadata, epoch = _match_version_pattern(
Expand Down Expand Up @@ -1141,6 +1154,7 @@ def from_git(
branch=branch,
timestamp=timestamp,
concerns=concerns,
vcs=vcs,
)

detailed_tags = [] # type: List[_GitRefInfo]
Expand Down Expand Up @@ -1169,6 +1183,7 @@ def from_git(
branch=branch,
timestamp=timestamp,
concerns=concerns,
vcs=vcs,
)
version._matched_tag = tag
version._newer_unmatched_tags = unmatched
Expand All @@ -1195,6 +1210,8 @@ def from_mercurial(
When there are no tags, fail instead of falling back to 0.0.0.
:returns: Detected version.
"""
vcs = Vcs.Mercurial

archival = _find_higher_file(".hg_archival.txt", ".hg")
if archival is not None:
content = archival.read_text("utf8")
Expand All @@ -1212,7 +1229,9 @@ def from_mercurial(
branch = data.get("branch")

if tag is None or tag == "null":
return cls._fallback(strict, distance=distance, commit=commit, branch=branch)
return cls._fallback(
strict, distance=distance, commit=commit, branch=branch, vcs=vcs
)

all_tags_file = _find_higher_file(".hgtags", ".hg")
if all_tags_file is None:
Expand All @@ -1237,12 +1256,13 @@ def from_mercurial(
tagged_metadata=tagged_metadata,
epoch=epoch,
branch=branch,
vcs=vcs,
)
version._matched_tag = tag
version._newer_unmatched_tags = unmatched
return version

_detect_vcs(Vcs.Mercurial)
_detect_vcs(vcs)

code, msg = _run_cmd("hg summary")
dirty = "commit: (clean)" not in msg.splitlines()
Expand Down Expand Up @@ -1276,6 +1296,7 @@ def from_mercurial(
dirty=dirty,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)
tags = [tag for tags in [line.split(":") for line in msg.splitlines()] for tag in tags]
tag, base, stage, unmatched, tagged_metadata, epoch = _match_version_pattern(
Expand All @@ -1296,6 +1317,7 @@ def from_mercurial(
epoch=epoch,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)
version._matched_tag = tag
version._newer_unmatched_tags = unmatched
Expand All @@ -1320,7 +1342,8 @@ def from_darcs(
When there are no tags, fail instead of falling back to 0.0.0.
:returns: Detected version.
"""
_detect_vcs(Vcs.Darcs)
vcs = Vcs.Darcs
_detect_vcs(vcs)

code, msg = _run_cmd("darcs status", codes=[0, 1])
dirty = msg != "No changes!"
Expand All @@ -1342,7 +1365,7 @@ def from_darcs(
except Exception:
distance = 0
return cls._fallback(
strict, distance=distance, commit=commit, dirty=dirty, timestamp=timestamp
strict, distance=distance, commit=commit, dirty=dirty, timestamp=timestamp, vcs=vcs
)
tags = msg.splitlines()
tag, base, stage, unmatched, tagged_metadata, epoch = _match_version_pattern(
Expand All @@ -1362,6 +1385,7 @@ def from_darcs(
tagged_metadata=tagged_metadata,
epoch=epoch,
timestamp=timestamp,
vcs=vcs,
)
version._matched_tag = tag
version._newer_unmatched_tags = unmatched
Expand All @@ -1388,7 +1412,8 @@ def from_subversion(
When there are no tags, fail instead of falling back to 0.0.0.
:returns: Detected version.
"""
_detect_vcs(Vcs.Subversion)
vcs = Vcs.Subversion
_detect_vcs(vcs)

tag_dir = tag_dir.strip("/")

Expand All @@ -1411,7 +1436,7 @@ def from_subversion(

if not commit:
return cls._fallback(
strict, distance=0, commit=commit, dirty=dirty, timestamp=timestamp
strict, distance=0, commit=commit, dirty=dirty, timestamp=timestamp, vcs=vcs
)
code, msg = _run_cmd('svn ls -v -r {} "{}/{}"'.format(commit, url, tag_dir))
lines = [line.split(maxsplit=5) for line in msg.splitlines()[1:]]
Expand All @@ -1422,7 +1447,7 @@ def from_subversion(
except Exception:
distance = 0
return cls._fallback(
strict, distance=distance, commit=commit, dirty=dirty, timestamp=timestamp
strict, distance=distance, commit=commit, dirty=dirty, timestamp=timestamp, vcs=vcs
)
tags_to_sources_revs = {}
for tag, rev in tags_to_revs.items():
Expand Down Expand Up @@ -1450,6 +1475,7 @@ def from_subversion(
tagged_metadata=tagged_metadata,
epoch=epoch,
timestamp=timestamp,
vcs=vcs,
)
version._matched_tag = tag
version._newer_unmatched_tags = unmatched
Expand All @@ -1474,7 +1500,8 @@ def from_bazaar(
When there are no tags, fail instead of falling back to 0.0.0.
:returns: Detected version.
"""
_detect_vcs(Vcs.Bazaar)
vcs = Vcs.Bazaar
_detect_vcs(vcs)

code, msg = _run_cmd("bzr status")
dirty = msg != ""
Expand Down Expand Up @@ -1509,6 +1536,7 @@ def from_bazaar(
dirty=dirty,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)
tags_to_revs = {
line.split()[0]: int(line.split()[1])
Expand All @@ -1532,6 +1560,7 @@ def from_bazaar(
epoch=epoch,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)
version._matched_tag = tag
version._newer_unmatched_tags = unmatched
Expand All @@ -1555,7 +1584,8 @@ def from_fossil(
When there are no tags, fail instead of falling back to 0.0.0.
:returns: Detected version.
"""
_detect_vcs(Vcs.Fossil)
vcs = Vcs.Fossil
_detect_vcs(vcs)

code, msg = _run_cmd("fossil changes --differ")
dirty = bool(msg)
Expand All @@ -1580,7 +1610,13 @@ def from_fossil(
total_commits = int(msg) - 1
if total_commits <= 0:
return cls._fallback(
strict, distance=0, commit=commit, dirty=dirty, branch=branch, timestamp=timestamp
strict,
distance=0,
commit=commit,
dirty=dirty,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)

# Based on `compute_direct_ancestors` from descendants.c in the
Expand Down Expand Up @@ -1621,6 +1657,7 @@ def from_fossil(
dirty=dirty,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)

tags_to_distance = [
Expand All @@ -1642,6 +1679,7 @@ def from_fossil(
epoch=epoch,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)
version._matched_tag = tag
version._newer_unmatched_tags = unmatched
Expand All @@ -1666,7 +1704,8 @@ def from_pijul(
When there are no tags, fail instead of falling back to 0.0.0.
:returns: Detected version.
"""
_detect_vcs(Vcs.Pijul)
vcs = Vcs.Pijul
_detect_vcs(vcs)

code, msg = _run_cmd("pijul diff --short")
dirty = msg.strip() != ""
Expand All @@ -1681,7 +1720,7 @@ def from_pijul(
code, msg = _run_cmd("pijul log --limit 1 --output-format json")
limited_commits = json.loads(msg)
if len(limited_commits) == 0:
return cls._fallback(strict, dirty=dirty, branch=branch)
return cls._fallback(strict, dirty=dirty, branch=branch, vcs=vcs)

commit = limited_commits[0]["hash"]
timestamp = _parse_timestamp(limited_commits[0]["timestamp"])
Expand All @@ -1700,6 +1739,7 @@ def from_pijul(
dirty=dirty,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)

tag_meta = [] # type: List[dict]
Expand Down Expand Up @@ -1775,6 +1815,7 @@ def from_pijul(
epoch=epoch,
branch=branch,
timestamp=timestamp,
vcs=vcs,
)
version._matched_tag = tag
version._newer_unmatched_tags = unmatched
Expand Down
7 changes: 7 additions & 0 deletions tests/integration/test_dunamai.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def test__version__from_git__with_annotated_tags(tmp_path) -> None:
except Exception:
pass
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=True, branch=b)
assert from_vcs(fresh=True).vcs == Vcs.Git

# Additional one-off check not in other VCS integration tests:
# strict mode requires there to be a tag
Expand Down Expand Up @@ -471,6 +472,7 @@ def test__version__from_mercurial(tmp_path) -> None:
with chdir(vcs):
run("hg init")
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=False, branch=b)
assert from_vcs(fresh=True).vcs == Vcs.Mercurial

(vcs / "foo.txt").write_text("hi")
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=True, branch=b)
Expand Down Expand Up @@ -556,6 +558,7 @@ def test__version__from_darcs(tmp_path) -> None:
with chdir(vcs):
run("darcs init")
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=False)
assert from_vcs(fresh=True).vcs == Vcs.Darcs

(vcs / "foo.txt").write_text("hi")
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=True)
Expand Down Expand Up @@ -609,6 +612,7 @@ def test__version__from_subversion(tmp_path) -> None:
with chdir(vcs):
run('svn checkout "{}" .'.format(vcs_srv_uri))
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=False)
assert from_vcs(fresh=True).vcs == Vcs.Subversion

run("svn mkdir trunk tags")

Expand Down Expand Up @@ -695,6 +699,7 @@ def test__version__from_bazaar(tmp_path) -> None:
with chdir(vcs):
run("bzr init")
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=False)
assert from_vcs(fresh=True).vcs == Vcs.Bazaar

(vcs / "foo.txt").write_text("hi")
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=True)
Expand Down Expand Up @@ -759,6 +764,7 @@ def test__version__from_fossil(tmp_path) -> None:
run("fossil init repo")
run("fossil open repo --force")
assert from_vcs() == Version("0.0.0", distance=0, dirty=False, branch=b)
assert from_vcs().vcs == Vcs.Fossil

(vcs / "foo.txt").write_text("hi")
assert from_vcs() == Version("0.0.0", distance=0, dirty=True, branch=b)
Expand Down Expand Up @@ -812,6 +818,7 @@ def test__version__from_pijul(tmp_path) -> None:
with chdir(vcs):
run("pijul init")
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=False, branch=b)
assert from_vcs(fresh=True).vcs == Vcs.Pijul

(vcs / "foo.txt").write_text("hi")
assert from_vcs(fresh=True) == Version("0.0.0", distance=0, dirty=False, branch=b)
Expand Down

0 comments on commit 74bd4a4

Please sign in to comment.