Skip to content

Commit 47e8afb

Browse files
authored
Merge pull request #61 from SYMSCAE/version-naming
chore: standardize release tags
2 parents 9d7bd8b + 6da4961 commit 47e8afb

1 file changed

Lines changed: 60 additions & 39 deletions

File tree

‎site_scons/libdiffpybuildutils.py‎

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import os
66
import re
7+
import subprocess
78

89
MYDIR = os.path.dirname(os.path.abspath(__file__))
910

@@ -18,35 +19,50 @@
1819
Inconsistent FALLBACK_VERSION {} vs {} from git tag.
1920
"""
2021

22+
RELEASE_TAG = re.compile(r"([0-9]+\.[0-9]+\.[0-9]+)(?:-rc\.([0-9]+))?")
23+
24+
25+
def release_version(tag):
26+
"""Normalize a release tag to the internal version format."""
27+
match = RELEASE_TAG.fullmatch(tag)
28+
if not match:
29+
raise RuntimeError(
30+
f"Invalid release tag {tag!r}; expected X.Y.Z or X.Y.Z-rc.N."
31+
)
32+
base, candidate = match.groups()
33+
return base if candidate is None else f"{base}rc{candidate}"
34+
2135

2236
def gitinfo():
2337
"Extract dictionary of version data from git records."
24-
from subprocess import PIPE, Popen
25-
2638
global _cached_gitinfo
2739
if _cached_gitinfo is not None:
2840
return _cached_gitinfo
29-
nullfile = open(os.devnull, "w")
30-
kw = dict(stdout=PIPE, stderr=nullfile, cwd=MYDIR, universal_newlines=True)
31-
# Release tags may be lightweight, as with v1.4.1.
32-
proc = Popen(["git", "describe", "--tags", "--match=v[[:digit:]]*"], **kw)
33-
desc = proc.stdout.read()
34-
if proc.wait():
41+
kw = dict(
42+
stdout=subprocess.PIPE,
43+
stderr=subprocess.DEVNULL,
44+
cwd=MYDIR,
45+
text=True,
46+
)
47+
proc = subprocess.run(["git", "log", "-1", "--format=%H %ci"], **kw)
48+
if proc.returncode:
3549
_cached_gitinfo = {}
36-
return gitinfo()
37-
proc = Popen(["git", "log", "-1", "--format=%H %ci"], **kw)
38-
glog = proc.stdout.read()
39-
words = desc.strip().split("-")
40-
vtag = words[0].lstrip("v")
41-
vnum = int((words[1:2] or ["0"])[0])
50+
return _cached_gitinfo
4251
rv = {}
43-
rv["commit"], rv["date"] = glog.strip().split(None, 1)
44-
rv["patchnumber"] = vnum
45-
rv["version"] = vtag
46-
if vnum:
47-
rv["version"] += ".post" + str(vnum)
52+
rv["commit"], rv["date"] = proc.stdout.strip().split(None, 1)
53+
# --long makes the commit count explicit even at a tag. Split from
54+
# the right so the -rc.N suffix remains part of the release tag.
55+
proc = subprocess.run(
56+
["git", "describe", "--tags", "--long", "--match=[0-9]*"], **kw
57+
)
58+
if not proc.returncode:
59+
tag, count, _ = proc.stdout.strip().rsplit("-", 2)
60+
rv["patchnumber"] = int(count)
61+
rv["version"] = release_version(tag)
62+
if rv["patchnumber"]:
63+
rv["version"] += ".post" + count
4864
_cached_gitinfo = rv
49-
return gitinfo()
65+
return _cached_gitinfo
5066

5167

5268
_cached_gitinfo = None
@@ -56,11 +72,17 @@ def getversion():
5672
"""Extract version from gitinfo and/or gitarchive.cfg file.
5773
5874
Process gitinfo first and make sure it matches FALLBACK_VERSION in
59-
gitarchive.cfg. Use expanded data from gitarchive.cfg when these
60-
sources are from git archive bundle.
75+
fallback_version.py. Use expanded data from gitarchive.cfg when
76+
these sources are from git archive bundle.
6177
"""
6278
from fallback_version import FALLBACK_VERSION
6379

80+
if not re.fullmatch(
81+
r"[0-9]+\.[0-9]+\.[0-9]+(?:rc[0-9]+)?\.post0", FALLBACK_VERSION
82+
):
83+
raise RuntimeError(
84+
"FALLBACK_VERSION must be X.Y.Z.post0 or X.Y.ZrcN.post0."
85+
)
6486
gitarchivecfgfile = os.path.join(MYDIR, "gitarchive.cfg")
6587
assert os.path.isfile(gitarchivecfgfile)
6688
with open(gitarchivecfgfile) as fp:
@@ -69,33 +91,32 @@ def getversion():
6991
ga = dict(gaitems)
7092
gi = gitinfo()
7193
rv = {}
72-
if gi:
94+
if not gi:
95+
# Not a git repository. Require an expanded source archive.
96+
if "$Format:" in ga["commit"]:
97+
raise RuntimeError(EMSG_GIT_MISSING)
98+
gi = dict(commit=ga["commit"], date=ga["date"])
99+
for ref in ga["refnames"].split(", "):
100+
if ref.startswith("tag: ") and re.match(r"[0-9]", ref[5:]):
101+
gi["version"] = release_version(ref[5:])
102+
gi["patchnumber"] = 0
103+
break
104+
rv.update(gi)
105+
if "version" in gi:
73106
afb = FALLBACK_VERSION
74107
gfb = gi["version"].split(".post")[0] + ".post0"
75108
if gfb != afb:
76109
raise RuntimeError(EMSG_BAD_FALLBACK_VERSION.format(afb, gfb))
77-
rv.update(gi)
78110
else:
79-
# Not a git repository. Require that gitarchive.cfg is expanded.
80-
if "$Format:" in ga["commit"]:
81-
raise RuntimeError(EMSG_GIT_MISSING)
82-
rv["commit"] = ga["commit"]
83-
rv["date"] = ga["date"]
84-
# First assume we have an undetermined post-release. Keep version
85-
# suffix as ".post0", but set patchnumber to ensure we are post
86-
# FALLBACK_VERSION.
111+
# A development checkout without a new-format tag, or an untagged
112+
# archive, has no known commit count. Keep the fallback version.
87113
rv["version"] = FALLBACK_VERSION
88114
rv["patchnumber"] = 1
89-
# If we are at version tag turn this to regular release.
90-
mx = re.search(r"\btag: v(\d[^,]*)", ga["refnames"])
91-
if mx:
92-
rv["version"] = mx.group(1)
93-
rv["patchnumber"] = 0
94115
# rv['version'] is resolved, let's parse its subfields.
95116
vbase = rv["version"].split(".post")[0]
96-
mx = re.match(r"^(\d+)\.(\d+)(?:\.(\d+))?((?:[ab]|rc)\d*)?", vbase)
117+
mx = re.fullmatch(r"([0-9]+)\.([0-9]+)\.([0-9]+)(rc[0-9]+)?", vbase)
97118
rv["major"] = int(mx.group(1))
98119
rv["minor"] = int(mx.group(2))
99-
rv["micro"] = int(mx.group(3) or 0)
120+
rv["micro"] = int(mx.group(3))
100121
rv["prerelease"] = mx.group(4)
101122
return rv

0 commit comments

Comments
 (0)