class CloseCommand(Command): command_name = "close" description = "close jira issue" arguments = [Parameter("issue_key")] def main(self): result = self.app.jira.close(self.arguments.issue_key) self.logger.info(result)
class TestCommand(Command): command_name = COMMAND_NAMES[0] arguments = [ Parameter("test_param"), Option(["--test-option"]), ] def main(self): self.logger.info(self.arguments.test_param) self.logger.info(self.arguments.test_option) self.logger.info(self.arguments.parent_option)
class TestCommand(Command): command_name = COMMAND_NAMES[0] description = TEST_STRING arguments = [ Parameter("test_param"), Option(["--test-option"], required=True), ] def main(self): self.logger.info(self.arguments.test_param) self.logger.info(self.arguments.test_option) self.logger.info(self.arguments.parent_option)
class UrlCommand(Command): command_name = "url" description = "preprend url to issue" arguments = [ Parameter("issue_key", nargs="?") ] def main(self): if self.arguments.issue_key: self.logger.info("https://happnapp.atlassian.net/browse/{}".format(str(self.arguments.issue_key).rstrip())) else: self.logger.info("https://happnapp.atlassian.net/")
class TestCommand2(Command): command_name = COMMAND_NAMES[1] arguments = [ Parameter("test_param"), Option(["--test-option"]), ] merge_parent_arguments = False def main(self): self.logger.info(self.arguments.test_param) self.logger.info(self.arguments.test_option) self.logger.info(getattr(self.arguments, "parent_option", None))
class SearchCommand(Command): command_name = "search" description = "search jira issues" arguments = [Parameter("pattern", nargs="?")] def main(self): if self.arguments.pattern: for issue in self.app.jira.search( self.arguments.pattern)["issues"]: self.app.workflow.add_item( WorkflowItem(title=issue["fields"]["summary"], subtitle=issue["key"], arg=issue["key"])) else: self.app.workflow.add_item( WorkflowItem(title="Open dashboard", subtitle="", arg="")) self.logger.info(self.app.workflow.to_json())
class BasicArgsApp(App): arguments = [Parameter("test_param"), Option(["--test-option", "-T"])] def main(self): self.logger.info(self.arguments.test_param) self.logger.info(self.arguments.test_option)
self.logger.info(self.arguments.test_param) self.logger.info(self.arguments.test_option) app = BasicArgsApp() app.run() stdout, _ = capsys.readouterr() test_param = argv[1] test_option = None if len(argv) <= 3 else argv[3] assert stdout == "{}\n{}\n".format(test_param, test_option) @pytest.mark.parametrize("param", [ Parameter(["test_param"]), Parameter(1), Parameter(-1), Parameter({}), Parameter(False), Parameter(True), ]) def test_type_params(param): class InvalidParamApp(App): arguments = [param] with pytest.raises(TypeError): InvalidParamApp().run() @pytest.mark.parametrize("option, exception_type", [
class CreateCommand(Command): command_name = "create" arguments = [ Parameter("name"), Option(["--blueprint", "-b"], default=None) ] ctx = {} builder = ContextBuilder() hooks = HooksRunner() bp_manager = BlueprintManager() jinja_env = None def main(self): self.bp_manager.setup(self.config) blueprint_folder = self.bp_manager.get_blueprint_folder( self.arguments.blueprint) if not blueprint_folder.exists(): raise InvalidBlueprint(f"{blueprint_folder} doesn't exist") self.hooks.setup(blueprint_folder / "hooks.py") target_folder = Path(".") / self.arguments.name self.ctx["blueprint_folder"] = blueprint_folder self.ctx["folder_name"] = self.arguments.name self.ctx["target_folder"] = target_folder self.ctx = self.hooks.run("pre_run_hook", self.ctx) structure_file_path = get_structure_path(blueprint_folder) manifest_file_path = get_manifest_path(blueprint_folder) if manifest_file_path is None: raise InvalidBlueprint( f"{blueprint_folder}/manifest.yml doesn't exist") if structure_file_path is None: raise InvalidBlueprint( f"Neither {blueprint_folder}/structure.yml nor {blueprint_folder}/structure.yml.jinja exist" ) self.create_target_folder() manifest = yaml.safe_load(manifest_file_path.read_text()) utils_path = blueprint_folder / "utils.py" if utils_path.exists(): utils_path = str(utils_path.resolve()) else: utils_path = None self.ctx = self.hooks.run("pre_prompt_hook", self.ctx) self.ctx.update(self.builder.build_context(manifest, utils_path)) self.ctx = self.hooks.run("post_prompt_hook", self.ctx) self.jinja_env = self.create_jinja_env() structure_content = structure_file_path.read_text() if structure_file_path.suffix == ".jinja": structure_content = self.jinja_env.from_string( structure_content).render() structure = yaml.safe_load(structure_file_path.read_text()) self.create_structure(structure, target_folder, blueprint_folder) self.ctx = self.hooks.run("post_run_hook", self.ctx) def create_target_folder(self): target_folder = self.ctx["target_folder"] if target_folder.exists(): should_continue = YesNo( prompt= f"{target_folder} already exist. Do you want to delete it ? " ).launch() if not should_continue: sys.exit(0) rmtree(target_folder) target_folder.mkdir() def create_jinja_env(self): env = Environment( loader=FileSystemLoader(str(self.ctx["blueprint_folder"]))) env.globals = self.ctx return env def is_empty_directory_marker(self, value): return isinstance(value, list) or isinstance(value, tuple) or value is None def create_structure(self, dict_: dict, base_path: Path, blueprint_folder: Path): for key, value in dict_.items(): new_path = base_path / key if isinstance(value, dict): # Directory new_path.mkdir() self.create_structure(value, new_path, blueprint_folder) elif self.is_empty_directory_marker(value): # Directory new_path.mkdir() elif isinstance(value, str): # File source_path = blueprint_folder / "src" / value if value.endswith(".jinja"): # Template new_path.touch() template = self.jinja_env.get_template(f"src/{value}") new_path.write_text(template.render()) else: copy(source_path, new_path) else: raise InvalidBlueprint( f"structure.yml file as invalid value: {value}")
class KhopeshApp(App): arguments = [ Parameter("executable"), Parameter("everything", nargs=REMAINDER) ] def filter_command_name(self, string): return not (string.startswith("-") or string.startswith(".") or string.startswith("/")) def make_executable(self, file): st = os.stat(file) os.chmod(file, st.st_mode | stat.S_IEXEC) def get_hooks(self, command_name): hooks_folder = Path(f"./hooks/{self.arguments.executable}") hooks = {} if hooks_folder.is_dir(): pre_hook_sh = (hooks_folder / f"pre-{command_name}-hook.sh") pre_hook_py = (hooks_folder / f"pre-{command_name}-hook.py") post_hook_sh = (hooks_folder / f"post-{command_name}-hook.sh") post_hook_py = (hooks_folder / f"post-{command_name}-hook.py") if pre_hook_sh.is_file() and not pre_hook_py.is_file(): self.make_executable(pre_hook_sh) hooks["pre"] = {"type": "sh", "path": pre_hook_sh} if pre_hook_py.is_file(): hooks["pre"] = {"type": "py", "path": pre_hook_py} if post_hook_sh.is_file() and not post_hook_py.is_file(): self.make_executable(post_hook_sh) hooks["post"] = {"type": "sh", "path": post_hook_sh} if post_hook_py.is_file(): hooks["post"] = {"type": "py", "path": post_hook_py} return hooks def exec_hook(self, hook): if hook["type"] == "sh": sh.Command(hook["path"])(_out=sys.stdout, _err=sys.stderr) if hook["type"] == "py": module_name = hook["path"].stem.replace("-", "_") spec = importlib.util.spec_from_file_location(module_name, str(hook["path"])) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) module.hook() def main(self): try: executable = sh.Command(self.arguments.executable) potential_commands = [arg for arg in self.arguments.everything if self.filter_command_name(arg)] command_name = None if len(potential_commands) >= 1: command_name = potential_commands[0] hooks = self.get_hooks(command_name) if hooks.get("pre", None): self.exec_hook(hooks["pre"]) executable(self.arguments.everything, _fg=True) if hooks.get("post", None): self.exec_hook(hooks["post"]) except sh.ErrorReturnCode as exc: sys.stdout.write(exc.stdout.decode("UTF-8")) sys.stderr.write(exc.stderr.decode("UTF-8")) except sh.CommandNotFound: self.logger.error(f"{self.arguments.executable} not found")