Exemplo n.º 1
0
def make_actions_deploy_conda(repo_path: pathlib.Path,
                              templates: Environment) -> List[str]:
    """
	Add script to build Conda package and deploy to Anaconda.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    old_deploy_file = PathPlus(repo_path / ".ci" / "actions_deploy_conda.sh")
    old_build_file = PathPlus(repo_path / ".ci" / "actions_build_conda.sh")
    old_deploy_file.unlink(missing_ok=True)
    old_build_file.unlink(missing_ok=True)

    deploy_file = PathPlus(repo_path / ".github" / "actions_deploy_conda.sh")
    build_file = PathPlus(repo_path / ".github" / "actions_build_conda.sh")
    deploy_file.parent.maybe_make()

    build_file.write_clean(templates.get_template(build_file.name).render())
    build_file.make_executable()
    deploy_file.write_clean(templates.get_template(deploy_file.name).render())
    deploy_file.make_executable()

    return [
        build_file.relative_to(repo_path).as_posix(),
        old_build_file.relative_to(repo_path).as_posix(),
        deploy_file.relative_to(repo_path).as_posix(),
        old_deploy_file.relative_to(repo_path).as_posix(),
    ]
Exemplo n.º 2
0
def make_docutils_conf(repo_path: pathlib.Path,
                       templates: Environment) -> List[str]:
    """
	Add configuration for ``Docutils``.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    file = PathPlus(repo_path / templates.globals["docs_dir"] /
                    "docutils.conf")
    file.parent.maybe_make(parents=True)

    if not file.is_file():
        file.write_text('\n'.join([
            "[restructuredtext parser]",
            "tab_width = 4",
            '',
            '',
        ]))

    conf = ConfigUpdater()
    conf.read(str(file))
    required_sections = ["restructuredtext parser"]

    for section in required_sections:
        if section not in conf.sections():
            conf.add_section(section)

    conf["restructuredtext parser"]["tab_width"] = 4

    file.write_clean(str(conf))

    return [file.relative_to(repo_path).as_posix()]
Exemplo n.º 3
0
def make_dependabotv2(repo_path: pathlib.Path, templates: Environment) -> List[str]:
	"""
	Add configuration for ``dependabot`` to the desired repo.

	https://dependabot.com/

	:param repo_path: Path to the repository root.
	:param templates:

	.. versionadded:: 2020.12.11
	"""

	dependabot_file = PathPlus(repo_path / ".github" / "dependabot.yml")
	dependabot_file.parent.maybe_make()

	updates = {
			"package-ecosystem": "pip",
			"directory": '/',
			"schedule": {"interval": "weekly"},
			"reviewers": [templates.globals["assignee"]],
			}

	config = {"version": 2, "updates": [updates]}

	dependabot_file.write_lines([
			f"# {templates.globals['managed_message']}",
			"---",
			_round_trip_dump(config),
			])

	return [dependabot_file.relative_to(repo_path).as_posix()]
