Skip to content

Commit 19a458a

Browse files
add support for branch name based testing, add simplified semver support
1 parent 339cfa1 commit 19a458a

File tree

8 files changed

+106
-23
lines changed

8 files changed

+106
-23
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ htmlcov/
3737
.coverage
3838
.coverage.*
3939
.cache
40+
.pytest_cache
4041
nosetests.xml
4142
coverage.xml
4243
*,cover

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ def parse(root):
8787
[setuptools_scm.version_scheme]
8888
guess-next-dev = setuptools_scm.version:guess_next_dev_version
8989
post-release = setuptools_scm.version:postrelease_version
90+
python-simplified-semver = setuptools_scm.version:simplified_semver_version
9091
9192
[setuptools_scm.local_scheme]
9293
node-and-date = setuptools_scm.version:get_local_node_and_date

setuptools_scm/git.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ def is_dirty(self):
3939
out, _, _ = self.do_ex("git status --porcelain --untracked-files=no")
4040
return bool(out)
4141

42+
def get_branch(self):
43+
branch, err, ret = self.do_ex("git rev-parse --abbrev-ref HEAD")
44+
if ret:
45+
trace("branch err", branch, err, ret)
46+
return
47+
return branch
48+
4249
def is_shallow(self):
4350
return isfile(join(self.path, '.git/shallow'))
4451

@@ -89,7 +96,7 @@ def parse(root, describe_command=DEFAULT_DESCRIBE, pre_parse=warn_on_shallow):
8996
if pre_parse:
9097
pre_parse(wd)
9198

92-
out, err, ret = do_ex(describe_command, root)
99+
out, err, ret = wd.do_ex(describe_command)
93100
if ret:
94101
# If 'git describe' failed, try to get the information otherwise.
95102
rev_node = wd.node()
@@ -103,6 +110,7 @@ def parse(root, describe_command=DEFAULT_DESCRIBE, pre_parse=warn_on_shallow):
103110
distance=wd.count_all_nodes(),
104111
node='g' + rev_node,
105112
dirty=dirty,
113+
branch=wd.get_branch(),
106114
)
107115

108116
# 'out' looks e.g. like 'v1.5.0-0-g4060507' or
@@ -115,10 +123,11 @@ def parse(root, describe_command=DEFAULT_DESCRIBE, pre_parse=warn_on_shallow):
115123

116124
tag, number, node = out.rsplit('-', 2)
117125
number = int(number)
126+
branch = wd.get_branch()
118127
if number:
119-
return meta(tag, distance=number, node=node, dirty=dirty)
128+
return meta(tag, distance=number, node=node, dirty=dirty, branch=branch)
120129
else:
121-
return meta(tag, node=node, dirty=dirty)
130+
return meta(tag, node=node, dirty=dirty, branch=branch)
122131

123132

124133
def list_files_in_archive(path):

setuptools_scm/hg.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
FILES_COMMAND = 'hg locate -I .'
66

77

8-
def _hg_tagdist_normalize_tagcommit(root, tag, dist, node):
8+
def _hg_tagdist_normalize_tagcommit(root, tag, dist, node, branch):
99
dirty = node.endswith('+')
1010
node = 'h' + node.strip('+')
1111

