Skip to content

Commit 213b26e

Browse files
authored
Merge pull request #141 from dwhswenson/refactor-config-source
Refactor to avoid duplication of config-file source of metadata
2 parents 407876b + 995399c commit 213b26e

13 files changed

Lines changed: 382 additions & 35 deletions

File tree

autorelease/gh_actions_stages/autorelease-gh-rel.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ jobs:
2929
fi
3030
name: "Install autorelease"
3131
- run: |
32-
VERSION=`python setup.py --version`
33-
PROJECT=`python setup.py --name`
32+
VERSION=`autorelease metadata version`
33+
PROJECT=`autorelease metadata name`
3434
echo $$PROJECT $$VERSION
3535
autorelease-release --project $$PROJECT --version $$VERSION --token $$AUTORELEASE_TOKEN
3636
env:

autorelease/gh_actions_stages/autorelease-prep.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
name: "Install release tools"
4040
- run: |
4141
bump-dev-version
42-
python setup.py --version
42+
autorelease metadata version
4343
name: "Bump testpypi dev version"
4444
- run: |
4545
python setup.py sdist bdist_wheel

autorelease/scripts/bump_dev_version.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import argparse
22
import time
33

4-
try:
5-
from configparser import ConfigParser, NoSectionError, NoOptionError
6-
except ImportError:
7-
# py2
8-
from ConfigParser import ConfigParser, NoSectionError, NoOptionError
9-
10-
114
from json import JSONDecodeError
125

136
from packaging.version import Version
147
import requests
8+
from autorelease.utils import split_setup_cfg_path
9+
from autorelease.version import (
10+
ConfigParserError, get_setup_cfg, get_setup_name, get_setup_version
11+
)
1512

1613
def get_latest_pypi(package, index="https://test.pypi.org/pypi"):
1714
url = "/".join([index, package, 'json'])
@@ -60,10 +57,22 @@ def shared_parser():
6057
return parser
6158

6259
def get_version_info(conf_name, index):
63-
conf = ConfigParser()
64-
conf.read(conf_name)
65-
v_setup = conf.get('metadata', 'version')
66-
package = conf.get('metadata', 'name')
60+
directory, filename = split_setup_cfg_path(conf_name)
61+
try:
62+
conf = get_setup_cfg(directory=directory, filename=filename)
63+
except ConfigParserError as exc:
64+
raise RuntimeError(
65+
f"Unable to parse setup config: {conf_name}"
66+
) from exc
67+
if conf is None:
68+
raise RuntimeError(f"Unable to find setup config: {conf_name}")
69+
70+
v_setup = get_setup_version(conf, default_version=None)
71+
package = get_setup_name(conf, default_name=None)
72+
if v_setup is None:
73+
raise RuntimeError(f"Missing [metadata] version in {conf_name}")
74+
if package is None:
75+
raise RuntimeError(f"Missing [metadata] name in {conf_name}")
6776
v_pypi = get_latest_pypi(package, index)
6877
return conf, package, v_setup, v_pypi
6978

autorelease/scripts/cli.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
from autorelease.scripts.vendor import vendor_actions
66
from autorelease.scripts.check import run_checks
7+
from autorelease.utils import split_setup_cfg_path
8+
from autorelease.version import (
9+
ConfigParserError, get_setup_cfg, get_setup_name, get_setup_version
10+
)
711
# from autorelease import ReleaseNoteWriter
812
from autorelease.gh_api4.notes4 import NotesWriter, prs_since_latest_release
913

@@ -77,6 +81,60 @@ def auth(auth):
7781
auth = load_auth(auth)
7882
pprint(auth)
7983

