Merge branch 'dev'

This commit is contained in:
Manuel Barkhau 2018-12-08 19:32:07 +01:00
commit 3407f95090
14 changed files with 206 additions and 135 deletions

View file

@ -231,7 +231,11 @@ if [[ -z "$DOCKER_REGISTRY_DOMAIN" ]]; then
fi
if [[ -z "$DOCKER_ROOT_IMAGE" ]]; then
DOCKER_ROOT_IMAGE=debian:stable-slim
DOCKER_ROOT_IMAGE=registry.gitlab.com/mbarkhau/bootstrapit/root
fi
if [[ -z "$DOCKER_ENV_BUILDER_IMAGE" ]]; then
DOCKER_ENV_BUILDER_IMAGE=registry.gitlab.com/mbarkhau/bootstrapit/env_builder
fi
if [[ -z "$DOCKER_REGISTRY_URL" ]]; then
@ -283,6 +287,7 @@ function format_template()
| sed "s;\${DOCKER_REGISTRY_DOMAIN};${DOCKER_REGISTRY_DOMAIN};g" \
| sed "s;\${DOCKER_REGISTRY_URL};${DOCKER_REGISTRY_URL};g" \
| sed "s;\${DOCKER_ROOT_IMAGE};${DOCKER_ROOT_IMAGE};g" \
| sed "s;\${DOCKER_ENV_BUILDER_IMAGE};${DOCKER_ENV_BUILDER_IMAGE};g" \
| sed "s;\${DOCKER_BASE_IMAGE};${DOCKER_BASE_IMAGE};g" \
| sed "s;\${PAGES_DOMAIN};${PAGES_DOMAIN};g" \
| sed "s;\${PAGES_URL};${PAGES_URL};g" \

View file

@ -12,7 +12,7 @@ for i in ${!env_paths[@]}; do
if [[ ! -f ${env_path_python} ]]; then
echo "conda create --name ${env_name} ${py_version} ...";
${CONDA_BIN} create --name ${env_name} ${py_version} --yes --quiet;
${CONDA_BIN} create --name ${env_name} --channel conda-forge ${py_version} --yes --quiet;
fi;
echo "updating ${env_name} conda deps ...";

View file