@@ -17,42 +17,44 @@ def _hg_tagdist_normalize_tagcommit(root, tag, dist, node):
1717
" and not tag({tag!r}))" # ignore the tagged commit itself
1818
).format(tag=tag)
1919
if tag != '0.0':
20-
commits = do(['hg', 'log', '-r', revset, '--template', '{node|short}'],
20+
commits = do(['hg', 'log', '-r', revset,
21+
'--template', '{node|short}'],
2122
root)
2223
else:
2324
commits = True
2425
trace('normalize', locals())
2526
if commits or dirty:
26-
return meta(tag, distance=dist, node=node, dirty=dirty)
27+
return meta(tag, distance=dist, node=node, dirty=dirty, branch=branch)
2728
else:
2829
return meta(tag)
2930

3031

3132
def parse(root):
3233
if not has_command('hg'):
3334
return
34-
identity_data = do('hg id -i -t', root).split()
35+
identity_data = do('hg id -i -b -t', root).split()
3536
if not identity_data:
3637
return
3738
node = identity_data.pop(0)
39+
branch = identity_data.pop(0)
3840
tags = tags_to_versions(identity_data)
3941
# filter tip in degraded mode on old setuptools
4042
tags = [x for x in tags if x != 'tip']
4143
dirty = node[-1] == '+'
4244
if tags:
43-
return meta(tags[0], dirty=dirty)
45+
return meta(tags[0], dirty=dirty, branch=branch)
4446

45-
if node.strip('+') == '0'*12:
47+
if node.strip('+') == '0' * 12:
4648
trace('initial node', root)
47-
return meta('0.0', dirty=dirty)
49+
return meta('0.0', dirty=dirty, branch=branch)
4850

4951
try:
5052
tag = get_latest_normalizable_tag(root)
5153
dist = get_graph_distance(root, tag)
5254
if tag == 'null':
5355
tag = '0.0'
5456
dist = int(dist) + 1
55-
return _hg_tagdist_normalize_tagcommit(root, tag, dist, node)
57+
return _hg_tagdist_normalize_tagcommit(root, tag, dist, node, branch)
5658
except ValueError:
5759
pass # unpacking failed, old hg
5860

setuptools_scm/version.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class ScmVersion(object):
6464
def __init__(self, tag_version,
6565
distance=None, node=None, dirty=False,
6666
preformatted=False,
67+
branch=None,
6768
**kw):
6869
if kw:
6970
trace("unknown args", kw)
@@ -76,6 +77,7 @@ def __init__(self, tag_version,
7677
self.extra = kw
7778
self.dirty = dirty
7879
self.preformatted = preformatted
80+
self.branch = branch
7981

8082
@property
8183
def exact(self):
@@ -84,13 +86,14 @@ def exact(self):
8486
def __repr__(self):
8587
return self.format_with(
8688
'<ScmVersion {tag} d={distance}'
87-
' n={node} d={dirty} x={extra}>')
89+
' n={node} d={dirty} b={branch} x={extra}>')
8890

8991
def format_with(self, fmt, **kw):
9092
return fmt.format(
9193
time=self.time,
9294
tag=self.tag, distance=self.distance,
93-
node=self.node, dirty=self.dirty, extra=self.extra, **kw)
95+
node=self.node, dirty=self.dirty, extra=self.extra,
96+
branch=self.branch, **kw)
9497

