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()]
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()]
def make_automerge_action(repo_path: pathlib.Path, templates: Environment) -> List[str]: """ Add configuration for https://github.com/pascalgn/automerge-action to the desired repo. :param repo_path: Path to the repository root. :param templates: """ dot_github = PathPlus(repo_path / ".github") (dot_github / "workflows").maybe_make(parents=True) automerge_workflow = dot_github / "workflows" / "automerge.yml" pr_types = [ "labeled", "unlabeled", "synchronize", "opened", "edited", "ready_for_review", "reopened", "unlocked", ] steps = [{ "name": "automerge", "uses": "pascalgn/[email protected]", "env": { "GITHUB_TOKEN": "${{ secrets.GITHUB_TOKEN }}", "MERGE_METHOD": "squash", }, }] config: MutableMapping[str, Any] = { "name": "automerge", "on": { "pull_request": {"types": pr_types}, "pull_request_review": {"types": ["submitted"]}, "check_suite": {"types": ["completed"]}, "status": {}, }, "jobs": {"automerge": {"runs-on": "ubuntu-latest", "steps": steps}} } automerge_workflow.write_lines([ f"# {templates.globals['managed_message']}", "---", _round_trip_dump(config), ]) return [automerge_workflow.relative_to(repo_path).as_posix()]
def make_auto_assign_action(repo_path: pathlib.Path, templates: Environment) -> List[str]: """ Add configuration for ``auto-assign`` to the desired repo. https://github.com/kentaro-m/auto-assign :param repo_path: Path to the repository root. :param templates: """ dot_github = PathPlus(repo_path / ".github") (dot_github / "workflows").maybe_make(parents=True) assign_workflow = dot_github / "workflows" / "assign.yml" old_assign_workflow = dot_github / "workflow" / "assign.yml" auto_assign_yml = dot_github / "auto_assign.yml" if old_assign_workflow.is_file(): old_assign_workflow.unlink() if old_assign_workflow.parent.is_dir(): old_assign_workflow.parent.rmdir() if assign_workflow.is_file(): assign_workflow.unlink() config: MutableMapping[str, Any] = { "addReviewers": True, "addAssignees": True, } # A list of reviewers to be added to pull requests (GitHub user name) config["reviewers"] = [templates.globals["assignee"]] # A number of reviewers added to the pull request # Set 0 to add all the reviewers config["numberOfReviewers"] = 0 # A list of assignees, overrides reviewers if set # assignees: # - assigneeA # A number of assignees to add to the pull request # Set to 0 to add assignees. # Uses numberOfReviewers if unset. # numberOfAssignees: 2 # more settings at https://github.com/marketplace/actions/auto-assign-action auto_assign_yml.write_lines([ f"# {templates.globals['managed_message']}", "---", _round_trip_dump(config), "# more settings at https://github.com/marketplace/actions/auto-assign-action", ]) return [ assign_workflow.relative_to(repo_path).as_posix(), old_assign_workflow.relative_to(repo_path).as_posix(), auto_assign_yml.relative_to(repo_path).as_posix(), ]
def wizard() -> None: """ Run the wizard 🧙 to create a 'repo_helper.yml' file. """ # stdlib import datetime import getpass import os import socket # 3rd party from apeye.email_validator import EmailSyntaxError, validate_email from consolekit.terminal_colours import Fore from domdf_python_tools.paths import PathPlus from dulwich.errors import NotGitRepository from ruamel.yaml import scalarstring from southwark.repo import Repo # this package from repo_helper.utils import _round_trip_dump, license_lookup path = PathPlus.cwd() config_file = path / "repo_helper.yml" try: r = Repo(path) except NotGitRepository: with Fore.RED: click.echo(f"The directory {path} is not a git repository.") click.echo( "You may need to run 'git init' in that directory first.") raise click.Abort # ---------- intro ---------- click.echo( "This wizard 🧙will guide you through creating a 'repo_helper.yml' configuration file." ) click.echo(f"This will be created in '{config_file}'.") if not confirm("Do you want to continue?"): raise click.Abort() # ---------- file exists warning ---------- if config_file.is_file(): click.echo( f"\nWoah! That file already exists. It will be overwritten if you continue!" ) if not confirm("Are you sure you want to continue?"): raise click.Abort() click.echo("\nDefault options are indicated in [square brackets].") # ---------- modname ---------- click.echo("\nThe name of the library/project.") modname = prompt("Name") # ---------- name ---------- click.echo("\nThe name of the author.") click.echo("The author is usually the person who wrote the library.") git_config = r.get_config_stack() try: default_author = git_config.get(("user", ), "name").decode("UTF-8") except KeyError: try: getpass_user = getpass.getuser() default_author = os.getenv( "GIT_AUTHOR_NAME", default=os.getenv("GIT_COMMITTER_NAME", default=getpass_user), ) except ImportError: # Usually USERNAME is not set when trying getpass.getuser() default_author = '' author = prompt("Name", default=default_author) # ---------- email ---------- try: default_email = git_config.get(("user", ), "email").decode("UTF-8") except KeyError: default_email = os.getenv( "GIT_AUTHOR_EMAIL", default=os.getenv("GIT_COMMITTER_EMAIL", default=f"{author}@{socket.gethostname()}")) click.echo( "\nThe email address of the author. This will be shown on PyPI, amongst other places." ) while True: try: email = validate_email(prompt("Email", default=default_email)).email break except EmailSyntaxError: click.echo("That is not a valid email address.") # ---------- username ---------- click.echo("\nThe username of the author.") click.echo( "(repo_helper naïvely assumes that you use the same username on GitHub as on other sites.)" ) username = prompt("Username", default=author) # TODO: validate username # ---------- version ---------- click.echo("\nThe version number of the library, in semver format.") version = prompt("Version number", default="0.0.0") # ---------- copyright_years ---------- click.echo("\nThe copyright years for the library.") copyright_years = prompt("Copyright years", default=str(datetime.datetime.today().year), type=str) # ---------- license_ ---------- click.echo(""" The SPDX identifier for the license this library is distributed under. Not all SPDX identifiers are allowed as not all map to PyPI Trove classifiers.""" ) while True: license_ = prompt("License") if license_ in license_lookup: break else: click.echo("That is not a valid identifier.") # ---------- short_desc ---------- click.echo("\nEnter a short, one-line description for the project.") short_desc = prompt("Description") # ---------- writeout ---------- data = { "modname": modname, "copyright_years": copyright_years, "author": author, "email": email, "username": username, "version": str(version), "license": license_, "short_desc": short_desc, } data = { k: scalarstring.SingleQuotedScalarString(v) for k, v in data.items() } config_file.write_lines([ "# Configuration for 'repo_helper' (https://github.com/repo-helper/repo_helper)", "---", _round_trip_dump(data), "enable_conda: false", ]) click.echo(f""" The options you provided have been written to the file {config_file}. You can configure additional options in that file. The schema for the Yaml file can be found at: https://github.com/repo-helper/repo_helper/blob/master/repo_helper/repo_helper_schema.json You may be able to configure your code editor to validate your configuration file against that schema. repo_helper can now be run with the 'repo_helper' command in the repository root. Be seeing you! """)