84+
@cli.group()
85+
def metadata():
86+
pass
87+
88+
89+
@metadata.command(name="version")
90+
@click.option("-c", "--conf", type=str, default="setup.cfg",
91+
help="setup.cfg file to use")
92+
def metadata_version(conf):
93+
directory, filename = split_setup_cfg_path(conf)
94+
try:
95+
setup_cfg = get_setup_cfg(directory=directory, filename=filename)
96+
except ConfigParserError as exc:
97+
raise click.ClickException(
98+
f"Unable to parse setup config: {conf}"
99+
) from exc
100+
if setup_cfg is None:
101+
raise click.ClickException(
102+
f"Unable to find setup config: {conf}"
103+
)
104+
value = get_setup_version(setup_cfg, default_version=None)
105+
field = "version"
106+
107+
if value is None:
108+
raise click.ClickException(
109+
f"Missing [metadata] {field} in {conf}"
110+
)
111+
click.echo(value)
112+
113+
114+
@metadata.command(name="name")
115+
@click.option("-c", "--conf", type=str, default="setup.cfg",
116+
help="setup.cfg file to use")
117+
def metadata_name(conf):
118+
directory, filename = split_setup_cfg_path(conf)
119+
try:
120+
setup_cfg = get_setup_cfg(directory=directory, filename=filename)
121+
except ConfigParserError as exc:
122+
raise click.ClickException(
123+
f"Unable to parse setup config: {conf}"
124+
) from exc
125+
if setup_cfg is None:
126+
raise click.ClickException(
127+
f"Unable to find setup config: {conf}"
128+
)
129+
value = get_setup_name(setup_cfg, default_name=None)
130+
field = "name"
131+
132+
if value is None:
133+
raise click.ClickException(
134+
f"Missing [metadata] {field} in {conf}"
135+
)
136+
click.echo(value)
137+
80138

81139
@cli.command()
82140
@click.option('--conf', type=click.File('r'))

autorelease/tests/test_bump_dev_version.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import pytest
22
from autorelease.scripts.bump_dev_version import *
3+
import autorelease.scripts.bump_dev_version as bump_mod
4+
import autorelease.version as version_mod
35

46
def test_shared_parser():
57
parser = shared_parser()
@@ -22,3 +24,50 @@ def test_select_version(v_pypi, v_setup, expected):
2224
])
2325
def test_bump_dev_version(version_str, expected):
2426
assert bump_dev_version(version_str) == expected
27+
28+
29+
def test_get_version_info_reuses_loaded_conf(tmp_path, monkeypatch):
30+
setup_cfg = tmp_path / "setup.cfg"
31+
setup_cfg.write_text(
32+
"[metadata]\n"
33+
"name = mypkg\n"
34+
"version = 1.2.3.dev0\n"
35+
)
36+
37+
real_get_setup_cfg = bump_mod.get_setup_cfg
38+
calls = {"count": 0}
39+
40+
def counted_get_setup_cfg(*args, **kwargs):
41+
calls["count"] += 1
42+
return real_get_setup_cfg(*args, **kwargs)
43+
44+
def unexpected_get_setup_cfg(*args, **kwargs):
45+
raise AssertionError("setup.cfg was reloaded")
46+
47+
monkeypatch.setattr(bump_mod, "get_setup_cfg", counted_get_setup_cfg)
48+
monkeypatch.setattr(version_mod, "get_setup_cfg", unexpected_get_setup_cfg)
49+
monkeypatch.setattr(bump_mod, "get_latest_pypi", lambda *args: "1.2.2")
50+
51+
conf, package, v_setup, v_pypi = bump_mod.get_version_info(
52+
str(setup_cfg), "https://example.invalid/pypi"
53+
)
54+
55+
assert calls["count"] == 1
56+
assert conf.get("metadata", "name") == "mypkg"
57+
assert package == "mypkg"
58+
assert v_setup == "1.2.3.dev0"
59+
assert v_pypi == "1.2.2"
60+
61+
62+
def test_get_version_info_malformed_cfg(tmp_path):
63+
setup_cfg = tmp_path / "setup.cfg"
64+
setup_cfg.write_text(
65+
"[metadata\n"
66+
"name = badpkg\n"
67+
"version = 0.0.0\n"
68+
)
69+
70+
with pytest.raises(RuntimeError, match="Unable to parse setup config"):
71+
bump_mod.get_version_info(
72+
str(setup_cfg), "https://example.invalid/pypi"
73+
)

