Skip to content

Commit f568380

Browse files
authored
Merge pull request #184 from minrk/dont-require-0.dev
accept non-prerelease baseVersion (append -0.dev)
2 parents 4b85272 + 3ea5d40 commit f568380

File tree

8 files changed

+239
-29
lines changed

8 files changed

+239
-29
lines changed

README.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ charts:
178178
# This gives you more control over development version tags
179179
# and lets you ensure prerelease tags are always sorted in the right order.
180180
# Only useful when publishing development releases.
181+
# Recommended together with a version-bumping tool like `tbump`.
182+
# if baseVersion is not a prerelease version (no -suffix),
183+
# the suffix `-0.dev` will be appended.
181184
baseVersion: 3.2.1-0.dev
182185

183186
# The git repo whose gh-pages contains the charts. This can be a local
@@ -289,24 +292,31 @@ This takes some extra configuration, and steps in your release process:
289292
```
290293

291294
2. You must update baseVersion, especially after making a release.
295+
We recommend using a version bumping tool like [tbump][] to keep your baseVersion config and git tags in sync.
296+
297+
[tbump]: https://github.com/your-tools/tbump
292298

293299
A release process would generally look like this:
294300

295301
```bash
296302
V=1.2.3
297-
git tag -am "release $V" "$V"
298-
git push --atomic --follow-tags
303+
# tbump updates version, commits changes, tags commit, pushes branch and tag
304+
tbump "$V"
299305
300306
# back to development
301307
NEXT_V=1.2.4-0.dev
302-
# edit chartpress.yaml to set baseVersion: $NEXT_V
303-
git add chartpress.yaml
304-
git commit -m "Back to $NEXT_V"
305-
git push --atomic
308+
# bump version config, but no tag for starting development
309+
tbump --no-tag "${NEXT_V}"
306310
```
307311

308312
Any prerelease fields (such as `-0.dev` above, or `-alpha.1`)
309313
will be left as-is, with the `.git.n.hash` suffix added.
314+
If there is no prerelease (e.g. on the exact commit of a tagged release),
315+
`-0.dev` will be added to the base version.
316+
You **must** update baseVersion after making a release,
317+
or `chartpress --reset` will fail due to incorrect ordering of versions.
318+
319+
A sample tbump config file can be found in [our tests](./tests/test_helm_chart/tbump.toml).
310320

311321
## Caveats
312322

chartpress.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -976,17 +976,17 @@ def _check_base_version(base_version):
976976
2. sort after the latest tag on the branch
977977
"""
978978

979+
if "-" not in base_version:
980+
# config version is a stable release,
981+
# append default '-0.dev' so we always produce a prerelease
982+
base_version = f"{base_version}-0.dev"
979983
# check valid value (baseVersion must be semver prerelease)
980984
match = _semver2.fullmatch(base_version)
981985
if not match:
982986
raise ValueError(
983-
f"baseVersion: {base_version} must be a valid semver prerelease (e.g. 1.2.3-0.dev), but doesn't appear to be valid."
987+
f"baseVersion: {base_version} must be a valid semver version (e.g. 1.2.3-0.dev), but doesn't appear to be valid."
984988
)
985989
base_version_groups = match.groupdict()
986-
if not base_version_groups["prerelease"]:
987-
raise ValueError(
988-
f"baseVersion: {base_version} must be a valid semver prerelease (e.g. 1.2.3-0.dev), but is not a prerelease."
989-
)
990990

991991
def _version_number(groups):
992992
"""Return comparable semver"""
@@ -1020,6 +1020,9 @@ def _version_number(groups):
10201020
# tag not semver. ignore? Not really our problem.
10211021
_log(f"Latest tag {tag} does not appear to be a semver version")
10221022

1023+
# return base_version, in case it was modified
1024+
return base_version
1025+
10231026

10241027
class ActionStoreDeprecated(argparse.Action):
10251028
"""Used with argparse as a deprecation action."""
@@ -1183,7 +1186,7 @@ def main(argv=None):
11831186
# (e.g. forgetting to update after release)
11841187
base_version = chart.get("baseVersion", None)
11851188
if base_version:
1186-
_check_base_version(base_version)
1189+
base_version = _check_base_version(base_version)
11871190

11881191
if not args.list_images:
11891192
# update Chart.yaml with a version

dev-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ gitpython
44
pre-commit
55
pytest
66
pytest-cov
7+
tbump

tests/conftest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,20 @@ def git_repo_alternative(monkeypatch, git_repo):
146146
yield r
147147

148148

149+
@pytest.fixture
150+
def git_repo_base_version(monkeypatch, git_repo):
151+
"""
152+
This fixture modifies the default git_repo fixture to use another the
153+
chartpress_alternative.yaml as chartpress.yaml.
154+
"""
155+
r = git_repo
156+
shutil.move("chartpress_base_version.yaml", "chartpress.yaml")
157+
r.git.add(all=True)
158+
r.index.commit("chartpress_base_version.yaml initial commit")
159+
160+
yield r
161+
162+
149163
class MockCheckCall:
150164
def __init__(self):
151165
self.commands = []
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
charts:
2+
- name: testchart
3+
baseVersion: "1.0.0-0.dev"
4+
resetTag: test-reset-tag
5+
resetVersion: 0.0.1-test.reset.version
6+
imagePrefix: testchart/
7+
paths:
8+
- extra-chart-path.txt
9+
images:
10+
testimage:
11+
dockerfilePath: image/Dockerfile
12+
valuesPath:
13+
- image
14+
paths:
15+
- extra-image-path.txt

tests/test_helm_chart/tbump.toml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# tbump config sets baseVersion in chartpress.yaml
2+
[version]
3+
current = "1.0.0-0.dev"
4+
5+
# match our prerelease prefixes
6+
# -alpha.1
7+
# -beta.2
8+
# -0.dev
9+
10+
regex = '''
11+
(?P<major>\d+)
12+
\.
13+
(?P<minor>\d+)
14+
\.
15+
(?P<patch>\d+)
16+
(\-
17+
(?P<prelease>
18+
(
19+
(alpha|beta|rc)\.\d+|
20+
0\.dev
21+
)
22+
)
23+
)?
24+
'''
25+
26+
[git]
27+
message_template = "Bump to {new_version}"
28+
tag_template = "{new_version}"
29+
30+
# For each file to patch, add a [[file]] config
31+
# section containing the path of the file, relative to the
32+
# tbump.toml location.
33+
[[file]]
34+
src = "chartpress.yaml"
35+
search = 'baseVersion: "{current_version}"'

tests/test_helpers.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -162,35 +162,36 @@ def test__get_image_extra_build_command_options(git_repo):
162162

163163

164164
@pytest.mark.parametrize(
165-
"base_version, tag, n_commits, status",
165+
"base_version, tag, n_commits, result",
166166
[
167167
# OK, normal state
168-
("1.2.4-0.dev", "1.2.3", 10, "ok"),
168+
("1.2.4-0.dev", "1.2.3", 10, "1.2.4-0.dev"),
169169
# don't compare prereleases on the same tag
170-
("1.2.3-0.dev", "1.2.3-alpha.1", 10, "ok"),
170+
("1.2.3-0.dev", "1.2.3-alpha.1", 10, "1.2.3-0.dev"),
171171
# invalid baseVersion (not semver)
172-
("x.y.z", "1.2.3", 10, "valid semver prerelease"),
172+
("x.y.z", "1.2.3", 10, ValueError("valid semver version")),
173173
# not prerelease baseVersion
174-
("1.2.4", "1.2.3", 10, "valid semver prerelease"),
174+
("1.2.4", "1.2.3", 10, "1.2.4-0.dev"),
175175
# check comparison with tag
176-
("1.2.2-0.dev", "1.2.3-alpha.1", 10, "is not greater"),
177-
("1.2.3-0.dev", "1.2.3", 10, "is not greater"),
178-
("1.2.3-0.dev", "2.0.0", 10, "is not greater"),
179-
("1.2.3-0.dev", "1.2.4-alpha.1", 10, "is not greater"),
176+
("1.2.2-0.dev", "1.2.3-alpha.1", 10, ValueError("is not greater")),
177+
("1.2.3-0.dev", "1.2.3", 10, ValueError("is not greater")),
178+
("1.2.3-0.dev", "2.0.0", 10, ValueError("is not greater")),
179+
("1.2.3-0.dev", "1.2.4-alpha.1", 10, ValueError("is not greater")),
180180
# don't check exactly on a tag
181-
("1.2.3-0.dev", "2.0.0", 0, "ok"),
181+
("1.2.3-0.dev", "2.0.0", 0, "1.2.3-0.dev"),
182182
# ignore invalid semver tags
183-
("1.2.3-0.dev", "x.y.z", 10, "ok"),
183+
("1.2.3-0.dev", "x.y.z", 10, "1.2.3-0.dev"),
184184
],
185185
)
186-
def test_check_base_version(base_version, tag, n_commits, status):
186+
def test_check_base_version(base_version, tag, n_commits, result):
187187
with mock.patch.object(
188188
chartpress, "_get_latest_tag_and_count", lambda: (tag, n_commits)
189189
):
190-
if status == "ok":
191-
chartpress._check_base_version(base_version)
192-
else:
193-
with pytest.raises(ValueError) as exc:
190+
if isinstance(result, Exception):
191+
with pytest.raises(result.__class__) as exc:
194192
chartpress._check_base_version(base_version)
195-
assert status in str(exc)
193+
assert str(result) in str(exc)
196194
assert base_version in str(exc)
195+
else:
196+
used_version = chartpress._check_base_version(base_version)
197+
assert used_version == result

tests/test_repo_interactions.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import subprocess
23
import sys
34

45
import pytest
@@ -244,6 +245,136 @@ def test_chartpress_run(git_repo, capfd, base_version):
244245
git_repo.git.stash("pop")
245246

246247

248+
def test_tbump_release(git_repo, git_repo_base_version, capfd):
249+
"""Run through tagging"""
250+
251+
def get_base_version():
252+
"""Get baseVersion config from chartpress.yaml"""
253+
with open("chartpress.yaml") as f:
254+
chartpress_config = yaml.load(f)
255+
256+
chart = chartpress_config["charts"][0]
257+
return chart["baseVersion"]
258+
259+
def get_chart_version():
260+
"""Get the current version in Chart.yaml"""
261+
with open("testchart/Chart.yaml") as f:
262+
chart = yaml.load(f)
263+
return chart["version"]
264+
265+
# run chartpress with --no-build and any additional arguments
266+
def run_chartpress(args=None):
267+
"""run chartpress with --no-build and any additional arguments"""
268+
if args is None:
269+
args = []
270+
if args != ["--reset"]:
271+
args = ["--no-build"] + args
272+
out = _capture_output(args, capfd)
273+
print(out)
274+
return out
275+
276+
def tbump(args):
277+
"""Run tbump with args"""
278+
subprocess.run(["git", "status"])
279+
proc = subprocess.run(
280+
["tbump", "--non-interactive", "--no-push"] + args,
281+
capture_output=True,
282+
text=True,
283+
)
284+
# echo output before checking return code
285+
# so we see it on errors
286+
sys.stdout.write(proc.stdout)
287+
sys.stderr.write(proc.stderr)
288+
assert proc.returncode == 0
289+
# increment commit count because tbump makes a commit
290+
nonlocal n
291+
n += 1
292+
return proc.stdout, proc.stderr
293+
294+
base_version = get_base_version()
295+
assert base_version == "1.0.0-0.dev"
296+
297+
# summarize information from git_repo
298+
sha = git_repo.commit("HEAD").hexsha[:7]
299+
n = chartpress._count_commits(sha)
300+
tag = f"{base_version}.git.{n}.h{sha}"
301+
run_chartpress()
302+
assert get_chart_version() == tag
303+
304+
# tag a prerelease
305+
run_chartpress(["--reset"])
306+
version = "1.0.0-beta.1"
307+
with open("chartpress.yaml") as f:
308+
print(f.read())
309+
tbump([version])
310+
base_version = get_base_version()
311+
assert base_version == version
312+
313+
# reset passes
314+
run_chartpress(["--reset"])
315+
# after chartpress, version is correct (no suffix)
316+
run_chartpress()
317+
assert get_chart_version() == version
318+
319+
extra_chart_path = "extra-chart-path.txt"
320+
# add a commit
321+
with open(extra_chart_path, "w") as f:
322+
f.write("first")
323+
324+
git_repo.git.add(extra_chart_path)
325+
sha = git_repo.index.commit("Added commit").hexsha[:7]
326+
n += 1 # added a commit
327+
tag = f"{base_version}.git.{n}.h{sha}"
328+
329+
# reset passes
330+
run_chartpress(["--reset"])
331+
# after chartpress, version is correct (with suffix)
332+
run_chartpress()
333+
assert get_chart_version() == tag
334+
335+
# tag a final release
336+
run_chartpress(["--reset"])
337+
version = "1.0.0"
338+
tbump([version])
339+
base_version = get_base_version()
340+
341+
# reset passes
342+
run_chartpress(["--reset"])
343+
344+
# chartpress gets tag version
345+
run_chartpress()
346+
assert get_chart_version() == version
347+
348+
# reset before making a commit
349+
run_chartpress(["--reset"])
350+
351+
# Add a commit (without bumping baseVersion)
352+
with open(extra_chart_path, "w") as f:
353+
f.write("second")
354+
355+
git_repo.git.add(extra_chart_path)
356+
sha = git_repo.index.commit("Added commit").hexsha[:7]
357+
n += 1 # added a commit
358+
359+
# reset balks because baseVersion hasn't been updated
360+
with pytest.raises(ValueError, match="not greater than latest tag"):
361+
run_chartpress(["--reset"])
362+
363+
# tbump next dev release (the last step of making a stable release)
364+
base_version = "1.1.0-0.dev"
365+
tbump(["--no-tag", base_version])
366+
367+
assert get_base_version() == base_version
368+
# reset is happy now
369+
run_chartpress(["--reset"])
370+
371+
# final chartpress render
372+
run_chartpress()
373+
sha = git_repo.heads.main.commit.hexsha[:7]
374+
tag = f"{base_version}.git.{n}.h{sha}"
375+
assert get_chart_version() == tag
376+
377+
247378
def test_chartpress_paths_configuration(git_repo, capfd):
248379
"""
249380
Background:

0 commit comments

Comments
 (0)