From 430e8da919ca4e4df05a4e57e824be431c34c0e5 Mon Sep 17 00:00:00 2001 From: vguptarippling Date: Tue, 23 Apr 2024 00:29:13 +0530 Subject: [PATCH 1/6] Added rippling flux build init command --- .gitignore | 3 + rippling_cli/cli/commands/flux/app.py | 16 ++- rippling_cli/cli/commands/flux/build.py | 51 +++++++++ rippling_cli/cli/commands/flux/flux.py | 2 + rippling_cli/config/config.py | 5 +- rippling_cli/core/api_client.py | 10 +- rippling_cli/core/setup_project.py | 112 ++++++++++++++++++++ rippling_cli/exceptions/__init__.py | 0 rippling_cli/exceptions/build_exceptions.py | 10 ++ rippling_cli/utils/app_utils.py | 24 +++++ rippling_cli/utils/build_utils.py | 107 +++++++++++++++++++ rippling_cli/utils/file_utils.py | 79 ++++++++++++++ rippling_cli/utils/login_utils.py | 27 +++++ 13 files changed, 430 insertions(+), 16 deletions(-) create mode 100644 rippling_cli/cli/commands/flux/build.py create mode 100644 rippling_cli/core/setup_project.py create mode 100644 rippling_cli/exceptions/__init__.py create mode 100644 rippling_cli/exceptions/build_exceptions.py create mode 100644 rippling_cli/utils/app_utils.py create mode 100644 rippling_cli/utils/build_utils.py create mode 100644 rippling_cli/utils/file_utils.py diff --git a/.gitignore b/.gitignore index b126c53..5cdac40 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,6 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ + +# rippling cli +.rippling_cli/ diff --git a/rippling_cli/cli/commands/flux/app.py b/rippling_cli/cli/commands/flux/app.py index a9727b0..a88f64d 100644 --- a/rippling_cli/cli/commands/flux/app.py +++ b/rippling_cli/cli/commands/flux/app.py @@ -4,6 +4,7 @@ from rippling_cli.config.config import get_app_config, save_app_config from rippling_cli.constants import RIPPLING_API from rippling_cli.core.api_client import APIClient +from rippling_cli.utils.app_utils import get_app_from_id from rippling_cli.utils.login_utils import ensure_logged_in @@ -38,20 +39,17 @@ def list() -> None: def set(app_id: str) -> None: """This command sets the current app within the app_config.json file located in the .rippling directory.""" ctx: click.Context = click.get_current_context() - api_client = APIClient(base_url=RIPPLING_API, headers={"Authorization": f"Bearer {ctx.obj.oauth_token}"}) - - endpoint = "/apps/api/apps/?large_get_query=true" - response = api_client.post(endpoint, data={"query": f"id={app_id}&limit=1"}) - app_list = response.json() if response.status_code == 200 else [] + app_json = get_app_from_id(app_id, ctx.obj.oauth_token) - if response.status_code != 200 or len(app_list) == 0: + if not app_json: click.echo(f"Invalid app id: {app_id}") return - app_name = app_list[0].get("displayName") + display_name = app_json.get("displayName") + app_name = app_json.get("name") - save_app_config(app_id, app_name) - click.echo(f"Current app set to {app_name} ({app_id})") + save_app_config(app_id, display_name, app_name) + click.echo(f"Current app set to {display_name} ({app_id})") @app.command() diff --git a/rippling_cli/cli/commands/flux/build.py b/rippling_cli/cli/commands/flux/build.py new file mode 100644 index 0000000..4263b20 --- /dev/null +++ b/rippling_cli/cli/commands/flux/build.py @@ -0,0 +1,51 @@ +import click + +from rippling_cli.config.config import get_app_config +from rippling_cli.utils.app_utils import get_starter_package_for_app +from rippling_cli.utils.build_utils import ( + remove_existing_starter_package, + starter_package_already_extracted_on_current_directory, +) +from rippling_cli.utils.file_utils import download_file_using_url, extract_zip_to_current_cwd +from rippling_cli.utils.login_utils import ensure_logged_in, get_current_role_name_and_email +from rippling_cli.utils.setup_project import setup_project + + +@click.group() +@click.pass_context +def build(ctx: click.Context) -> None: + """Manage flux builds""" + ensure_logged_in(ctx) + + +@build.command() +def init() -> None: + """This command downloads the starter package and extracts it into a specified folder.""" + ctx: click.Context = click.get_current_context() + + if starter_package_already_extracted_on_current_directory(): + if not click.confirm("Starter package already extracted. Do you want to replace?"): + return + remove_existing_starter_package() + + # get the starter package for the app + download_url: str = get_starter_package_for_app(ctx.obj.oauth_token) + if not download_url: + click.echo("No starter package found.") + return + app_config = get_app_config() + app_display_name = app_config.get('displayName') + filename = app_display_name + ".zip" + # download the starter package + is_file_downloaded = download_file_using_url(download_url, filename) + if not is_file_downloaded: + click.echo("Failed to download the starter package.") + return + + # extract the starter package + extract_zip_to_current_cwd(filename) + + name, email = get_current_role_name_and_email(ctx.obj.oauth_token) + + # setup the project + setup_project(name, email) diff --git a/rippling_cli/cli/commands/flux/flux.py b/rippling_cli/cli/commands/flux/flux.py index 0055862..5903f82 100644 --- a/rippling_cli/cli/commands/flux/flux.py +++ b/rippling_cli/cli/commands/flux/flux.py @@ -1,6 +1,7 @@ import click from rippling_cli.cli.commands.flux.app import app +from rippling_cli.cli.commands.flux.build import build from rippling_cli.utils.login_utils import ensure_logged_in @@ -12,3 +13,4 @@ def flux(ctx: click.Context) -> None: flux.add_command(app) # type: ignore +flux.add_command(build) # type: ignore diff --git a/rippling_cli/config/config.py b/rippling_cli/config/config.py index 8734df7..c8406d7 100644 --- a/rippling_cli/config/config.py +++ b/rippling_cli/config/config.py @@ -83,7 +83,7 @@ def get_app_config(): return {} -def save_app_config(app_id: str, app_name: str): +def save_app_config(app_id: str, display_name: str, app_name: str): """ Save the app configuration to the specified directory. Args: @@ -95,7 +95,8 @@ def save_app_config(app_id: str, app_name: str): app_config = { "id": app_id, - "displayName": app_name + "displayName": display_name, + "name": app_name, } config_file = config_dir / APP_CONFIG_FILE diff --git a/rippling_cli/core/api_client.py b/rippling_cli/core/api_client.py index f6c72d0..10c9738 100644 --- a/rippling_cli/core/api_client.py +++ b/rippling_cli/core/api_client.py @@ -6,15 +6,15 @@ def __init__(self, base_url, headers=None): self.base_url = base_url self.headers = headers or {} - def make_request(self, method, endpoint, params=None, data=None): + def make_request(self, method, endpoint, params=None, data=None, stream=False): url = f"{self.base_url.rstrip('/')}/{endpoint.lstrip('/')}" - response = requests.request(method, url, params=params, json=data, headers=self.headers) + response = requests.request(method, url, params=params, json=data, headers=self.headers, stream=stream) return response - def get(self, endpoint, params=None): - return self.make_request("GET", endpoint, params=params) + def get(self, endpoint, params=None, stream=False): + return self.make_request("GET", endpoint, params=params, stream=stream) - def post(self, endpoint, data): + def post(self, endpoint, data=None): return self.make_request("POST", endpoint, data=data) def put(self, endpoint, data): diff --git a/rippling_cli/core/setup_project.py b/rippling_cli/core/setup_project.py new file mode 100644 index 0000000..0c1f6ad --- /dev/null +++ b/rippling_cli/core/setup_project.py @@ -0,0 +1,112 @@ +import os +import subprocess +import sys + +import click + +from rippling_cli.exceptions.build_exceptions import PythonCreationFailed +from rippling_cli.utils.build_utils import create_pyproject_toml, get_run_config_xml_content +from rippling_cli.utils.file_utils import create_directory_inside_path + + +# TODO: Since run configuration cannot be transferred from import/export settings , it lies inside .idea folder in \ +# the project directory. This should be a separate command +def create_run_configurations(project_name: str): + # Create the .idea directory if it doesn't exist + create_directory_inside_path(os.getcwd(), ".idea") + + # Create the runConfigurations directory inside .idea + create_directory_inside_path(f"{os.getcwd()}/.idea", "runConfigurations") + + # Create the Flask__flux_dev_tools_server_flask_.xml file + xml_file_path = os.path.join(f"{os.getcwd()}/.idea/runConfigurations", "Flask__flux_dev_tools_server_flask_.xml") + with open(xml_file_path, "w") as xml_file: + xml_file.write(get_run_config_xml_content(project_name)) + + +def setup_project(name=None, email=None): + # Check if pip is available + try: + subprocess.check_output(["pip", "--version"]) + except FileNotFoundError: + click.echo("pip is not installed. Installing Python and pip...") + + # Install Python + install_python() + + # Check if Python installation was successful + try: + subprocess.check_output(["python", "--version"]) + except FileNotFoundError: + click.echo("Python installation failed. Please install Python manually.") + return + + # Install pip using ensurepip + subprocess.run([sys.executable, "-m", "ensurepip", "--default-pip"]) + click.echo("pip has been installed.") + + # Check if Poetry is installed + try: + subprocess.check_output(["poetry", "--version"]) + click.echo("Poetry is already installed.") + except FileNotFoundError: + click.echo("Poetry is not installed. Installing Poetry...") + + # Install Poetry using pip + subprocess.run(["pip", "install", "poetry"]) + click.echo("Poetry has been installed.") + + # Check if Poetry is installed successfully + try: + subprocess.check_output(["poetry", "--version"]) + except FileNotFoundError: + click.echo("Poetry installation failed. Please install Poetry manually.") + return + + # Check if pyproject.toml already exists + if os.path.exists("pyproject.toml"): + click.echo("pyproject.toml already exists. Aborting setup.") + return + + authors = "developer " + if name and email: + authors = f"{name} <{email}>" # Use provided name and email + + # Get the current working directory + current_directory = os.getcwd() + + project_name = os.path.basename(current_directory) # Default project name + project_name.replace("-", "_") + + # Create pyproject.toml file with default content + create_pyproject_toml(project_name, authors) + + # Install dependencies + click.echo("Installing dependencies...") + subprocess.run(["poetry", "install"]) + click.echo("Dependencies installed.") + + +def install_python(): + if sys.platform == "darwin": # Check if macOS + # Try installing Python using Homebrew + try: + subprocess.run(["brew", "install", "python"]) + return + except FileNotFoundError: + pass # Homebrew not available, fall back to manual installation + + # Prompt the user to install Python manually from python.org + click.echo("Python is not installed. Please install Python manually from https://www.python.org/downloads/") + raise PythonCreationFailed() + elif sys.platform.startswith("linux"): + # Install Python on Linux using package manager (e.g., apt) + subprocess.run(["sudo", "apt", "update"]) + subprocess.run(["sudo", "apt", "install", "python3"]) + elif sys.platform.startswith("win"): + # Install Python on Windows using python.org installer + click.echo("Please install Python manually from https://www.python.org/downloads/") + raise PythonCreationFailed() + else: + click.echo("Unsupported platform. Please install Python manually.") + raise PythonCreationFailed() diff --git a/rippling_cli/exceptions/__init__.py b/rippling_cli/exceptions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rippling_cli/exceptions/build_exceptions.py b/rippling_cli/exceptions/build_exceptions.py new file mode 100644 index 0000000..8261b3c --- /dev/null +++ b/rippling_cli/exceptions/build_exceptions.py @@ -0,0 +1,10 @@ +class PythonCreationFailed(Exception): + def __init__(self, message="Failed to install Python. Please install Python manually."): + self.message = message + super().__init__(self.message) + + +class DirectoryCreationFailed(Exception): + def __init__(self, message="Failed to create directory."): + self.message = message + super().__init__(self.message) \ No newline at end of file diff --git a/rippling_cli/utils/app_utils.py b/rippling_cli/utils/app_utils.py new file mode 100644 index 0000000..5361375 --- /dev/null +++ b/rippling_cli/utils/app_utils.py @@ -0,0 +1,24 @@ +from rippling_cli.config.config import get_app_config +from rippling_cli.constants import RIPPLING_API +from rippling_cli.core.api_client import APIClient + + +def get_app_from_id(app_id, oauth_token): + api_client = APIClient(base_url=RIPPLING_API, headers={"Authorization": f"Bearer {oauth_token}"}) + + endpoint = "/apps/api/apps/?large_get_query=true" + response = api_client.post(endpoint, data={"query": f"id={app_id}&limit=1"}) + app_list = response.json() if response.status_code == 200 else [] + + if response.status_code != 200 or len(app_list) == 0: + return None + return app_list[0] + + +def get_starter_package_for_app(oauth_token): + api_client = APIClient(base_url=RIPPLING_API, headers={"Authorization": f"Bearer {oauth_token}"}) + app_config = get_app_config() + endpoint = f"/apps/api/flux_apps/get_starter_package?app_name={app_config.get('name')}" + response = api_client.post(endpoint) + response.raise_for_status() + return response.json().get("link") \ No newline at end of file diff --git a/rippling_cli/utils/build_utils.py b/rippling_cli/utils/build_utils.py new file mode 100644 index 0000000..7b73ac4 --- /dev/null +++ b/rippling_cli/utils/build_utils.py @@ -0,0 +1,107 @@ +import os +import shutil + +import click + + +def get_target_directory_path(): + # Get the current working directory + cwd = os.getcwd() + + # Get the directory name from the cwd and replace hyphens with underscores + directory_name = os.path.basename(cwd).replace("-", "_") + + # Construct the path for the directory we're looking for + return os.path.join(cwd, directory_name) + + +def starter_package_already_extracted_on_current_directory(): + target_dir_path = get_target_directory_path() + + # Check if the directory exists + if os.path.exists(target_dir_path): + # Check if the 'manifest' file exists in the target directory + app_dir_path = os.path.join(target_dir_path, "app") + if os.path.isdir(app_dir_path): + # Check if the 'app' directory exists in the target directory + manifest_dir_path = os.path.join(app_dir_path, "manifest.json") + if os.path.isfile(manifest_dir_path): + return True + + return False + + +def remove_existing_starter_package(): + # Construct the path for the directory we want to remove + target_dir_path = get_target_directory_path() + + # Remove the directory with hyphens replaced by underscores and its contents + if os.path.exists(target_dir_path): + try: + shutil.rmtree(target_dir_path) + except Exception: + pass + + # Remove the pyproject.toml, poetry.lock, .venv, and .idea files/directories + files_to_remove = ["pyproject.toml", "poetry.lock", ".venv", ".idea"] + for file_or_dir in files_to_remove: + file_or_dir_path = os.path.join(os.getcwd(), file_or_dir) + if os.path.exists(file_or_dir_path): + try: + if os.path.isfile(file_or_dir_path): + os.remove(file_or_dir_path) + else: + shutil.rmtree(file_or_dir_path) + except Exception: + pass + + +def get_run_config_xml_content(project_name): + return f""" + + + + + +""" + + +def get_pyproject_toml_content(project_name="my-project", authors="developer "): + return f""" +[tool.poetry] +name = "{project_name}" +version = "0.1.0" +description = "" +authors = ["{authors}"] + +[tool.poetry.dependencies] +python = "^3.10" +rippling-flux-sdk = "^0.16.40" +rippling-flux-dev-tools = "^0.1.12" +flask = "^2" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +""" + + +def create_pyproject_toml(project_name="my-project", authors="developer "): + click.echo("Creating pyproject.toml file...") + with open("pyproject.toml", "w") as toml_file: + toml_file.write(get_pyproject_toml_content(project_name, authors)) + click.echo("pyproject.toml file created.") + diff --git a/rippling_cli/utils/file_utils.py b/rippling_cli/utils/file_utils.py new file mode 100644 index 0000000..80487de --- /dev/null +++ b/rippling_cli/utils/file_utils.py @@ -0,0 +1,79 @@ +import os +import zipfile +from pathlib import Path + +import click +import requests # type: ignore + +from rippling_cli.exceptions.build_exceptions import DirectoryCreationFailed + + +def create_directory_inside_path(path: str, dir_name: str): + # Construct the path for the new directory + new_dir_path = os.path.join(path, dir_name) + + # Create the new directory + try: + os.mkdir(new_dir_path) + except FileExistsError: + return + except Exception: + raise DirectoryCreationFailed() + + +def extract_zip_to_current_cwd(filename): + """Extracts the contents of a ZIP archive to a new directory with the same name as the archive inside the current + working directory. """ + # Get the current working directory + cwd = os.getcwd() + + # Get the directory name from the cwd + dir_name = os.path.basename(cwd) + + # Replace any hyphens in the directory name with underscores + dir_name = dir_name.replace('-', '_') + # Create a new directory with same name inside the current working directory + create_directory_inside_path(cwd, dir_name) + + output_path = Path.cwd() / dir_name # Path to the new directory + + # Create the __init__.py file inside the new directory to make it a package + init_file_path = os.path.join(output_path, "__init__.py") + open(init_file_path, "w").close() + + file_path = Path.cwd() / filename # Path to the zip file + if filename.endswith(".zip"): + with zipfile.ZipFile(file_path, "r") as zip_ref: + zip_ref.extractall(output_path) + click.echo("ZIP archive extracted successfully.") + + delete_zip_file(file_path) + + +def download_file_using_url(url: str, app_display_name: str = None): + filename = app_display_name if app_display_name else url.split("/")[-1] + output_path = Path.cwd() + output_file = output_path / filename + try: + response = requests.get(url, stream=True) + response.raise_for_status() + with open(output_file, "wb") as file: + for chunk in response.iter_content(chunk_size=8192): + file.write(chunk) + except Exception: + click.echo("Failed to download file") + return False + return True + + +def delete_zip_file(zip_file_path): + """ + Delete the zip file after it has been extracted. + + Args: + zip_file_path (str): The path to the zip file to delete. + """ + try: + os.remove(zip_file_path) + except FileNotFoundError: + raise FileNotFoundError(f"File {zip_file_path} not found.") diff --git a/rippling_cli/utils/login_utils.py b/rippling_cli/utils/login_utils.py index 7169611..3ed5680 100644 --- a/rippling_cli/utils/login_utils.py +++ b/rippling_cli/utils/login_utils.py @@ -1,6 +1,8 @@ import click from rippling_cli.cli.commands.login import login +from rippling_cli.constants import RIPPLING_API +from rippling_cli.core.api_client import APIClient from rippling_cli.core.oauth_token import OAuthToken @@ -8,3 +10,28 @@ def ensure_logged_in(ctx: click.Context): if OAuthToken.is_token_expired(): click.echo("You are not logged in. Please log in first.") ctx.invoke(login) + + +def get_account_info(oauth_token): + api_client = APIClient(base_url=RIPPLING_API, headers={"Authorization": f"Bearer {oauth_token}"}) + endpoint = "/auth_ext/get_account_info" + response = api_client.get(endpoint) + response.raise_for_status() + return response.json() + + +def get_employee_details(role_id, oauth_token): + api_client = APIClient(base_url=RIPPLING_API, headers={"Authorization": f"Bearer {oauth_token}"}) + endpoint = f"/api/hub/api/employment_roles_with_company/{role_id}" + response = api_client.get(endpoint) + response.raise_for_status() + return response.json() + + +def get_current_role_name_and_email(oauth_token): + account_info_dict = get_account_info(oauth_token) + if not account_info_dict and len(account_info_dict) == 0: + return None, None + role_id = account_info_dict[0].get("id") + employee_details = get_employee_details(role_id, oauth_token) + return employee_details.get("fullName"), employee_details.get("workEmail") From 16920d5c501ec94fee51223592fa86801d05a982 Mon Sep 17 00:00:00 2001 From: vguptarippling Date: Tue, 23 Apr 2024 00:30:43 +0530 Subject: [PATCH 2/6] added comment --- rippling_cli/core/setup_project.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rippling_cli/core/setup_project.py b/rippling_cli/core/setup_project.py index 0c1f6ad..cd391da 100644 --- a/rippling_cli/core/setup_project.py +++ b/rippling_cli/core/setup_project.py @@ -10,7 +10,8 @@ # TODO: Since run configuration cannot be transferred from import/export settings , it lies inside .idea folder in \ -# the project directory. This should be a separate command +# the project directory. This should be a separate command \ +# https://intellij-support.jetbrains.com/hc/en-us/community/posts/206600965-Export-Import-Run-Configurations def create_run_configurations(project_name: str): # Create the .idea directory if it doesn't exist create_directory_inside_path(os.getcwd(), ".idea") From 8f2e73c3f591e66b510220eee150619494f36460 Mon Sep 17 00:00:00 2001 From: vguptarippling Date: Tue, 23 Apr 2024 00:40:40 +0530 Subject: [PATCH 3/6] fixed import --- rippling_cli/cli/commands/flux/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rippling_cli/cli/commands/flux/build.py b/rippling_cli/cli/commands/flux/build.py index 4263b20..efae776 100644 --- a/rippling_cli/cli/commands/flux/build.py +++ b/rippling_cli/cli/commands/flux/build.py @@ -1,6 +1,7 @@ import click from rippling_cli.config.config import get_app_config +from rippling_cli.core.setup_project import setup_project from rippling_cli.utils.app_utils import get_starter_package_for_app from rippling_cli.utils.build_utils import ( remove_existing_starter_package, @@ -8,7 +9,6 @@ ) from rippling_cli.utils.file_utils import download_file_using_url, extract_zip_to_current_cwd from rippling_cli.utils.login_utils import ensure_logged_in, get_current_role_name_and_email -from rippling_cli.utils.setup_project import setup_project @click.group() From 9556b29cdd0c97e49fbae033b6612dea01bf661f Mon Sep 17 00:00:00 2001 From: vguptarippling Date: Tue, 23 Apr 2024 00:42:20 +0530 Subject: [PATCH 4/6] fixed typing --- rippling_cli/utils/file_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rippling_cli/utils/file_utils.py b/rippling_cli/utils/file_utils.py index 80487de..5cafe2c 100644 --- a/rippling_cli/utils/file_utils.py +++ b/rippling_cli/utils/file_utils.py @@ -1,6 +1,7 @@ import os import zipfile from pathlib import Path +from typing import Optional import click import requests # type: ignore @@ -50,7 +51,7 @@ def extract_zip_to_current_cwd(filename): delete_zip_file(file_path) -def download_file_using_url(url: str, app_display_name: str = None): +def download_file_using_url(url: str, app_display_name: Optional[str] = None): filename = app_display_name if app_display_name else url.split("/")[-1] output_path = Path.cwd() output_file = output_path / filename From 8c1c6274d5c77814abf71869822ea797328bda1d Mon Sep 17 00:00:00 2001 From: vguptarippling Date: Wed, 24 Apr 2024 14:48:15 +0530 Subject: [PATCH 5/6] review comment changes --- rippling_cli/core/setup_project.py | 68 ++++++++++++++++++------------ rippling_cli/utils/build_utils.py | 31 +++++--------- rippling_cli/utils/file_utils.py | 18 +------- rippling_cli/utils/login_utils.py | 2 +- 4 files changed, 54 insertions(+), 65 deletions(-) diff --git a/rippling_cli/core/setup_project.py b/rippling_cli/core/setup_project.py index cd391da..d738a49 100644 --- a/rippling_cli/core/setup_project.py +++ b/rippling_cli/core/setup_project.py @@ -25,44 +25,59 @@ def create_run_configurations(project_name: str): xml_file.write(get_run_config_xml_content(project_name)) -def setup_project(name=None, email=None): - # Check if pip is available +def check_python_installed(): try: - subprocess.check_output(["pip", "--version"]) + subprocess.check_output(["python", "--version"]) + return True except FileNotFoundError: - click.echo("pip is not installed. Installing Python and pip...") + return False - # Install Python - install_python() - # Check if Python installation was successful - try: - subprocess.check_output(["python", "--version"]) - except FileNotFoundError: - click.echo("Python installation failed. Please install Python manually.") - return +def install_pip(): + subprocess.run([sys.executable, "-m", "ensurepip", "--default-pip"]) + click.echo("pip has been installed.") - # Install pip using ensurepip - subprocess.run([sys.executable, "-m", "ensurepip", "--default-pip"]) - click.echo("pip has been installed.") - # Check if Poetry is installed +def check_pip_installed(): try: - subprocess.check_output(["poetry", "--version"]) - click.echo("Poetry is already installed.") + subprocess.check_output(["pip", "--version"]) except FileNotFoundError: - click.echo("Poetry is not installed. Installing Poetry...") + click.echo("pip is not installed. Installing pip...") + install_pip() + + +def install_poetry(): + subprocess.run(["pip", "install", "poetry"]) + click.echo("Poetry has been installed.") - # Install Poetry using pip - subprocess.run(["pip", "install", "poetry"]) - click.echo("Poetry has been installed.") - # Check if Poetry is installed successfully +def check_poetry_installed(): try: subprocess.check_output(["poetry", "--version"]) + return True except FileNotFoundError: - click.echo("Poetry installation failed. Please install Poetry manually.") - return + return False + + +def setup_project(name=None, email=None): + # Check if Python is already installed + if not check_python_installed(): + click.echo("Python is not installed. Installing Python...") + install_python() + if not check_python_installed(): + click.echo("Python installation failed. Please install Python manually.") + return + + # Check if pip is installed + check_pip_installed() + + # Check if Poetry is installed + if not check_poetry_installed(): + click.echo("Poetry is not installed. Installing Poetry...") + install_poetry() + if not check_poetry_installed(): + click.echo("Poetry installation failed. Please install Poetry manually.") + return # Check if pyproject.toml already exists if os.path.exists("pyproject.toml"): @@ -76,8 +91,7 @@ def setup_project(name=None, email=None): # Get the current working directory current_directory = os.getcwd() - project_name = os.path.basename(current_directory) # Default project name - project_name.replace("-", "_") + project_name = "app" # Default project name # Create pyproject.toml file with default content create_pyproject_toml(project_name, authors) diff --git a/rippling_cli/utils/build_utils.py b/rippling_cli/utils/build_utils.py index 7b73ac4..12ac564 100644 --- a/rippling_cli/utils/build_utils.py +++ b/rippling_cli/utils/build_utils.py @@ -4,36 +4,25 @@ import click -def get_target_directory_path(): - # Get the current working directory - cwd = os.getcwd() - - # Get the directory name from the cwd and replace hyphens with underscores - directory_name = os.path.basename(cwd).replace("-", "_") - - # Construct the path for the directory we're looking for - return os.path.join(cwd, directory_name) - def starter_package_already_extracted_on_current_directory(): - target_dir_path = get_target_directory_path() + cwd = os.getcwd() - # Check if the directory exists - if os.path.exists(target_dir_path): - # Check if the 'manifest' file exists in the target directory - app_dir_path = os.path.join(target_dir_path, "app") - if os.path.isdir(app_dir_path): - # Check if the 'app' directory exists in the target directory - manifest_dir_path = os.path.join(app_dir_path, "manifest.json") - if os.path.isfile(manifest_dir_path): - return True + # Check if the 'manifest' file exists in the target directory + app_dir_path = os.path.join(cwd, "app") + if os.path.isdir(app_dir_path): + # Check if the 'app' directory exists in the target directory + manifest_dir_path = os.path.join(app_dir_path, "manifest.json") + if os.path.isfile(manifest_dir_path): + return True return False def remove_existing_starter_package(): # Construct the path for the directory we want to remove - target_dir_path = get_target_directory_path() + cwd = os.getcwd() + target_dir_path = os.path.join(cwd, "app") # Remove the directory with hyphens replaced by underscores and its contents if os.path.exists(target_dir_path): diff --git a/rippling_cli/utils/file_utils.py b/rippling_cli/utils/file_utils.py index 5cafe2c..1c2598d 100644 --- a/rippling_cli/utils/file_utils.py +++ b/rippling_cli/utils/file_utils.py @@ -25,22 +25,8 @@ def create_directory_inside_path(path: str, dir_name: str): def extract_zip_to_current_cwd(filename): """Extracts the contents of a ZIP archive to a new directory with the same name as the archive inside the current working directory. """ - # Get the current working directory - cwd = os.getcwd() - # Get the directory name from the cwd - dir_name = os.path.basename(cwd) - - # Replace any hyphens in the directory name with underscores - dir_name = dir_name.replace('-', '_') - # Create a new directory with same name inside the current working directory - create_directory_inside_path(cwd, dir_name) - - output_path = Path.cwd() / dir_name # Path to the new directory - - # Create the __init__.py file inside the new directory to make it a package - init_file_path = os.path.join(output_path, "__init__.py") - open(init_file_path, "w").close() + output_path = Path.cwd() # Path to the new directory file_path = Path.cwd() / filename # Path to the zip file if filename.endswith(".zip"): @@ -77,4 +63,4 @@ def delete_zip_file(zip_file_path): try: os.remove(zip_file_path) except FileNotFoundError: - raise FileNotFoundError(f"File {zip_file_path} not found.") + pass diff --git a/rippling_cli/utils/login_utils.py b/rippling_cli/utils/login_utils.py index 3ed5680..0bcc8ab 100644 --- a/rippling_cli/utils/login_utils.py +++ b/rippling_cli/utils/login_utils.py @@ -14,7 +14,7 @@ def ensure_logged_in(ctx: click.Context): def get_account_info(oauth_token): api_client = APIClient(base_url=RIPPLING_API, headers={"Authorization": f"Bearer {oauth_token}"}) - endpoint = "/auth_ext/get_account_info" + endpoint = "/auth_ext/get_account_info_v2/" response = api_client.get(endpoint) response.raise_for_status() return response.json() From 34faa2fc3cddb037a0ba11524ec0433de09b2fb2 Mon Sep 17 00:00:00 2001 From: vguptarippling Date: Wed, 24 Apr 2024 14:48:30 +0530 Subject: [PATCH 6/6] import fixes --- rippling_cli/core/setup_project.py | 3 --- rippling_cli/utils/build_utils.py | 1 - 2 files changed, 4 deletions(-) diff --git a/rippling_cli/core/setup_project.py b/rippling_cli/core/setup_project.py index d738a49..c668c7e 100644 --- a/rippling_cli/core/setup_project.py +++ b/rippling_cli/core/setup_project.py @@ -88,9 +88,6 @@ def setup_project(name=None, email=None): if name and email: authors = f"{name} <{email}>" # Use provided name and email - # Get the current working directory - current_directory = os.getcwd() - project_name = "app" # Default project name # Create pyproject.toml file with default content diff --git a/rippling_cli/utils/build_utils.py b/rippling_cli/utils/build_utils.py index 12ac564..89c195b 100644 --- a/rippling_cli/utils/build_utils.py +++ b/rippling_cli/utils/build_utils.py @@ -4,7 +4,6 @@ import click - def starter_package_already_extracted_on_current_directory(): cwd = os.getcwd()