autorelease/tests/test_cli.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
from click.testing import CliRunner
2+
3+
import autorelease.scripts.cli as cli_mod
4+
5+
6+
def test_metadata_version(monkeypatch):
7+
monkeypatch.setattr(
8+
cli_mod, "get_setup_version",
9+
lambda _conf, default_version=None: "1.2.3"
10+
)
11+
runner = CliRunner()
12+
result = runner.invoke(cli_mod.cli, ["metadata", "version"])
13+
assert result.exit_code == 0
14+
assert result.output.strip() == "1.2.3"
15+
16+
17+
def test_metadata_name(monkeypatch):
18+
monkeypatch.setattr(
19+
cli_mod, "get_setup_name",
20+
lambda _conf, default_name=None: "mypackage"
21+
)
22+
runner = CliRunner()
23+
result = runner.invoke(cli_mod.cli, ["metadata", "name"])
24+
assert result.exit_code == 0
25+
assert result.output.strip() == "mypackage"
26+
27+
28+
def test_metadata_cli_name_and_version(tmp_path):
29+
setup_cfg = tmp_path / "setup.cfg"
30+
setup_cfg.write_text(
31+
"[metadata]\n"
32+
"name = mypkg\n"
33+
"version = 1.2.3.dev0\n"
34+
)
35+
36+
runner = CliRunner()
37+
name_result = runner.invoke(
38+
cli_mod.cli, ["metadata", "name", "--conf", str(setup_cfg)]
39+
)
40+
version_result = runner.invoke(
41+
cli_mod.cli, ["metadata", "version", "--conf", str(setup_cfg)]
42+
)
43+
44+
assert name_result.exit_code == 0
45+
assert name_result.output == "mypkg\n"
46+
assert version_result.exit_code == 0
47+
assert version_result.output == "1.2.3.dev0\n"
48+
49+
50+
def test_metadata_cli_missing_file(tmp_path):
51+
missing_cfg = tmp_path / "missing.cfg"
52+
runner = CliRunner()
53+
54+
name_result = runner.invoke(
55+
cli_mod.cli, ["metadata", "name", "--conf", str(missing_cfg)]
56+
)
57+
version_result = runner.invoke(
58+
cli_mod.cli, ["metadata", "version", "--conf", str(missing_cfg)]
59+
)
60+
61+
assert name_result.exit_code != 0
62+
assert f"Unable to find setup config: {missing_cfg}" in name_result.output
63+
assert version_result.exit_code != 0
64+
assert f"Unable to find setup config: {missing_cfg}" in version_result.output
65+
66+
67+
def test_metadata_cli_missing_fields(tmp_path):
68+
no_name_cfg = tmp_path / "setup_no_name.cfg"
69+
no_name_cfg.write_text(
70+
"[metadata]\n"
71+
"version = 2.0.0\n"
72+
)
73+
no_version_cfg = tmp_path / "setup_no_version.cfg"
74+
no_version_cfg.write_text(
75+
"[metadata]\n"
76+
"name = pkg-without-version\n"
77+
)
78+
79+
runner = CliRunner()
80+
missing_name_result = runner.invoke(
81+
cli_mod.cli, ["metadata", "name", "--conf", str(no_name_cfg)]
82+
)
83+
missing_version_result = runner.invoke(
84+
cli_mod.cli, ["metadata", "version", "--conf", str(no_version_cfg)]
85+
)
86+
87+
assert missing_name_result.exit_code != 0
88+
assert f"Missing [metadata] name in {no_name_cfg}" in missing_name_result.output
89+
assert missing_version_result.exit_code != 0
90+
assert (
91+
f"Missing [metadata] version in {no_version_cfg}"
92+
in missing_version_result.output
93+
)
94+
95+
96+
def test_metadata_cli_malformed_cfg(tmp_path):
97+
setup_cfg = tmp_path / "setup.cfg"
98+
setup_cfg.write_text(
99+
"[metadata\n"
100+
"name = badpkg\n"
101+
"version = 0.0.0\n"
102+
)
103+
104+
runner = CliRunner()
105+
name_result = runner.invoke(
106+
cli_mod.cli, ["metadata", "name", "--conf", str(setup_cfg)]
107+
)
108+
version_result = runner.invoke(
109+
cli_mod.cli, ["metadata", "version", "--conf", str(setup_cfg)]
110+
)
111+
112+
assert name_result.exit_code != 0
113+
assert f"Unable to parse setup config: {setup_cfg}" in name_result.output
114+
assert version_result.exit_code != 0
115+
assert (
116+
f"Unable to parse setup config: {setup_cfg}"
117+
in version_result.output
118+
)