@ -10,10 +10,7 @@ CLI module for PyCalVer.
Provided subcommands: show, incr, init, bump
"""
import io
import os
import sys
import toml
import click
import logging
import typing as typ
@ -144,16 +141,16 @@ def init(verbose: int = 0, dry: bool = False) -> None:
cfg: config.MaybeConfig = config.parse(ctx)
if cfg:
log.error("Configuration already initialized in {cfg.filename}")
log.error("Configuration already initialized in {ctx.config_filepath}")
sys.exit(1)
if dry:
print("Exiting because of '--dry'. Would have written to setup.cfg:")
cfg_lines = config.default_config(output_fmt)
cfg_lines = config.default_config(ctx)
print("\n " + "\n ".join(cfg_lines))
return
config.write_default_config()
config.write_content(ctx)
def _assert_not_dirty(vcs, filepaths: typ.Set[str], allow_dirty: bool):

View file

@ -22,6 +22,8 @@ log = logging.getLogger("pycalver.config")
PatternsByFilePath = typ.Dict[str, typ.List[str]]
SUPPORTED_CONFIGS = ["setup.cfg", "pyproject.toml", "pycalver.toml"]
class ProjectContext(typ.NamedTuple):
"""Container class for project info."""
@ -49,6 +51,8 @@ def init_project_ctx(project_path: typ.Union[str, pl.Path, None] = ".") -> Proje
config_filepath = path / "pycalver.toml"
config_format = 'toml'
vcs_type: typ.Optional[str]
if (path / ".git").exists():
vcs_type = 'git'
elif (path / ".hg").exists():
@ -70,7 +74,7 @@ class Config(typ.NamedTuple):
tag : bool
commit: bool
push: bool
push : bool
file_patterns: PatternsByFilePath
@ -95,13 +99,12 @@ def _debug_str(cfg: Config) -> str:
MaybeConfig = typ.Optional[Config]
MaybeRawConfig = typ.Optional[RawConfig]
FilePatterns = typ.Dict[str, typ.List[str]]
def _parse_cfg_file_patterns(
cfg_parser: configparser.RawConfigParser,
) -> FilePatterns:
def _parse_cfg_file_patterns(cfg_parser: configparser.RawConfigParser,) -> FilePatterns:
file_patterns: FilePatterns = {}
@ -117,14 +120,26 @@ def _parse_cfg_file_patterns(
return file_patterns
def _parse_cfg_option(option_name):
# preserve uppercase filenames
return option_name
class _ConfigParser(configparser.RawConfigParser):
"""Custom parser, simply to override optionxform behaviour."""
def optionxform(self, optionstr: str) -> str:
"""Non-xforming (ie. uppercase preserving) override.
This is important because our option names are actually
filenames, so case sensitivity is relevant. The default
behaviour is to do optionstr.lower()
"""
return optionstr
OptionVal = typ.Union[str, bool, None]
BOOL_OPTIONS: typ.Mapping[str, OptionVal] = {'commit': False, 'tag': None, 'push': None}
def _parse_cfg(cfg_buffer: typ.TextIO) -> RawConfig:
cfg_parser = configparser.RawConfigParser()
cfg_parser.optionxform = _parse_cfg_option
cfg_parser = _ConfigParser()
if hasattr(cfg_parser, 'read_file'):
cfg_parser.read_file(cfg_buffer)
@ -132,21 +147,15 @@ def _parse_cfg(cfg_buffer: typ.TextIO) -> RawConfig:
cfg_parser.readfp(cfg_buffer) # python2 compat
if not cfg_parser.has_section("pycalver"):
log.error("Missing [pycalver] section.")
return None
raise ValueError("Missing [pycalver] section.")
raw_cfg = dict(cfg_parser.items("pycalver"))
raw_cfg: RawConfig = dict(cfg_parser.items("pycalver"))
raw_cfg['commit'] = raw_cfg.get('commit', False)
raw_cfg['tag' ] = raw_cfg.get('tag' , None)
raw_cfg['push' ] = raw_cfg.get('push' , None)
if isinstance(raw_cfg['commit'], str):
raw_cfg['commit'] = raw_cfg['commit'].lower() in ("yes", "true", "1", "on")
if isinstance(raw_cfg['tag'], str):
raw_cfg['tag'] = raw_cfg['tag'].lower() in ("yes", "true", "1", "on")
if isinstance(raw_cfg['push'], str):
raw_cfg['push'] = raw_cfg['push'].lower() in ("yes", "true", "1", "on")
for option, default_val in BOOL_OPTIONS.items():
val: OptionVal = raw_cfg.get(option, default_val)
if isinstance(val, str):
val = val.lower() in ("yes", "true", "1", "on")
raw_cfg[option] = val
raw_cfg['file_patterns'] = _parse_cfg_file_patterns(cfg_parser)
@ -157,9 +166,8 @@ def _parse_toml(cfg_buffer: typ.TextIO) -> RawConfig:
raw_full_cfg = toml.load(cfg_buffer)
raw_cfg = raw_full_cfg.get('pycalver', {})
raw_cfg['commit'] = raw_cfg.get('commit', False)
raw_cfg['tag' ] = raw_cfg.get('tag' , None)
raw_cfg['push' ] = raw_cfg.get('push' , None)
for option, default_val in BOOL_OPTIONS.items():
raw_cfg[option] = raw_cfg.get(option, default_val)
return raw_cfg
@ -208,8 +216,6 @@ def parse(ctx: ProjectContext) -> MaybeConfig:
log.error(f"File not found: {ctx.config_filepath}")
return None
raw_cfg: typ.Optional[RawConfig]
try:
with ctx.config_filepath.open(mode="rt", encoding="utf-8") as fh:
if ctx.config_format == 'toml':
@ -231,6 +237,7 @@ current_version = "{initial_version}"
commit = True
tag = True
push = True
[pycalver:file_patterns]
"""
@ -268,6 +275,7 @@ current_version = "{initial_version}"
commit = true
tag = true
push = true
[pycalver.file_patterns]
"""
@ -312,7 +320,8 @@ DEFAULT_TOML_README_MD_STR = """
def default_config(ctx: ProjectContext) -> str:
"""Generate initial default config."""
if ctx.config_format == 'cfg':
fmt = ctx.config_format
if fmt == 'cfg':
base_str = DEFAULT_CONFIGPARSER_BASE_STR
default_pattern_strs_by_filename = {
@ -321,7 +330,7 @@ def default_config(ctx: ProjectContext) -> str:
"README.rst": DEFAULT_CONFIGPARSER_README_RST_STR,
"README.md" : DEFAULT_CONFIGPARSER_README_MD_STR,
}
elif ctx.config_format == 'toml':
elif fmt == 'toml':
base_str = DEFAULT_TOML_BASE_STR
default_pattern_strs_by_filename = {
@ -332,7 +341,7 @@ def default_config(ctx: ProjectContext) -> str:
"README.md" : DEFAULT_TOML_README_MD_STR,
}
else:
raise ValueError(f"Invalid fmt='{fmt}', must be either 'toml' or 'cfg'.")
raise ValueError(f"Invalid config_format='{fmt}', must be either 'toml' or 'cfg'.")
initial_version = dt.datetime.now().strftime("v%Y%m.0001-dev")
@ -342,11 +351,7 @@ def default_config(ctx: ProjectContext) -> str:
if (ctx.path / filename).exists():
cfg_str += default_str
has_config_file = (
(ctx.path / "setup.cfg").exists() or
(ctx.path / "pyproject.toml").exists() or
(ctx.path / "pycalver.toml").exists()
)
has_config_file = any((ctx.path / fn).exists() for fn in SUPPORTED_CONFIGS)
if not has_config_file:
if ctx.config_format == 'cfg':
@ -359,7 +364,14 @@ def default_config(ctx: ProjectContext) -> str:
return cfg_str
def write_content(cfg: Config) -> None:
def write_content(ctx: ProjectContext) -> None:
"""Update project config file with initial default config."""
# path : pl.Path
# config_filepath: pl.Path
# config_format : str
# vcs_type : typ.Optional[str]
cfg_lines = default_config(ctx)
cfg_content = "\n" + "\n".join(cfg_lines)
if os.path.exists("pyproject.toml"):
with io.open("pyproject.toml", mode="at", encoding="utf-8") as fh:

