Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

accept non-prerelease baseVersion (append -0.dev) #184

Merged
merged 3 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ charts:
# This gives you more control over development version tags
# and lets you ensure prerelease tags are always sorted in the right order.
# Only useful when publishing development releases.
# Recommended together with a version-bumping tool like `tbump`.
# if baseVersion is not a prerelease version (no -suffix),
# the suffix `-0.dev` will be appended.
baseVersion: 3.2.1-0.dev

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

2. You must update baseVersion, especially after making a release.
We recommend using a version bumping tool like [tbump][] to keep your baseVersion config and git tags in sync.

[tbump]: https://github.com/your-tools/tbump

A release process would generally look like this:

```bash
V=1.2.3
git tag -am "release $V" "$V"
git push --atomic --follow-tags
# tbump updates version, commits changes, tags commit, pushes branch and tag
tbump "$V"

# back to development
NEXT_V=1.2.4-0.dev
# edit chartpress.yaml to set baseVersion: $NEXT_V
git add chartpress.yaml
git commit -m "Back to $NEXT_V"
git push --atomic
# bump version config, but no tag for starting development
tbump --no-tag "${NEXT_V}"
```

Any prerelease fields (such as `-0.dev` above, or `-alpha.1`)
will be left as-is, with the `.git.n.hash` suffix added.
If there is no prerelease (e.g. on the exact commit of a tagged release),
`-0.dev` will be added to the base version.
You **must** update baseVersion after making a release,
or `chartpress --reset` will fail due to incorrect ordering of versions.

A sample tbump config file can be found in [our tests](./tests/test_helm_chart/tbump.toml).

## Caveats

