From 65fbde3efff23999b38732e0c7db9744c497459e Mon Sep 17 00:00:00 2001 From: Grashalmbeisser <57599830+Grashalmbeisser@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:21:45 +0100 Subject: [PATCH] Redid viur create workflow (#176) * ported clean base tio setup.py * fixed replacement bug * removed viur gcloud setup function * pythonesque directory changes * now using subprocess * minor fixes * minor fixes --- src/viur_cli/cloud.py | 118 +----------------------------------------- src/viur_cli/setup.py | 88 ++++++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 131 deletions(-) diff --git a/src/viur_cli/cloud.py b/src/viur_cli/cloud.py index 206e017..5c582fc 100644 --- a/src/viur_cli/cloud.py +++ b/src/viur_cli/cloud.py @@ -245,7 +245,7 @@ def disable_gcp_backup(): @cloud.command(context_settings={"ignore_unknown_options": True}) -@click.argument("action", type=click.Choice(["gcloud", "gcroles"])) +@click.argument("action", type=click.Choice(["gcroles"])) @click.argument("profile", default="default") def setup(action, profile): """ @@ -258,7 +258,6 @@ def setup(action, profile): echo_error("No 'deploy' directory found in your current working directory." "\n Please make sure you are in the correct directory." "\n If you want to create a new ViUR Project use 'viur create {name}'") - if action == "gcroles": gcloud_setup_roles(profile) @@ -420,121 +419,6 @@ def transform_dict_to_yaml(transformed_data): return original_data -def gcloud_setup(): - """ - Set up the Google Cloud Platform (GCP) environment for a ViUR project. - - This method performs the following steps: - 1. Prompts the user to enter the GCP project ID. - 2. Checks if the user is authorized with gcloud. - - If not authorized, prompts the user to authenticate with gcloud and login. - 3. Checks if the GCP App Engine app already exists. - - If not, prompts the user to create the app and confirm the project is connected to a billing account. - 4. Enables necessary APIs and services for the project. - 5. Configures Google Cloud Storage for the project. - 6. Deploys necessary deployment files (cron.yaml, queue.yaml, index.yaml) to the project. - 7. Checks if the app engine default credentials are set. - - If not set, prompts the user to authenticate and set the application default user. - 8. Prints a success message with instructions on how to run the project locally. - - Note: This method does not return anything. - """ - project = input("Enter PROJECT_ID: ").strip() - - if not project: - echo_fatal("Usage: viur setup gcloud PROJECT_ID") - return - - echo_info("Check if user is authorized with gcloud....") - - try: - run_command("gcloud auth print-access-token") - except subprocess.CalledProcessError: - echo_warning( - "##############################################################\n" - "# Please authenticate your Google user with gcloud SDK to #\n" - "# execute administrative commands. #\n" - "# In this step, a separate browser window opens to #\n" - "# authenticate. #\n" - "# This step is only required once on this computer. #\n" - "##############################################################\n" - ) - response = input("Are you ready?[Y/n]") - if not response.lower() in ("y", ""): - echo_fatal("User aborted") - return - - run_command("gcloud auth login --no-ptomote") - - # Check if App already exists - try: - run_command(f"gcloud app describe --project={project}") - except subprocess.CalledProcessError: - echo_warning( - "##############################################################\n" - "# Please check and confirm that your project is created and #\n" - "# connected with a billing account in Google Cloud console. #\n" - "# Otherwise, some of the following calls may fail. #\n" - "##############################################################" - ) - response = input("Continue? [Y/n] ") - if not response.lower() in ("y", ""): - echo_error("User aborted.") - return - - # Create the Appengine app - run_command(f"gcloud app create --project={project} --region=europe-west3") - - # Activate APIs and Services - services = [ - "datastore.googleapis.com", - "firestore.googleapis.com", - "iamcredentials.googleapis.com", - "cloudbuild.googleapis.com", - "cloudtasks.googleapis.com", - "cloudscheduler.googleapis.com", - "secretmanager.googleapis.com" - ] - - for service in services: - run_command(f"gcloud services enable --project={project} {service}") - - # Configure Google Cloud Storage - run_command(f"gsutil uniformbucketlevelaccess set on gs://{project}.appspot.com/") - - for yaml in ["cron.yaml", "queue.yaml", "index.yaml"]: - run_command(f"cd deploy && gcloud app deploy -q --project={project} {yaml}") - - echo_info("Check if app engine default credentials are set...") - try: - run_command("gcloud auth application-default print-access-token") - - except subprocess.CalledProcessError: - echo_warning( - "##############################################################\n" - "# Please authenticate your Google user with gcloud SDK now #\n" - "# to set the application default user. This step is required #\n" - "# to run ViUR applications locally without further #\n" - "# credentials that must be supplied from a file. #\n" - "# This step is only required once on this computer. #\n" - "##############################################################") - response = input("Are you ready? [Y/n] ") - if not response.lower() in ("y", ""): - echo_fatal("User aborted.") - return - - run_command("gcloud auth application-default login") - - echo_positive( - "All done!\n" - "You should now be able to run your project locally with\n" - " viur run \n" - "At the first run, it might happen that some functions are\n" - "causing error 500 because indexes are not immediately\n" - "served. Therefore, maybe wait a few minutes.\n" - "Have a nice day.\n") - - # Helper function for running Commands in subprocess and getting the Output def run_command(command): """ diff --git a/src/viur_cli/setup.py b/src/viur_cli/setup.py index f52bcaa..f95b4d6 100644 --- a/src/viur_cli/setup.py +++ b/src/viur_cli/setup.py @@ -1,10 +1,71 @@ -import click import os -from .conf import config +import subprocess +import click from .cli import cli from .utils import * +def clean_base(app_id, author=None): + """ + Sets up a clean ViUR project base. + + Args: + clean_history (bool, optional): Whether to clean the git history. Defaults to True. + app_id (str, optional): The application-id to use. If not provided, prompts the user. + author (str, optional): The author's name to use. If not provided, defaults to the current user. + """ + + try: + whoami = getpass.getuser() + except Exception: + whoami = "viur" + + timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + os.chdir(app_id) + + file_list = ["viur-project.md"] + replacements = {"{{app_id}}": app_id, "{{whoami}}": whoami, "{{timestamp}}": timestamp} + + for subdir, dirs, files in os.walk("."): + for file in files: + filepath = subdir + os.sep + file + + if any([filepath.endswith(ext) for ext in + [".py", ".yaml", ".html", ".md", ".sh", ".json", ".js", ".less"]]): + file_list.append(filepath) + + for file_obj in file_list: + lines = [] + with open(file_obj, "r") as infile: + for line in infile: + for src, target in replacements.items(): + line = line.replace(src, target) + lines.append(line) + with open(file_obj, "w") as outfile: + for line in lines: + outfile.write(line) + + if os.path.exists(".git"): + echo_info("Cleaning git history") + subprocess.check_output("git checkout --orphan main_tmp", shell=True) + echo_info(subprocess.check_output("git branch -D main", shell=True).decode().rstrip("\n")) + + subprocess.check_output("git branch -m main", shell=True) + echo_info( + f"Current branch is: {subprocess.check_output("git branch --show-current", shell=True) + .decode().rstrip("\n")}") + echo_info("---") + + echo_info("Generating project documentation...") + sys.stdout.flush() + + os.remove("README.md") # Remove README.md if it exists + os.rename("viur-project.md", "README.md") + os.remove(sys.argv[0]) # Remove the script itself + + echo_positive("Project repository has been set-up now.") + + @cli.command() @click.argument("name") @click.pass_context @@ -31,21 +92,20 @@ def create(ctx, name): """ if os.path.exists(f'./{name}'): - echo_error(f'"{name}" Folder exists. Please use a different name or remove this folder ./{name}') + echo_error(f'"{name}" Folder already exists. Please use a different name or remove this folder ./{name}') return # fetch base project - os.system( - f'git clone https://github.com/viur-framework/viur-base.git {name}') - project_json_path = f'./{name}/project.json' + git_clonne_cmd = ['git', 'clone', f'https://github.com/viur-framework/viur-base.git', name] + subprocess.run(git_clonne_cmd, check=True) - # collect project info - conf = config.get_profile("default") - appname = conf['application_name'] + wdir = f"{os.getcwd()}/{name}" - # run clean-base - os.system(f'cd ./{name} && python3 clean-base.py -A={appname}') + # Run clean-base.py + clean_base_cmd = ['python3', 'clean-base.py', '-A', f'{name}'] + subprocess.run(clean_base_cmd, check=True, cwd=wdir) - # run gcloud config - if click.confirm(f'Do you want to configure "{appname}" as a new gcloud project?'): - os.system(f'cd ./{name} && ./viur-gcloud-setup.sh {appname}') + # Run gcloud config (if confirmed) + if click.confirm(f'Do you want to configure "{name}" as a new gcloud project?'): + gcloud_setup_cmd = ['./viur-gcloud-setup.sh', name] + subprocess.run(gcloud_setup_cmd, check=True, cwd=wdir)