thestage 0.6.7__py3-none-any.whl → 0.6.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- thestage/__init__.py +1 -1
- thestage/cli_command_helper.py +2 -2
- thestage/config/__init__.py +1 -1
- thestage/{services → config/business}/app_config_service.py +3 -4
- thestage/{services/config_provider → config/business}/config_provider.py +6 -5
- thestage/config/{config_storage.py → business/config_storage.py} +1 -1
- thestage/{services → config/business}/validation_service.py +9 -10
- thestage/{controllers/config_controller.py → config/communication/config_command.py} +7 -7
- thestage/{services/connect → connect/business}/connect_service.py +22 -19
- thestage/{services → connect/business}/remote_server_service.py +4 -5
- thestage/connect/communication/connect_api_client.py +84 -0
- thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_response.py +0 -1
- thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_response.py +1 -4
- thestage/{services/clients/thestage_api/dtos/base_controller → connect/dto}/connect_resolve_response.py +0 -1
- thestage/controllers/base_controller.py +2 -2
- thestage/debug_main.dist.py +16 -14
- thestage/{services/container → docker_container/business}/container_service.py +27 -22
- thestage/{services/container → docker_container/business}/mapper/container_mapper.py +3 -3
- thestage/docker_container/communication/__init__.py +0 -0
- thestage/{controllers/container_controller.py → docker_container/communication/docker_command.py} +17 -23
- thestage/docker_container/communication/docker_container_api_client.py +99 -0
- thestage/docker_container/dto/__init__.py +0 -0
- thestage/docker_container/dto/container_action_request.py +11 -0
- thestage/{services/clients/thestage_api/dtos → docker_container/dto}/container_response.py +4 -4
- thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_response.py +3 -5
- thestage/docker_container/dto/enum/__init__.py +0 -0
- thestage/git/__init__.py +0 -0
- thestage/git/business/__init__.py +0 -0
- thestage/git/communication/__init__.py +0 -0
- thestage/{services/clients/git → git/communication}/git_client.py +4 -4
- thestage/global_dto/__init__.py +0 -0
- thestage/global_dto/enums/__init__.py +0 -0
- thestage/helpers/error_handler.py +3 -3
- thestage/helpers/logger/app_logger.py +1 -3
- thestage/i18n/en_GB/messages.po +14 -14
- thestage/inference_model/__init__.py +0 -0
- thestage/inference_model/business/__init__.py +0 -0
- thestage/inference_model/business/inference_model_service.py +281 -0
- thestage/inference_model/business/mapper/__init__.py +0 -0
- thestage/{services/project/mapper/project_inference_simulator_model_mapper.py → inference_model/business/mapper/inference_model_mapper.py} +5 -5
- thestage/inference_model/communication/__init__.py +0 -0
- thestage/inference_model/communication/inference_model_api_client.py +139 -0
- thestage/inference_model/communication/inference_model_command.py +246 -0
- thestage/inference_model/dto/__init__.py +0 -0
- thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_response.py +0 -1
- thestage/inference_model/dto/enum/__init__.py +0 -0
- thestage/{services/project/dto/inference_simulator_model_dto.py → inference_model/dto/inference_model.py} +1 -1
- thestage/{entities/project_inference_simulator_model.py → inference_model/dto/inference_model_entity.py} +1 -1
- thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_response.py +2 -3
- thestage/{services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py → inference_model/dto/push_inference_simulator_model_request.py} +1 -1
- thestage/{services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_response.py → inference_model/dto/push_inference_simulator_model_response.py} +1 -1
- thestage/inference_simulator/__init__.py +0 -0
- thestage/inference_simulator/business/__init__.py +0 -0
- thestage/inference_simulator/business/inference_simulator_service.py +338 -0
- thestage/inference_simulator/business/mapper/__init__.py +0 -0
- thestage/{services/project/mapper/project_inference_simulator_mapper.py → inference_simulator/business/mapper/inference_simulator_mapper.py} +5 -5
- thestage/inference_simulator/communication/__init__.py +0 -0
- thestage/inference_simulator/communication/inference_simulator_api_client.py +114 -0
- thestage/inference_simulator/communication/inference_simulator_command.py +347 -0
- thestage/inference_simulator/dto/__init__.py +0 -0
- thestage/inference_simulator/dto/enum/__init__.py +0 -0
- thestage/inference_simulator/dto/get_inference_simulator_response.py +12 -0
- thestage/{services/project/dto/inference_simulator_dto.py → inference_simulator/dto/inference_simulator.py} +1 -1
- thestage/{entities/project_inference_simulator.py → inference_simulator/dto/inference_simulator_entity.py} +1 -1
- thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_response.py +2 -2
- thestage/{services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py → inference_simulator/dto/start_inference_simulator_request.py} +1 -1
- thestage/inference_simulator/dto/start_inference_simulator_response.py +10 -0
- thestage/instance/__init__.py +0 -0
- thestage/instance/business/__init__.py +0 -0
- thestage/{services/instance → instance/business}/instance_service.py +26 -27
- thestage/instance/business/mapper/__init__.py +0 -0
- thestage/{services/instance/mapper/instance_mapper.py → instance/business/mapper/rented_instance_mapper.py} +3 -3
- thestage/{services/instance/mapper/selfhosted_mapper.py → instance/business/mapper/selfhosted_instance_mapper.py} +5 -7
- thestage/instance/communication/__init__.py +0 -0
- thestage/instance/communication/instance_api_client.py +150 -0
- thestage/{controllers/instance_controller.py → instance/communication/instance_command.py} +5 -5
- thestage/instance/dto/__init__.py +0 -0
- thestage/instance/dto/enum/__init__.py +0 -0
- thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_detected_gpus.py +1 -2
- thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_rented_response.py +2 -2
- thestage/{services/clients/thestage_api/dtos → instance/dto}/selfhosted_instance_response.py +2 -3
- thestage/logging/__init__.py +0 -0
- thestage/logging/business/__init__.py +0 -0
- thestage/{services/logging → logging/business}/logging_service.py +40 -28
- thestage/logging/communication/__init__.py +0 -0
- thestage/logging/communication/logging_api_client.py +63 -0
- thestage/logging/dto/__init__.py +0 -0
- thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_response.py +2 -2
- thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_response.py +2 -2
- thestage/main.py +47 -8
- thestage/project/__init__.py +0 -0
- thestage/project/business/__init__.py +0 -0
- thestage/project/business/project_service.py +480 -0
- thestage/project/communication/__init__.py +0 -0
- thestage/project/communication/project_api_client.py +46 -0
- thestage/project/communication/project_command.py +284 -0
- thestage/project/dto/__init__.py +0 -0
- thestage/services/clients/thestage_api/core/api_client_core.py +1 -1
- thestage/services/clients/thestage_api/dtos/entity_filter_request.py +1 -1
- thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +1 -1
- thestage/services/filesystem_service.py +2 -2
- thestage/services/service_factory.py +130 -43
- thestage/task/__init__.py +0 -0
- thestage/task/business/__init__.py +0 -0
- thestage/task/business/mapper/__init__.py +0 -0
- thestage/{services/project/mapper/project_task_mapper.py → task/business/mapper/task_mapper.py} +5 -5
- thestage/task/business/task_service.py +304 -0
- thestage/task/communication/__init__.py +0 -0
- thestage/task/communication/task_api_client.py +122 -0
- thestage/task/communication/task_command.py +212 -0
- thestage/task/dto/__init__.py +0 -0
- thestage/task/dto/enum/__init__.py +0 -0
- thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_response.py → task/dto/list_for_project_response.py} +2 -2
- thestage/{services/clients/thestage_api/dtos/project_controller/project_run_task_request.py → task/dto/run_task_request.py} +1 -1
- thestage/task/dto/run_task_response.py +13 -0
- thestage/{services/task/dto/task_dto.py → task/dto/task.py} +1 -4
- thestage/{entities/project_task.py → task/dto/task_entity.py} +1 -1
- thestage/{services/clients/thestage_api/dtos/task_controller/task_view_response.py → task/dto/view_response.py} +2 -2
- {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/METADATA +1 -1
- thestage-0.6.8.dist-info/RECORD +219 -0
- {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/WHEEL +1 -1
- thestage/controllers/project_controller.py +0 -1056
- thestage/services/clients/thestage_api/api_client.py +0 -751
- thestage/services/clients/thestage_api/dtos/container_param_request.py +0 -11
- thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_response.py +0 -13
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +0 -13
- thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_response.py +0 -10
- thestage/services/clients/thestage_api/dtos/user_controller/user_profile.py +0 -12
- thestage/services/project/project_service.py +0 -1287
- thestage-0.6.7.dist-info/RECORD +0 -167
- /thestage/{entities → color_scheme}/__init__.py +0 -0
- /thestage/{entities/enums → config/business}/__init__.py +0 -0
- /thestage/{services/clients/git → config/communication}/__init__.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → config/dto}/__init__.py +0 -0
- /thestage/{services/core_files → config/dto}/config_entity.py +0 -0
- /thestage/{services/connect → config}/dto/remote_server_config.py +0 -0
- /thestage/{services/config_provider → connect}/__init__.py +0 -0
- /thestage/{services/container → connect/business}/__init__.py +0 -0
- /thestage/{services/container/mapper → connect/communication}/__init__.py +0 -0
- /thestage/{services/instance → connect/dto}/__init__.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_response.py +0 -0
- /thestage/{services/instance/mapper → docker_container}/__init__.py +0 -0
- /thestage/{services/project → docker_container/business}/__init__.py +0 -0
- /thestage/{services/project → docker_container/business}/mapper/__init__.py +0 -0
- /thestage/{entities/container.py → docker_container/dto/container_entity.py} +0 -0
- /thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos → docker_container/dto}/docker_container_mapping.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_pending_action.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_status.py +0 -0
- /thestage/{services/logging/exception → exceptions}/log_polling_exception.py +0 -0
- /thestage/git/{ProgressPrinter.py → business/ProgressPrinter.py} +0 -0
- /thestage/{entities → global_dto}/enums/order_direction_type.py +0 -0
- /thestage/{entities → global_dto}/enums/shell_type.py +0 -0
- /thestage/{entities → global_dto}/enums/tail_output_type.py +0 -0
- /thestage/{entities → global_dto}/enums/yes_no_response.py +0 -0
- /thestage/{entities → global_dto}/file_item.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_response.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → inference_model/dto/enum}/inference_model_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos → inference_model/dto}/inference_simulator_model_response.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → inference_simulator/dto/enum}/inference_simulator_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/get_inference_simulator_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos → inference_simulator/dto}/inference_simulator_response.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/cpu_type.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/gpu_name.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/instance_rented_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/provider_name.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/selfhosted_status.py +0 -0
- /thestage/{entities → instance/dto}/rented_instance.py +0 -0
- /thestage/{entities → instance/dto}/self_hosted_instance.py +0 -0
- /thestage/{services/logging → logging}/byte_print_style.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/docker_container_log_stream_request.py +0 -0
- /thestage/{services/logging → logging}/dto/log_message.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_request.py +0 -0
- /thestage/{services/logging → logging}/dto/log_type.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/task_log_stream_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_request.py +0 -0
- /thestage/{services/logging → logging}/logging_constants.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py → project/dto/get_deploy_ssh_key_request.py} +0 -0
- /thestage/{services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_response.py → project/dto/get_deploy_ssh_key_response.py} +0 -0
- /thestage/{services/project → project}/dto/project_config.py +0 -0
- /thestage/{services/clients/thestage_api/dtos → project/dto}/project_response.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_execution_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py → task/dto/list_for_project_request.py} +0 -0
- /thestage/{services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py → task/dto/status_localized_map_response.py} +0 -0
- {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/entry_points.txt +0 -0
- {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/licenses/LICENSE.txt +0 -0
|
File without changes
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from typing import Optional, List
|
|
2
2
|
|
|
3
|
-
from pydantic import Field, ConfigDict
|
|
3
|
+
from pydantic import Field, ConfigDict
|
|
4
4
|
|
|
5
5
|
from thestage.services.clients.thestage_api.dtos.base_response import TheStageBaseResponse
|
|
6
|
-
from thestage.
|
|
6
|
+
from thestage.logging.dto.log_message import LogMessage
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class LogPollingResponse(TheStageBaseResponse):
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from typing import Optional, List
|
|
2
2
|
|
|
3
|
-
from pydantic import Field, ConfigDict
|
|
3
|
+
from pydantic import Field, ConfigDict
|
|
4
4
|
|
|
5
5
|
from thestage.services.clients.thestage_api.dtos.base_response import TheStageBaseResponse
|
|
6
|
-
from thestage.
|
|
6
|
+
from thestage.logging.dto.log_message import LogMessage
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class UserLogsQueryResponse(TheStageBaseResponse):
|
thestage/main.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from thestage.helpers import exception_hook
|
|
2
1
|
import traceback
|
|
3
2
|
|
|
4
3
|
from thestage.cli_command_helper import get_command_group_help_panel
|
|
5
4
|
from thestage.helpers.logger.app_logger import app_logger, get_log_path_from_os
|
|
5
|
+
from thestage.services.clients.thestage_api.core.api_client_core import TheStageApiClientCore
|
|
6
6
|
from thestage.services.service_factory import ServiceFactory
|
|
7
7
|
from rich import print
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ def main():
|
|
|
14
14
|
|
|
15
15
|
try:
|
|
16
16
|
try:
|
|
17
|
-
api_client =
|
|
17
|
+
api_client = TheStageApiClientCore(url=config.main.thestage_api_url)
|
|
18
18
|
token_info = api_client.validate_token(config.main.thestage_auth_token)
|
|
19
19
|
config_provider.update_allowed_commands_and_is_token_valid(validate_token_response=token_info)
|
|
20
20
|
except Exception as e:
|
|
@@ -23,13 +23,52 @@ def main():
|
|
|
23
23
|
print(f'Application logs path: {str(get_log_path_from_os())}')
|
|
24
24
|
return
|
|
25
25
|
|
|
26
|
-
from thestage.controllers import base_controller
|
|
27
|
-
|
|
26
|
+
from thestage.controllers import base_controller
|
|
27
|
+
from thestage.config.communication import config_command
|
|
28
|
+
from thestage.project.communication import project_command
|
|
29
|
+
from thestage.inference_simulator.communication import inference_simulator_command
|
|
30
|
+
from thestage.inference_model.communication import inference_model_command
|
|
31
|
+
from thestage.task.communication import task_command
|
|
32
|
+
from thestage.instance.communication import instance_command
|
|
33
|
+
from thestage.docker_container.communication import docker_command
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
project_command.app.add_typer(
|
|
36
|
+
inference_simulator_command.app,
|
|
37
|
+
name="inference-simulator",
|
|
38
|
+
rich_help_panel=get_command_group_help_panel()
|
|
39
|
+
)
|
|
40
|
+
project_command.app.add_typer(
|
|
41
|
+
inference_model_command.app,
|
|
42
|
+
name="model",
|
|
43
|
+
rich_help_panel=get_command_group_help_panel()
|
|
44
|
+
)
|
|
45
|
+
project_command.app.add_typer(
|
|
46
|
+
task_command.app,
|
|
47
|
+
name="task",
|
|
48
|
+
rich_help_panel=get_command_group_help_panel()
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
base_controller.app.add_typer(
|
|
52
|
+
project_command.app,
|
|
53
|
+
name="project",
|
|
54
|
+
rich_help_panel=get_command_group_help_panel()
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
base_controller.app.add_typer(
|
|
58
|
+
docker_command.app,
|
|
59
|
+
name="container",
|
|
60
|
+
rich_help_panel=get_command_group_help_panel()
|
|
61
|
+
)
|
|
62
|
+
base_controller.app.add_typer(
|
|
63
|
+
instance_command.app,
|
|
64
|
+
name="instance",
|
|
65
|
+
rich_help_panel=get_command_group_help_panel()
|
|
66
|
+
)
|
|
67
|
+
base_controller.app.add_typer(
|
|
68
|
+
config_command.app,
|
|
69
|
+
name="config",
|
|
70
|
+
rich_help_panel=get_command_group_help_panel()
|
|
71
|
+
)
|
|
33
72
|
|
|
34
73
|
base_controller.app()
|
|
35
74
|
except KeyboardInterrupt:
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
import typer
|
|
6
|
+
from rich import print
|
|
7
|
+
from tabulate import tabulate
|
|
8
|
+
|
|
9
|
+
from thestage.color_scheme.color_scheme import ColorScheme
|
|
10
|
+
from thestage.config.business.config_provider import ConfigProvider
|
|
11
|
+
from thestage.connect.business.remote_server_service import RemoteServerService
|
|
12
|
+
from thestage.docker_container.communication.docker_container_api_client import DockerContainerApiClient
|
|
13
|
+
from thestage.docker_container.dto.container_response import DockerContainerDto
|
|
14
|
+
from thestage.docker_container.dto.enum.container_status import DockerContainerStatus
|
|
15
|
+
from thestage.exceptions.git_access_exception import GitAccessException
|
|
16
|
+
from thestage.git.communication.git_client import GitLocalClient
|
|
17
|
+
from thestage.global_dto.enums.yes_no_response import YesOrNoResponse
|
|
18
|
+
from thestage.helpers.error_handler import error_handler
|
|
19
|
+
from thestage.i18n.translation import __
|
|
20
|
+
from thestage.project.communication.project_api_client import ProjectApiClient
|
|
21
|
+
from thestage.project.dto.project_config import ProjectConfig
|
|
22
|
+
from thestage.project.dto.project_response import ProjectDto
|
|
23
|
+
from thestage.services.abstract_service import AbstractService
|
|
24
|
+
from thestage.services.clients.thestage_api.core.http_client_exception import HttpClientException
|
|
25
|
+
from thestage.services.filesystem_service import FileSystemService
|
|
26
|
+
from thestage.task.communication.task_api_client import TaskApiClient
|
|
27
|
+
from thestage.task.dto.view_response import TaskViewResponse
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ProjectService(AbstractService):
|
|
31
|
+
__docker_container_api_client: DockerContainerApiClient = None
|
|
32
|
+
__project_api_client: ProjectApiClient = None
|
|
33
|
+
__task_api_client: TaskApiClient = None
|
|
34
|
+
__config_provider: ConfigProvider = None
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
task_api_client: TaskApiClient,
|
|
39
|
+
project_api_client: ProjectApiClient,
|
|
40
|
+
docker_container_api_client: DockerContainerApiClient,
|
|
41
|
+
config_provider: ConfigProvider,
|
|
42
|
+
remote_server_service: RemoteServerService,
|
|
43
|
+
file_system_service: FileSystemService,
|
|
44
|
+
git_local_client: GitLocalClient,
|
|
45
|
+
):
|
|
46
|
+
self.__docker_container_api_client = docker_container_api_client
|
|
47
|
+
self.__task_api_client = task_api_client
|
|
48
|
+
self.__project_api_client = project_api_client
|
|
49
|
+
self.__remote_server_service = remote_server_service
|
|
50
|
+
self.__file_system_service = file_system_service
|
|
51
|
+
self.__git_local_client = git_local_client
|
|
52
|
+
self.__config_provider = config_provider
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@error_handler()
|
|
56
|
+
def init_project(
|
|
57
|
+
self,
|
|
58
|
+
project_slug: Optional[str] = None,
|
|
59
|
+
project_public_id: Optional[str] = None,
|
|
60
|
+
):
|
|
61
|
+
config = self.__config_provider.get_config()
|
|
62
|
+
project: Optional[ProjectDto] = self.__project_api_client.get_project(
|
|
63
|
+
slug=project_slug,
|
|
64
|
+
public_id=project_public_id,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if not project:
|
|
68
|
+
typer.echo('Project not found')
|
|
69
|
+
raise typer.Exit(1)
|
|
70
|
+
|
|
71
|
+
is_git_folder = self.__git_local_client.is_present_local_git(
|
|
72
|
+
path=config.runtime.working_directory,
|
|
73
|
+
)
|
|
74
|
+
if is_git_folder:
|
|
75
|
+
has_remote = self.__git_local_client.has_remote(
|
|
76
|
+
path=config.runtime.working_directory,
|
|
77
|
+
)
|
|
78
|
+
if has_remote:
|
|
79
|
+
typer.echo(__('Local repository already has a remote configured; aborting initialization'))
|
|
80
|
+
raise typer.Exit(1)
|
|
81
|
+
|
|
82
|
+
if not project.git_repository_url:
|
|
83
|
+
typer.echo(__('Project does not have git repository url'))
|
|
84
|
+
raise typer.Exit(1)
|
|
85
|
+
|
|
86
|
+
if project.last_commit_hash or project.last_commit_description:
|
|
87
|
+
continue_with_non_empty_repo: YesOrNoResponse = typer.prompt(
|
|
88
|
+
text=__('Remote repository is probably not empty: latest commit is "{commit_description}" (sha: {commit_hash})\nDo you wish to continue?').format(commit_description=project.last_commit_description, commit_hash=project.last_commit_hash),
|
|
89
|
+
show_choices=True,
|
|
90
|
+
default=YesOrNoResponse.YES.value,
|
|
91
|
+
type=click.Choice([r.value for r in YesOrNoResponse]),
|
|
92
|
+
show_default=True,
|
|
93
|
+
)
|
|
94
|
+
if continue_with_non_empty_repo == YesOrNoResponse.NO:
|
|
95
|
+
typer.echo(__('Project init aborted'))
|
|
96
|
+
raise typer.Exit(0)
|
|
97
|
+
|
|
98
|
+
deploy_ssh_key = self.__project_api_client.get_project_deploy_ssh_key(
|
|
99
|
+
public_id=project.public_id,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(
|
|
103
|
+
deploy_ssh_key=deploy_ssh_key,
|
|
104
|
+
project_public_id=project.public_id,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
if is_git_folder:
|
|
108
|
+
has_changes = self.__git_local_client.has_changes_with_untracked(
|
|
109
|
+
path=config.runtime.working_directory,
|
|
110
|
+
)
|
|
111
|
+
if has_changes:
|
|
112
|
+
typer.echo(__('Local repository has uncommitted changes or untracked files. Use an empty directory'))
|
|
113
|
+
raise typer.Exit(1)
|
|
114
|
+
else:
|
|
115
|
+
repo = self.__git_local_client.init_repository(
|
|
116
|
+
path=config.runtime.working_directory,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
is_remote_added = self.__git_local_client.add_remote_to_repo(
|
|
120
|
+
path=config.runtime.working_directory,
|
|
121
|
+
remote_url=project.git_repository_url,
|
|
122
|
+
remote_name=project.git_repository_name,
|
|
123
|
+
)
|
|
124
|
+
if not is_remote_added:
|
|
125
|
+
typer.echo(__('We cannot add remote, something wrong'))
|
|
126
|
+
raise typer.Exit(2)
|
|
127
|
+
|
|
128
|
+
self.__git_local_client.git_fetch(path=config.runtime.working_directory, deploy_key_path=deploy_key_path)
|
|
129
|
+
|
|
130
|
+
self.__git_local_client.init_gitignore(path=config.runtime.working_directory)
|
|
131
|
+
|
|
132
|
+
self.__git_local_client.git_add_all(repo_path=config.runtime.working_directory)
|
|
133
|
+
|
|
134
|
+
project_config = ProjectConfig()
|
|
135
|
+
project_config.public_id = project.public_id
|
|
136
|
+
project_config.slug = project.slug
|
|
137
|
+
project_config.git_repository_url = project.git_repository_url
|
|
138
|
+
project_config.deploy_key_path = str(deploy_key_path)
|
|
139
|
+
self.__config_provider.save_project_config(project_config=project_config)
|
|
140
|
+
|
|
141
|
+
typer.echo(__("Project successfully initialized at %path%", {"path": config.runtime.working_directory}))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@error_handler()
|
|
145
|
+
def clone_project(
|
|
146
|
+
self,
|
|
147
|
+
project_slug: str,
|
|
148
|
+
project_public_id: str
|
|
149
|
+
):
|
|
150
|
+
config = self.__config_provider.get_config()
|
|
151
|
+
project: Optional[ProjectDto] = self.__project_api_client.get_project(
|
|
152
|
+
slug=project_slug,
|
|
153
|
+
public_id=project_public_id
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
if not project:
|
|
157
|
+
typer.echo('Project not found')
|
|
158
|
+
raise typer.Exit(1)
|
|
159
|
+
|
|
160
|
+
if not self.__file_system_service.is_folder_empty(folder=config.runtime.working_directory, auto_create=True):
|
|
161
|
+
typer.echo(__("Cannot clone: the folder is not empty"))
|
|
162
|
+
raise typer.Exit(1)
|
|
163
|
+
|
|
164
|
+
is_git_folder = self.__git_local_client.is_present_local_git(
|
|
165
|
+
path=config.runtime.working_directory,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
if is_git_folder:
|
|
169
|
+
typer.echo(__('Directory already contains a git repository. Cannot clone here'))
|
|
170
|
+
raise typer.Exit(1)
|
|
171
|
+
|
|
172
|
+
if not project.git_repository_url:
|
|
173
|
+
typer.echo(__("Unexpected Project error, missing Repository"))
|
|
174
|
+
raise typer.Exit(1)
|
|
175
|
+
|
|
176
|
+
deploy_ssh_key = self.__project_api_client.get_project_deploy_ssh_key(public_id=project.public_id)
|
|
177
|
+
deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(deploy_ssh_key=deploy_ssh_key, project_public_id=project.public_id,)
|
|
178
|
+
|
|
179
|
+
try:
|
|
180
|
+
self.__git_local_client.clone(
|
|
181
|
+
url=project.git_repository_url,
|
|
182
|
+
path=config.runtime.working_directory,
|
|
183
|
+
deploy_key_path=deploy_key_path
|
|
184
|
+
)
|
|
185
|
+
self.__git_local_client.init_gitignore(path=config.runtime.working_directory)
|
|
186
|
+
except GitAccessException as ex:
|
|
187
|
+
typer.echo(ex.get_message())
|
|
188
|
+
typer.echo(ex.get_dop_message())
|
|
189
|
+
typer.echo(__(
|
|
190
|
+
"Check you email or open this repo url %git_url% and 'Accept invitation'",
|
|
191
|
+
{
|
|
192
|
+
'git_url': ex.get_url()
|
|
193
|
+
}
|
|
194
|
+
))
|
|
195
|
+
raise typer.Exit(1)
|
|
196
|
+
|
|
197
|
+
project_config = ProjectConfig()
|
|
198
|
+
project_config.public_id = project.public_id
|
|
199
|
+
project_config.slug = project.slug
|
|
200
|
+
project_config.git_repository_url = project.git_repository_url
|
|
201
|
+
project_config.deploy_key_path = str(deploy_key_path)
|
|
202
|
+
self.__config_provider.save_project_config(project_config=project_config)
|
|
203
|
+
typer.echo(__("Project successfully cloned to %path%", {"path": config.runtime.working_directory}))
|
|
204
|
+
|
|
205
|
+
@error_handler()
|
|
206
|
+
def checkout_project(
|
|
207
|
+
self,
|
|
208
|
+
task_public_id: Optional[str],
|
|
209
|
+
branch_name: Optional[str],
|
|
210
|
+
):
|
|
211
|
+
config = self.__config_provider.get_config()
|
|
212
|
+
project_config: ProjectConfig = self.get_fixed_project_config()
|
|
213
|
+
if not project_config:
|
|
214
|
+
typer.echo(__("Command must be run from an initialized project directory"))
|
|
215
|
+
raise typer.Exit(1)
|
|
216
|
+
|
|
217
|
+
target_commit_hash: Optional[str] = None
|
|
218
|
+
if task_public_id:
|
|
219
|
+
task_view_response: Optional[TaskViewResponse] = None
|
|
220
|
+
try:
|
|
221
|
+
task_view_response = self.__task_api_client.get_task(task_public_id=task_public_id)
|
|
222
|
+
except HttpClientException as e:
|
|
223
|
+
if e.get_status_code() == 400:
|
|
224
|
+
typer.echo(f"Task {task_public_id} was not found")
|
|
225
|
+
# overriding arguments here
|
|
226
|
+
branch_name = str(task_public_id)
|
|
227
|
+
task_public_id = None
|
|
228
|
+
|
|
229
|
+
if task_view_response and task_view_response.task:
|
|
230
|
+
target_commit_hash = task_view_response.task.commit_hash
|
|
231
|
+
if not target_commit_hash:
|
|
232
|
+
typer.echo(f"Task ({task_public_id}) has no commit hash") # possible legacy problems
|
|
233
|
+
raise typer.Exit(1)
|
|
234
|
+
|
|
235
|
+
is_commit_allowed: bool = True
|
|
236
|
+
|
|
237
|
+
if self.__git_local_client.is_head_detached(path=config.runtime.working_directory):
|
|
238
|
+
is_commit_allowed = False
|
|
239
|
+
if self.__git_local_client.is_head_committed_in_headless_state(path=config.runtime.working_directory):
|
|
240
|
+
commit_message = self.__git_local_client.get_current_commit(
|
|
241
|
+
path=config.runtime.working_directory).message
|
|
242
|
+
print(
|
|
243
|
+
f"[{ColorScheme.GIT_HEADLESS.value}]Your current commit '{commit_message.strip()}' was likely created in detached head state. Checking out will discard all changes.[/{ColorScheme.GIT_HEADLESS.value}]")
|
|
244
|
+
response: YesOrNoResponse = typer.prompt(
|
|
245
|
+
text=__('Continue?'),
|
|
246
|
+
show_choices=True,
|
|
247
|
+
default=YesOrNoResponse.YES.value,
|
|
248
|
+
type=click.Choice([r.value for r in YesOrNoResponse]),
|
|
249
|
+
show_default=True,
|
|
250
|
+
)
|
|
251
|
+
if response == YesOrNoResponse.NO:
|
|
252
|
+
raise typer.Exit(0)
|
|
253
|
+
else:
|
|
254
|
+
if self.__git_local_client.get_active_branch_name(path=config.runtime.working_directory) == branch_name:
|
|
255
|
+
typer.echo(f"You are already at branch '{branch_name}'")
|
|
256
|
+
raise typer.Exit(0)
|
|
257
|
+
|
|
258
|
+
if is_commit_allowed:
|
|
259
|
+
self.__git_local_client.git_add_all(repo_path=config.runtime.working_directory)
|
|
260
|
+
|
|
261
|
+
has_changes = self.__git_local_client.has_changes_with_untracked(
|
|
262
|
+
path=config.runtime.working_directory,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
if has_changes:
|
|
266
|
+
active_branch_name = self.__git_local_client.get_active_branch_name(config.runtime.working_directory)
|
|
267
|
+
diff_stat = self.__git_local_client.git_diff_stat(repo_path=config.runtime.working_directory)
|
|
268
|
+
typer.echo(__('Active branch [%branch_name%] has uncommitted changes: %diff_stat_bottomline%', {
|
|
269
|
+
'diff_stat_bottomline': diff_stat,
|
|
270
|
+
'branch_name': active_branch_name,
|
|
271
|
+
}))
|
|
272
|
+
|
|
273
|
+
response: str = typer.prompt(
|
|
274
|
+
text=__('Commit changes?'),
|
|
275
|
+
show_choices=True,
|
|
276
|
+
default=YesOrNoResponse.YES.value,
|
|
277
|
+
type=click.Choice([r.value for r in YesOrNoResponse]),
|
|
278
|
+
show_default=True,
|
|
279
|
+
)
|
|
280
|
+
if response == YesOrNoResponse.NO.value:
|
|
281
|
+
typer.echo(__('Cannot checkout with uncommitted changes'))
|
|
282
|
+
raise typer.Exit(0)
|
|
283
|
+
|
|
284
|
+
commit_name = typer.prompt(
|
|
285
|
+
text=__('Please provide commit message'),
|
|
286
|
+
show_choices=False,
|
|
287
|
+
type=str,
|
|
288
|
+
show_default=False,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
if commit_name:
|
|
292
|
+
commit_result = self.__git_local_client.commit_local_changes(
|
|
293
|
+
path=config.runtime.working_directory,
|
|
294
|
+
name=commit_name
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
if commit_result:
|
|
298
|
+
# in docs not Commit object, on real - str
|
|
299
|
+
if isinstance(commit_result, str):
|
|
300
|
+
typer.echo(commit_result)
|
|
301
|
+
|
|
302
|
+
self.__git_local_client.push_changes(
|
|
303
|
+
path=config.runtime.working_directory,
|
|
304
|
+
deploy_key_path=project_config.deploy_key_path
|
|
305
|
+
)
|
|
306
|
+
typer.echo(__("Pushed changes to remote repository"))
|
|
307
|
+
else:
|
|
308
|
+
typer.echo(__('Cannot commit with empty commit name'))
|
|
309
|
+
raise typer.Exit(0)
|
|
310
|
+
|
|
311
|
+
if target_commit_hash:
|
|
312
|
+
if self.__git_local_client.get_current_commit(
|
|
313
|
+
path=config.runtime.working_directory).hexsha != target_commit_hash:
|
|
314
|
+
is_checkout_successful = self.__git_local_client.git_checkout_to_commit(
|
|
315
|
+
path=config.runtime.working_directory,
|
|
316
|
+
commit_hash=target_commit_hash
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
if is_checkout_successful:
|
|
320
|
+
print(f"Checked out to commit {target_commit_hash}")
|
|
321
|
+
print(
|
|
322
|
+
f"[{ColorScheme.GIT_HEADLESS.value}]HEAD is detached. To be able make changes in repository, checkout to any branch.[/{ColorScheme.GIT_HEADLESS.value}]")
|
|
323
|
+
else:
|
|
324
|
+
typer.echo("HEAD is already at requested commit")
|
|
325
|
+
elif branch_name:
|
|
326
|
+
if self.__git_local_client.is_branch_exists(path=config.runtime.working_directory, branch_name=branch_name):
|
|
327
|
+
self.__git_local_client.git_checkout_to_branch(
|
|
328
|
+
path=config.runtime.working_directory,
|
|
329
|
+
branch=branch_name
|
|
330
|
+
)
|
|
331
|
+
typer.echo(f"Checked out to branch '{branch_name}'")
|
|
332
|
+
else:
|
|
333
|
+
typer.echo(f"Branch '{branch_name}' was not found in project repository")
|
|
334
|
+
else:
|
|
335
|
+
main_branch = self.__git_local_client.find_main_branch_name(path=config.runtime.working_directory)
|
|
336
|
+
if main_branch:
|
|
337
|
+
self.__git_local_client.git_checkout_to_branch(
|
|
338
|
+
path=config.runtime.working_directory,
|
|
339
|
+
branch=main_branch
|
|
340
|
+
)
|
|
341
|
+
typer.echo(f"Checked out to detected main branch: '{main_branch}'")
|
|
342
|
+
else:
|
|
343
|
+
typer.echo("No main branch found")
|
|
344
|
+
|
|
345
|
+
@error_handler()
|
|
346
|
+
def set_default_container(
|
|
347
|
+
self,
|
|
348
|
+
container_public_id: Optional[str],
|
|
349
|
+
container_slug: Optional[str],
|
|
350
|
+
):
|
|
351
|
+
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
352
|
+
|
|
353
|
+
if project_config is None:
|
|
354
|
+
typer.echo(f"No project found in working directory")
|
|
355
|
+
raise typer.Exit(1)
|
|
356
|
+
|
|
357
|
+
container: Optional[DockerContainerDto] = None
|
|
358
|
+
if container_slug or container_public_id:
|
|
359
|
+
container: DockerContainerDto = self.__docker_container_api_client.get_container(
|
|
360
|
+
container_public_id=container_public_id,
|
|
361
|
+
container_slug=container_slug,
|
|
362
|
+
)
|
|
363
|
+
if container is None:
|
|
364
|
+
typer.echo(f"Could not find container '{container_slug or container_public_id}'")
|
|
365
|
+
raise typer.Exit(1)
|
|
366
|
+
|
|
367
|
+
if container.project.public_id != project_config.public_id:
|
|
368
|
+
typer.echo(
|
|
369
|
+
f"Provided container '{container_slug or container_public_id}' is not related to current project '{project_config.public_id}'")
|
|
370
|
+
raise typer.Exit(1)
|
|
371
|
+
|
|
372
|
+
if container.frontend_status.status_key != DockerContainerStatus.RUNNING:
|
|
373
|
+
typer.echo(
|
|
374
|
+
f"Note: provided container '{container_slug or container_public_id}' is in status '{container.frontend_status.status_translation}'")
|
|
375
|
+
|
|
376
|
+
project_config.default_container_public_id = container.public_id if container else None
|
|
377
|
+
project_config.prompt_for_default_container = False
|
|
378
|
+
self.__config_provider.save_project_config(project_config=project_config)
|
|
379
|
+
typer.echo("Default container settings were updated")
|
|
380
|
+
|
|
381
|
+
@error_handler()
|
|
382
|
+
def print_project_config(self):
|
|
383
|
+
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
384
|
+
|
|
385
|
+
if project_config is None:
|
|
386
|
+
typer.echo(f"No project found in working directory")
|
|
387
|
+
raise typer.Exit(1)
|
|
388
|
+
|
|
389
|
+
is_deploy_key_exists = project_config.deploy_key_path and self.__file_system_service.check_if_path_exist(
|
|
390
|
+
project_config.deploy_key_path)
|
|
391
|
+
|
|
392
|
+
typer.echo(tabulate(
|
|
393
|
+
[
|
|
394
|
+
[
|
|
395
|
+
"Project ID", project_config.public_id
|
|
396
|
+
],
|
|
397
|
+
[
|
|
398
|
+
"Project name", project_config.slug
|
|
399
|
+
],
|
|
400
|
+
[
|
|
401
|
+
"Default docker container ID",
|
|
402
|
+
project_config.default_container_public_id if project_config.default_container_public_id else "<None>"
|
|
403
|
+
],
|
|
404
|
+
[
|
|
405
|
+
"Deploy key path", project_config.deploy_key_path if is_deploy_key_exists else "<None>"
|
|
406
|
+
],
|
|
407
|
+
],
|
|
408
|
+
showindex=False,
|
|
409
|
+
tablefmt="simple",
|
|
410
|
+
))
|
|
411
|
+
|
|
412
|
+
if is_deploy_key_exists:
|
|
413
|
+
typer.echo("")
|
|
414
|
+
typer.echo(f"You can insert the following text:")
|
|
415
|
+
print(
|
|
416
|
+
f"[{ColorScheme.USEFUL_INFO.value}]GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i {project_config.deploy_key_path}\"[{ColorScheme.USEFUL_INFO.value}]")
|
|
417
|
+
typer.echo(f"before any regular git command to manage your local Project repository directly")
|
|
418
|
+
|
|
419
|
+
@error_handler()
|
|
420
|
+
def get_fixed_project_config(self) -> Optional[ProjectConfig]:
|
|
421
|
+
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
422
|
+
if project_config is None:
|
|
423
|
+
return None
|
|
424
|
+
|
|
425
|
+
if project_config.public_id is None:
|
|
426
|
+
project = self.__project_api_client.get_project(public_id=None, slug=project_config.slug)
|
|
427
|
+
project_config.public_id = project.public_id
|
|
428
|
+
self.__config_provider.save_project_config(project_config=project_config)
|
|
429
|
+
|
|
430
|
+
if not Path(project_config.deploy_key_path).is_file():
|
|
431
|
+
deploy_ssh_key = self.__project_api_client.get_project_deploy_ssh_key(
|
|
432
|
+
public_id=project_config.public_id,
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(
|
|
436
|
+
deploy_ssh_key=deploy_ssh_key,
|
|
437
|
+
project_public_id=project_config.public_id,
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
project_config.deploy_key_path = deploy_key_path
|
|
441
|
+
self.__config_provider.save_project_config(project_config=project_config)
|
|
442
|
+
typer.echo(f'Recreated missing deploy key for the project')
|
|
443
|
+
|
|
444
|
+
return project_config
|
|
445
|
+
|
|
446
|
+
@error_handler()
|
|
447
|
+
def pull_project(self):
|
|
448
|
+
config = self.__config_provider.get_config()
|
|
449
|
+
project_config: ProjectConfig = self.get_fixed_project_config()
|
|
450
|
+
if not project_config:
|
|
451
|
+
typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.",
|
|
452
|
+
{"path": config.runtime.working_directory}))
|
|
453
|
+
raise typer.Exit(1)
|
|
454
|
+
|
|
455
|
+
typer.echo("Pulling code from remote repository...")
|
|
456
|
+
self.__git_local_client.git_pull(
|
|
457
|
+
path=config.runtime.working_directory,
|
|
458
|
+
deploy_key_path=project_config.deploy_key_path,
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
@error_handler()
|
|
462
|
+
def reset_project(self):
|
|
463
|
+
config = self.__config_provider.get_config()
|
|
464
|
+
project_config: ProjectConfig = self.get_fixed_project_config()
|
|
465
|
+
if not project_config:
|
|
466
|
+
typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.",
|
|
467
|
+
{"path": config.runtime.working_directory}))
|
|
468
|
+
raise typer.Exit(1)
|
|
469
|
+
|
|
470
|
+
typer.echo("Fetching code from remote repository...")
|
|
471
|
+
self.__git_local_client.git_fetch(
|
|
472
|
+
path=config.runtime.working_directory,
|
|
473
|
+
deploy_key_path=project_config.deploy_key_path,
|
|
474
|
+
)
|
|
475
|
+
typer.echo("Resetting local branch...")
|
|
476
|
+
self.__git_local_client.reset_hard(
|
|
477
|
+
path=config.runtime.working_directory,
|
|
478
|
+
deploy_key_path=project_config.deploy_key_path,
|
|
479
|
+
reset_to_origin=True
|
|
480
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from thestage.config.business.config_provider import ConfigProvider
|
|
4
|
+
from thestage.services.clients.thestage_api.core.api_client_core import TheStageApiClientCore
|
|
5
|
+
|
|
6
|
+
from thestage.project.dto.project_response import ProjectDto, ProjectViewResponse
|
|
7
|
+
from thestage.project.dto.get_deploy_ssh_key_request import ProjectGetDeploySshKeyRequest
|
|
8
|
+
from thestage.project.dto.get_deploy_ssh_key_response import ProjectGetDeploySshKeyResponse
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ProjectApiClient(TheStageApiClientCore):
|
|
12
|
+
def __init__(self, config_provider: ConfigProvider):
|
|
13
|
+
super().__init__(url=config_provider.get_config().main.thestage_api_url)
|
|
14
|
+
self.__config_provider = config_provider
|
|
15
|
+
|
|
16
|
+
def get_project(self, slug: Optional[str], public_id: Optional[str]) -> Optional[ProjectDto]:
|
|
17
|
+
data = {
|
|
18
|
+
"projectSlug": slug,
|
|
19
|
+
"projectPublicId": public_id,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
response = self._request(
|
|
23
|
+
method='POST',
|
|
24
|
+
url='/user-api/v2/project/view',
|
|
25
|
+
data=data,
|
|
26
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
result = ProjectViewResponse.model_validate(response) if response else None
|
|
30
|
+
project = ProjectDto.model_validate(result.project) if result else None
|
|
31
|
+
return project if result and result.is_success else None
|
|
32
|
+
|
|
33
|
+
def get_project_deploy_ssh_key(self, public_id: str) -> str:
|
|
34
|
+
request = ProjectGetDeploySshKeyRequest(
|
|
35
|
+
projectPublicId=public_id,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
response = self._request(
|
|
39
|
+
method='POST',
|
|
40
|
+
url='/user-api/v1/project/get-deploy-ssh-key',
|
|
41
|
+
data=request.model_dump(),
|
|
42
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
result = ProjectGetDeploySshKeyResponse.model_validate(response) if response else None
|
|
46
|
+
return result.privateKey if result and result.is_success else None
|