Expand Down
15 changes: 9 additions & 6 deletions chartpress.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,17 +976,17 @@ def _check_base_version(base_version):
2. sort after the latest tag on the branch
"""

if "-" not in base_version:
# config version is a stable release,
# append default '-0.dev' so we always produce a prerelease
base_version = f"{base_version}-0.dev"
# check valid value (baseVersion must be semver prerelease)
match = _semver2.fullmatch(base_version)
if not match:
raise ValueError(
f"baseVersion: {base_version} must be a valid semver prerelease (e.g. 1.2.3-0.dev), but doesn't appear to be valid."
f"baseVersion: {base_version} must be a valid semver version (e.g. 1.2.3-0.dev), but doesn't appear to be valid."
)
base_version_groups = match.groupdict()
if not base_version_groups["prerelease"]:
raise ValueError(
f"baseVersion: {base_version} must be a valid semver prerelease (e.g. 1.2.3-0.dev), but is not a prerelease."
)

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

# return base_version, in case it was modified
return base_version


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

if not args.list_images:
# update Chart.yaml with a version
Expand Down
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ gitpython
pre-commit
pytest
pytest-cov
tbump
14 changes: 14 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,20 @@ def git_repo_alternative(monkeypatch, git_repo):
yield r


@pytest.fixture
def git_repo_base_version(monkeypatch, git_repo):
"""
This fixture modifies the default git_repo fixture to use another the
chartpress_alternative.yaml as chartpress.yaml.
"""
r = git_repo
shutil.move("chartpress_base_version.yaml", "chartpress.yaml")
r.git.add(all=True)
r.index.commit("chartpress_base_version.yaml initial commit")

yield r


class MockCheckCall:
def __init__(self):
self.commands = []
Expand Down
15 changes: 15 additions & 0 deletions tests/test_helm_chart/chartpress_base_version.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
charts:
- name: testchart
baseVersion: "1.0.0-0.dev"
resetTag: test-reset-tag
resetVersion: 0.0.1-test.reset.version
imagePrefix: testchart/
paths:
- extra-chart-path.txt
images:
testimage:
dockerfilePath: image/Dockerfile
valuesPath:
- image
paths:
- extra-image-path.txt
35 changes: 35 additions & 0 deletions tests/test_helm_chart/tbump.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# tbump config sets baseVersion in chartpress.yaml
[version]
current = "1.0.0-0.dev"

# match our prerelease prefixes
# -alpha.1
# -beta.2
# -0.dev

regex = '''
(?P<major>\d+)
\.
(?P<minor>\d+)
\.
(?P<patch>\d+)
(\-
(?P<prelease>
(
(alpha|beta|rc)\.\d+|
0\.dev
)
)
)?
'''

[git]
message_template = "Bump to {new_version}"
tag_template = "{new_version}"

# For each file to patch, add a [[file]] config
# section containing the path of the file, relative to the
# tbump.toml location.
[[file]]
src = "chartpress.yaml"
search = 'baseVersion: "{current_version}"'
35 changes: 18 additions & 17 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,35 +162,36 @@ def test__get_image_extra_build_command_options(git_repo):


@pytest.mark.parametrize(
"base_version, tag, n_commits, status",
"base_version, tag, n_commits, result",
[
# OK, normal state
("1.2.4-0.dev", "1.2.3", 10, "ok"),
("1.2.4-0.dev", "1.2.3", 10, "1.2.4-0.dev"),
# don't compare prereleases on the same tag
("1.2.3-0.dev", "1.2.3-alpha.1", 10, "ok"),
("1.2.3-0.dev", "1.2.3-alpha.1", 10, "1.2.3-0.dev"),
# invalid baseVersion (not semver)
("x.y.z", "1.2.3", 10, "valid semver prerelease"),
("x.y.z", "1.2.3", 10, ValueError("valid semver version")),
# not prerelease baseVersion
("1.2.4", "1.2.3", 10, "valid semver prerelease"),
("1.2.4", "1.2.3", 10, "1.2.4-0.dev"),
# check comparison with tag
("1.2.2-0.dev", "1.2.3-alpha.1", 10, "is not greater"),
("1.2.3-0.dev", "1.2.3", 10, "is not greater"),
("1.2.3-0.dev", "2.0.0", 10, "is not greater"),
("1.2.3-0.dev", "1.2.4-alpha.1", 10, "is not greater"),
("1.2.2-0.dev", "1.2.3-alpha.1", 10, ValueError("is not greater")),
("1.2.3-0.dev", "1.2.3", 10, ValueError("is not greater")),
("1.2.3-0.dev", "2.0.0", 10, ValueError("is not greater")),
("1.2.3-0.dev", "1.2.4-alpha.1", 10, ValueError("is not greater")),
# don't check exactly on a tag
("1.2.3-0.dev", "2.0.0", 0, "ok"),
("1.2.3-0.dev", "2.0.0", 0, "1.2.3-0.dev"),
# ignore invalid semver tags
("1.2.3-0.dev", "x.y.z", 10, "ok"),
("1.2.3-0.dev", "x.y.z", 10, "1.2.3-0.dev"),
],
)
def test_check_base_version(base_version, tag, n_commits, status):
def test_check_base_version(base_version, tag, n_commits, result):
with mock.patch.object(
chartpress, "_get_latest_tag_and_count", lambda: (tag, n_commits)
):
if status == "ok":
chartpress._check_base_version(base_version)
else:
with pytest.raises(ValueError) as exc:
if isinstance(result, Exception):
with pytest.raises(result.__class__) as exc:
chartpress._check_base_version(base_version)
assert status in str(exc)
assert str(result) in str(exc)
assert base_version in str(exc)
else:
used_version = chartpress._check_base_version(base_version)
assert used_version == result
131 changes: 131 additions & 0 deletions tests/test_repo_interactions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import subprocess
import sys

import pytest
Expand Down Expand Up @@ -244,6 +245,136 @@ def test_chartpress_run(git_repo, capfd, base_version):
git_repo.git.stash("pop")


def test_tbump_release(git_repo, git_repo_base_version, capfd):
"""Run through tagging"""

def get_base_version():
"""Get baseVersion config from chartpress.yaml"""
with open("chartpress.yaml") as f:
chartpress_config = yaml.load(f)

chart = chartpress_config["charts"][0]
return chart["baseVersion"]

def get_chart_version():
"""Get the current version in Chart.yaml"""
with open("testchart/Chart.yaml") as f:
chart = yaml.load(f)
return chart["version"]

# run chartpress with --no-build and any additional arguments
def run_chartpress(args=None):
"""run chartpress with --no-build and any additional arguments"""
if args is None:
args = []
if args != ["--reset"]:
args = ["--no-build"] + args
out = _capture_output(args, capfd)
print(out)
return out

def tbump(args):
"""Run tbump with args"""
subprocess.run(["git", "status"])
proc = subprocess.run(
["tbump", "--non-interactive", "--no-push"] + args,
capture_output=True,
text=True,
)
# echo output before checking return code
# so we see it on errors
sys.stdout.write(proc.stdout)
sys.stderr.write(proc.stderr)
assert proc.returncode == 0
# increment commit count because tbump makes a commit
nonlocal n
n += 1
return proc.stdout, proc.stderr

base_version = get_base_version()
assert base_version == "1.0.0-0.dev"

# summarize information from git_repo
sha = git_repo.commit("HEAD").hexsha[:7]
n = chartpress._count_commits(sha)
tag = f"{base_version}.git.{n}.h{sha}"
run_chartpress()
assert get_chart_version() == tag

# tag a prerelease
run_chartpress(["--reset"])
version = "1.0.0-beta.1"
with open("chartpress.yaml") as f:
print(f.read())
tbump([version])
base_version = get_base_version()
assert base_version == version

# reset passes
run_chartpress(["--reset"])
# after chartpress, version is correct (no suffix)
run_chartpress()
assert get_chart_version() == version

extra_chart_path = "extra-chart-path.txt"
# add a commit
with open(extra_chart_path, "w") as f:
f.write("first")

git_repo.git.add(extra_chart_path)
sha = git_repo.index.commit("Added commit").hexsha[:7]
n += 1 # added a commit
tag = f"{base_version}.git.{n}.h{sha}"

# reset passes
run_chartpress(["--reset"])
# after chartpress, version is correct (with suffix)
run_chartpress()
assert get_chart_version() == tag

# tag a final release
run_chartpress(["--reset"])
version = "1.0.0"
tbump([version])
base_version = get_base_version()

# reset passes
run_chartpress(["--reset"])

# chartpress gets tag version
run_chartpress()
assert get_chart_version() == version

# reset before making a commit
run_chartpress(["--reset"])

# Add a commit (without bumping baseVersion)
with open(extra_chart_path, "w") as f:
f.write("second")

git_repo.git.add(extra_chart_path)
sha = git_repo.index.commit("Added commit").hexsha[:7]
n += 1 # added a commit

# reset balks because baseVersion hasn't been updated
with pytest.raises(ValueError, match="not greater than latest tag"):
run_chartpress(["--reset"])

# tbump next dev release (the last step of making a stable release)
base_version = "1.1.0-0.dev"
tbump(["--no-tag", base_version])

assert get_base_version() == base_version
# reset is happy now
run_chartpress(["--reset"])

# final chartpress render
run_chartpress()
sha = git_repo.heads.main.commit.hexsha[:7]
tag = f"{base_version}.git.{n}.h{sha}"
assert get_chart_version() == tag


def test_chartpress_paths_configuration(git_repo, capfd):
"""
Background:
Expand Down