View file

@ -152,6 +152,7 @@ def diff(new_version: str, file_patterns: config.PatternsByFilePath) -> str:
content = fh.read()
rfd = rfd_from_content(patterns, new_version, content)
rfd = rfd._replace(path=file_path)
full_diff += "\n".join(diff_lines(rfd)) + "\n"
full_diff = full_diff.rstrip("\n")

View file

@ -1,10 +1,16 @@
[pycalver]
current_version = "{initial_version}"
current_version = "v201710.0123-alpha"
commit = true
tag = true
push = true
[pycalver.file_patterns]
"pycalver.toml" = [
'current_version = "{version}"',
]
"README.md" = [
"{version}",
"{pep440_version}",
]

13
test/fixtures/project_b/setup.cfg vendored Normal file
View file

@ -0,0 +1,13 @@
[pycalver]
current_version = v201307.0456-beta
commit = True
tag = True
push = True
[pycalver:file_patterns]
setup.cfg =
current_version = {version}
setup.py =
version="{pep440_version}"
README.rst =
img.shields.io/badge/PyCalVer-{calver}{build}--{release}-blue

3
test/fixtures/project_b/setup.py vendored Normal file
View file

@ -0,0 +1,3 @@
import setuptools
setuptools.setup(name="mylib", license="MIT", version="201307.456b0", keywords="awesome library")

View file

