Show missing dependencies in dependency graph instead of failing

When dependencies are not cached on the server (common since we removed
proactive caching), the dependency graph now:
- Continues resolving what it can find
- Shows missing dependencies in a separate section with amber styling
- Displays the constraint and which package required them
- Updates the header stats to show "X cached • Y not cached"

This provides a better user experience than showing an error when
some dependencies haven't been downloaded yet.
This commit is contained in:
Mondo Diaz
2026-02-02 16:29:37 -06:00
parent ba0a658611
commit b3ae3b03eb
5 changed files with 111 additions and 6 deletions

View File

@@ -42,6 +42,7 @@ from .schemas import (
ResolvedArtifact,
DependencyResolutionResponse,
DependencyConflict,
MissingDependency,
PaginationMeta,
)
@@ -690,6 +691,8 @@ def resolve_dependencies(
# Track resolved artifacts and their versions
resolved_artifacts: Dict[str, ResolvedArtifact] = {}
# Track missing dependencies (not cached on server)
missing_dependencies: List[MissingDependency] = []
# Track version requirements for conflict detection
version_requirements: Dict[str, List[Dict[str, Any]]] = {} # pkg_key -> [(version, required_by)]
# Track visiting/visited for cycle detection
@@ -773,12 +776,15 @@ def resolve_dependencies(
)
if not resolved_dep:
# Dependency not cached on server - track as missing but continue
constraint = dep.version_constraint or dep.tag_constraint
raise DependencyNotFoundError(
dep.dependency_project,
dep.dependency_package,
constraint,
)
missing_dependencies.append(MissingDependency(
project=dep.dependency_project,
package=dep.dependency_package,
constraint=constraint,
required_by=pkg_key,
))
continue
dep_artifact_id, dep_version, dep_size = resolved_dep
_resolve_recursive(
@@ -828,6 +834,7 @@ def resolve_dependencies(
"ref": ref,
},
resolved=resolved_list,
missing=missing_dependencies,
total_size=total_size,
artifact_count=len(resolved_list),
)

View File

@@ -1033,10 +1033,19 @@ class ResolvedArtifact(BaseModel):
download_url: str
class MissingDependency(BaseModel):
"""A dependency that could not be resolved (not cached on server)"""
project: str
package: str
constraint: Optional[str] = None
required_by: Optional[str] = None
class DependencyResolutionResponse(BaseModel):
"""Response from dependency resolution endpoint"""
requested: Dict[str, str] # project, package, ref
resolved: List[ResolvedArtifact]
missing: List[MissingDependency] = []
total_size: int
artifact_count: int