def check_pyproject_toml(): """Check pyproject.toml.""" check_path("pyproject.toml") errors = 0 try: last_release = semantic_version.Version(CONFIG["last_release"]) except ValueError: errors += err( f"last_release is not a valid semantic version: {CONFIG['last_release']}" ) return errors # Get list of all semantic version tags repo = git.Repo() tags = sorted( semantic_version.Version(t.name) for t in repo.tags if semantic_version.validate(t.name)) if not tags: # not present in GitHub actions return errors if not last_release == tags[-1]: errors += err( f"last_release does not match last git tag: {last_release} vs. {tags[-1]}" ) return errors
def check_tox(): """Check tox.ini.""" errors = 0 check_path("tox.ini") tox_config = configparser.ConfigParser() tox_config.read(os.path.join(ROOT_DIR, "tox.ini")) # Mapping of additional testenv specific requirements tox_deps = tox_config["testenv"]["deps"].splitlines() tox_env_reqs = dict( [line.split(": ", 1) for line in tox_deps if ": " in line]) # Check that there is a testenv listing all versions # pylint: disable=consider-using-f-string # this line is just ugly otherwise # expected_envlist = "py{%s}-django{%s}-cryptography{%s}-acme{%s}-idna{%s}" % ( # ",".join([pyver.replace(".", "") for pyver in CONFIG["python-map"]]), # ",".join(CONFIG["django-map"]), # ",".join(CONFIG["cryptography-map"]), # ",".join(CONFIG["acme-map"]), # ",".join(CONFIG["idna-map"]), # ) # pylint: enable=consider-using-f-string # Check disabled as long as different Django versions support different Python versions # if expected_envlist not in tox_config["tox"]["envlist"].splitlines(): # errors += err(f"Expected envlist item not found: {expected_envlist}") # Check that conditional dependencies are up to date for component in ["django", "cryptography", "acme", "idna"]: # First, check if there are any left over conditional settings for this component errors += simple_diff( f"{component} conditional dependencies present", [e for e in tox_env_reqs if e.startswith(component)], [f"{component}{major}" for major in CONFIG[f"{component}-map"]], ) for major, minor in CONFIG[f"{component}-map"].items(): name = f"{component}{major}" try: actual = tox_env_reqs[name] except KeyError: errors += err(f"{name}: Conditional dependency not found.") continue expected = f"{CANONICAL_PYPI_NAMES[component]}=={minor}" if name not in tox_env_reqs: continue # handled in simple-diff above if actual != expected: errors += err( f"conditional dependency for {name}: Have {actual}, expected {expected}." ) return errors
def check_readme(): """Check contents of README.md.""" errors = 0 check_path("README.md") readme_fullpath = os.path.join(ROOT_DIR, "README.md") with open(readme_fullpath, encoding="utf-8") as stream: readme = stream.read() if f"{exp_version_line}" not in readme: errors += err('Does not contain correct version line ("Written in ...").') return errors
def check_intro(): """Check intro.rst (reused in a couple of places).""" errors = 0 intro_path = os.path.join("docs", "source", "intro.rst") intro_fullpath = os.path.join(ROOT_DIR, intro_path) check_path(intro_path) with open(intro_fullpath, encoding="utf-8") as stream: intro = stream.read() if f"#. {exp_version_line}" not in intro.splitlines(): errors += err('Does not contain correct version line ("Written in ...").') return errors
def check_setup_cfg(): """Check setup.cfg""" check_path("setup.cfg") errors = 0 setup_config = read_configuration(os.path.join(ROOT_DIR, "setup.cfg")) # parse data from setup.cfg classifiers = setup_config["metadata"]["classifiers"] install_requires = setup_config["options"]["install_requires"] # validate that we have the proper language/django classifiers pyver_cfs = [ m.groups(0)[0] for m in filter( None, [re.search(r"Python :: (3\.[0-9]+)$", cf) for cf in classifiers]) ] if pyver_cfs != CONFIG["python-major"]: errors += err( f'Wrong python classifiers: Have {pyver_cfs}, wanted {CONFIG["python-major"]}' ) djver_cfs = [ m.groups(0)[0] for m in filter(None, [ re.search(r"Django :: ([0-9]\.[0-9]+)$", cf) for cf in classifiers ]) ] if djver_cfs != CONFIG["django-major"]: errors += err( f'Wrong python classifiers: Have {djver_cfs}, wanted {CONFIG["django-major"]}' ) for djver in CONFIG["django-map"]: if f"Framework :: Django :: {djver}" not in classifiers: errors += err(f"Django {djver} classifier not found.") expected_py_req = f">={CONFIG['python-major'][0]}" actual_py_req = setup_config["options"]["python_requires"] if actual_py_req != expected_py_req: errors += err( f"python_requires: Have {actual_py_req}, expected {expected_py_req}" ) expected_django_req = f"Django>={CONFIG['django-major'][0]}" if expected_django_req not in install_requires: errors += err( f"{expected_django_req}: Expected Django requirement not found.") expected_cg_req = f"cryptography>={CONFIG['cryptography-major'][0]}" if expected_cg_req not in install_requires: errors += err( f"{expected_cg_req}: Expected cryptography requirement not found.") # Do not check setup.cfg minimum dependency, as actually any version works fine right now # expected_idna_req = f"idna>={CONFIG['idna-major'][0]}" # if expected_idna_req not in install_requires: # errors += err(f"{expected_idna_req}: Expected idna requirement not found.") return errors
def check_test_settings(): """Check test_settings.py""" relpath = os.path.join("ca", "ca", "test_settings.py") fullpath = os.path.join(ROOT_DIR, relpath) check_path(relpath) errors = 0 test_settings = import_mod("test_settings", fullpath) for component in ["python", "django", "cryptography"]: config_key = f"{component}-map" setting = f"NEWEST_{component.upper()}_VERSION" value = getattr(test_settings, setting) expected = tuple(int(e) for e in list(CONFIG[config_key])[-1].split(".")) if value == expected: ok(f"{setting} = {value}") else: errors += err(f"{setting}: Have {value}, expected {expected}") return errors
def simple_diff(what, actual, expected) -> int: """Simply compare two values and output any difference.""" if expected == actual: return ok(what) return err(f"{what}: Have {actual}, expected {expected}.")