@ -2,18 +2,18 @@ import io
from pycalver import config
from . import util as test_util
from . import util
PYCALVER_TOML_FIXTURE = """
[pycalver]
current_version = "v201808.0123-dev"
current_version = "v201808.0123-alpha"
commit = true
tag = true
push = true
[pycalver.file_patterns]
"setup.py" = [
"README.md" = [
"{version}",
"{pep440_version}",
]
@ -25,7 +25,7 @@ push = true
SETUP_CFG_FIXTURE = """
[pycalver]
current_version = "v201808.0456-dev"
current_version = "v201808.0456-beta"
commit = True
tag = True
push = True
@ -52,13 +52,13 @@ def test_parse_toml():
raw_cfg = config._parse_toml(buf)
cfg = config._parse_config(raw_cfg)
assert cfg.current_version == "v201808.0123-dev"
assert cfg.current_version == "v201808.0123-alpha"
assert cfg.commit is True
assert cfg.tag is True
assert cfg.push is True
assert "pycalver.toml" in cfg.file_patterns
assert cfg.file_patterns["setup.py" ] == ["{version}", "{pep440_version}"]
assert cfg.file_patterns["README.md" ] == ["{version}", "{pep440_version}"]
assert cfg.file_patterns["pycalver.toml"] == ['current_version = "{version}"']
@ -68,7 +68,7 @@ def test_parse_cfg():
raw_cfg = config._parse_cfg(buf)
cfg = config._parse_config(raw_cfg)
assert cfg.current_version == "v201808.0456-dev"
assert cfg.current_version == "v201808.0456-beta"
assert cfg.commit is True
assert cfg.tag is True
assert cfg.push is True
@ -79,76 +79,144 @@ def test_parse_cfg():
def test_parse_default_toml():
project_path = test_util.FIXTURES_DIR / "project_a"
config_path = test_util.FIXTURES_DIR / "project_a" / "pycalver.toml"
project_path = util.FIXTURES_DIR / "project_a"
ctx = config.ProjectContext(project_path, config_path, "toml", None)
buf = mk_buf(config.default_config(ctx))
ctx = config.init_project_ctx(project_path)
default_toml = config.default_config(ctx)
buf = mk_buf(default_toml)
raw_cfg = config._parse_toml(buf)
cfg = config._parse_config(raw_cfg)
assert cfg
assert cfg.current_version.endswith(".0001-dev")
assert cfg.commit is True
assert cfg.tag is True
assert cfg.push is True
assert "setup.py" in cfg.file_patterns
assert "README.md" in cfg.file_patterns
assert "pycalver.toml" in cfg.file_patterns
def test_parse_default_cfg():
project_path = test_util.FIXTURES_DIR / "project_a"
config_path = test_util.FIXTURES_DIR / "project_a" / "setup.cfg"
project_path = util.FIXTURES_DIR / "project_b"
ctx = config.ProjectContext(project_path, config_path, "cfg", None)
buf = mk_buf(config.default_config(ctx))
ctx = config.init_project_ctx(project_path)
default_cfg = config.default_config(ctx)
buf = mk_buf(default_cfg)
raw_cfg = config._parse_cfg(buf)
cfg = config._parse_config(raw_cfg)
assert cfg
assert cfg.current_version.endswith(".0001-dev")
def test_parse_project_toml():
project_path = util.FIXTURES_DIR / "project_a"
config_path = util.FIXTURES_DIR / "project_a" / "pycalver.toml"
with config_path.open() as fh:
config_data = fh.read()
assert "v201710.0123-alpha" in config_data
ctx = config.init_project_ctx(project_path)
assert ctx == config.ProjectContext(project_path, config_path, "toml", None)
cfg = config.parse(ctx)
assert cfg
assert cfg.current_version == "v201710.0123-alpha"
assert cfg.commit is True
assert cfg.tag is True
assert cfg.push is True
assert "setup.py" in cfg.file_patterns
assert "README.md" in cfg.file_patterns
assert "setup.cfg" in cfg.file_patterns
assert set(cfg.file_patterns.keys()) == {"pycalver.toml", "README.md"}
def test_parse_project_cfg():
project_path = util.FIXTURES_DIR / "project_b"
config_path = util.FIXTURES_DIR / "project_b" / "setup.cfg"
with config_path.open() as fh:
config_data = fh.read()
assert "v201307.0456-beta" in config_data
ctx = config.init_project_ctx(project_path)
assert ctx == config.ProjectContext(project_path, config_path, 'cfg', None)
cfg = config.parse(ctx)
assert cfg
assert cfg.current_version == "v201307.0456-beta"
assert cfg.commit is True
assert cfg.tag is True
assert cfg.push is True
assert set(cfg.file_patterns.keys()) == {"setup.py", "README.rst", "setup.cfg"}
def test_parse_toml_file(tmpdir):
project_path = tmpdir.mkdir("minimal")
setup_cfg = project_path.join("pycalver.toml")
setup_cfg.write(PYCALVER_TOML_FIXTURE)
ctx = config.init_project_ctx(project_path)
assert ctx == config.ProjectContext(project_path, setup_cfg, 'toml', None)
cfg = config.parse(ctx)
assert cfg
assert cfg.current_version == "v201808.0123-alpha"
assert cfg.tag is True
assert cfg.commit is True
assert cfg.push is True
assert cfg.file_patterns == {
"README.md" : ["{version}", "{pep440_version}"],
"pycalver.toml": ['current_version = "{version}"'],
}
def test_parse_cfg_file(tmpdir):
setup_path = tmpdir.mkdir("minimal").join("setup.cfg")
setup_path.write(SETUP_CFG_FIXTURE)
project_path = tmpdir.mkdir("minimal")
setup_cfg = project_path.join("setup.cfg")
setup_cfg.write(SETUP_CFG_FIXTURE)
cfg = config.parse(str(setup_path))
ctx = config.init_project_ctx(project_path)
assert ctx == config.ProjectContext(project_path, setup_cfg, 'cfg', None)
cfg = config.parse(ctx)
assert cfg
assert cfg.current_version == "v201808.0001-dev"
assert not cfg.tag
assert not cfg.commit
assert cfg.current_version == "v201808.0456-beta"
assert cfg.tag is True
assert cfg.commit is True
assert cfg.push is True
assert cfg.file_patterns == {"setup.cfg": ["current_version = {version}"]}
assert cfg.file_patterns == {
"setup.py" : ["{version}", "{pep440_version}"],
"setup.cfg": ['current_version = "{version}"'],
}
def test_parse_config_missing(tmpdir):
cfg = config.parse("does_not_exist/setup.cfg")
ctx = config.init_project_ctx("does_not_exist/setup.cfg")
assert ctx
cfg = config.parse(ctx)
assert cfg is None
setup_path = tmpdir.mkdir("fail").join("setup.cfg")
ctx = config.init_project_ctx(setup_path)
assert ctx
cfg = config.parse(str(setup_path))
cfg = config.parse(ctx)
assert cfg is None
def test_parse_empty_config(tmpdir):
setup_path = tmpdir.mkdir("fail").join("setup.cfg")
setup_path.write("")
ctx = config.init_project_ctx(setup_path)
assert ctx
cfg = config.parse(str(setup_path))
cfg = config.parse(ctx)
assert cfg is None
@ -164,7 +232,10 @@ def test_parse_missing_version(tmpdir):
)
)
cfg = config.parse(str(setup_path))
ctx = config.init_project_ctx(setup_path)
assert ctx
cfg = config.parse(ctx)
assert cfg is None
@ -172,5 +243,8 @@ def test_parse_invalid_version(tmpdir):
setup_path = tmpdir.mkdir("fail").join("setup.cfg")
setup_path.write("\n".join(("[pycalver]", "current_version = 0.1.0", "commit = False")))
cfg = config.parse(str(setup_path))
ctx = config.init_project_ctx(setup_path)
assert ctx
cfg = config.parse(ctx)
assert cfg is None

