Skip to content

Commit 083520c

Browse files
committed
Add new dynamic_version option
1 parent 7ee1f03 commit 083520c

File tree

7 files changed

+105
-2
lines changed

7 files changed

+105
-2
lines changed

attribution/__version__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,28 @@
55
"""
66

77
__version__ = "1.8.0"
8+
9+
try:
10+
import re
11+
import subprocess
12+
from pathlib import Path
13+
14+
version_suffix = "+dev"
15+
path = Path(__file__).resolve().parent
16+
while path != path.parent:
17+
if (path / ".git").is_dir():
18+
proc = subprocess.run(
19+
("git", "describe"), text=True, capture_output=True, check=True
20+
)
21+
if match := re.search(r"-(\d+)-(g[a-f0-9]+)$", proc.stdout):
22+
count, ref = match.groups()
23+
version_suffix = f"+dev{count}-{ref}"
24+
break
25+
26+
path = path.parent
27+
28+
except Exception as e:
29+
print(f"version suffix failed: {e}")
30+
31+
finally:
32+
__version__ += version_suffix

attribution/generate.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,45 @@ class VersionFile(GeneratedFile):
103103
'''
104104

105105

106+
class DynamicVersionFile(GeneratedFile):
107+
FILENAME = "{project.package}/__version__.py"
108+
TEMPLATE = '''\
109+
"""
110+
This file is automatically generated by attribution.
111+
112+
Do not edit manually. Get more info at https://attribution.omnilib.dev
113+
"""
114+
115+
__version__ = "{{ project.latest.version }}"
116+
117+
try:
118+
import re
119+
import subprocess
120+
from pathlib import Path
121+
122+
version_suffix = "+dev"
123+
path = Path(__file__).resolve().parent
124+
while path != path.parent:
125+
if (path / ".git").is_dir():
126+
proc = subprocess.run(
127+
("git", "describe"), text=True, capture_output=True, check=True
128+
)
129+
if match := re.search(r"-(\\d+)-(g[a-f0-9]+)$", proc.stdout):
130+
count, ref = match.groups()
131+
version_suffix = f"+dev{count}-{ref}"
132+
break
133+
134+
path = path.parent
135+
136+
except Exception as e:
137+
print(f"version suffix failed: {e}")
138+
139+
finally:
140+
__version__ += version_suffix
141+
142+
'''
143+
144+
106145
class CargoFile(GeneratedFile):
107146
EXPECTS = ("package_name", "package_dir")
108147
FILENAME = "{package_dir}/Cargo.toml"

attribution/main.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import tomlkit
1111

1212
from attribution import __version__
13-
from .generate import CargoFile, Changelog, NpmFile, VersionFile
13+
from .generate import CargoFile, Changelog, DynamicVersionFile, NpmFile, VersionFile
1414
from .helpers import sh
1515
from .project import Project
1616
from .tag import Tag
@@ -37,6 +37,12 @@ def init() -> None:
3737
version_file = click.confirm(
3838
"Use __version__.py file", default=project.config["version_file"]
3939
)
40+
dynamic_version = False
41+
if version_file:
42+
dynamic_version = click.confirm(
43+
"Use dynamic version suffix (eg. '1.0+git4-gabc123')",
44+
default=project.config["dynamic_version"],
45+
)
4046
signed_tags = click.confirm(
4147
"Use GPG signed tags", default=project.config["signed_tags"]
4248
)
@@ -66,13 +72,17 @@ def init() -> None:
6672
table["package"] = package
6773
table["signed_tags"] = signed_tags
6874
table["version_file"] = version_file
75+
table["dynamic_version"] = dynamic_version
6976

7077
project.pyproject_path().write_text(tomlkit.dumps(pyproject))
7178

7279
# pick up any changes
7380
project = Project.load()
7481
if version_file:
75-
VersionFile(project).write()
82+
if dynamic_version:
83+
DynamicVersionFile(project).write()
84+
else:
85+
VersionFile(project).write()
7686

7787

7888
@main.command("debug")
@@ -186,6 +196,11 @@ def tag_release(version: Version, message: Optional[str]) -> None:
186196
sh("git commit --amend --no-edit")
187197
tag.update(message=message, signed=project.config["signed_tags"])
188198

199+
if project.config.get("dynamic_version"):
200+
path = DynamicVersionFile(project).write()
201+
sh(f"git add {path}")
202+
sh("git commit -m 'Dynamic version file'")
203+
189204
except Exception:
190205
mfile = Path(f".attribution-{version}.txt").resolve()
191206
mfile.write_text(message)

attribution/project.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def load(cls, path: Optional[Path] = None) -> "Project":
102102
"ignored_authors": [],
103103
"version_file": True,
104104
"signed_tags": True,
105+
"dynamic_version": False,
105106
}
106107

107108
if cls.pyproject_path(path).is_file():

attribution/tests/project.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ def test_load(self, cwd_mock):
164164
"cargo_packages": [],
165165
"ignored_authors": [],
166166
"version_file": True,
167+
"dynamic_version": False,
167168
"signed_tags": True,
168169
},
169170
)
@@ -181,6 +182,7 @@ def test_load(self, cwd_mock):
181182
"cargo_packages": [],
182183
"ignored_authors": [],
183184
"version_file": True,
185+
"dynamic_version": False,
184186
"signed_tags": True,
185187
},
186188
)
@@ -197,6 +199,7 @@ def test_load(self, cwd_mock):
197199
"cargo_packages": [],
198200
"ignored_authors": [],
199201
"version_file": True,
202+
"dynamic_version": False,
200203
"signed_tags": True,
201204
},
202205
)
@@ -213,6 +216,7 @@ def test_load(self, cwd_mock):
213216
"cargo_packages": [],
214217
"ignored_authors": [],
215218
"version_file": False,
219+
"dynamic_version": False,
216220
"signed_tags": True,
217221
},
218222
)
@@ -228,6 +232,7 @@ def test_load(self, cwd_mock):
228232
"cargo_packages": [],
229233
"ignored_authors": [],
230234
"version_file": True,
235+
"dynamic_version": False,
231236
"signed_tags": True,
232237
},
233238
)
@@ -243,6 +248,7 @@ def test_load(self, cwd_mock):
243248
"cargo_packages": [],
244249
"ignored_authors": [],
245250
"version_file": True,
251+
"dynamic_version": False,
246252
"signed_tags": True,
247253
},
248254
)

docs/guide.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,22 @@ Options available are described as follows:
171171
to not have a managed ``__version__.py`` file, this value should be set to
172172
``false``.
173173

174+
.. attribute:: dynamic_version
175+
:type: bool
176+
:value: False
177+
178+
Enables generating a dynamic ``__version__.py`` that generates version
179+
suffixes based on the local repository's revision relative to the last
180+
release. When a release is tagged, a static version file is committed,
181+
without the dynamic suffix logic, before tagging the version bump, and
182+
then the dynamic version file is reinstated after the release is tagged.
183+
184+
If the project's git revision can be queried, then the dynamic version
185+
string will look like ``1.8.0+dev6-g3c61fc2``. Otherwise, the version
186+
string will fall back to the generic form ``1.8.0+dev``.
187+
188+
Requires enabling :attr:`version_file`.
189+
174190

175191
Alternative Packaging
176192
^^^^^^^^^^^^^^^^^^^^^

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ ignored_authors = ["dependabot[bot]", "pyup.io bot"]
6767
version_file = true
6868
signed_tags = true
6969
cargo_packages = ["fake_crate"]
70+
dynamic_version = true
7071

7172
[tool.coverage.run]
7273
branch = true

0 commit comments

Comments
 (0)