9598
def format_choice(self, clean_format, dirty_format, **kw):
9699
return self.format_with(
@@ -145,6 +148,31 @@ def guess_next_dev_version(version):
145148
return guess_next_version(version.tag, version.distance)
146149

147150

151+
def guess_next_simple_semver(version, distance, retain, increment=True):
152+
parts = str(version).split('.', retain)
153+
del parts[retain:]
154+
while len(parts) < retain:
155+
parts.append("0")
156+
if increment:
157+
parts[-1] = str(int(parts[-1]) + 1)
158+
while len(parts) < 3:
159+
parts.append("0")
160+
del parts[3:]
161+
if distance:
162+
parts.append("dev" + str(distance))
163+
return '.'.join(parts)
164+
165+
166+
def simplified_semver_version(version):
167+
if version.exact:
168+
return guess_next_simple_semver(version.tag, 0, 3, increment=False)
169+
else:
170+
if version.branch is not None and 'feature' in version.branch:
171+
return guess_next_simple_semver(version.tag, version.distance, retain=2)
172+
else:
173+
return guess_next_simple_semver(version.tag, version.distance, retain=3)
174+
175+
148176
def _format_local_with_time(version, time_format):
149177

150178
if version.exact or version.node is None:

testing/test_git.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def test_git_shallow_autocorrect(shallow_wd, recwarn):
9999
def test_find_files_stop_at_root_git(wd):
100100
wd.commit_testfile()
101101
wd.cwd.ensure('project/setup.cfg')
102-
assert integration.find_files(str(wd.cwd/'project')) == []
102+
assert integration.find_files(str(wd.cwd / 'project')) == []
103103

104104

105105
@pytest.mark.issue(128)
@@ -133,3 +133,13 @@ def test_git_archive_subdirectory(wd):
133133
wd('git add foobar')
134134
wd.commit()
135135
assert integration.find_files(str(wd.cwd)) == ['foobar/test1.txt']
136+
137+
138+
def test_git_feature_branch_increments_major(wd):
139+
wd.commit_testfile()
140+
wd("git tag 1.0.0")
141+
wd.commit_testfile()
142+
assert wd.get_version(version_scheme="python-simplified-semver").startswith("1.0.1")
143+
wd("git checkout -b feature/fun")
144+
wd.commit_testfile()
145+
assert wd.get_version(version_scheme="python-simplified-semver").startswith("1.1.0")

testing/test_mercurial.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ def wd(wd):
1818
'1.1.dev3+h000000000000': {
1919
'latesttag': '1.0',
2020
'latesttagdistance': '3',
21-
'node': '0'*20,
21+
'node': '0' * 20,
2222
},
2323
'0.0': {
24-
'node': '0'*20,
24+
'node': '0' * 20,
2525
},
2626
'1.2.2': {'tag': 'release-1.2.2'},
2727
'1.2.2.dev0': {'tag': 'release-1.2.2.dev'},
@@ -41,7 +41,7 @@ def test_archival_to_version(expected, data):
4141
def test_find_files_stop_at_root_hg(wd):
4242
wd.commit_testfile()
4343
wd.cwd.ensure('project/setup.cfg')
44-
assert integration.find_files(str(wd.cwd/'project')) == []
44+
assert integration.find_files(str(wd.cwd / 'project')) == []
4545

4646

4747
# XXX: better tests for tag prefixes
@@ -114,7 +114,7 @@ def test_parse_no_worktree(tmpdir):
114114
def version_1_0(wd):
115115
wd('hg branch default')
116116
wd.commit_testfile()
117-
wd('hg tag 1.0 -u test -d "0 0"')
117+
wd('hg tag 1.0.0 -u test -d "0 0"')
118118
return wd
119119

120120

@@ -131,14 +131,14 @@ def pre_merge_commit_after_tag(wd, version_1_0):
131131

132132
@pytest.mark.usefixtures("pre_merge_commit_after_tag")
133133
def test_version_bump_before_merge_commit(wd):
134-
assert wd.version.startswith('1.1.dev1+')
134+
assert wd.version.startswith('1.0.1.dev1+')
135135

136136

137137
@pytest.mark.issue(219)
138138
@pytest.mark.usefixtures("pre_merge_commit_after_tag")
139139
def test_version_bump_from_merge_commit(wd):
140140
wd.commit()
141-
assert wd.version.startswith('1.1.dev3+') # issue 219
141+
assert wd.version.startswith('1.0.1.dev3+') # issue 219
142142

143143

144144
@pytest.mark.usefixtures("version_1_0")
@@ -149,9 +149,9 @@ def test_version_bump_from_commit_including_hgtag_mods(wd):
149149
tagfile.write('0 0\n')
150150
wd.write('branchfile', 'branchtext')
151151
wd(wd.add_command)
152-
assert wd.version.startswith('1.1.dev1+') # bump from dirty version
152+
assert wd.version.startswith('1.0.1.dev1+') # bump from dirty version
153153
wd.commit() # commits both the testfile _and_ .hgtags
154-
assert wd.version.startswith('1.1.dev2+')
154+
assert wd.version.startswith('1.0.1.dev2+')
155155

156156

157157
@pytest.mark.issue(229)
@@ -161,4 +161,13 @@ def test_latest_tag_detection(wd):
161161
Note that will be superceded by the fix for pypa/setuptools_scm/issues/235
162162
"""
163163
wd('hg tag some-random-tag')
164-
assert wd.version == '1.0'
164+
assert wd.version == '1.0.0'
165+
166+
167+
@pytest.mark.usefixtures("version_1_0")
168+
def test_feature_branch_increments_major(wd):
169+
170+
wd.commit_testfile()
171+
assert wd.get_version(version_scheme="python-simplified-semver").startswith("1.0.1")
172+
wd("hg branch feature/fun")
173+
assert wd.get_version(version_scheme="python-simplified-semver").startswith("1.1.0")

testing/test_version.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import pytest
2+
from setuptools_scm.version import meta, simplified_semver_version
3+
4+
5+
@pytest.mark.parametrize('version, expected_next', [
6+
pytest.param(meta("1.0.0"), "1.0.0", id='exact'),
7+
8+
pytest.param(meta("1.0"), "1.0.0", id='short_tag'),
9+
pytest.param(meta("1.0.0", distance=2, branch='default'), "1.0.1.dev2",
10+
id='normal_branch'),
11+
12+
pytest.param(meta("1.0", distance=2, branch='default'), "1.0.1.dev2",
13+
id='normal_branch_short_tag'),
14+
pytest.param(meta("1.0.0", distance=2, branch='feature'), "1.1.0.dev2",
15+
id='feature_branch'),
16+
pytest.param(meta("1.0", distance=2, branch='feature'), "1.1.0.dev2",
17+
id='feature_branch_short_tag'),
18+
pytest.param(meta("1.0.0", distance=2, branch='features/test'), "1.1.0.dev2",
19+
id='feature_in_branch'),
20+
])
21+
def test_next_semver(version, expected_next):
22+
computed = simplified_semver_version(version)
23+
assert computed == expected_next

0 commit comments

Comments
 (0)