Exemplo n.º 4
0
def make_github_docs_test(repo_path: pathlib.Path,
                          templates: Environment) -> List[str]:
    """
	Add configuration for GitHub Actions documentation check to the desired repo.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    file = PathPlus(repo_path / ".github" / "workflows" /
                    "docs_test_action.yml")
    file.parent.maybe_make(parents=True)

    if templates.globals["enable_docs"]:

        if templates.globals["docs_fail_on_warning"]:
            build_command = "tox -e docs -- -W "
        else:
            build_command = "tox -e docs -- "

        file.write_clean(
            templates.get_template(
                file.name).render(build_command=build_command))

    else:
        file.unlink(missing_ok=True)

    return [file.relative_to(repo_path).as_posix()]
Exemplo n.º 5
0
def make_dependabot(repo_path: pathlib.Path, templates: Environment) -> List[str]:
	"""
	Add configuration for ``dependabot`` to the desired repo.

	https://dependabot.com/

	:param repo_path: Path to the repository root.
	:param templates:

	.. deprecated:: 2020.12.11
	"""

	dependabot_file = PathPlus(repo_path / ".dependabot" / "config.yml")
	dependabot_file.parent.maybe_make()

	update_configs = {
			"package_manager": "python",
			"directory": '/',
			"update_schedule": "weekly",
			"default_reviewers": [templates.globals["assignee"]],
			}

	config = {"version": 1, "update_configs": [update_configs]}

	dependabot_file.write_lines([
			f"# {templates.globals['managed_message']}",
			"---",
			_round_trip_dump(config),
			])

	return [dependabot_file.relative_to(repo_path).as_posix()]
Exemplo n.º 6
0
def test_iterchildren_match(
        advanced_data_regression: AdvancedDataRegressionFixture,
        absolute: bool):
    repo_path = PathPlus(__file__).parent.parent
    with in_directory(repo_path.parent):

        assert repo_path.is_dir()

        if not absolute:
            repo_path = repo_path.relative_to(repo_path.parent)

        if (repo_path / "build").is_dir():
            shutil.rmtree(repo_path / "build")

        children = list(repo_path.iterchildren(match="**/*.py"))
        assert children

        child_paths = sorted(
            p.relative_to(repo_path).as_posix() for p in children)

        for exclude_filename in {
                ".coverage", "pathtype_demo.py", "dist", "htmlcov", "conda",
                ".idea", "mutdef.py"
        }:
            if exclude_filename in child_paths:
                child_paths.remove(exclude_filename)

        advanced_data_regression.check(child_paths,
                                       basename="test_iterchildren_match")
Exemplo n.º 7
0
def make_stale_bot(repo_path: pathlib.Path, templates: Environment) -> List[str]:
	"""
	Add configuration for ``stale`` to the desired repo.

	https://probot.github.io/apps/stale/

	:param repo_path: Path to the repository root.
	:param templates:
	"""

	stale_file = PathPlus(repo_path) / ".github" / "stale.yml"
	stale_file.parent.maybe_make()
	stale_file.write_clean(templates.get_template("stale_bot.yaml").render())
	return [stale_file.relative_to(repo_path).as_posix()]
Exemplo n.º 8
0
def remove_copy_pypi_2_github(repo_path: pathlib.Path,
                              templates: Environment) -> List[str]:
    """
	Remove deprecated copy_pypi_2_github.py script.

	Uue octocheese and its GitHub Action instead.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    copier = PathPlus(repo_path / ".ci" / "copy_pypi_2_github.py")
    if copier.is_file():
        copier.unlink()

    return [copier.relative_to(repo_path).as_posix()]
Exemplo n.º 9
0
def travis_bad(repo_path: pathlib.Path, templates: Environment) -> List[str]:
    """
	Removes Travis CI configuration.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    if PathPlus(repo_path / ".travis.yml").is_file():
        PathPlus(repo_path / ".travis.yml").unlink()

    conda_file = PathPlus(repo_path / ".ci" / "travis_deploy_conda.sh")
    if conda_file.is_file():
        conda_file.unlink()

    return [".travis.yml", conda_file.relative_to(repo_path).as_posix()]
Exemplo n.º 10
0
def remove_autodoc_augment_defaults(repo_path: pathlib.Path,
                                    templates: Environment) -> List[str]:
    """
	Remove the redundant "autodoc_augment_defaults" extension.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    target_file = PathPlus(repo_path / templates.globals["docs_dir"] /
                           "autodoc_augment_defaults.py")

    if target_file.is_file():
        target_file.unlink()

    return [target_file.relative_to(repo_path).as_posix()]
