llama-deploy-core 0.2.7a1__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.
- llama_deploy/core/__init__.py +3 -0
- llama_deploy/core/config.py +1 -0
- llama_deploy/core/git/git_util.py +224 -0
- llama_deploy/core/schema/__init__.py +27 -0
- llama_deploy/core/schema/base.py +20 -0
- llama_deploy/core/schema/deployments.py +188 -0
- llama_deploy/core/schema/git_validation.py +46 -0
- llama_deploy/core/schema/projects.py +14 -0
- llama_deploy_core-0.2.7a1.dist-info/METADATA +12 -0
- llama_deploy_core-0.2.7a1.dist-info/RECORD +11 -0
- llama_deploy_core-0.2.7a1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DEFAULT_DEPLOYMENT_FILE_PATH = "llama_deploy.yaml"
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Git utilities for the purpose of exploring, cloning, and parsing llama-deploy repositories.
|
|
3
|
+
Responsibilities are lower level git access, as well as some application specific config parsing.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
import re
|
|
8
|
+
import subprocess
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import tempfile
|
|
11
|
+
|
|
12
|
+
import yaml
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_github_repo_url(repo_url: str) -> tuple[str, str]:
|
|
16
|
+
"""
|
|
17
|
+
Parse GitHub repository URL to extract owner and repo name.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
repo_url: GitHub repository URL (various formats supported)
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Tuple of (owner, repo_name)
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
ValueError: If URL format is not recognized
|
|
27
|
+
"""
|
|
28
|
+
# Remove .git suffix if present
|
|
29
|
+
url = repo_url.rstrip("/").removesuffix(".git")
|
|
30
|
+
|
|
31
|
+
# Handle different GitHub URL formats
|
|
32
|
+
patterns = [
|
|
33
|
+
r"https://github\.com/([^/]+)/([^/]+)",
|
|
34
|
+
r"git@github\.com:([^/]+)/([^/]+)",
|
|
35
|
+
r"github\.com/([^/]+)/([^/]+)",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
for pattern in patterns:
|
|
39
|
+
match = re.match(pattern, url)
|
|
40
|
+
if match:
|
|
41
|
+
return match.group(1), match.group(2)
|
|
42
|
+
|
|
43
|
+
raise ValueError(f"Could not parse GitHub repository URL: {repo_url}")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def inject_basic_auth(url: str, basic_auth: str | None = None) -> str:
|
|
47
|
+
"""Inject basic auth into a URL if provided"""
|
|
48
|
+
if basic_auth and "://" in url and "@" not in url:
|
|
49
|
+
url = url.replace("https://", f"https://{basic_auth}@")
|
|
50
|
+
return url
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _run_process(args: list[str], cwd: str | None = None) -> str:
|
|
54
|
+
"""Run a process and raise an exception if it fails"""
|
|
55
|
+
result = subprocess.run(
|
|
56
|
+
args, cwd=cwd, capture_output=True, text=True, check=True, timeout=30
|
|
57
|
+
)
|
|
58
|
+
if result.returncode != 0:
|
|
59
|
+
raise subprocess.CalledProcessError(
|
|
60
|
+
result.returncode, args, result.stdout, result.stderr
|
|
61
|
+
)
|
|
62
|
+
return result.stdout.strip()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class GitAccessError(Exception):
|
|
66
|
+
"""Error raised when a user reportable git error occurs, e.g connection fails, cannot access repository, timeout, ref not found, etc."""
|
|
67
|
+
|
|
68
|
+
def __init__(self, message: str):
|
|
69
|
+
self.message = message
|
|
70
|
+
super().__init__(message)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass
|
|
74
|
+
class GitCloneResult:
|
|
75
|
+
git_sha: str
|
|
76
|
+
git_ref: str | None = None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def clone_repo(
|
|
80
|
+
repository_url: str,
|
|
81
|
+
git_ref: str | None = None,
|
|
82
|
+
basic_auth: str | None = None,
|
|
83
|
+
dest_dir: Path | str | None = None,
|
|
84
|
+
) -> GitCloneResult:
|
|
85
|
+
"""
|
|
86
|
+
Clone a repository and checkout a specific ref, if provided. If user reportable access errors occur, raises a GitAccessError.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
repository_url: The URL of the repository to clone
|
|
90
|
+
git_ref: The git reference to checkout, if provided
|
|
91
|
+
basic_auth: The basic auth to use to clone the repository
|
|
92
|
+
dest_dir: The directory to clone the repository to, if provided
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
GitCloneResult: A dataclass containing the git SHA and resolved git ref (e.g. main if None was provided)
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
99
|
+
dest_dir = Path(temp_dir) if dest_dir is None else Path(dest_dir)
|
|
100
|
+
authenticated_url = inject_basic_auth(repository_url, basic_auth)
|
|
101
|
+
did_exist = (
|
|
102
|
+
dest_dir.exists() and dest_dir.is_dir() and list(dest_dir.iterdir())
|
|
103
|
+
)
|
|
104
|
+
if not did_exist:
|
|
105
|
+
# need to do a full clone to resolve any kind of ref without exploding in
|
|
106
|
+
# complexity (tag, branch, commit, short commit)
|
|
107
|
+
clone_args = [
|
|
108
|
+
"git",
|
|
109
|
+
"clone",
|
|
110
|
+
authenticated_url,
|
|
111
|
+
str(dest_dir.absolute()),
|
|
112
|
+
]
|
|
113
|
+
_run_process(clone_args)
|
|
114
|
+
|
|
115
|
+
if not git_ref:
|
|
116
|
+
resolved_branch = _run_process(
|
|
117
|
+
["git", "branch", "--show-current"],
|
|
118
|
+
cwd=str(dest_dir.absolute()),
|
|
119
|
+
)
|
|
120
|
+
if resolved_branch:
|
|
121
|
+
git_ref = resolved_branch
|
|
122
|
+
else:
|
|
123
|
+
try:
|
|
124
|
+
resolved_tag = _run_process(
|
|
125
|
+
["git", "describe", "--tags", "--exact-match"],
|
|
126
|
+
cwd=str(dest_dir.absolute()),
|
|
127
|
+
)
|
|
128
|
+
if resolved_tag:
|
|
129
|
+
git_ref = resolved_tag
|
|
130
|
+
except subprocess.CalledProcessError:
|
|
131
|
+
pass
|
|
132
|
+
else: # Checkout the ref
|
|
133
|
+
if did_exist:
|
|
134
|
+
try:
|
|
135
|
+
_run_process(
|
|
136
|
+
["git", "fetch", "origin"], cwd=str(dest_dir.absolute())
|
|
137
|
+
)
|
|
138
|
+
except subprocess.CalledProcessError:
|
|
139
|
+
raise GitAccessError("Failed to resolve git reference")
|
|
140
|
+
try:
|
|
141
|
+
_run_process(
|
|
142
|
+
["git", "checkout", git_ref], cwd=str(dest_dir.absolute())
|
|
143
|
+
)
|
|
144
|
+
except subprocess.CalledProcessError as e:
|
|
145
|
+
# Check error message to determine if it's a network issue or ref not found
|
|
146
|
+
if "unable to access" in str(
|
|
147
|
+
e.stderr
|
|
148
|
+
) or "fatal: unable to access repository" in str(e.stderr):
|
|
149
|
+
raise GitAccessError("Failed to resolve git reference")
|
|
150
|
+
else:
|
|
151
|
+
raise GitAccessError(f"Commit SHA '{git_ref}' not found")
|
|
152
|
+
# if no ref, stay on whatever the clone gave us/current commit
|
|
153
|
+
# return the resolved sha
|
|
154
|
+
resolved_sha = _run_process(
|
|
155
|
+
["git", "rev-parse", "HEAD"], cwd=str(dest_dir.absolute())
|
|
156
|
+
).strip()
|
|
157
|
+
return GitCloneResult(git_sha=resolved_sha, git_ref=git_ref)
|
|
158
|
+
except subprocess.TimeoutExpired:
|
|
159
|
+
raise GitAccessError("Timeout while cloning repository")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def validate_deployment_file(repo_dir: Path, deployment_file_path: str) -> bool:
|
|
163
|
+
"""
|
|
164
|
+
Validate that the deployment file exists in the repository.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
repo_dir: The directory of the repository
|
|
168
|
+
deployment_file_path: The path to the deployment file, relative to the repository root
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
True if the deployment file exists and appears to be valid, False otherwise
|
|
172
|
+
"""
|
|
173
|
+
deployment_file = repo_dir / deployment_file_path
|
|
174
|
+
if not deployment_file.exists():
|
|
175
|
+
return False
|
|
176
|
+
with open(deployment_file, "r") as f:
|
|
177
|
+
try:
|
|
178
|
+
loaded = yaml.safe_load(f)
|
|
179
|
+
if not isinstance(loaded, dict):
|
|
180
|
+
return False
|
|
181
|
+
if "name" not in loaded:
|
|
182
|
+
return False
|
|
183
|
+
if not isinstance(loaded["name"], str):
|
|
184
|
+
return False
|
|
185
|
+
if "services" not in loaded:
|
|
186
|
+
return False
|
|
187
|
+
if not isinstance(loaded["services"], dict):
|
|
188
|
+
return False
|
|
189
|
+
return True # good nuff for now. Eventually this should parse it into a model validated format
|
|
190
|
+
except yaml.YAMLError:
|
|
191
|
+
return False
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
async def validate_git_public_access(repository_url: str) -> bool:
|
|
195
|
+
"""Check if a git repository is publicly accessible using git ls-remote."""
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
result = subprocess.run(
|
|
199
|
+
["git", "ls-remote", "--heads", repository_url],
|
|
200
|
+
capture_output=True,
|
|
201
|
+
text=True,
|
|
202
|
+
timeout=30,
|
|
203
|
+
check=False, # Don't raise on non-zero exit
|
|
204
|
+
)
|
|
205
|
+
return result.returncode == 0
|
|
206
|
+
except (subprocess.TimeoutExpired, Exception):
|
|
207
|
+
return False
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
async def validate_git_credential_access(repository_url: str, basic_auth: str) -> bool:
|
|
211
|
+
"""Check if a credential provides access to a git repository."""
|
|
212
|
+
|
|
213
|
+
auth_url = inject_basic_auth(repository_url, basic_auth)
|
|
214
|
+
try:
|
|
215
|
+
result = subprocess.run(
|
|
216
|
+
["git", "ls-remote", "--heads", auth_url],
|
|
217
|
+
capture_output=True,
|
|
218
|
+
text=True,
|
|
219
|
+
timeout=30,
|
|
220
|
+
check=False,
|
|
221
|
+
)
|
|
222
|
+
return result.returncode == 0
|
|
223
|
+
except (subprocess.TimeoutExpired, Exception):
|
|
224
|
+
return False
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from .base import Base
|
|
2
|
+
from .deployments import (
|
|
3
|
+
DeploymentCreate,
|
|
4
|
+
DeploymentResponse,
|
|
5
|
+
DeploymentUpdate,
|
|
6
|
+
DeploymentsListResponse,
|
|
7
|
+
LlamaDeploymentSpec,
|
|
8
|
+
apply_deployment_update,
|
|
9
|
+
LlamaDeploymentPhase,
|
|
10
|
+
)
|
|
11
|
+
from .git_validation import RepositoryValidationResponse, RepositoryValidationRequest
|
|
12
|
+
from .projects import ProjectSummary, ProjectsListResponse
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"Base",
|
|
16
|
+
"DeploymentCreate",
|
|
17
|
+
"DeploymentResponse",
|
|
18
|
+
"DeploymentUpdate",
|
|
19
|
+
"DeploymentsListResponse",
|
|
20
|
+
"LlamaDeploymentSpec",
|
|
21
|
+
"apply_deployment_update",
|
|
22
|
+
"LlamaDeploymentPhase",
|
|
23
|
+
"RepositoryValidationResponse",
|
|
24
|
+
"RepositoryValidationRequest",
|
|
25
|
+
"ProjectSummary",
|
|
26
|
+
"ProjectsListResponse",
|
|
27
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from pydantic import BaseModel, ConfigDict
|
|
2
|
+
|
|
3
|
+
base_config = ConfigDict(
|
|
4
|
+
from_attributes=True,
|
|
5
|
+
arbitrary_types_allowed=True,
|
|
6
|
+
use_enum_values=False,
|
|
7
|
+
# ===== timedelta serialization =====
|
|
8
|
+
# Serialize timedelta as float
|
|
9
|
+
# This was the default behavior in pydantic v1, but was changed in v2 to be "iso8601"
|
|
10
|
+
# We want to keep the same behavior as v1 for now
|
|
11
|
+
# ================================
|
|
12
|
+
ser_json_timedelta="float",
|
|
13
|
+
# NOTE: we often use data model with fields that have "model_" prefix,
|
|
14
|
+
# so we need to set protected_namespaces=() to avoid conflict
|
|
15
|
+
protected_namespaces=(),
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Base(BaseModel):
|
|
20
|
+
model_config = base_config
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
from pydantic import HttpUrl
|
|
5
|
+
|
|
6
|
+
from .base import Base
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# K8s CRD phase values
|
|
10
|
+
LlamaDeploymentPhase = Literal[
|
|
11
|
+
"Syncing", # Initial reconciliation phase - controller is processing the deployment
|
|
12
|
+
"Pending", # Waiting for deployment resources to be ready (pods starting up)
|
|
13
|
+
"Running", # Deployment is healthy and serving traffic
|
|
14
|
+
"Failed", # Complete deployment failure - no pods available
|
|
15
|
+
"Succeeded", # Deployment completed successfully (for one-time jobs)
|
|
16
|
+
"RollingOut", # Rolling update in progress - new pods being created while old ones still serve traffic
|
|
17
|
+
"RolloutFailed", # New deployment failed but old pods are still available and serving traffic
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DeploymentResponse(Base):
|
|
22
|
+
id: str
|
|
23
|
+
name: str
|
|
24
|
+
repo_url: str
|
|
25
|
+
deployment_file_path: str
|
|
26
|
+
git_ref: str | None = None
|
|
27
|
+
git_sha: str | None = None
|
|
28
|
+
has_personal_access_token: bool = False
|
|
29
|
+
project_id: str
|
|
30
|
+
secret_names: list[str] | None = None
|
|
31
|
+
apiserver_url: HttpUrl | None
|
|
32
|
+
status: LlamaDeploymentPhase
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class DeploymentsListResponse(Base):
|
|
36
|
+
deployments: list[DeploymentResponse]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class DeploymentCreate(Base):
|
|
40
|
+
name: str
|
|
41
|
+
repo_url: str
|
|
42
|
+
deployment_file_path: str | None = None
|
|
43
|
+
git_ref: str | None = None
|
|
44
|
+
personal_access_token: str | None = None
|
|
45
|
+
secrets: dict[str, str] | None = None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class LlamaDeploymentMetadata(Base):
|
|
49
|
+
name: str
|
|
50
|
+
namespace: str
|
|
51
|
+
uid: str | None = None
|
|
52
|
+
resourceVersion: str | None = None
|
|
53
|
+
creationTimestamp: datetime | None = None
|
|
54
|
+
annotations: dict[str, str] | None = None
|
|
55
|
+
labels: dict[str, str] | None = None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class LlamaDeploymentSpec(Base):
|
|
59
|
+
"""
|
|
60
|
+
LlamaDeployment spec fields as defined in the Kubernetes CRD.
|
|
61
|
+
|
|
62
|
+
Maps to the spec section of the LlamaDeployment custom resource.
|
|
63
|
+
Field names match exactly with the K8s CRD for direct conversion.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
projectId: str
|
|
67
|
+
repoUrl: str
|
|
68
|
+
deploymentFilePath: str = "llama_deploy.yaml"
|
|
69
|
+
gitRef: str | None = None
|
|
70
|
+
gitSha: str | None = None
|
|
71
|
+
name: str
|
|
72
|
+
secretName: str | None = None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class LlamaDeploymentStatus(Base):
|
|
76
|
+
"""
|
|
77
|
+
LlamaDeployment status fields as defined in the Kubernetes CRD.
|
|
78
|
+
|
|
79
|
+
Maps to the status section of the LlamaDeployment custom resource.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
phase: LlamaDeploymentPhase | None = None
|
|
83
|
+
message: str | None = None
|
|
84
|
+
lastUpdated: datetime | None = None
|
|
85
|
+
authToken: str | None = None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class LlamaDeploymentCRD(Base):
|
|
89
|
+
metadata: LlamaDeploymentMetadata
|
|
90
|
+
spec: LlamaDeploymentSpec
|
|
91
|
+
status: LlamaDeploymentStatus
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class DeploymentUpdate(Base):
|
|
95
|
+
"""
|
|
96
|
+
Patch-style update model for deployments.
|
|
97
|
+
|
|
98
|
+
Fields not included in the request will remain unchanged.
|
|
99
|
+
Fields explicitly set to None will clear/delete the field value.
|
|
100
|
+
|
|
101
|
+
For secrets: provide a dict where string values add/update secrets
|
|
102
|
+
and null values remove secrets.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
repo_url: str | None = None
|
|
106
|
+
deployment_file_path: str | None = None
|
|
107
|
+
git_ref: str | None = None
|
|
108
|
+
git_sha: str | None = None
|
|
109
|
+
personal_access_token: str | None = None
|
|
110
|
+
secrets: dict[str, str | None] | None = None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class DeploymentUpdateResult(Base):
|
|
114
|
+
"""
|
|
115
|
+
Result of applying a DeploymentUpdate to a LlamaDeploymentSpec.
|
|
116
|
+
|
|
117
|
+
Contains the updated spec and lists of secret changes to apply.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
updated_spec: LlamaDeploymentSpec
|
|
121
|
+
secret_adds: dict[str, str]
|
|
122
|
+
secret_removes: list[str]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def apply_deployment_update(
|
|
126
|
+
update: DeploymentUpdate,
|
|
127
|
+
existing_spec: LlamaDeploymentSpec,
|
|
128
|
+
) -> DeploymentUpdateResult:
|
|
129
|
+
"""
|
|
130
|
+
Apply a DeploymentUpdate to an existing LlamaDeploymentSpec.
|
|
131
|
+
|
|
132
|
+
Returns the updated spec and lists of secret changes.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
update: The update to apply (snake_case fields from API)
|
|
136
|
+
existing_spec: The current LlamaDeploymentSpec (camelCase fields)
|
|
137
|
+
git_sha: The resolved git SHA to set
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
DeploymentUpdateResult with updated spec and secret changes
|
|
141
|
+
"""
|
|
142
|
+
# Start with a copy of the existing spec
|
|
143
|
+
updated_spec = existing_spec.model_copy()
|
|
144
|
+
|
|
145
|
+
# Apply direct field updates (only if not None)
|
|
146
|
+
# Convert from snake_case API fields to camelCase spec fields
|
|
147
|
+
if update.repo_url is not None:
|
|
148
|
+
updated_spec.repoUrl = update.repo_url
|
|
149
|
+
|
|
150
|
+
if update.deployment_file_path is not None:
|
|
151
|
+
updated_spec.deploymentFilePath = update.deployment_file_path
|
|
152
|
+
|
|
153
|
+
if update.git_ref is not None:
|
|
154
|
+
updated_spec.gitRef = update.git_ref
|
|
155
|
+
|
|
156
|
+
# Update gitSha if provided
|
|
157
|
+
if update.git_sha is not None:
|
|
158
|
+
updated_spec.gitSha = None if update.git_sha == "" else update.git_sha
|
|
159
|
+
|
|
160
|
+
# Track secret changes
|
|
161
|
+
secret_adds: dict[str, str] = {}
|
|
162
|
+
secret_removes: list[str] = []
|
|
163
|
+
|
|
164
|
+
# Handle personal access token (stored as GITHUB_PAT secret)
|
|
165
|
+
if update.personal_access_token is not None:
|
|
166
|
+
if update.personal_access_token == "":
|
|
167
|
+
# Empty string means remove the PAT
|
|
168
|
+
secret_removes.append("GITHUB_PAT")
|
|
169
|
+
else:
|
|
170
|
+
# Non-empty string means add/update the PAT
|
|
171
|
+
secret_adds["GITHUB_PAT"] = update.personal_access_token
|
|
172
|
+
|
|
173
|
+
# Handle explicit secret updates
|
|
174
|
+
secrets = update.secrets
|
|
175
|
+
if secrets is not None:
|
|
176
|
+
for key, value in secrets.items():
|
|
177
|
+
if value is None:
|
|
178
|
+
# None means remove this secret
|
|
179
|
+
secret_removes.append(key)
|
|
180
|
+
else:
|
|
181
|
+
# String value means add/update this secret
|
|
182
|
+
secret_adds[key] = value
|
|
183
|
+
|
|
184
|
+
return DeploymentUpdateResult(
|
|
185
|
+
updated_spec=updated_spec,
|
|
186
|
+
secret_adds=secret_adds,
|
|
187
|
+
secret_removes=secret_removes,
|
|
188
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from pydantic import BaseModel, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class RepositoryValidationResponse(BaseModel):
|
|
6
|
+
"""
|
|
7
|
+
Unified response for repository validation that works for any git repository.
|
|
8
|
+
This is the primary schema that should be used for the /validate-repository endpoint.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
accessible: bool = Field(
|
|
12
|
+
...,
|
|
13
|
+
description="Whether the repository can be accessed by any means available to the server",
|
|
14
|
+
)
|
|
15
|
+
message: str = Field(..., description="Human-readable string explaining the status")
|
|
16
|
+
pat_is_obsolete: bool = Field(
|
|
17
|
+
default=False,
|
|
18
|
+
description="True if validation succeeded via GitHub App for a deployment that previously used a PAT",
|
|
19
|
+
)
|
|
20
|
+
github_app_name: Optional[str] = Field(
|
|
21
|
+
default=None,
|
|
22
|
+
description="Name of the GitHub App if repository is a private GitHub repo and server has GitHub App configured",
|
|
23
|
+
)
|
|
24
|
+
github_app_installation_url: Optional[str] = Field(
|
|
25
|
+
default=None,
|
|
26
|
+
description="GitHub App installation URL if repository is a private GitHub repo and server has GitHub App configured",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class RepositoryValidationRequest(BaseModel):
|
|
31
|
+
repository_url: str
|
|
32
|
+
deployment_id: Optional[str] = None
|
|
33
|
+
pat: Optional[str] = None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class GitApplicationValidationResponse(BaseModel):
|
|
37
|
+
"""
|
|
38
|
+
After general repository validation, a model that describes further validation of configuration, such as the
|
|
39
|
+
git reference, it's resolved SHA (if resolveable), and whether the deployment file is valid.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
is_valid: bool
|
|
43
|
+
error_message: str | None = None
|
|
44
|
+
git_ref: str | None = None
|
|
45
|
+
git_sha: str | None = None
|
|
46
|
+
valid_deployment_file_path: str | None = None
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .base import Base
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ProjectSummary(Base):
|
|
5
|
+
"""Summary of a project with deployment count"""
|
|
6
|
+
|
|
7
|
+
project_id: str
|
|
8
|
+
deployment_count: int
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ProjectsListResponse(Base):
|
|
12
|
+
"""Response model for listing projects with deployment counts"""
|
|
13
|
+
|
|
14
|
+
projects: list[ProjectSummary]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: llama-deploy-core
|
|
3
|
+
Version: 0.2.7a1
|
|
4
|
+
Summary: Core models and schemas for LlamaDeploy
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Dist: pydantic>=2.0.0
|
|
7
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
8
|
+
Requires-Python: >=3.12, <4
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
> [!WARNING]
|
|
12
|
+
> This repository contains pre-release software. It is unstable, incomplete, and subject to breaking changes. Not recommended for use.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
llama_deploy/core/__init__.py,sha256=112612bf2e928c2e0310d6556bb13fc28c00db70297b90a8527486cd2562e408,43
|
|
2
|
+
llama_deploy/core/config.py,sha256=41c5a1baa25a67f0bb58b701ef8f0b8b3281714d7116580b8f87674eb9e396a3,51
|
|
3
|
+
llama_deploy/core/git/git_util.py,sha256=da62903621e80e3a9ea80009d6b711533dfa2403bb2fe3b8c4ddf3cde9a019e3,8084
|
|
4
|
+
llama_deploy/core/schema/__init__.py,sha256=c6821c749182cab73e5b21cce9e0f80d1e0f403f4abc3d050b84d613f640be60,713
|
|
5
|
+
llama_deploy/core/schema/base.py,sha256=2de6d23e58c36b6bb311ec0aea4b902661867056c1250c6b7ce3bad17141fe15,677
|
|
6
|
+
llama_deploy/core/schema/deployments.py,sha256=a269bcdc98b0a5ce09838dbc6dd68541720a0edb956ec8df5c123c3e1b253e80,5670
|
|
7
|
+
llama_deploy/core/schema/git_validation.py,sha256=5faee3f5fc071f10813e7d3755f43fa11aae76a87467583ac7392bf1e8844f1c,1711
|
|
8
|
+
llama_deploy/core/schema/projects.py,sha256=c97eda38207d80354c2ee3a237cba9c3f6838148197cfa2d97b9a18d3da1a38b,294
|
|
9
|
+
llama_deploy_core-0.2.7a1.dist-info/WHEEL,sha256=cc8ae5806c5874a696cde0fcf78fdf73db4982e7c824f3ceab35e2b65182fa1a,79
|
|
10
|
+
llama_deploy_core-0.2.7a1.dist-info/METADATA,sha256=bdcc94edd19ccb608b8526a454dd03cf70e623709b83fe9c5b525ddcbd8489bc,402
|
|
11
|
+
llama_deploy_core-0.2.7a1.dist-info/RECORD,,
|