loopix-sdk 2.30.0__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.
- loopix/__init__.py +260 -0
- loopix/api/__init__.py +287 -0
- loopix/api/client/__init__.py +8 -0
- loopix/api/client/api/__init__.py +1 -0
- loopix/api/client/api/sandboxes/__init__.py +1 -0
- loopix/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py +161 -0
- loopix/api/client/api/sandboxes/get_sandboxes.py +176 -0
- loopix/api/client/api/sandboxes/get_sandboxes_metrics.py +173 -0
- loopix/api/client/api/sandboxes/get_sandboxes_sandbox_id.py +163 -0
- loopix/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py +199 -0
- loopix/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +212 -0
- loopix/api/client/api/sandboxes/get_v2_sandboxes.py +230 -0
- loopix/api/client/api/sandboxes/get_v_2_sandboxes_sandbox_id_logs.py +254 -0
- loopix/api/client/api/sandboxes/post_sandboxes.py +172 -0
- loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
- loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py +187 -0
- loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py +181 -0
- loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py +189 -0
- loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_snapshots.py +195 -0
- loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py +193 -0
- loopix/api/client/api/sandboxes/put_sandboxes_sandbox_id_network.py +199 -0
- loopix/api/client/api/snapshots/__init__.py +1 -0
- loopix/api/client/api/snapshots/get_snapshots.py +202 -0
- loopix/api/client/api/tags/__init__.py +1 -0
- loopix/api/client/api/tags/delete_templates_tags.py +174 -0
- loopix/api/client/api/tags/get_templates_template_id_tags.py +172 -0
- loopix/api/client/api/tags/post_templates_tags.py +176 -0
- loopix/api/client/api/templates/__init__.py +1 -0
- loopix/api/client/api/templates/delete_templates_template_id.py +157 -0
- loopix/api/client/api/templates/get_templates.py +172 -0
- loopix/api/client/api/templates/get_templates_aliases_alias.py +167 -0
- loopix/api/client/api/templates/get_templates_template_id.py +195 -0
- loopix/api/client/api/templates/get_templates_template_id_builds_build_id_logs.py +272 -0
- loopix/api/client/api/templates/get_templates_template_id_builds_build_id_status.py +232 -0
- loopix/api/client/api/templates/get_templates_template_id_files_hash.py +180 -0
- loopix/api/client/api/templates/patch_templates_template_id.py +183 -0
- loopix/api/client/api/templates/patch_v_2_templates_template_id.py +185 -0
- loopix/api/client/api/templates/post_templates.py +172 -0
- loopix/api/client/api/templates/post_templates_template_id.py +181 -0
- loopix/api/client/api/templates/post_templates_template_id_builds_build_id.py +170 -0
- loopix/api/client/api/templates/post_v2_templates.py +172 -0
- loopix/api/client/api/templates/post_v3_templates.py +176 -0
- loopix/api/client/api/templates/post_v_2_templates_template_id_builds_build_id.py +192 -0
- loopix/api/client/api/volumes/__init__.py +1 -0
- loopix/api/client/api/volumes/delete_volumes_volume_id.py +161 -0
- loopix/api/client/api/volumes/get_volumes.py +140 -0
- loopix/api/client/api/volumes/get_volumes_volume_id.py +163 -0
- loopix/api/client/api/volumes/post_volumes.py +172 -0
- loopix/api/client/client.py +286 -0
- loopix/api/client/errors.py +16 -0
- loopix/api/client/models/__init__.py +185 -0
- loopix/api/client/models/admin_build_cancel_result.py +67 -0
- loopix/api/client/models/admin_sandbox_kill_result.py +67 -0
- loopix/api/client/models/assign_template_tags_request.py +67 -0
- loopix/api/client/models/assigned_template_tags.py +68 -0
- loopix/api/client/models/aws_registry.py +85 -0
- loopix/api/client/models/aws_registry_type.py +8 -0
- loopix/api/client/models/build_log_entry.py +89 -0
- loopix/api/client/models/build_status_reason.py +95 -0
- loopix/api/client/models/connect_sandbox.py +59 -0
- loopix/api/client/models/created_access_token.py +100 -0
- loopix/api/client/models/created_team_api_key.py +166 -0
- loopix/api/client/models/delete_template_tags_request.py +67 -0
- loopix/api/client/models/disk_metrics.py +91 -0
- loopix/api/client/models/error.py +67 -0
- loopix/api/client/models/gcp_registry.py +69 -0
- loopix/api/client/models/gcp_registry_type.py +8 -0
- loopix/api/client/models/general_registry.py +77 -0
- loopix/api/client/models/general_registry_type.py +8 -0
- loopix/api/client/models/identifier_masking_details.py +83 -0
- loopix/api/client/models/listed_sandbox.py +179 -0
- loopix/api/client/models/log_level.py +11 -0
- loopix/api/client/models/logs_direction.py +9 -0
- loopix/api/client/models/logs_source.py +9 -0
- loopix/api/client/models/machine_info.py +83 -0
- loopix/api/client/models/max_team_metric.py +78 -0
- loopix/api/client/models/mcp_type_0.py +44 -0
- loopix/api/client/models/new_access_token.py +59 -0
- loopix/api/client/models/new_sandbox.py +224 -0
- loopix/api/client/models/new_team_api_key.py +59 -0
- loopix/api/client/models/new_volume.py +59 -0
- loopix/api/client/models/node.py +160 -0
- loopix/api/client/models/node_detail.py +160 -0
- loopix/api/client/models/node_metrics.py +122 -0
- loopix/api/client/models/node_status.py +12 -0
- loopix/api/client/models/node_status_change.py +82 -0
- loopix/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py +59 -0
- loopix/api/client/models/post_sandboxes_sandbox_id_snapshots_body.py +60 -0
- loopix/api/client/models/post_sandboxes_sandbox_id_timeout_body.py +59 -0
- loopix/api/client/models/resumed_sandbox.py +68 -0
- loopix/api/client/models/sandbox.py +145 -0
- loopix/api/client/models/sandbox_auto_resume_config.py +60 -0
- loopix/api/client/models/sandbox_detail.py +267 -0
- loopix/api/client/models/sandbox_lifecycle.py +70 -0
- loopix/api/client/models/sandbox_log.py +70 -0
- loopix/api/client/models/sandbox_log_entry.py +93 -0
- loopix/api/client/models/sandbox_log_entry_fields.py +44 -0
- loopix/api/client/models/sandbox_logs.py +91 -0
- loopix/api/client/models/sandbox_logs_v2_response.py +73 -0
- loopix/api/client/models/sandbox_metric.py +126 -0
- loopix/api/client/models/sandbox_network_config.py +118 -0
- loopix/api/client/models/sandbox_network_config_rules.py +72 -0
- loopix/api/client/models/sandbox_network_rule.py +74 -0
- loopix/api/client/models/sandbox_network_transform.py +79 -0
- loopix/api/client/models/sandbox_network_transform_headers.py +47 -0
- loopix/api/client/models/sandbox_network_update_config.py +114 -0
- loopix/api/client/models/sandbox_network_update_config_rules.py +71 -0
- loopix/api/client/models/sandbox_on_timeout.py +9 -0
- loopix/api/client/models/sandbox_pause_request.py +62 -0
- loopix/api/client/models/sandbox_state.py +9 -0
- loopix/api/client/models/sandbox_volume_mount.py +67 -0
- loopix/api/client/models/sandboxes_with_metrics.py +59 -0
- loopix/api/client/models/snapshot_info.py +70 -0
- loopix/api/client/models/team.py +83 -0
- loopix/api/client/models/team_api_key.py +158 -0
- loopix/api/client/models/team_metric.py +86 -0
- loopix/api/client/models/team_user.py +75 -0
- loopix/api/client/models/template.py +225 -0
- loopix/api/client/models/template_alias_response.py +67 -0
- loopix/api/client/models/template_build.py +139 -0
- loopix/api/client/models/template_build_file_upload.py +70 -0
- loopix/api/client/models/template_build_info.py +126 -0
- loopix/api/client/models/template_build_logs_response.py +73 -0
- loopix/api/client/models/template_build_request.py +115 -0
- loopix/api/client/models/template_build_request_v2.py +88 -0
- loopix/api/client/models/template_build_request_v3.py +107 -0
- loopix/api/client/models/template_build_start_v2.py +184 -0
- loopix/api/client/models/template_build_status.py +11 -0
- loopix/api/client/models/template_legacy.py +207 -0
- loopix/api/client/models/template_request_response_v3.py +99 -0
- loopix/api/client/models/template_step.py +91 -0
- loopix/api/client/models/template_tag.py +78 -0
- loopix/api/client/models/template_update_request.py +59 -0
- loopix/api/client/models/template_update_response.py +59 -0
- loopix/api/client/models/template_with_builds.py +156 -0
- loopix/api/client/models/update_team_api_key.py +59 -0
- loopix/api/client/models/volume.py +67 -0
- loopix/api/client/models/volume_and_token.py +75 -0
- loopix/api/client/models/volume_token.py +59 -0
- loopix/api/client/py.typed +1 -0
- loopix/api/client/types.py +54 -0
- loopix/api/client_async/__init__.py +74 -0
- loopix/api/client_sync/__init__.py +73 -0
- loopix/api/metadata.py +14 -0
- loopix/connection_config.py +309 -0
- loopix/envd/api.py +170 -0
- loopix/envd/filesystem/filesystem_connect.py +193 -0
- loopix/envd/filesystem/filesystem_pb2.py +80 -0
- loopix/envd/filesystem/filesystem_pb2.pyi +272 -0
- loopix/envd/process/process_connect.py +174 -0
- loopix/envd/process/process_pb2.py +96 -0
- loopix/envd/process/process_pb2.pyi +316 -0
- loopix/envd/rpc.py +139 -0
- loopix/envd/versions.py +11 -0
- loopix/exceptions.py +133 -0
- loopix/io_utils.py +57 -0
- loopix/paginator.py +52 -0
- loopix/py.typed +0 -0
- loopix/sandbox/_git/__init__.py +85 -0
- loopix/sandbox/_git/args.py +363 -0
- loopix/sandbox/_git/auth.py +132 -0
- loopix/sandbox/_git/config.py +32 -0
- loopix/sandbox/_git/parse.py +222 -0
- loopix/sandbox/_git/types.py +149 -0
- loopix/sandbox/commands/command_handle.py +69 -0
- loopix/sandbox/commands/main.py +39 -0
- loopix/sandbox/filesystem/filesystem.py +337 -0
- loopix/sandbox/filesystem/watch_handle.py +70 -0
- loopix/sandbox/main.py +227 -0
- loopix/sandbox/mcp.py +1949 -0
- loopix/sandbox/network.py +8 -0
- loopix/sandbox/sandbox_api.py +624 -0
- loopix/sandbox/signature.py +47 -0
- loopix/sandbox/utils.py +34 -0
- loopix/sandbox_async/commands/command.py +396 -0
- loopix/sandbox_async/commands/command_handle.py +298 -0
- loopix/sandbox_async/commands/pty.py +257 -0
- loopix/sandbox_async/filesystem/filesystem.py +720 -0
- loopix/sandbox_async/filesystem/watch_handle.py +97 -0
- loopix/sandbox_async/git.py +1100 -0
- loopix/sandbox_async/main.py +987 -0
- loopix/sandbox_async/paginator.py +140 -0
- loopix/sandbox_async/sandbox_api.py +504 -0
- loopix/sandbox_async/utils.py +7 -0
- loopix/sandbox_domains.py +5 -0
- loopix/sandbox_sync/commands/command.py +420 -0
- loopix/sandbox_sync/commands/command_handle.py +239 -0
- loopix/sandbox_sync/commands/pty.py +279 -0
- loopix/sandbox_sync/filesystem/filesystem.py +710 -0
- loopix/sandbox_sync/filesystem/watch_handle.py +102 -0
- loopix/sandbox_sync/git.py +1077 -0
- loopix/sandbox_sync/main.py +975 -0
- loopix/sandbox_sync/paginator.py +140 -0
- loopix/sandbox_sync/sandbox_api.py +491 -0
- loopix/template/consts.py +45 -0
- loopix/template/dockerfile_parser.py +286 -0
- loopix/template/logger.py +232 -0
- loopix/template/main.py +1368 -0
- loopix/template/readycmd.py +144 -0
- loopix/template/types.py +194 -0
- loopix/template/utils.py +426 -0
- loopix/template_async/build_api.py +419 -0
- loopix/template_async/main.py +528 -0
- loopix/template_sync/build_api.py +409 -0
- loopix/template_sync/main.py +529 -0
- loopix/volume/client/__init__.py +8 -0
- loopix/volume/client/api/__init__.py +1 -0
- loopix/volume/client/api/volumes/__init__.py +1 -0
- loopix/volume/client/api/volumes/delete_volumecontent_volume_id_path.py +174 -0
- loopix/volume/client/api/volumes/get_volumecontent_volume_id_dir.py +204 -0
- loopix/volume/client/api/volumes/get_volumecontent_volume_id_file.py +179 -0
- loopix/volume/client/api/volumes/get_volumecontent_volume_id_path.py +176 -0
- loopix/volume/client/api/volumes/patch_volumecontent_volume_id_path.py +203 -0
- loopix/volume/client/api/volumes/post_volumecontent_volume_id_dir.py +239 -0
- loopix/volume/client/api/volumes/put_volumecontent_volume_id_file.py +259 -0
- loopix/volume/client/client.py +286 -0
- loopix/volume/client/errors.py +16 -0
- loopix/volume/client/models/__init__.py +13 -0
- loopix/volume/client/models/error.py +67 -0
- loopix/volume/client/models/patch_volumecontent_volume_id_path_body.py +77 -0
- loopix/volume/client/models/volume_entry_stat.py +145 -0
- loopix/volume/client/models/volume_entry_stat_type.py +11 -0
- loopix/volume/client/py.typed +1 -0
- loopix/volume/client/types.py +54 -0
- loopix/volume/client_async/__init__.py +88 -0
- loopix/volume/client_sync/__init__.py +80 -0
- loopix/volume/connection_config.py +145 -0
- loopix/volume/types.py +62 -0
- loopix/volume/utils.py +52 -0
- loopix/volume/volume_async.py +639 -0
- loopix/volume/volume_sync.py +639 -0
- loopix_connect/__init__.py +1 -0
- loopix_connect/client.py +534 -0
- loopix_connect/py.typed +0 -0
- loopix_sdk-2.30.0.dist-info/METADATA +98 -0
- loopix_sdk-2.30.0.dist-info/RECORD +238 -0
- loopix_sdk-2.30.0.dist-info/WHEEL +4 -0
- loopix_sdk-2.30.0.dist-info/licenses/LICENSE +9 -0
|
@@ -0,0 +1,1077 @@
|
|
|
1
|
+
from typing import Dict, List, Optional
|
|
2
|
+
|
|
3
|
+
from loopix.sandbox._git import (
|
|
4
|
+
GitBranches,
|
|
5
|
+
GitResetMode,
|
|
6
|
+
GitStatus,
|
|
7
|
+
build_add_args,
|
|
8
|
+
build_auth_error_message,
|
|
9
|
+
build_branches_args,
|
|
10
|
+
build_checkout_branch_args,
|
|
11
|
+
build_clone_plan,
|
|
12
|
+
build_commit_args,
|
|
13
|
+
build_credential_approve_command,
|
|
14
|
+
build_create_branch_args,
|
|
15
|
+
build_delete_branch_args,
|
|
16
|
+
build_git_command,
|
|
17
|
+
build_has_upstream_args,
|
|
18
|
+
build_pull_args,
|
|
19
|
+
build_push_args,
|
|
20
|
+
build_remote_add_args,
|
|
21
|
+
build_remote_add_shell_command,
|
|
22
|
+
build_remote_get_command,
|
|
23
|
+
build_remote_get_url_args,
|
|
24
|
+
build_remote_set_url_args,
|
|
25
|
+
build_reset_args,
|
|
26
|
+
build_restore_args,
|
|
27
|
+
build_status_args,
|
|
28
|
+
build_upstream_error_message,
|
|
29
|
+
is_auth_failure,
|
|
30
|
+
is_missing_upstream,
|
|
31
|
+
parse_git_branches,
|
|
32
|
+
parse_git_status,
|
|
33
|
+
parse_remote_url,
|
|
34
|
+
resolve_config_scope,
|
|
35
|
+
with_credentials,
|
|
36
|
+
)
|
|
37
|
+
from loopix.exceptions import (
|
|
38
|
+
GitAuthException,
|
|
39
|
+
GitUpstreamException,
|
|
40
|
+
InvalidArgumentException,
|
|
41
|
+
)
|
|
42
|
+
from loopix.sandbox.commands.command_handle import CommandExitException
|
|
43
|
+
from loopix.sandbox_sync.commands.command import Commands
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
DEFAULT_GIT_ENV = {"GIT_TERMINAL_PROMPT": "0"}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Git:
|
|
50
|
+
"""
|
|
51
|
+
Module for running git operations in the sandbox.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, commands: Commands) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Create a Git helper bound to the sandbox command runner.
|
|
57
|
+
|
|
58
|
+
:param commands: Command runner used to execute git commands
|
|
59
|
+
"""
|
|
60
|
+
self._commands = commands
|
|
61
|
+
|
|
62
|
+
def _run_git(
|
|
63
|
+
self,
|
|
64
|
+
args: List[str],
|
|
65
|
+
repo_path: Optional[str],
|
|
66
|
+
envs: Optional[Dict[str, str]] = None,
|
|
67
|
+
user: Optional[str] = None,
|
|
68
|
+
cwd: Optional[str] = None,
|
|
69
|
+
timeout: Optional[float] = None,
|
|
70
|
+
request_timeout: Optional[float] = None,
|
|
71
|
+
):
|
|
72
|
+
"""
|
|
73
|
+
Build and execute a git command inside the sandbox.
|
|
74
|
+
|
|
75
|
+
:param args: Git arguments to pass to the git binary
|
|
76
|
+
:param repo_path: Repository path used with `git -C`, if provided
|
|
77
|
+
:param envs: Extra environment variables for the command
|
|
78
|
+
:param user: User to run the command as
|
|
79
|
+
:param cwd: Working directory to run the command
|
|
80
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
81
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
82
|
+
:return: Command result from the command runner
|
|
83
|
+
"""
|
|
84
|
+
cmd = build_git_command(args, repo_path)
|
|
85
|
+
merged_envs = {**DEFAULT_GIT_ENV, **(envs or {})}
|
|
86
|
+
return self._commands.run(
|
|
87
|
+
cmd,
|
|
88
|
+
envs=merged_envs,
|
|
89
|
+
user=user,
|
|
90
|
+
cwd=cwd,
|
|
91
|
+
timeout=timeout,
|
|
92
|
+
request_timeout=request_timeout,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def _run_shell(
|
|
96
|
+
self,
|
|
97
|
+
cmd: str,
|
|
98
|
+
envs: Optional[Dict[str, str]] = None,
|
|
99
|
+
user: Optional[str] = None,
|
|
100
|
+
cwd: Optional[str] = None,
|
|
101
|
+
timeout: Optional[float] = None,
|
|
102
|
+
request_timeout: Optional[float] = None,
|
|
103
|
+
):
|
|
104
|
+
"""
|
|
105
|
+
Execute a raw shell command while applying default git environment variables.
|
|
106
|
+
|
|
107
|
+
:param cmd: Shell command to execute
|
|
108
|
+
:param envs: Extra environment variables for the command
|
|
109
|
+
:param user: User to run the command as
|
|
110
|
+
:param cwd: Working directory to run the command
|
|
111
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
112
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
113
|
+
:return: Command result from the command runner
|
|
114
|
+
"""
|
|
115
|
+
merged_envs = {**DEFAULT_GIT_ENV, **(envs or {})}
|
|
116
|
+
return self._commands.run(
|
|
117
|
+
cmd,
|
|
118
|
+
envs=merged_envs,
|
|
119
|
+
user=user,
|
|
120
|
+
cwd=cwd,
|
|
121
|
+
timeout=timeout,
|
|
122
|
+
request_timeout=request_timeout,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def _has_upstream(
|
|
126
|
+
self,
|
|
127
|
+
path: str,
|
|
128
|
+
envs: Optional[Dict[str, str]] = None,
|
|
129
|
+
user: Optional[str] = None,
|
|
130
|
+
cwd: Optional[str] = None,
|
|
131
|
+
timeout: Optional[float] = None,
|
|
132
|
+
request_timeout: Optional[float] = None,
|
|
133
|
+
) -> bool:
|
|
134
|
+
try:
|
|
135
|
+
result = self._run_git(
|
|
136
|
+
build_has_upstream_args(),
|
|
137
|
+
path,
|
|
138
|
+
envs,
|
|
139
|
+
user,
|
|
140
|
+
cwd,
|
|
141
|
+
timeout,
|
|
142
|
+
request_timeout,
|
|
143
|
+
)
|
|
144
|
+
return bool(result.stdout.strip())
|
|
145
|
+
except Exception:
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
def _get_remote_url(
|
|
149
|
+
self,
|
|
150
|
+
path: str,
|
|
151
|
+
remote: str,
|
|
152
|
+
envs: Optional[Dict[str, str]] = None,
|
|
153
|
+
user: Optional[str] = None,
|
|
154
|
+
cwd: Optional[str] = None,
|
|
155
|
+
timeout: Optional[float] = None,
|
|
156
|
+
request_timeout: Optional[float] = None,
|
|
157
|
+
) -> str:
|
|
158
|
+
result = self._run_git(
|
|
159
|
+
build_remote_get_url_args(remote),
|
|
160
|
+
path,
|
|
161
|
+
envs,
|
|
162
|
+
user,
|
|
163
|
+
cwd,
|
|
164
|
+
timeout,
|
|
165
|
+
request_timeout,
|
|
166
|
+
)
|
|
167
|
+
return parse_remote_url(result.stdout, remote)
|
|
168
|
+
|
|
169
|
+
def _resolve_remote_name(
|
|
170
|
+
self,
|
|
171
|
+
path: str,
|
|
172
|
+
remote: Optional[str],
|
|
173
|
+
envs: Optional[Dict[str, str]] = None,
|
|
174
|
+
user: Optional[str] = None,
|
|
175
|
+
cwd: Optional[str] = None,
|
|
176
|
+
timeout: Optional[float] = None,
|
|
177
|
+
request_timeout: Optional[float] = None,
|
|
178
|
+
) -> str:
|
|
179
|
+
if remote:
|
|
180
|
+
return remote
|
|
181
|
+
|
|
182
|
+
result = self._run_git(
|
|
183
|
+
["remote"],
|
|
184
|
+
path,
|
|
185
|
+
envs,
|
|
186
|
+
user,
|
|
187
|
+
cwd,
|
|
188
|
+
timeout,
|
|
189
|
+
request_timeout,
|
|
190
|
+
)
|
|
191
|
+
remotes = [line.strip() for line in result.stdout.splitlines() if line.strip()]
|
|
192
|
+
if len(remotes) == 1:
|
|
193
|
+
return remotes[0]
|
|
194
|
+
|
|
195
|
+
raise InvalidArgumentException(
|
|
196
|
+
"Remote is required when using username/password and the repository has multiple remotes."
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
def _with_remote_credentials(
|
|
200
|
+
self,
|
|
201
|
+
path: str,
|
|
202
|
+
remote: str,
|
|
203
|
+
username: str,
|
|
204
|
+
password: str,
|
|
205
|
+
envs: Optional[Dict[str, str]] = None,
|
|
206
|
+
user: Optional[str] = None,
|
|
207
|
+
cwd: Optional[str] = None,
|
|
208
|
+
timeout: Optional[float] = None,
|
|
209
|
+
request_timeout: Optional[float] = None,
|
|
210
|
+
operation=None,
|
|
211
|
+
):
|
|
212
|
+
original_url = self._get_remote_url(
|
|
213
|
+
path, remote, envs, user, cwd, timeout, request_timeout
|
|
214
|
+
)
|
|
215
|
+
credential_url = with_credentials(original_url, username, password)
|
|
216
|
+
self._run_git(
|
|
217
|
+
["remote", "set-url", remote, credential_url],
|
|
218
|
+
path,
|
|
219
|
+
envs,
|
|
220
|
+
user,
|
|
221
|
+
cwd,
|
|
222
|
+
timeout,
|
|
223
|
+
request_timeout,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
result = None
|
|
227
|
+
operation_error: Exception | None = None
|
|
228
|
+
try:
|
|
229
|
+
if operation is None:
|
|
230
|
+
raise InvalidArgumentException("Operation is required.")
|
|
231
|
+
result = operation()
|
|
232
|
+
except Exception as err:
|
|
233
|
+
operation_error = err
|
|
234
|
+
|
|
235
|
+
restore_error: Exception | None = None
|
|
236
|
+
try:
|
|
237
|
+
self._run_git(
|
|
238
|
+
["remote", "set-url", remote, original_url],
|
|
239
|
+
path,
|
|
240
|
+
envs,
|
|
241
|
+
user,
|
|
242
|
+
cwd,
|
|
243
|
+
timeout,
|
|
244
|
+
request_timeout,
|
|
245
|
+
)
|
|
246
|
+
except Exception as err:
|
|
247
|
+
restore_error = err
|
|
248
|
+
|
|
249
|
+
if operation_error:
|
|
250
|
+
raise operation_error
|
|
251
|
+
if restore_error:
|
|
252
|
+
raise restore_error
|
|
253
|
+
|
|
254
|
+
return result
|
|
255
|
+
|
|
256
|
+
def clone(
|
|
257
|
+
self,
|
|
258
|
+
url: str,
|
|
259
|
+
path: Optional[str] = None,
|
|
260
|
+
branch: Optional[str] = None,
|
|
261
|
+
depth: Optional[int] = None,
|
|
262
|
+
username: Optional[str] = None,
|
|
263
|
+
password: Optional[str] = None,
|
|
264
|
+
envs: Optional[Dict[str, str]] = None,
|
|
265
|
+
user: Optional[str] = None,
|
|
266
|
+
cwd: Optional[str] = None,
|
|
267
|
+
timeout: Optional[float] = None,
|
|
268
|
+
request_timeout: Optional[float] = None,
|
|
269
|
+
dangerously_store_credentials: bool = False,
|
|
270
|
+
):
|
|
271
|
+
"""
|
|
272
|
+
Clone a git repository into the sandbox.
|
|
273
|
+
|
|
274
|
+
:param url: Git repository URL
|
|
275
|
+
:param path: Destination path for the clone
|
|
276
|
+
:param branch: Branch to check out
|
|
277
|
+
:param depth: If set, perform a shallow clone with this depth
|
|
278
|
+
:param username: Username for HTTP(S) authentication
|
|
279
|
+
:param password: Password or token for HTTP(S) authentication
|
|
280
|
+
:param envs: Environment variables used for the command
|
|
281
|
+
:param user: User to run the command as
|
|
282
|
+
:param cwd: Working directory to run the command
|
|
283
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
284
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
285
|
+
:param dangerously_store_credentials: Store credentials in the cloned repository when True
|
|
286
|
+
:return: Command result from the command runner
|
|
287
|
+
"""
|
|
288
|
+
if password and not username:
|
|
289
|
+
raise InvalidArgumentException(
|
|
290
|
+
"Username is required when using a password or token for git clone."
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
def attempt_clone(auth_username: Optional[str], auth_password: Optional[str]):
|
|
294
|
+
plan = build_clone_plan(
|
|
295
|
+
url=url,
|
|
296
|
+
path=path,
|
|
297
|
+
branch=branch,
|
|
298
|
+
depth=depth,
|
|
299
|
+
auth_username=auth_username,
|
|
300
|
+
auth_password=auth_password,
|
|
301
|
+
dangerously_store_credentials=dangerously_store_credentials,
|
|
302
|
+
)
|
|
303
|
+
result = self._run_git(
|
|
304
|
+
plan.args, None, envs, user, cwd, timeout, request_timeout
|
|
305
|
+
)
|
|
306
|
+
if plan.should_strip and plan.repo_path and plan.sanitized_url:
|
|
307
|
+
self._run_git(
|
|
308
|
+
build_remote_set_url_args("origin", plan.sanitized_url),
|
|
309
|
+
plan.repo_path,
|
|
310
|
+
envs,
|
|
311
|
+
user,
|
|
312
|
+
cwd,
|
|
313
|
+
timeout,
|
|
314
|
+
request_timeout,
|
|
315
|
+
)
|
|
316
|
+
return result
|
|
317
|
+
|
|
318
|
+
try:
|
|
319
|
+
return attempt_clone(username, password)
|
|
320
|
+
except CommandExitException as err:
|
|
321
|
+
if is_auth_failure(err):
|
|
322
|
+
raise GitAuthException(
|
|
323
|
+
build_auth_error_message("clone", bool(username) and not password)
|
|
324
|
+
) from err
|
|
325
|
+
raise
|
|
326
|
+
|
|
327
|
+
def init(
|
|
328
|
+
self,
|
|
329
|
+
path: str,
|
|
330
|
+
bare: bool = False,
|
|
331
|
+
initial_branch: Optional[str] = None,
|
|
332
|
+
envs: Optional[Dict[str, str]] = None,
|
|
333
|
+
user: Optional[str] = None,
|
|
334
|
+
cwd: Optional[str] = None,
|
|
335
|
+
timeout: Optional[float] = None,
|
|
336
|
+
request_timeout: Optional[float] = None,
|
|
337
|
+
):
|
|
338
|
+
"""
|
|
339
|
+
Initialize a new git repository.
|
|
340
|
+
|
|
341
|
+
:param path: Destination path for the repository
|
|
342
|
+
:param bare: Create a bare repository when True
|
|
343
|
+
:param initial_branch: Initial branch name (for example, "main")
|
|
344
|
+
:param envs: Environment variables used for the command
|
|
345
|
+
:param user: User to run the command as
|
|
346
|
+
:param cwd: Working directory to run the command
|
|
347
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
348
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
349
|
+
:return: Command result from the command runner
|
|
350
|
+
"""
|
|
351
|
+
args = ["init"]
|
|
352
|
+
if initial_branch:
|
|
353
|
+
args.extend(["--initial-branch", initial_branch])
|
|
354
|
+
if bare:
|
|
355
|
+
args.append("--bare")
|
|
356
|
+
args.append(path)
|
|
357
|
+
return self._run_git(args, None, envs, user, cwd, timeout, request_timeout)
|
|
358
|
+
|
|
359
|
+
def remote_add(
|
|
360
|
+
self,
|
|
361
|
+
path: str,
|
|
362
|
+
name: str,
|
|
363
|
+
url: str,
|
|
364
|
+
fetch: bool = False,
|
|
365
|
+
overwrite: bool = False,
|
|
366
|
+
envs: Optional[Dict[str, str]] = None,
|
|
367
|
+
user: Optional[str] = None,
|
|
368
|
+
cwd: Optional[str] = None,
|
|
369
|
+
timeout: Optional[float] = None,
|
|
370
|
+
request_timeout: Optional[float] = None,
|
|
371
|
+
):
|
|
372
|
+
"""
|
|
373
|
+
Add (or update) a remote for a repository.
|
|
374
|
+
|
|
375
|
+
:param path: Repository path
|
|
376
|
+
:param name: Remote name (for example, "origin")
|
|
377
|
+
:param url: Remote URL
|
|
378
|
+
:param fetch: Fetch the remote after adding it when True
|
|
379
|
+
:param overwrite: Overwrite the remote URL if it already exists when True
|
|
380
|
+
:param envs: Environment variables used for the command
|
|
381
|
+
:param user: User to run the command as
|
|
382
|
+
:param cwd: Working directory to run the command
|
|
383
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
384
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
385
|
+
:return: Command result from the command runner
|
|
386
|
+
"""
|
|
387
|
+
args = build_remote_add_args(name, url, fetch)
|
|
388
|
+
|
|
389
|
+
if not overwrite:
|
|
390
|
+
return self._run_git(args, path, envs, user, cwd, timeout, request_timeout)
|
|
391
|
+
|
|
392
|
+
cmd = build_remote_add_shell_command(args, path, name, url, fetch)
|
|
393
|
+
return self._run_shell(
|
|
394
|
+
cmd,
|
|
395
|
+
envs,
|
|
396
|
+
user,
|
|
397
|
+
cwd,
|
|
398
|
+
timeout,
|
|
399
|
+
request_timeout,
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
def remote_get(
|
|
403
|
+
self,
|
|
404
|
+
path: str,
|
|
405
|
+
name: str,
|
|
406
|
+
envs: Optional[Dict[str, str]] = None,
|
|
407
|
+
user: Optional[str] = None,
|
|
408
|
+
cwd: Optional[str] = None,
|
|
409
|
+
timeout: Optional[float] = None,
|
|
410
|
+
request_timeout: Optional[float] = None,
|
|
411
|
+
) -> Optional[str]:
|
|
412
|
+
"""
|
|
413
|
+
Get the URL for a git remote.
|
|
414
|
+
|
|
415
|
+
Returns `None` when the remote does not exist.
|
|
416
|
+
|
|
417
|
+
:param path: Repository path
|
|
418
|
+
:param name: Remote name (for example, "origin")
|
|
419
|
+
:param envs: Environment variables used for the command
|
|
420
|
+
:param user: User to run the command as
|
|
421
|
+
:param cwd: Working directory to run the command
|
|
422
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
423
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
424
|
+
:return: Remote URL if present, otherwise `None`
|
|
425
|
+
"""
|
|
426
|
+
cmd = build_remote_get_command(path, name)
|
|
427
|
+
result = self._run_shell(
|
|
428
|
+
cmd,
|
|
429
|
+
envs,
|
|
430
|
+
user,
|
|
431
|
+
cwd,
|
|
432
|
+
timeout,
|
|
433
|
+
request_timeout,
|
|
434
|
+
).stdout.strip()
|
|
435
|
+
return result or None
|
|
436
|
+
|
|
437
|
+
def status(
|
|
438
|
+
self,
|
|
439
|
+
path: str,
|
|
440
|
+
envs: Optional[Dict[str, str]] = None,
|
|
441
|
+
user: Optional[str] = None,
|
|
442
|
+
cwd: Optional[str] = None,
|
|
443
|
+
timeout: Optional[float] = None,
|
|
444
|
+
request_timeout: Optional[float] = None,
|
|
445
|
+
) -> GitStatus:
|
|
446
|
+
"""
|
|
447
|
+
Get repository status information.
|
|
448
|
+
|
|
449
|
+
:param path: Repository path
|
|
450
|
+
:param envs: Environment variables used for the command
|
|
451
|
+
:param user: User to run the command as
|
|
452
|
+
:param cwd: Working directory to run the command
|
|
453
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
454
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
455
|
+
:return: Parsed git status
|
|
456
|
+
"""
|
|
457
|
+
result = self._run_git(
|
|
458
|
+
build_status_args(),
|
|
459
|
+
path,
|
|
460
|
+
envs,
|
|
461
|
+
user,
|
|
462
|
+
cwd,
|
|
463
|
+
timeout,
|
|
464
|
+
request_timeout,
|
|
465
|
+
)
|
|
466
|
+
return parse_git_status(result.stdout)
|
|
467
|
+
|
|
468
|
+
def branches(
|
|
469
|
+
self,
|
|
470
|
+
path: str,
|
|
471
|
+
envs: Optional[Dict[str, str]] = None,
|
|
472
|
+
user: Optional[str] = None,
|
|
473
|
+
cwd: Optional[str] = None,
|
|
474
|
+
timeout: Optional[float] = None,
|
|
475
|
+
request_timeout: Optional[float] = None,
|
|
476
|
+
) -> GitBranches:
|
|
477
|
+
"""
|
|
478
|
+
List branches in a repository.
|
|
479
|
+
|
|
480
|
+
:param path: Repository path
|
|
481
|
+
:param envs: Environment variables used for the command
|
|
482
|
+
:param user: User to run the command as
|
|
483
|
+
:param cwd: Working directory to run the command
|
|
484
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
485
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
486
|
+
:return: Parsed branch list
|
|
487
|
+
"""
|
|
488
|
+
result = self._run_git(
|
|
489
|
+
build_branches_args(),
|
|
490
|
+
path,
|
|
491
|
+
envs,
|
|
492
|
+
user,
|
|
493
|
+
cwd,
|
|
494
|
+
timeout,
|
|
495
|
+
request_timeout,
|
|
496
|
+
)
|
|
497
|
+
return parse_git_branches(result.stdout)
|
|
498
|
+
|
|
499
|
+
def create_branch(
|
|
500
|
+
self,
|
|
501
|
+
path: str,
|
|
502
|
+
branch: str,
|
|
503
|
+
envs: Optional[Dict[str, str]] = None,
|
|
504
|
+
user: Optional[str] = None,
|
|
505
|
+
cwd: Optional[str] = None,
|
|
506
|
+
timeout: Optional[float] = None,
|
|
507
|
+
request_timeout: Optional[float] = None,
|
|
508
|
+
):
|
|
509
|
+
"""
|
|
510
|
+
Create and check out a new branch.
|
|
511
|
+
|
|
512
|
+
:param path: Repository path
|
|
513
|
+
:param branch: Branch name to create
|
|
514
|
+
:param envs: Environment variables used for the command
|
|
515
|
+
:param user: User to run the command as
|
|
516
|
+
:param cwd: Working directory to run the command
|
|
517
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
518
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
519
|
+
:return: Command result from the command runner
|
|
520
|
+
"""
|
|
521
|
+
return self._run_git(
|
|
522
|
+
build_create_branch_args(branch),
|
|
523
|
+
path,
|
|
524
|
+
envs,
|
|
525
|
+
user,
|
|
526
|
+
cwd,
|
|
527
|
+
timeout,
|
|
528
|
+
request_timeout,
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
def checkout_branch(
|
|
532
|
+
self,
|
|
533
|
+
path: str,
|
|
534
|
+
branch: str,
|
|
535
|
+
envs: Optional[Dict[str, str]] = None,
|
|
536
|
+
user: Optional[str] = None,
|
|
537
|
+
cwd: Optional[str] = None,
|
|
538
|
+
timeout: Optional[float] = None,
|
|
539
|
+
request_timeout: Optional[float] = None,
|
|
540
|
+
):
|
|
541
|
+
"""
|
|
542
|
+
Check out an existing branch.
|
|
543
|
+
|
|
544
|
+
:param path: Repository path
|
|
545
|
+
:param branch: Branch name to check out
|
|
546
|
+
:param envs: Environment variables used for the command
|
|
547
|
+
:param user: User to run the command as
|
|
548
|
+
:param cwd: Working directory to run the command
|
|
549
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
550
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
551
|
+
:return: Command result from the command runner
|
|
552
|
+
"""
|
|
553
|
+
return self._run_git(
|
|
554
|
+
build_checkout_branch_args(branch),
|
|
555
|
+
path,
|
|
556
|
+
envs,
|
|
557
|
+
user,
|
|
558
|
+
cwd,
|
|
559
|
+
timeout,
|
|
560
|
+
request_timeout,
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
def delete_branch(
|
|
564
|
+
self,
|
|
565
|
+
path: str,
|
|
566
|
+
branch: str,
|
|
567
|
+
force: bool = False,
|
|
568
|
+
envs: Optional[Dict[str, str]] = None,
|
|
569
|
+
user: Optional[str] = None,
|
|
570
|
+
cwd: Optional[str] = None,
|
|
571
|
+
timeout: Optional[float] = None,
|
|
572
|
+
request_timeout: Optional[float] = None,
|
|
573
|
+
):
|
|
574
|
+
"""
|
|
575
|
+
Delete a branch.
|
|
576
|
+
|
|
577
|
+
:param path: Repository path
|
|
578
|
+
:param branch: Branch name to delete
|
|
579
|
+
:param force: Force deletion with `-D` when `True`
|
|
580
|
+
:param envs: Environment variables used for the command
|
|
581
|
+
:param user: User to run the command as
|
|
582
|
+
:param cwd: Working directory to run the command
|
|
583
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
584
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
585
|
+
:return: Command result from the command runner
|
|
586
|
+
"""
|
|
587
|
+
args = build_delete_branch_args(branch, force)
|
|
588
|
+
return self._run_git(args, path, envs, user, cwd, timeout, request_timeout)
|
|
589
|
+
|
|
590
|
+
def add(
|
|
591
|
+
self,
|
|
592
|
+
path: str,
|
|
593
|
+
files: Optional[List[str]] = None,
|
|
594
|
+
all: bool = True,
|
|
595
|
+
envs: Optional[Dict[str, str]] = None,
|
|
596
|
+
user: Optional[str] = None,
|
|
597
|
+
cwd: Optional[str] = None,
|
|
598
|
+
timeout: Optional[float] = None,
|
|
599
|
+
request_timeout: Optional[float] = None,
|
|
600
|
+
):
|
|
601
|
+
"""
|
|
602
|
+
Stage files for commit.
|
|
603
|
+
|
|
604
|
+
:param path: Repository path
|
|
605
|
+
:param files: Files to add; when omitted, adds the current directory
|
|
606
|
+
:param all: When `True` and `files` is omitted, stage all changes
|
|
607
|
+
:param envs: Environment variables used for the command
|
|
608
|
+
:param user: User to run the command as
|
|
609
|
+
:param cwd: Working directory to run the command
|
|
610
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
611
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
612
|
+
:return: Command result from the command runner
|
|
613
|
+
"""
|
|
614
|
+
args = build_add_args(files, all)
|
|
615
|
+
return self._run_git(args, path, envs, user, cwd, timeout, request_timeout)
|
|
616
|
+
|
|
617
|
+
def commit(
|
|
618
|
+
self,
|
|
619
|
+
path: str,
|
|
620
|
+
message: str,
|
|
621
|
+
author_name: Optional[str] = None,
|
|
622
|
+
author_email: Optional[str] = None,
|
|
623
|
+
allow_empty: bool = False,
|
|
624
|
+
envs: Optional[Dict[str, str]] = None,
|
|
625
|
+
user: Optional[str] = None,
|
|
626
|
+
cwd: Optional[str] = None,
|
|
627
|
+
timeout: Optional[float] = None,
|
|
628
|
+
request_timeout: Optional[float] = None,
|
|
629
|
+
):
|
|
630
|
+
"""
|
|
631
|
+
Create a commit in the repository.
|
|
632
|
+
|
|
633
|
+
:param path: Repository path
|
|
634
|
+
:param message: Commit message
|
|
635
|
+
:param author_name: Commit author name
|
|
636
|
+
:param author_email: Commit author email
|
|
637
|
+
:param allow_empty: Allow empty commits when `True`
|
|
638
|
+
:param envs: Environment variables used for the command
|
|
639
|
+
:param user: User to run the command as
|
|
640
|
+
:param cwd: Working directory to run the command
|
|
641
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
642
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
643
|
+
:return: Command result from the command runner
|
|
644
|
+
"""
|
|
645
|
+
args = build_commit_args(message, author_name, author_email, allow_empty)
|
|
646
|
+
return self._run_git(args, path, envs, user, cwd, timeout, request_timeout)
|
|
647
|
+
|
|
648
|
+
def reset(
|
|
649
|
+
self,
|
|
650
|
+
path: str,
|
|
651
|
+
mode: Optional[GitResetMode] = None,
|
|
652
|
+
target: Optional[str] = None,
|
|
653
|
+
paths: Optional[List[str]] = None,
|
|
654
|
+
envs: Optional[Dict[str, str]] = None,
|
|
655
|
+
user: Optional[str] = None,
|
|
656
|
+
cwd: Optional[str] = None,
|
|
657
|
+
timeout: Optional[float] = None,
|
|
658
|
+
request_timeout: Optional[float] = None,
|
|
659
|
+
):
|
|
660
|
+
"""
|
|
661
|
+
Reset the current HEAD to a specified state.
|
|
662
|
+
|
|
663
|
+
:param path: Repository path
|
|
664
|
+
:param mode: Reset mode (soft, mixed, hard, merge, keep)
|
|
665
|
+
:param target: Commit, branch, or ref to reset to (defaults to HEAD)
|
|
666
|
+
:param paths: Paths to reset
|
|
667
|
+
:param envs: Environment variables used for the command
|
|
668
|
+
:param user: User to run the command as
|
|
669
|
+
:param cwd: Working directory to run the command
|
|
670
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
671
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
672
|
+
:return: Command result from the command runner
|
|
673
|
+
"""
|
|
674
|
+
args = build_reset_args(mode, target, paths)
|
|
675
|
+
return self._run_git(args, path, envs, user, cwd, timeout, request_timeout)
|
|
676
|
+
|
|
677
|
+
def restore(
|
|
678
|
+
self,
|
|
679
|
+
path: str,
|
|
680
|
+
paths: List[str],
|
|
681
|
+
staged: Optional[bool] = None,
|
|
682
|
+
worktree: Optional[bool] = None,
|
|
683
|
+
source: Optional[str] = None,
|
|
684
|
+
envs: Optional[Dict[str, str]] = None,
|
|
685
|
+
user: Optional[str] = None,
|
|
686
|
+
cwd: Optional[str] = None,
|
|
687
|
+
timeout: Optional[float] = None,
|
|
688
|
+
request_timeout: Optional[float] = None,
|
|
689
|
+
):
|
|
690
|
+
"""
|
|
691
|
+
Restore working tree files or unstage changes.
|
|
692
|
+
|
|
693
|
+
:param path: Repository path
|
|
694
|
+
:param paths: Paths to restore (use ["."] for all)
|
|
695
|
+
:param staged: When True, restore the index (unstage)
|
|
696
|
+
:param worktree: When True, restore working tree files
|
|
697
|
+
:param source: Restore from the given source (commit, branch, or ref)
|
|
698
|
+
:param envs: Environment variables used for the command
|
|
699
|
+
:param user: User to run the command as
|
|
700
|
+
:param cwd: Working directory to run the command
|
|
701
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
702
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
703
|
+
:return: Command result from the command runner
|
|
704
|
+
"""
|
|
705
|
+
args = build_restore_args(paths, staged, worktree, source)
|
|
706
|
+
return self._run_git(args, path, envs, user, cwd, timeout, request_timeout)
|
|
707
|
+
|
|
708
|
+
def push(
|
|
709
|
+
self,
|
|
710
|
+
path: str,
|
|
711
|
+
remote: Optional[str] = None,
|
|
712
|
+
branch: Optional[str] = None,
|
|
713
|
+
set_upstream: bool = True,
|
|
714
|
+
username: Optional[str] = None,
|
|
715
|
+
password: Optional[str] = None,
|
|
716
|
+
envs: Optional[Dict[str, str]] = None,
|
|
717
|
+
user: Optional[str] = None,
|
|
718
|
+
cwd: Optional[str] = None,
|
|
719
|
+
timeout: Optional[float] = None,
|
|
720
|
+
request_timeout: Optional[float] = None,
|
|
721
|
+
):
|
|
722
|
+
"""
|
|
723
|
+
Push commits to a remote.
|
|
724
|
+
|
|
725
|
+
:param path: Repository path
|
|
726
|
+
:param remote: Remote name, e.g. `origin`
|
|
727
|
+
:param branch: Branch name to push
|
|
728
|
+
:param set_upstream: Set upstream tracking when `True`
|
|
729
|
+
:param username: Username for HTTP(S) authentication
|
|
730
|
+
:param password: Password or token for HTTP(S) authentication
|
|
731
|
+
:param envs: Environment variables used for the command
|
|
732
|
+
:param user: User to run the command as
|
|
733
|
+
:param cwd: Working directory to run the command
|
|
734
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
735
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
736
|
+
:return: Command result from the command runner
|
|
737
|
+
"""
|
|
738
|
+
if password and not username:
|
|
739
|
+
raise InvalidArgumentException(
|
|
740
|
+
"Username is required when using a password or token for git push."
|
|
741
|
+
)
|
|
742
|
+
|
|
743
|
+
if username and password:
|
|
744
|
+
remote_name = self._resolve_remote_name(
|
|
745
|
+
path, remote, envs, user, cwd, timeout, request_timeout
|
|
746
|
+
)
|
|
747
|
+
return self._with_remote_credentials(
|
|
748
|
+
path,
|
|
749
|
+
remote_name,
|
|
750
|
+
username,
|
|
751
|
+
password,
|
|
752
|
+
envs,
|
|
753
|
+
user,
|
|
754
|
+
cwd,
|
|
755
|
+
timeout,
|
|
756
|
+
request_timeout,
|
|
757
|
+
operation=lambda: self._run_git(
|
|
758
|
+
build_push_args(
|
|
759
|
+
remote_name,
|
|
760
|
+
remote=remote,
|
|
761
|
+
branch=branch,
|
|
762
|
+
set_upstream=set_upstream,
|
|
763
|
+
),
|
|
764
|
+
path,
|
|
765
|
+
envs,
|
|
766
|
+
user,
|
|
767
|
+
cwd,
|
|
768
|
+
timeout,
|
|
769
|
+
request_timeout,
|
|
770
|
+
),
|
|
771
|
+
)
|
|
772
|
+
|
|
773
|
+
try:
|
|
774
|
+
return self._run_git(
|
|
775
|
+
build_push_args(
|
|
776
|
+
None,
|
|
777
|
+
remote=remote,
|
|
778
|
+
branch=branch,
|
|
779
|
+
set_upstream=set_upstream,
|
|
780
|
+
),
|
|
781
|
+
path,
|
|
782
|
+
envs,
|
|
783
|
+
user,
|
|
784
|
+
cwd,
|
|
785
|
+
timeout,
|
|
786
|
+
request_timeout,
|
|
787
|
+
)
|
|
788
|
+
except CommandExitException as err:
|
|
789
|
+
if is_auth_failure(err):
|
|
790
|
+
raise GitAuthException(
|
|
791
|
+
build_auth_error_message("push", bool(username) and not password)
|
|
792
|
+
) from err
|
|
793
|
+
if is_missing_upstream(err):
|
|
794
|
+
raise GitUpstreamException(
|
|
795
|
+
build_upstream_error_message("push")
|
|
796
|
+
) from err
|
|
797
|
+
raise
|
|
798
|
+
|
|
799
|
+
def pull(
|
|
800
|
+
self,
|
|
801
|
+
path: str,
|
|
802
|
+
remote: Optional[str] = None,
|
|
803
|
+
branch: Optional[str] = None,
|
|
804
|
+
username: Optional[str] = None,
|
|
805
|
+
password: Optional[str] = None,
|
|
806
|
+
envs: Optional[Dict[str, str]] = None,
|
|
807
|
+
user: Optional[str] = None,
|
|
808
|
+
cwd: Optional[str] = None,
|
|
809
|
+
timeout: Optional[float] = None,
|
|
810
|
+
request_timeout: Optional[float] = None,
|
|
811
|
+
):
|
|
812
|
+
"""
|
|
813
|
+
Pull changes from a remote.
|
|
814
|
+
|
|
815
|
+
:param path: Repository path
|
|
816
|
+
:param remote: Remote name, e.g. `origin`
|
|
817
|
+
:param branch: Branch name to pull
|
|
818
|
+
:param username: Username for HTTP(S) authentication
|
|
819
|
+
:param password: Password or token for HTTP(S) authentication
|
|
820
|
+
:param envs: Environment variables used for the command
|
|
821
|
+
:param user: User to run the command as
|
|
822
|
+
:param cwd: Working directory to run the command
|
|
823
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
824
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
825
|
+
:return: Command result from the command runner
|
|
826
|
+
"""
|
|
827
|
+
if password and not username:
|
|
828
|
+
raise InvalidArgumentException(
|
|
829
|
+
"Username is required when using a password or token for git pull."
|
|
830
|
+
)
|
|
831
|
+
|
|
832
|
+
if not remote and not branch:
|
|
833
|
+
if not self._has_upstream(path, envs, user, cwd, timeout, request_timeout):
|
|
834
|
+
raise GitUpstreamException(build_upstream_error_message("pull"))
|
|
835
|
+
|
|
836
|
+
if username and password:
|
|
837
|
+
remote_name = self._resolve_remote_name(
|
|
838
|
+
path, remote, envs, user, cwd, timeout, request_timeout
|
|
839
|
+
)
|
|
840
|
+
return self._with_remote_credentials(
|
|
841
|
+
path,
|
|
842
|
+
remote_name,
|
|
843
|
+
username,
|
|
844
|
+
password,
|
|
845
|
+
envs,
|
|
846
|
+
user,
|
|
847
|
+
cwd,
|
|
848
|
+
timeout,
|
|
849
|
+
request_timeout,
|
|
850
|
+
operation=lambda: self._run_git(
|
|
851
|
+
build_pull_args(remote, branch, remote_name),
|
|
852
|
+
path,
|
|
853
|
+
envs,
|
|
854
|
+
user,
|
|
855
|
+
cwd,
|
|
856
|
+
timeout,
|
|
857
|
+
request_timeout,
|
|
858
|
+
),
|
|
859
|
+
)
|
|
860
|
+
|
|
861
|
+
try:
|
|
862
|
+
return self._run_git(
|
|
863
|
+
build_pull_args(remote, branch),
|
|
864
|
+
path,
|
|
865
|
+
envs,
|
|
866
|
+
user,
|
|
867
|
+
cwd,
|
|
868
|
+
timeout,
|
|
869
|
+
request_timeout,
|
|
870
|
+
)
|
|
871
|
+
except CommandExitException as err:
|
|
872
|
+
if is_auth_failure(err):
|
|
873
|
+
raise GitAuthException(
|
|
874
|
+
build_auth_error_message("pull", bool(username) and not password)
|
|
875
|
+
) from err
|
|
876
|
+
if is_missing_upstream(err):
|
|
877
|
+
raise GitUpstreamException(
|
|
878
|
+
build_upstream_error_message("pull")
|
|
879
|
+
) from err
|
|
880
|
+
raise
|
|
881
|
+
|
|
882
|
+
def set_config(
|
|
883
|
+
self,
|
|
884
|
+
key: str,
|
|
885
|
+
value: str,
|
|
886
|
+
scope: str = "global",
|
|
887
|
+
path: Optional[str] = None,
|
|
888
|
+
envs: Optional[Dict[str, str]] = None,
|
|
889
|
+
user: Optional[str] = None,
|
|
890
|
+
cwd: Optional[str] = None,
|
|
891
|
+
timeout: Optional[float] = None,
|
|
892
|
+
request_timeout: Optional[float] = None,
|
|
893
|
+
):
|
|
894
|
+
"""
|
|
895
|
+
Set a git config value.
|
|
896
|
+
|
|
897
|
+
Use `scope="local"` together with `path` to configure a specific repository.
|
|
898
|
+
|
|
899
|
+
:param key: Git config key (e.g. `pull.rebase`)
|
|
900
|
+
:param value: Git config value
|
|
901
|
+
:param scope: Config scope: `global`, `local`, or `system`
|
|
902
|
+
:param path: Repository path required when `scope` is `local`
|
|
903
|
+
:param envs: Environment variables used for the command
|
|
904
|
+
:param user: User to run the command as
|
|
905
|
+
:param cwd: Working directory to run the command
|
|
906
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
907
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
908
|
+
:return: Command result from the command runner
|
|
909
|
+
"""
|
|
910
|
+
if not key:
|
|
911
|
+
raise InvalidArgumentException("Git config key is required.")
|
|
912
|
+
|
|
913
|
+
scope_flag, repo_path = resolve_config_scope(scope, path)
|
|
914
|
+
return self._run_git(
|
|
915
|
+
["config", scope_flag, key, value],
|
|
916
|
+
repo_path,
|
|
917
|
+
envs,
|
|
918
|
+
user,
|
|
919
|
+
cwd,
|
|
920
|
+
timeout,
|
|
921
|
+
request_timeout,
|
|
922
|
+
)
|
|
923
|
+
|
|
924
|
+
def get_config(
|
|
925
|
+
self,
|
|
926
|
+
key: str,
|
|
927
|
+
scope: str = "global",
|
|
928
|
+
path: Optional[str] = None,
|
|
929
|
+
envs: Optional[Dict[str, str]] = None,
|
|
930
|
+
user: Optional[str] = None,
|
|
931
|
+
cwd: Optional[str] = None,
|
|
932
|
+
timeout: Optional[float] = None,
|
|
933
|
+
request_timeout: Optional[float] = None,
|
|
934
|
+
) -> Optional[str]:
|
|
935
|
+
"""
|
|
936
|
+
Get a git config value.
|
|
937
|
+
|
|
938
|
+
Returns `None` when the key is not set in the requested scope.
|
|
939
|
+
|
|
940
|
+
:param key: Git config key (e.g. `pull.rebase`)
|
|
941
|
+
:param scope: Config scope: `global`, `local`, or `system`
|
|
942
|
+
:param path: Repository path required when `scope` is `local`
|
|
943
|
+
:param envs: Environment variables used for the command
|
|
944
|
+
:param user: User to run the command as
|
|
945
|
+
:param cwd: Working directory to run the command
|
|
946
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
947
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
948
|
+
:return: Config value if present, otherwise `None`
|
|
949
|
+
"""
|
|
950
|
+
if not key:
|
|
951
|
+
raise InvalidArgumentException("Git config key is required.")
|
|
952
|
+
|
|
953
|
+
scope_flag, repo_path = resolve_config_scope(scope, path)
|
|
954
|
+
cmd = (
|
|
955
|
+
f"{build_git_command(['config', scope_flag, '--get', key], repo_path)} "
|
|
956
|
+
"|| true"
|
|
957
|
+
)
|
|
958
|
+
result = self._run_shell(
|
|
959
|
+
cmd,
|
|
960
|
+
envs,
|
|
961
|
+
user,
|
|
962
|
+
cwd,
|
|
963
|
+
timeout,
|
|
964
|
+
request_timeout,
|
|
965
|
+
).stdout.strip()
|
|
966
|
+
return result or None
|
|
967
|
+
|
|
968
|
+
def dangerously_authenticate(
|
|
969
|
+
self,
|
|
970
|
+
username: str,
|
|
971
|
+
password: str,
|
|
972
|
+
host: str = "github.com",
|
|
973
|
+
protocol: str = "https",
|
|
974
|
+
envs: Optional[Dict[str, str]] = None,
|
|
975
|
+
user: Optional[str] = None,
|
|
976
|
+
cwd: Optional[str] = None,
|
|
977
|
+
timeout: Optional[float] = None,
|
|
978
|
+
request_timeout: Optional[float] = None,
|
|
979
|
+
):
|
|
980
|
+
"""
|
|
981
|
+
Dangerously authenticate git globally via the credential helper.
|
|
982
|
+
|
|
983
|
+
This persists credentials in the credential store and may be accessible to agents running on the sandbox.
|
|
984
|
+
Prefer short-lived credentials when possible.
|
|
985
|
+
|
|
986
|
+
:param username: Username for HTTP(S) authentication
|
|
987
|
+
:param password: Password or token for HTTP(S) authentication
|
|
988
|
+
:param host: Host to authenticate for, defaults to `github.com`
|
|
989
|
+
:param protocol: Protocol to authenticate for, defaults to `https`
|
|
990
|
+
:param envs: Environment variables used for the command
|
|
991
|
+
:param user: User to run the command as
|
|
992
|
+
:param cwd: Working directory to run the command
|
|
993
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
994
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
995
|
+
:return: Command result from the command runner
|
|
996
|
+
"""
|
|
997
|
+
if not username or not password:
|
|
998
|
+
raise InvalidArgumentException(
|
|
999
|
+
"Both username and password are required to authenticate git."
|
|
1000
|
+
)
|
|
1001
|
+
|
|
1002
|
+
self.set_config(
|
|
1003
|
+
"credential.helper",
|
|
1004
|
+
"store",
|
|
1005
|
+
scope="global",
|
|
1006
|
+
envs=envs,
|
|
1007
|
+
user=user,
|
|
1008
|
+
cwd=cwd,
|
|
1009
|
+
timeout=timeout,
|
|
1010
|
+
request_timeout=request_timeout,
|
|
1011
|
+
)
|
|
1012
|
+
approve_cmd = build_credential_approve_command(
|
|
1013
|
+
username=username,
|
|
1014
|
+
password=password,
|
|
1015
|
+
host=host,
|
|
1016
|
+
protocol=protocol,
|
|
1017
|
+
)
|
|
1018
|
+
return self._run_shell(
|
|
1019
|
+
approve_cmd,
|
|
1020
|
+
envs,
|
|
1021
|
+
user,
|
|
1022
|
+
cwd,
|
|
1023
|
+
timeout,
|
|
1024
|
+
request_timeout,
|
|
1025
|
+
)
|
|
1026
|
+
|
|
1027
|
+
def configure_user(
|
|
1028
|
+
self,
|
|
1029
|
+
name: str,
|
|
1030
|
+
email: str,
|
|
1031
|
+
scope: str = "global",
|
|
1032
|
+
path: Optional[str] = None,
|
|
1033
|
+
envs: Optional[Dict[str, str]] = None,
|
|
1034
|
+
user: Optional[str] = None,
|
|
1035
|
+
cwd: Optional[str] = None,
|
|
1036
|
+
timeout: Optional[float] = None,
|
|
1037
|
+
request_timeout: Optional[float] = None,
|
|
1038
|
+
):
|
|
1039
|
+
"""
|
|
1040
|
+
Configure git user name and email.
|
|
1041
|
+
|
|
1042
|
+
:param name: Git user name
|
|
1043
|
+
:param email: Git user email
|
|
1044
|
+
:param scope: Config scope: `global`, `local`, or `system`
|
|
1045
|
+
:param path: Repository path required when `scope` is `local`
|
|
1046
|
+
:param envs: Environment variables used for the command
|
|
1047
|
+
:param user: User to run the command as
|
|
1048
|
+
:param cwd: Working directory to run the command
|
|
1049
|
+
:param timeout: Timeout for the command connection in **seconds**
|
|
1050
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
1051
|
+
:return: Command result from the command runner
|
|
1052
|
+
"""
|
|
1053
|
+
if not name or not email:
|
|
1054
|
+
raise InvalidArgumentException("Both name and email are required.")
|
|
1055
|
+
|
|
1056
|
+
self.set_config(
|
|
1057
|
+
"user.name",
|
|
1058
|
+
name,
|
|
1059
|
+
scope=scope,
|
|
1060
|
+
path=path,
|
|
1061
|
+
envs=envs,
|
|
1062
|
+
user=user,
|
|
1063
|
+
cwd=cwd,
|
|
1064
|
+
timeout=timeout,
|
|
1065
|
+
request_timeout=request_timeout,
|
|
1066
|
+
)
|
|
1067
|
+
return self.set_config(
|
|
1068
|
+
"user.email",
|
|
1069
|
+
email,
|
|
1070
|
+
scope=scope,
|
|
1071
|
+
path=path,
|
|
1072
|
+
envs=envs,
|
|
1073
|
+
user=user,
|
|
1074
|
+
cwd=cwd,
|
|
1075
|
+
timeout=timeout,
|
|
1076
|
+
request_timeout=request_timeout,
|
|
1077
|
+
)
|