Exemplo n.º 11
0
def make_github_octocheese(repo_path: pathlib.Path,
                           templates: Environment) -> List[str]:
    """
	Add configuration for the OctoCheese GitHub Action.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    file = PathPlus(repo_path / ".github" / "workflows" / "octocheese.yml")
    file.parent.maybe_make(parents=True)

    if templates.globals["on_pypi"]:
        file.write_clean(templates.get_template(file.name).render())
    elif file.is_file():
        file.unlink()

    return [file.relative_to(repo_path).as_posix()]
Exemplo n.º 12
0
def stage_changes(
		repo: Union[PathLike, dulwich.repo.Repo],
		files: Iterable[PathLike],
		) -> List[PathPlus]:
	"""
	Stage any files that have been updated, added or removed.

	:param repo: The repository.
	:param files: List of files to stage.

	:returns: A list of staged files.
		Not all files in ``files`` will have been changed, and only changes are staged.

	.. versionadded:: 2020.11.23
	"""

	with open_repo_closing(repo) as repo:
		stat = status(repo)
		unstaged_changes = stat.unstaged
		untracked_files = stat.untracked

		staged_files = []

		for filename in files:
			filename = PathPlus(filename)

			if filename.is_absolute():
				filename = filename.relative_to(repo.path)

			if filename in unstaged_changes or filename in untracked_files:
				repo.stage(os.path.normpath(filename))
				staged_files.append(filename)

			elif (
					filename in stat.staged["add"] or filename in stat.staged["modify"]
					or filename in stat.staged["delete"]
					):
				staged_files.append(filename)

	return staged_files
Exemplo n.º 13
0
def make_github_manylinux(repo_path: pathlib.Path,
                          templates: Environment) -> List[str]:
    """
	Add configuration for `GitHub Actions` manylinux wheel builds the desired repo.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    # TODO: deploys from other supported platforms for not pure python

    file = PathPlus(repo_path / ".github" / "workflows" /
                    "manylinux_build.yml")
    file.parent.maybe_make(parents=True)

    if not templates.globals["pure_python"] and "Linux" in templates.globals[
            "platforms"]:
        actions = templates.get_template(file.name)
        wheel_py_versions = []
        PYVERSIONS = []

        for pyver in range(6, 8):
            if f"3.{pyver}" in templates.globals["python_versions"]:
                wheel_py_versions.append(f"cp3{pyver}-cp3{pyver}m")
                PYVERSIONS.append(f'"3{pyver}"')

        for pyver in range(8, 10):
            if f"3.{pyver}" in templates.globals["python_versions"]:
                wheel_py_versions.append(f"cp3{pyver}-cp3{pyver}")
                PYVERSIONS.append(f'"3{pyver}"')

        file.write_clean(
            actions.render(
                wheel_py_versions=wheel_py_versions,
                PYVERSIONS=' '.join(PYVERSIONS),
            ))
    elif file.is_file():
        file.unlink()

    return [file.relative_to(repo_path).as_posix()]
