def test_git(capfd: Capture, faker: Faker) -> None: create_project( capfd=capfd, name=random_project_name(faker), ) init_project(capfd) assert git.get_repo("does/not/exist") is None do_repo = git.get_repo("submodules/do") assert do_repo is not None assert git.get_active_branch(None) is None assert git.get_active_branch(do_repo) == __version__ assert not git.switch_branch(None, branch_name="0.7.3") # Same branch => no change => return True assert git.switch_branch(do_repo, branch_name=__version__) assert not git.switch_branch(do_repo, branch_name="XYZ") assert git.switch_branch(do_repo, branch_name="0.7.3") assert git.get_active_branch(do_repo) == "0.7.3" assert git.switch_branch(do_repo, branch_name=__version__) assert git.get_active_branch(do_repo) == __version__ assert git.get_origin(None) is None r = git.get_repo(".") assert git.get_origin(r) == "https://your_remote_git/your_project.git" # Create an invalid repo (i.e. without any remote) r = git.init("../justatest") assert git.get_origin(r) is None
def install_controller_from_folder(version: str) -> None: do_path = SUBMODULES_DIR.joinpath("do") try: Application.git_submodules() except SystemExit: log.info( """You asked to install rapydo {ver} in editable mode, but {p} is missing. You can force the installation by disabling the editable mode: rapydo install {ver} --no-editable """, ver=version, p=do_path, ) raise log.info( "You asked to install rapydo {}. It will be installed in editable mode", version, ) do_repo = Application.gits.get("do") b = git.get_active_branch(do_repo) if b is None: log.error( "Unable to read local controller repository") # pragma: no cover elif b == version: log.info("Controller repository already at {}", version) elif git.switch_branch(do_repo, version): log.info("Controller repository switched to {}", version) else: print_and_exit("Invalid version") Packages.install(do_path, editable=True) log.info("Controller version {} installed from local folder", version)
def test_base(capfd: Capture) -> None: execute_outside(capfd, "check") create_project( capfd=capfd, name="third", auth="postgres", frontend="angular", ) init_project(capfd) repo = git.get_repo("submodules/http-api") git.switch_branch(repo, "0.7.6") exec_command( capfd, "check -i main", f"http-api: wrong branch 0.7.6, expected {__version__}", f"You can fix it with {colors.RED}rapydo init{colors.RESET}", ) init_project(capfd) with TemporaryRemovePath(DATA_DIR): exec_command( capfd, "check -i main --no-git --no-builds", "Folder not found: data", "Please note that this command only works from inside a rapydo-like repo", "Verify that you are in the right folder, now you are in: ", ) with TemporaryRemovePath(Path("projects/third/builds")): exec_command( capfd, "check -i main --no-git --no-builds", "Project third is invalid: required folder not found projects/third/builds", ) with TemporaryRemovePath(Path(".gitignore")): exec_command( capfd, "check -i main --no-git --no-builds", "Project third is invalid: required file not found .gitignore", ) # Add a custom image to extend base backend image: with open("projects/third/confs/commons.yml", "a") as f: f.write( """ services: backend: build: ${PROJECT_DIR}/builds/backend image: third/backend:${RAPYDO_VERSION} """ ) os.makedirs("projects/third/builds/backend") with open("projects/third/builds/backend/Dockerfile", "w+") as f: f.write( f""" FROM rapydo/backend:{__version__} RUN mkdir xyz """ ) # Skipping main because we are on a fake git repository exec_command( capfd, "check -i main", f" image, execute {colors.RED}rapydo pull", f" image, execute {colors.RED}rapydo build", f"Compose is installed with version {COMPOSE_VERSION}", f"Buildx is installed with version {BUILDX_VERSION}", "Checks completed", ) exec_command( capfd, "--stack invalid check -i main", "Failed to read projects/third/confs/invalid.yml: File does not exist", ) os.mkdir("submodules/rapydo-confs") exec_command( capfd, "check -i main --no-git --no-builds", "Project third contains an obsolete file or folder: submodules/rapydo-confs", ) shutil.rmtree("submodules/rapydo-confs") # Test selection with two projects create_project( capfd=capfd, name="justanother", auth="postgres", frontend="no", ) os.remove(".projectrc") exec_command( capfd, "check -i main --no-git --no-builds", "Multiple projects found, please use --project to specify one of the following", ) # Test with zero projects with TemporaryRemovePath(Path("projects")): os.mkdir("projects") # in this case SystemExit is raised in the command init... with pytest.raises(SystemExit): exec_command( capfd, "check -i main --no-git --no-builds", "No project found (is projects folder empty?)", ) shutil.rmtree("projects") exec_command( capfd, "-p third check -i main --no-git --no-builds", "Checks completed", ) # Numbers are not allowed as first characters pname = "2invalidcharacter" os.makedirs(f"projects/{pname}") exec_command( capfd, f"-p {pname} check -i main --no-git --no-builds", "Wrong project name, found invalid characters: 2", ) shutil.rmtree(f"projects/{pname}") invalid_characters = { "_": "_", "-": "-", "C": "C", # Invalid characters in output are ordered # Numbers are allowed if not leading "_C-2": "-C_", } # Check invalid and reserved project names for invalid_key, invalid_value in invalid_characters.items(): pname = f"invalid{invalid_key}character" os.makedirs(f"projects/{pname}") exec_command( capfd, f"-p {pname} check -i main --no-git --no-builds", f"Wrong project name, found invalid characters: {invalid_value}", ) shutil.rmtree(f"projects/{pname}") os.makedirs("projects/celery") exec_command( capfd, "-p celery check -i main --no-git --no-builds", "You selected a reserved name, invalid project name: celery", ) shutil.rmtree("projects/celery") exec_command( capfd, "-p fourth check -i main --no-git --no-builds", "Wrong project fourth", "Select one of the following: ", ) # Test init of data folders shutil.rmtree(LOGS_FOLDER) assert not LOGS_FOLDER.is_dir() # Let's restore .projectrc and data/logs init_project(capfd, "--project third") assert LOGS_FOLDER.is_dir() exec_command( capfd, "check -i main --no-git --no-builds", "Checks completed", ) # Test dirty repo fin = open("submodules/do/new_file", "wt+") fin.write("xyz") fin.close() exec_command( capfd, "check -i main", "You have unstaged files on do", "Untracked files:", "submodules/do/new_file", ) with open(".gitattributes", "a") as a_file: a_file.write("\n") a_file.write("# new line") exec_command( capfd, "check -i main", ".gitattributes changed, " f"please execute {colors.RED}rapydo upgrade --path .gitattributes", ) exec_command( capfd, "--prod check -i main --no-git --no-builds", "The following variables are missing in your configuration", "You can fix this error by updating your .projectrc file", ) # Default ALCHEMY_PASSWORD has as score of 2 exec_command( capfd, "-e MIN_PASSWORD_SCORE=3 check -i main --no-git --no-builds", "The password used in ALCHEMY_PASSWORD is weak", ) exec_command( capfd, "-e MIN_PASSWORD_SCORE=4 check -i main --no-git --no-builds", "The password used in ALCHEMY_PASSWORD is very weak", ) exec_command( capfd, "-e MIN_PASSWORD_SCORE=4 -e AUTH_DEFAULT_PASSWORD=x check -i main --no-git --no-builds", "The password used in AUTH_DEFAULT_PASSWORD is extremely weak", ) exec_command( capfd, "--prod init -f", "Created default .projectrc file", "Project initialized", ) exec_command( capfd, "--prod check -i main --no-git --no-builds", "Checks completed", ) if Configuration.swarm_mode: # Skipping main because we are on a fake git repository exec_command( capfd, "check -i main", "Swarm is correctly initialized", "Checks completed", ) docker = Docker() docker.client.swarm.leave(force=True) exec_command( capfd, "check -i main", f"Swarm is not initialized, please execute {colors.RED}rapydo init", ) exec_command( capfd, "init", "Swarm is now initialized", "Project initialized", ) exec_command( capfd, "check -i main", "Swarm is correctly initialized", "Checks completed", ) check = "check -i main --no-git --no-builds" exec_command( capfd, f"-e ASSIGNED_MEMORY_BACKEND=50G {check}", "Your deployment requires 50GB of RAM but your nodes only have", # The error does not halt the checks execution "Checks completed", ) exec_command( capfd, f"-e ASSIGNED_CPU_BACKEND=50.0 {check}", "Your deployment requires ", " cpus but your nodes only have ", # The error does not halt the checks execution "Checks completed", ) exec_command( capfd, f"-e DEFAULT_SCALE_BACKEND=55 -e ASSIGNED_MEMORY_BACKEND=1G {check}", "Your deployment requires 55GB of RAM but your nodes only have", # The error does not halt the checks execution "Checks completed", ) exec_command( capfd, f"-e DEFAULT_SCALE_BACKEND=50 -e ASSIGNED_CPU_BACKEND=1.0 {check}", "Your deployment requires ", " cpus but your nodes only have ", # The error does not halt the checks execution "Checks completed", )
def test_init(capfd: Capture, faker: Faker) -> None: execute_outside(capfd, "init") create_project( capfd=capfd, name=random_project_name(faker), auth="postgres", frontend="no", ) exec_command( capfd, "check -i main", "Repo https://github.com/rapydo/http-api.git missing as submodules/http-api.", "You should init your project", ) if Configuration.swarm_mode: exec_command( capfd, "-e HEALTHCHECK_INTERVAL=1s -e SWARM_MANAGER_ADDRESS=127.0.0.1 init", "docker compose is installed", "Initializing Swarm with manager IP 127.0.0.1", "Swarm is now initialized", "Project initialized", ) docker = Docker() docker.client.swarm.leave(force=True) local_ip = system.get_local_ip(production=False) exec_command( capfd, "-e HEALTHCHECK_INTERVAL=1s -e SWARM_MANAGER_ADDRESS= init", "docker compose is installed", "Swarm is now initialized", f"Initializing Swarm with manager IP {local_ip}", "Project initialized", ) exec_command( capfd, "init", "Swarm is already initialized", "Project initialized", ) else: init_project(capfd) repo = git.get_repo("submodules/http-api") git.switch_branch(repo, "0.7.6") exec_command( capfd, "init", f"Switched http-api branch from 0.7.6 to {__version__}", f"build-templates already set on branch {__version__}", f"do already set on branch {__version__}", ) os.rename("submodules", "submodules.bak") os.mkdir("submodules") # This is to re-fill the submodules folder, # these folder will be removed by the next init exec_command(capfd, "init", "Project initialized") modules_path = Path("submodules.bak").resolve() with TemporaryRemovePath(Path("submodules.bak/do")): exec_command( capfd, f"init --submodules-path {modules_path}", "Submodule do not found in ", ) exec_command( capfd, f"init --submodules-path {modules_path}", "Path submodules/http-api already exists, removing", "Project initialized", ) assert os.path.islink("submodules/do") assert not os.path.islink("submodules.bak/do") # Init again, this time in submodules there are links... # and will be removed as well as the folders exec_command( capfd, f"init --submodules-path {modules_path}", "Path submodules/http-api already exists, removing", "Project initialized", ) exec_command( capfd, "init --submodules-path invalid/path", "Local path not found: invalid/path", ) exec_command( capfd, "--prod init -f", "Created default .projectrc file", "Project initialized", ) exec_command( capfd, "--prod -e MYVAR=MYVAL init -f", "Created default .projectrc file", "Project initialized", ) with open(".projectrc") as projectrc: lines = [line.strip() for line in projectrc.readlines()] assert "MYVAR: MYVAL" in lines
def test_install(capfd: Capture, faker: Faker) -> None: execute_outside(capfd, "install") project = random_project_name(faker) create_project( capfd=capfd, name=project, auth="postgres", frontend="no", ) init_project(capfd) # Initially the controller is installed from pip exec_command( capfd, "update -i main", "Controller not updated because it is installed outside this project", "Installation path is ", ", the current folder is ", "All updated", ) with TemporaryRemovePath(SUBMODULES_DIR.joinpath("do")): exec_command( capfd, "install", "missing as submodules/do. You should init your project", ) exec_command(capfd, "install 100.0", "Invalid version") exec_command(capfd, "install docker", "Docker current version:", "Docker installed version:") exec_command(capfd, "install compose", "Docker compose is installed") exec_command( capfd, "install buildx", "Docker buildx current version:", "Docker buildx installed version:", ) exec_command(capfd, "install auto") r = git.get_repo("submodules/do") git.switch_branch(r, "0.7.6") exec_command( capfd, "install", f"Controller repository switched to {__version__}", ) # Here the controller is installed in editable mode from the correct submodules # folder (this is exactly the default normal condition) exec_command( capfd, "update -i main", # Controller installed from {} and updated "Controller installed from ", " and updated", "All updated", ) # Install the controller from a linked folder to verify that the post-update checks # are able to correctly resolve symlinks # ########################################################### # Copied from test_init_check_update.py from here... SUBMODULES_DIR.rename("submodules.bak") SUBMODULES_DIR.mkdir() # This is to re-fill the submodules folder, # these folder will be removed by the next init exec_command(capfd, "init", "Project initialized") modules_path = Path("submodules.bak").resolve() exec_command( capfd, f"init --submodules-path {modules_path}", "Path submodules/http-api already exists, removing", "Project initialized", ) # ... to here # ########################################################### exec_command( capfd, "update -i main", # Controller installed from {} and updated "Controller installed from ", " and updated", "All updated", ) # This test will change the required version pconf = f"projects/{project}/project_configuration.yaml" # Read and change the content fin = open(pconf) data = fin.read() data = data.replace(f'rapydo: "{__version__}"', 'rapydo: "0.7.6"') fin.close() # Write the new content fin = open(pconf, "wt") fin.write(data) fin.close() exec_command( capfd, "version", f"This project is not compatible with rapydo version {__version__}", "Please downgrade rapydo to version 0.7.6 or modify this project", ) # Read and change the content fin = open(pconf) data = fin.read() data = data.replace('rapydo: "0.7.6"', 'rapydo: "99.99.99"') fin.close() # Write the new content fin = open(pconf, "wt") fin.write(data) fin.close() exec_command( capfd, "version", f"This project is not compatible with rapydo version {__version__}", "Please upgrade rapydo to version 99.99.99 or modify this project", ) exec_command(capfd, "install --no-editable 0.8") exec_command(capfd, "install --no-editable") exec_command(capfd, "install")