View file

@ -169,21 +169,25 @@ def test_badge_parse_patterns():
assert matches[1].match == ":alt: CalVer v201809.0002-beta"
def test_parse_error():
def test_parse_error_empty():
try:
parse.VersionInfo.parse("")
parse.parse_version_info("")
assert False
except ValueError as err:
pass
def test_parse_error_noprefix():
try:
parse.VersionInfo.parse("201809.0002")
parse.parse_version_info("201809.0002")
assert False
except ValueError as err:
pass
def test_parse_error_nopadding():
try:
parse.VersionInfo.parse("v201809.2b0")
parse.parse_version_info("v201809.2b0")
assert False
except ValueError as err:
pass

View file

@ -1,18 +0,0 @@
#!/bin/bash
set -e
if [[ $(python -c "import sys;sys.exit(sys.version[:3] < '3.6')") ]]; then
python --version
python -m pip install setuptools lib3to6
python setup.py bdist_wheel --python-tag=py2.py3
else
curl -sSf -o python-3.6.tar.bz2 https://s3.amazonaws.com/travis-python-archives/binaries/ubuntu/16.04/x86_64/python-3.6.tar.bz2
tar xjf python-3.6.tar.bz2 --directory /
source $HOME/virtualenv/python3.6.0/bin/activate
python3.6 --version
python3.6 -m pip install setuptools lib3to6
python3.6 setup.py bdist_wheel --python-tag=py2.py3
fi

View file

@ -1,26 +0,0 @@
#!/bin/bash
set -e
# minimal test requirements for py27 testing
python -m pip install -U pip
python -m pip install pytest rst2html5
rst2html5 --strict README.rst > /dev/null
rst2html5 --strict CHANGELOG.rst > /dev/null
# first test module from installed wheel
python -m pip install $(ls -1t dist/pycalver*.whl | head -n 1)
grep 'coding: utf-8' $(python -c 'import pycalver;print(pycalver.__file__.replace(".pyc", ".py"))')
python -m pytest test/
if [[ $(python -c "import sys;sys.exit(sys.version[:3] < '3.6')") ]]; then
python -m pip install $(cat requirements-test.txt)
python -m flake8 src/pycalver/
MYPYPATH=stubs/ python -m mypy src/pycalver/;
# next test module from src/
PYTHONPATH=src/:$PYTHONPATH python -m pytest --cov=pycalver test/;
codecov
fi