Exemplo n.º 14
0
def make_docs_contributing(repo_path: pathlib.Path, templates: Environment) -> List[str]:
	"""
	Add CONTRIBUTING.rst to the documentation directory of the repo.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

	file = PathPlus(repo_path / templates.globals["docs_dir"] / "contributing.rst")
	file.parent.maybe_make(parents=True)

	contributing = templates.get_template("CONTRIBUTING.rst")

	if templates.globals["standalone_contrib_guide"]:
		file.write_clean(contributing.render(bash_block=sphinx_bash_block))

	else:
		file.write_lines([
				"Overview",
				"---------",
				*contributing.render(bash_block=sphinx_bash_block).splitlines()[3:],
				])

	return [file.relative_to(repo_path).as_posix()]
Exemplo n.º 15
0
def make_conf(repo_path: pathlib.Path, templates: Environment) -> List[str]:
    """
	Add ``conf.py`` configuration file for ``Sphinx``.

	https://www.sphinx-doc.org/en/master/index.html

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    conf = templates.get_template("conf._py")
    file = PathPlus(repo_path / templates.globals["docs_dir"] / "conf.py")
    file.parent.maybe_make(parents=True)

    username = templates.globals["username"]
    repo_name = templates.globals["repo_name"]

    if templates.globals["sphinx_html_theme"] in {
            "sphinx-rtd-theme", "domdf-sphinx-theme"
    }:
        style = {
            "display_github": True,  # Integrate GitHub
            "github_user": username,  # Username
            "github_repo": repo_name,  # Repo name
            "github_version": "master",  # Version
            "conf_py_path":
            f"/{templates.globals['docs_dir']}/",  # Path in the checkout to the docs root
        }

        for key, val in style.items():
            if key not in templates.globals["html_context"]:
                templates.globals["html_context"][key] = val

        options = {
            # 'logo': 'logo.png',
            "logo_only": False,  # True will show just the logo
        }

        for key, val in options.items():
            if key not in templates.globals["html_theme_options"]:
                templates.globals["html_theme_options"][key] = val

    elif templates.globals["sphinx_html_theme"] in {
            "alabaster", "repo-helper-sphinx-theme"
    }:
        # See https://github.com/bitprophet/alabaster/blob/master/alabaster/theme.conf
        # and https://alabaster.readthedocs.io/en/latest/customization.html

        style = {
            # 'logo': 'logo.png',
            "page_width": "1200px",
            "logo_name": "true",
            "github_user": username,  # Username
            "github_repo": repo_name,  # Repo name
            "description": templates.globals["short_desc"],
            "github_banner": "true",
            "github_type": "star",
            "badge_branch": "master",
            "fixed_sidebar": "true",
        }

        for key, val in style.items():
            if key not in templates.globals["html_theme_options"]:
                templates.globals["html_theme_options"][key] = val

    elif templates.globals["sphinx_html_theme"] in {"furo"}:
        # See https://github.com/bitprophet/alabaster/blob/master/alabaster/theme.conf
        # and https://alabaster.readthedocs.io/en/latest/customization.html

        style = {
            "toc-title-font-size": "12pt",
            "toc-font-size": "12pt",
            "admonition-font-size": "12pt",
        }

        for key in ["light_css_variables", "dark_css_variables"]:
            if key not in templates.globals["html_theme_options"]:
                templates.globals["html_theme_options"][key] = style
            else:
                templates.globals["html_theme_options"][key] = {
                    **style,
                    **templates.globals["html_theme_options"][key],
                }

    file.write_clean(
        conf.render(pformat=pformat_tabs, enquote_value=enquote_value))

    with resource(repo_helper.files, "isort.cfg") as isort_config:
        yapf_style = PathPlus(
            isort_config).parent.parent / "templates" / "style.yapf"
        reformat_file(file,
                      yapf_style=str(yapf_style),
                      isort_config_file=str(isort_config))

    return [file.relative_to(repo_path).as_posix()]
