From 3fbd61efdefe22e29a53c8f0d46b6ef91bc55073 Mon Sep 17 00:00:00 2001 From: Abhijeet Saroha <108522472+abhijeetSaroha@users.noreply.github.com> Date: Fri, 8 Dec 2023 20:17:51 +0530 Subject: [PATCH] feat: Add working-directory to the target, group and global scope (#65) --- .github/workflows/main.yaml | 12 ++ .makim.yaml | 94 ++++++++++++++- docs/features.md | 103 ++++++++++++++++ pyproject.toml | 4 +- src/makim/makim.py | 40 ++++++- ...makim-working-directory-absolute-path.yaml | 111 +++++++++++++++++ tests/.makim-working-directory-no-path.yaml | 106 ++++++++++++++++ ...makim-working-directory-relative-path.yaml | 113 ++++++++++++++++++ 8 files changed, 574 insertions(+), 9 deletions(-) create mode 100644 docs/features.md create mode 100644 tests/.makim-working-directory-absolute-path.yaml create mode 100644 tests/.makim-working-directory-no-path.yaml create mode 100644 tests/.makim-working-directory-relative-path.yaml diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 6de495f..79abef4 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -39,6 +39,9 @@ jobs: brew install gnu-sed echo 'export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"' >> ~/.bashrc echo 'export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"' >> ~/.bash_profile + gsed -i s:/tmp:/private/tmp:g tests/.makim-working-directory-absolute-path.yaml + gsed -i s:/tmp:/private/tmp:g tests/.makim-working-directory-no-path.yaml + gsed -i s:/tmp:/private/tmp:g tests/.makim-working-directory-relative-path.yaml - name: Prepare conda environment (windows) if: ${{ matrix.os == 'windows' }} @@ -86,6 +89,15 @@ jobs: - name: Run smoke test for variable envs run: makim smoke-tests.vars-env + - name: Run smoke test for working-directory-absolute-path + run: makim smoke-tests.working-directory-absolute-path + + - name: Run smoke test for working-directory-no-path + run: makim smoke-tests.working-directory-no-path + + - name: Run smoke test for working-directory-relative-path + run: makim smoke-tests.working-directory-relative-path + - name: Run unit tests run: makim tests.unittest diff --git a/.makim.yaml b/.makim.yaml index be1a277..877a977 100644 --- a/.makim.yaml +++ b/.makim.yaml @@ -1,9 +1,10 @@ version: 1.0 groups: - default: + clean: targets: - clean: + tmp: help: Clean unnecessary temporary files + shell: bash run: | rm -fr build/ rm -fr dist/ @@ -11,9 +12,9 @@ groups: find . -name '*.egg-info' -exec rm -fr {} + find . -name '*.egg' -exec rm -f {} + find . -name '*.pyc' -exec rm -f {} + - find . -name - find . -name '__pycache__' -exec rm -fr '*.pyo' -exec rm -f {} + - find . -name '*~' -exec rm -f {} +{} + + find . -name '__pycache__' -exec rm -fr {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + rm -f .coverage rm -fr htmlcov/ rm -fr .pytest_cache @@ -75,6 +76,9 @@ groups: - target: smoke-tests.unittest - target: smoke-tests.vars-env - target: smoke-tests.bash + - target: smoke-tests.working-directory-absolute-path + - target: smoke-tests.working-directory-no-path + - target: smoke-tests.working-directory-relative-path ci: help: Run all targets used on CI @@ -213,8 +217,86 @@ groups: makim --makim-file $MAKIM_FILE rerender-env.from-target $VERBOSE_FLAG bash: - help: ... + help: Test makim shell attribute with bash run: | makim --makim-file tests/.makim-bash-main-scope.yaml main-scope.test makim --makim-file tests/.makim-bash-group-scope.yaml group-scope.test makim --makim-file tests/.makim-bash-target-scope.yaml target-scope.test + + working-directory-absolute-path: + help: | + Test makim with working-directory absolute for global path and its various combinations with group and target working-directory + args: + verbose-mode: + help: Run the all the tests in verbose mode + type: bool + action: store_true + env: + MAKIM_FILE: tests/.makim-working-directory-absolute-path.yaml + shell: bash + run: | + export VERBOSE_FLAG='{{ "--verbose" if args.verbose_mode else "" }}' + makim --makim-file $MAKIM_FILE --help + makim --makim-file $MAKIM_FILE --version + makim --makim-file $MAKIM_FILE group-no-path.target-no-path $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-no-path.target-absolute $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-no-path.target-relative $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-relative.target-no-path $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-relative.target-absolute $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-relative.target-relative $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-absolute.target-no-path $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-absolute.target-absolute $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-absolute.target-relative $VERBOSE_FLAG + + working-directory-no-path: + help: Test makim with working-directory for global no-path and its various combinations with group and target working-directory + args: + verbose-mode: + help: Run the all the tests in verbose mode + type: bool + action: store_true + env: + MAKIM_FILE: tests/.makim-working-directory-no-path.yaml + shell: bash + run: | + export VERBOSE_FLAG='{{ "--verbose" if args.verbose_mode else "" }}' + export MAKIM_FILE="$(pwd)/${MAKIM_FILE}" + cd /tmp + makim --makim-file $MAKIM_FILE --help + makim --makim-file $MAKIM_FILE --version + makim --makim-file $MAKIM_FILE group-no-path.target-no-path $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-no-path.target-absolute $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-no-path.target-relative $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-absolute.target-no-path $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-absolute.target-absolute $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-absolute.target-relative $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-relative.target-no-path $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-relative.target-absolute $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-relative.target-relative $VERBOSE_FLAG + + working-directory-relative-path: + help: Test makim with working-directory for global no-path and its various combinations with group and target working-directory + args: + verbose-mode: + help: Run the all the tests in verbose mode + type: bool + action: store_true + env: + MAKIM_FILE: tests/.makim-working-directory-relative-path.yaml + shell: bash + run: | + export VERBOSE_FLAG='{{ "--verbose" if args.verbose_mode else "" }}' + export MAKIM_FILE="$(pwd)/${MAKIM_FILE}" + mkdir -p /tmp/global-relative + cd /tmp + makim --makim-file $MAKIM_FILE --help + makim --makim-file $MAKIM_FILE --version + makim --makim-file $MAKIM_FILE group-no-path.target-no-path $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-no-path.target-absolute $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-no-path.target-relative $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-absolute.target-no-path $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-absolute.target-absolute $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-absolute.target-relative $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-relative.target-no-path $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-relative.target-absolute $VERBOSE_FLAG + makim --makim-file $MAKIM_FILE group-relative.target-relative $VERBOSE_FLAG diff --git a/docs/features.md b/docs/features.md new file mode 100644 index 0000000..2e16564 --- /dev/null +++ b/docs/features.md @@ -0,0 +1,103 @@ +# Makim Features + +## Working Directory Feature + +The working-directory feature in Makim allows users to define the directory +from which commands associated with specific targets or groups are executed. +This provides greater flexibility and control over the execution environment. + +### Attribute: working-directory + +The `working-directory` attribute can be specified at three different +scopes: global, group, and target. It allows users to set the working +directory for a specific target, a group of targets, or globally. + +### Syntax and Scopes +The working-directory attribute can be applied to three different scopes: + +- #### **Global Scope** + Setting the global working directory impacts all targets and groups in + the Makim configuration. + + ```yaml + version: 1.0 + working-directory: /path/to/global/directory + + # ... other configuration ... + ``` + +- #### Group Scope + + Setting the working directory at the group scope affects all targets within + that group. + + ```yaml + + version: 1.0 + + groups: + my-group: + working-directory: /path/to/group/directory + targets: + target-1: + run: | + # This target will run with the working directory set to + # /path/to/group/directory + ``` + +- #### Target Scope + + Setting the working directory at the target scope allows for fine grained + control over individual targets. + + ```yaml + version: 1.0 + groups: + my-group: + targets: + my-target: + working-directory: /path/to/target/directory + run: | + # This target will run with the working directory set to + # /path/to/target/directory + ``` + +## Example + +```yaml +version: 1.0 +working-directory: /project-root + +groups: + backend: + working-directory: backend + targets: + build: + help: Build the backend services + working-directory: services + run: | + echo "Building backend services..." + # Additional build commands specific to the backend + + test: + help: Run backend tests + working-directory: tests + run: | + echo "Running backend tests..." + # Additional test commands specific to the backend + + frontend: + working-directory: frontend + targets: + build: + help: Build the frontend application + run: | + echo "Building frontend application..." + # Additional build commands specific to the frontend + + test: + help: Run frontend tests + run: | + echo "Running frontend tests..." + # Additional test commands specific to the frontend +``` diff --git a/pyproject.toml b/pyproject.toml index 5738b0b..a16d9dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,8 @@ ignore = ["RUF012"] exclude = [ "docs", ] + +[tool.ruff.lint] select = [ "E", # pycodestyle "F", # pyflakes @@ -79,8 +81,6 @@ select = [ "RUF", # Ruff-specific rules "I001", # isort ] -# fixable = ["I001"] -fix = true [tool.ruff.pydocstyle] convention = "numpy" diff --git a/src/makim/makim.py b/src/makim/makim.py index 5492b70..9a76b58 100644 --- a/src/makim/makim.py +++ b/src/makim/makim.py @@ -14,7 +14,7 @@ from copy import deepcopy from pathlib import Path -from typing import Dict, Optional, Tuple +from typing import Dict, Optional, Tuple, Union import dotenv import sh @@ -63,6 +63,10 @@ class Makim(PrintPlugin): # temporary variables env: dict = {} # initial env env_scoped: dict = {} # current env + # initial working directory + working_directory: Optional[Path] = None + # current working directory + working_directory_scoped: Optional[Path] = None args: Optional[object] = None group_name: str = 'default' group_data: dict = {} @@ -91,6 +95,7 @@ def _call_shell_app(self, cmd): _no_err=True, _env=os.environ, _new_session=True, + _cwd=str(self._resolve_working_directory('target')), ) try: @@ -183,6 +188,39 @@ def _load_config_data(self): content_io = io.StringIO(content) self.global_data = yaml.safe_load(content_io) + def _resolve_working_directory(self, scope: str) -> Optional[Path]: + scope_options = ('global', 'group', 'target') + if scope not in scope_options: + raise Exception(f'The given scope `{scope}` is not valid.') + + def update_working_directory( + current_path: Union[None, Path], new_path: str + ) -> Path: + if not current_path: + return Path(new_path) + return current_path / Path(new_path) + + scope_id = scope_options.index(scope) + + working_dir: Optional[Path] = None + + if scope_id >= SCOPE_GLOBAL: + working_dir = update_working_directory( + working_dir, self.global_data.get('working-directory', '') + ) + + if scope_id >= SCOPE_GROUP: + working_dir = update_working_directory( + working_dir, self.group_data.get('working-directory', '') + ) + + if scope_id == SCOPE_TARGET: + working_dir = update_working_directory( + working_dir, self.target_data.get('working-directory', '') + ) + + return working_dir + def _load_shell_app(self, shell_app: str = ''): if not shell_app: shell_app = self.global_data.get('shell', 'xonsh') diff --git a/tests/.makim-working-directory-absolute-path.yaml b/tests/.makim-working-directory-absolute-path.yaml new file mode 100644 index 0000000..90c86f3 --- /dev/null +++ b/tests/.makim-working-directory-absolute-path.yaml @@ -0,0 +1,111 @@ +version: 1.0 +working-directory: "/tmp" + +groups: + setup: + targets: + folders: + help: Create necessary folders + run: | + mkdir -p /tmp/group1 + mkdir -p /tmp/group1/target3 + mkdir -p /tmp/group2 + mkdir -p /tmp/group2/target-relative + mkdir -p /tmp/group1/target4 + + group-no-path: + targets: + target-no-path: + help: Test global absolute path, group no path, target no path + dependencies: + - target: setup.folders + run: | + import os + print(os.getcwd()) + assert os.getcwd() == "/tmp" + echo "working-directory-absolute-path [I] Done!" + + target-absolute: + working-directory: "/tmp" + help: Test global absolute path, group no path, target absolute path + dependencies: + - target: setup.folders + run: | + import os + assert os.getcwd() == "/tmp" + echo "working-directory-absolute-path [II] Done!" + + target-relative: + working-directory: "/tmp/group1/target4" + help: est global absolute path, group no path, target relative path + dependencies: + - target: setup.folders + run: | + import os + assert os.getcwd() == "/tmp/group1/target4" + echo "working-directory-absolute-path [III] Done!" + + group-relative: + working-directory: "group1" + targets: + target-no-path: + help: Test global absolute path, group relative path, target no path + dependencies: + - target: setup.folders + run: | + import os + assert os.getcwd() == "/tmp/group1" + echo "working-directory-absolute-path [IV] Done!" + + target-absolute: + working-directory: "/tmp" + help: Test global absolute path, group relative path, target absolute path + dependencies: + - target: setup.folders + run: | + import os + assert os.getcwd() == "/tmp" + echo "working-directory-absolute-path [V] Done!" + + target-relative: + working-directory: "target3" + help: Test global absolute path, group relative path, target relative path + dependencies: + - target: setup.folders + run: | + import os + assert os.getcwd() == "/tmp/group1/target3" + echo "working-directory-absolute-path [VI] Done!" + + group-absolute: + working-directory: "/tmp/group2" + targets: + target-no-path: + help: Test global absolute path, group absolute path, target no path + dependencies: + - target: setup.folders + run: | + import os + assert os.getcwd() == "/tmp/group2" + echo "working-directory-absolute-path [VII] Done!" + + target-absolute: + working-directory: "/tmp" + help: Test global absolute path, group absolute path, target absolute path + dependencies: + - target: setup.folders + run: | + import os + assert os.getcwd() == "/tmp" + echo "working-directory-absolute-path [VIII] Done!" + + target-relative: + working-directory: "target-relative" + help: | + Test global absolute path, group absolute path, target relative path + dependencies: + - target: setup.folders + run: | + import os + assert os.getcwd() == "/tmp/group2/target-relative" + echo "working-directory-absolute-path [IX] Done!" diff --git a/tests/.makim-working-directory-no-path.yaml b/tests/.makim-working-directory-no-path.yaml new file mode 100644 index 0000000..9301b17 --- /dev/null +++ b/tests/.makim-working-directory-no-path.yaml @@ -0,0 +1,106 @@ +version: 1.0 + +groups: + setup: + targets: + create-folders: + run: | + mkdir -p /tmp/target1 + mkdir -p /tmp/target2 + mkdir -p /tmp/group-absolute/target1 + mkdir -p /tmp/group-relative/target1 + + group-no-path: + targets: + target-no-path: + help: Test global no-path, group no-path, target no-path + dependencies: + - target: setup.create-folders + run: | + import os + echo f"{os.getcwd()}" + echo "working-directory-no-path [I] Done!" + + target-absolute: + working-directory: "/tmp/target1" + help: Test global no-path, group no-path, target absolute + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/target1" + echo "working-directory-no-path [II] Done!" + + target-relative: + working-directory: "target2" + help: Test global no-path, group no-path, target relative + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/target2" + echo "working-directory-no-path [III] Done!" + + group-absolute: + working-directory: "/tmp/group-absolute" + targets: + target-no-path: + help: Test global no-path, group absolute path, target no-path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/group-absolute" + echo "working-directory-no-path [IV] Done!" + + target-absolute: + working-directory: /tmp/target1 + help: Test global no-path, group absolute path, target absolute path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/target1" + echo "working-directory-no-path [V] Done!" + + target-relative: + working-directory: "target1" + help: Test global no-path, group absolute path, target relative path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/group-absolute/target1" + echo "working-directory-no-path [VI] Done!" + + group-relative: + working-directory: "group-relative" + targets: + target-no-path: + help: Test global no-path, group relative path, target no-path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/group-relative" + echo "working-directory-no-path [VII] Done!" + + target-absolute: + working-directory: "/tmp/target2" + help: Test global no-path, group relative path, target absolute path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/target2" + echo "working-directory-no-path [VIII] Done!" + + target-relative: + working-directory: "target1" + help: Test global no-path, group relative path, target relative path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/group-relative/target1" + echo "working-directory-no-path [IX] Done!" diff --git a/tests/.makim-working-directory-relative-path.yaml b/tests/.makim-working-directory-relative-path.yaml new file mode 100644 index 0000000..136f17f --- /dev/null +++ b/tests/.makim-working-directory-relative-path.yaml @@ -0,0 +1,113 @@ +version: 1.0 +working-directory: "global-relative" + +groups: + setup: + targets: + create-folders: + run: | + mkdir -p /tmp/global-relative + mkdir -p /tmp/global-relative/target1 + mkdir -p /tmp/global-relative/target2 + mkdir -p /tmp/global-relative/group-absolute/target1 + mkdir -p /tmp/global-relative/group-relative/target1 + + group-no-path: + targets: + target-no-path: + help: Test global relative path, group no-path, target no-path + dependencies: + - target: setup.create-folders + run: | + import os + print(os.getcwd()) + assert os.getcwd() == "/tmp/global-relative" + echo "working-directory-relative-path [I] Done!" + + target-absolute: + working-directory: "/tmp/global-relative/target1" + help: Test global relative path, group no-path, target absolute path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/global-relative/target1" + echo "working-directory-relative-path [II] Done!" + + target-relative: + working-directory: "target2" + help: Test global relative path, group no-path, target relative path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/global-relative/target2" + echo "working-directory-relative-path [III] Done!" + + group-absolute: + working-directory: "/tmp/global-relative/group-absolute" + targets: + target-no-path: + help: Test global relative path, group absolute path, target no-path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/global-relative/group-absolute" + echo "working-directory-relative-path [IV] Done!" + + target-absolute: + working-directory: "/tmp/global-relative/target2" + help: | + Test global relative path, group absolute path, target absolute path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/global-relative/target2" + echo "working-directory-relative-path [V] Done!" + + target-relative: + working-directory: "target1" + help: | + Test global relative path, group absolute path, target relative path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/global-relative/group-absolute/target1" + echo "working-directory-relative-path [VI] Done!" + + group-relative: + working-directory: "group-relative" + targets: + target-no-path: + help: Test global relative path, group relative path, target no-path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/global-relative/group-relative" + echo "working-directory-relative-path [VII] Done!" + + target-absolute: + working-directory: "/tmp/global-relative/target2" + help: | + Test global relative path, group absolute path, target absolute path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/global-relative/target2" + echo "working-directory-relative-path [VIII] Done!" + + target-relative: + working-directory: "target1" + help: | + Test global relative path, group absolute path, target relative path + dependencies: + - target: setup.create-folders + run: | + import os + assert os.getcwd() == "/tmp/global-relative/group-relative/target1" + echo "working-directory-relative-path [IX] Done!"