autorelease/tests/test_version.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
import os
55

66

7-
from autorelease.version import _find_rel_path_for_file
7+
from autorelease.version import (
8+
ConfigParserError, _find_rel_path_for_file, get_setup_cfg,
9+
get_setup_name, get_setup_version
10+
)
811

912
@pytest.mark.parametrize("depth, result", [
1013
(0, '.'), (1, '..'), (2, '..' + os.sep + '..'),
@@ -25,3 +28,64 @@ def test_find_rel_path_for_file_finds_no_file():
2528
with mock.patch('autorelease.version.os.path.isfile', lambda x: False):
2629
assert _find_rel_path_for_file(-1, 'setup.cfg') is None
2730

31+
32+
def test_get_setup_name_and_version(tmp_path):
33+
setup_cfg = tmp_path / "setup.cfg"
34+
setup_cfg.write_text(
35+
"[metadata]\n"
36+
"name = mypkg\n"
37+
"version = 1.2.3.dev0\n"
38+
)
39+
conf = get_setup_cfg(str(tmp_path), "setup.cfg")
40+
assert get_setup_name(conf, default_name=None) == "mypkg"
41+
assert get_setup_version(conf, default_version=None) == "1.2.3.dev0"
42+
43+
44+
def test_get_setup_name_and_version_missing_file(tmp_path):
45+
default_name = "default-name"
46+
default_version = "0.0.0"
47+
conf = get_setup_cfg(str(tmp_path), "setup.cfg")
48+
assert get_setup_name(conf, default_name=default_name) == default_name
49+
assert get_setup_version(
50+
conf, default_version=default_version
51+
) == default_version
52+
53+
54+
def test_get_setup_name_and_version_missing_fields(tmp_path):
55+
setup_cfg_no_name = tmp_path / "setup_no_name.cfg"
56+
setup_cfg_no_name.write_text(
57+
"[metadata]\n"
58+
"version = 2.0.0\n"
59+
)
60+
conf_no_name = get_setup_cfg(str(tmp_path), "setup_no_name.cfg")
61+
assert get_setup_name(
62+
conf_no_name, default_name="default-name"
63+
) == "default-name"
64+
assert get_setup_version(
65+
conf_no_name, default_version=None
66+
) == "2.0.0"
67+
68+
setup_cfg_no_version = tmp_path / "setup_no_version.cfg"
69+
setup_cfg_no_version.write_text(
70+
"[metadata]\n"
71+
"name = pkg-without-version\n"
72+
)
73+
conf_no_version = get_setup_cfg(str(tmp_path), "setup_no_version.cfg")
74+
assert get_setup_version(
75+
conf_no_version, default_version="0.0.0"
76+
) == "0.0.0"
77+
assert get_setup_name(
78+
conf_no_version, default_name=None
79+
) == "pkg-without-version"
80+
81+
82+
def test_get_setup_name_and_version_malformed_cfg(tmp_path):
83+
setup_cfg = tmp_path / "setup.cfg"
84+
setup_cfg.write_text(
85+
"[metadata\n"
86+
"name = badpkg\n"
87+
"version = 0.0.0\n"
88+
)
89+
90+
with pytest.raises(ConfigParserError):
91+
get_setup_cfg(str(tmp_path), "setup.cfg")

0 commit comments

Comments
 (0)