Exemplo n.º 16
0
def make_rtfd(repo_path: pathlib.Path, templates: Environment) -> List[str]:
    """
	Add configuration for ``ReadTheDocs``.

	https://readthedocs.org/

	See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    file = PathPlus(repo_path / ".readthedocs.yml")

    docs_dir = PathPlus(repo_path / templates.globals["docs_dir"])

    sphinx_config = {
        "builder": "html",
        "configuration": f"{templates.globals['docs_dir']}/conf.py",
    }

    install_requirements = [
        "requirements.txt",
        f"{templates.globals['docs_dir']}/requirements.txt",
        *templates.globals["additional_requirements_files"],
    ]

    install_config: List[Dict] = [{
        "requirements": r
    } for r in install_requirements]

    if (docs_dir / "rtd-extra-deps.txt").is_file():
        install_config.append({
            "requirements":
            f"{templates.globals['docs_dir']}/rtd-extra-deps.txt"
        })
    elif templates.globals["tox_testenv_extras"]:
        install_config.append({
            "method":
            "pip",
            "path":
            '.',
            "extra_requirements": [templates.globals["tox_testenv_extras"]],
        })

    else:
        install_config.append({"method": "pip", "path": '.'})

    python_config = {"version": 3.8, "install": install_config}

    # Formats: Optionally build your docs in additional formats such as PDF and ePub
    config = {
        "version": 2,
        "sphinx": sphinx_config,
        "formats": ["pdf", "htmlzip"],
        "python": python_config
    }

    # TODO: support user customisation of search rankings
    # https://docs.readthedocs.io/en/stable/config-file/v2.html#search-ranking

    dumper = yaml.YAML()
    dumper.indent(mapping=2, sequence=3, offset=1)

    yaml_buf = yaml.StringIO()
    dumper.dump(config, yaml_buf)

    file.write_lines([
        f"# {templates.globals['managed_message']}",
        "# Read the Docs configuration file", "---",
        yaml_buf.getvalue()
    ])

    return [file.relative_to(repo_path).as_posix()]
Exemplo n.º 17
0
def rewrite_docs_index(repo_path: pathlib.Path,
                       templates: Environment) -> List[str]:
    """
	Update blocks in the documentation ``index.rst`` file.

	:param repo_path: Path to the repository root.
	:param templates:
	"""

    index_rst_file = PathPlus(repo_path / templates.globals["docs_dir"] /
                              "index.rst")
    index_rst_file.parent.maybe_make()

    # Set up the blocks
    sb = ShieldsBlock(
        username=templates.globals["username"],
        repo_name=templates.globals["repo_name"],
        version=templates.globals["version"],
        conda=templates.globals["enable_conda"],
        tests=templates.globals["enable_tests"]
        and not templates.globals["stubs_package"],
        docs=templates.globals["enable_docs"],
        pypi_name=templates.globals["pypi_name"],
        docker_shields=templates.globals["docker_shields"],
        docker_name=templates.globals["docker_name"],
        platforms=templates.globals["platforms"],
        pre_commit=templates.globals["enable_pre_commit"],
        on_pypi=templates.globals["on_pypi"],
        primary_conda_channel=templates.globals["primary_conda_channel"],
    )

    sb.set_docs_mode()
    make_out = sb.make()

    shield_block_list = StringList([*make_out[0:2], ".. only:: html"])

    with shield_block_list.with_indent_size(1):
        shield_block_list.extend(make_out[1:-1])

    shield_block_list.append(make_out[-1])

    shields_block = str(shield_block_list)

    if templates.globals["license"] == "GNU General Public License v2 (GPLv2)":
        source = f"https://img.shields.io/github/license/{templates.globals['username']}/{templates.globals['repo_name']}"
        shields_block.replace(
            source, "https://img.shields.io/badge/license-GPLv2-orange")

    # .. image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg

    install_block = create_docs_install_block(
        templates.globals["repo_name"],
        templates.globals["username"],
        templates.globals["enable_conda"],
        templates.globals["on_pypi"],
        templates.globals["pypi_name"],
        templates.globals["conda_channels"],
    ) + '\n'

    links_block = create_docs_links_block(
        templates.globals["username"],
        templates.globals["repo_name"],
    )

    # Do the replacement
    index_rst = index_rst_file.read_text(encoding="UTF-8")
    index_rst = shields_regex.sub(shields_block, index_rst)
    index_rst = installation_regex.sub(install_block, index_rst)
    index_rst = links_regex.sub(links_block, index_rst)
    index_rst = short_desc_regex.sub(
        ".. start short_desc\n\n.. documentation-summary::\n\t:meta:\n\n.. end short_desc",
        index_rst,
    )

    if ":caption: Links" not in index_rst and not templates.globals[
            "preserve_custom_theme"]:
        index_rst = index_rst.replace(
            ".. start links", '\n'.join([
                ".. sidebar-links::",
                "\t:caption: Links",
                "\t:github:",
                (f"	:pypi: {templates.globals['pypi_name']}"
                 if templates.globals["on_pypi"] else ''),
                '',
                '',
                ".. start links",
            ]))

    index_rst_file.write_clean(index_rst)

    return [index_rst_file.relative_to(repo_path).as_posix()]