fix: fetch root artifact from upstream when missing in auto_fetch mode
When auto_fetch=true and the root artifact doesn't exist locally in a system project (_pypi), now attempts to fetch it from upstream before starting dependency resolution. Also fixed a bug where fetched_artifacts was being redeclared, which would lose the root artifact from the list.
This commit is contained in:
@@ -886,6 +886,9 @@ async def resolve_dependencies_with_fetch(
|
||||
when a missing dependency is from a system project (e.g., _pypi), it attempts
|
||||
to fetch the package from the corresponding upstream registry.
|
||||
|
||||
If the root artifact itself doesn't exist in a system project, it will also
|
||||
be fetched from upstream before resolution begins.
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
project_name: Project name
|
||||
@@ -900,43 +903,94 @@ async def resolve_dependencies_with_fetch(
|
||||
DependencyResolutionResponse with all resolved artifacts and fetch status
|
||||
|
||||
Raises:
|
||||
DependencyNotFoundError: If the root artifact cannot be found
|
||||
DependencyNotFoundError: If the root artifact cannot be found (even after fetch attempt)
|
||||
CircularDependencyError: If circular dependencies are detected
|
||||
DependencyConflictError: If conflicting versions are required
|
||||
"""
|
||||
# Resolve the initial artifact (same as sync version)
|
||||
# Track fetched artifacts for response
|
||||
fetched_artifacts: List[ResolvedArtifact] = []
|
||||
|
||||
# Check if project exists
|
||||
project = db.query(Project).filter(Project.name == project_name).first()
|
||||
|
||||
# If project doesn't exist and it's a system project pattern, we can't auto-create it
|
||||
if not project:
|
||||
raise DependencyNotFoundError(project_name, package_name, ref)
|
||||
|
||||
# Check if package exists
|
||||
package = db.query(Package).filter(
|
||||
Package.project_id == project.id,
|
||||
Package.name == package_name,
|
||||
).first()
|
||||
if not package:
|
||||
raise DependencyNotFoundError(project_name, package_name, ref)
|
||||
|
||||
# Try to resolve the root artifact
|
||||
root_artifact_id = None
|
||||
root_version = None
|
||||
root_size = None
|
||||
|
||||
# Handle artifact: prefix for direct artifact ID references
|
||||
if ref.startswith("artifact:"):
|
||||
artifact_id = ref[9:]
|
||||
artifact = db.query(Artifact).filter(Artifact.id == artifact_id).first()
|
||||
if not artifact:
|
||||
raise DependencyNotFoundError(project_name, package_name, ref)
|
||||
root_artifact_id = artifact.id
|
||||
root_version = artifact_id[:12]
|
||||
root_size = artifact.size
|
||||
else:
|
||||
if artifact:
|
||||
root_artifact_id = artifact.id
|
||||
root_version = artifact_id[:12]
|
||||
root_size = artifact.size
|
||||
elif package:
|
||||
# Try to resolve by version/constraint
|
||||
resolved = _resolve_dependency_to_artifact(
|
||||
db, project_name, package_name, ref
|
||||
)
|
||||
if not resolved:
|
||||
raise DependencyNotFoundError(project_name, package_name, ref)
|
||||
root_artifact_id, root_version, root_size = resolved
|
||||
if resolved:
|
||||
root_artifact_id, root_version, root_size = resolved
|
||||
|
||||
# If root artifact not found and this is a system project, try to fetch it
|
||||
if root_artifact_id is None and project_name in SYSTEM_PROJECT_REGISTRY_MAP:
|
||||
logger.info(
|
||||
f"Root artifact {project_name}/{package_name}@{ref} not found, "
|
||||
"attempting to fetch from upstream"
|
||||
)
|
||||
|
||||
client = registry_clients.get(project_name)
|
||||
if client:
|
||||
try:
|
||||
# Resolve the version constraint from upstream
|
||||
version_info = await client.resolve_constraint(package_name, ref)
|
||||
if version_info:
|
||||
# Fetch and cache the package
|
||||
fetch_result = await client.fetch_package(
|
||||
package_name, version_info, db, storage
|
||||
)
|
||||
if fetch_result:
|
||||
logger.info(
|
||||
f"Successfully fetched root artifact {package_name}=="
|
||||
f"{fetch_result.version} (artifact {fetch_result.artifact_id[:12]})"
|
||||
)
|
||||
root_artifact_id = fetch_result.artifact_id
|
||||
root_version = fetch_result.version
|
||||
root_size = fetch_result.size
|
||||
|
||||
# Add to fetched list
|
||||
fetched_artifacts.append(ResolvedArtifact(
|
||||
artifact_id=fetch_result.artifact_id,
|
||||
project=project_name,
|
||||
package=package_name,
|
||||
version=fetch_result.version,
|
||||
size=fetch_result.size,
|
||||
download_url=f"{base_url}/api/v1/project/{project_name}/{package_name}/+/{fetch_result.version}",
|
||||
))
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to fetch root artifact {package_name}: {e}")
|
||||
|
||||
# If still no root artifact, raise error
|
||||
if root_artifact_id is None:
|
||||
raise DependencyNotFoundError(project_name, package_name, ref)
|
||||
|
||||
# Track state
|
||||
resolved_artifacts: Dict[str, ResolvedArtifact] = {}
|
||||
missing_dependencies: List[MissingDependency] = []
|
||||
fetched_artifacts: List[ResolvedArtifact] = [] # Newly fetched
|
||||
# Note: fetched_artifacts was already initialized above (line 911)
|
||||
# and may already contain the root artifact if it was fetched from upstream
|
||||
version_requirements: Dict[str, List[Dict[str, Any]]] = {}
|
||||
visiting: Set[str] = set()
|
||||
visited: Set[str] = set()
|
||||
|
||||
Reference in New Issue
Block a user