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
|
when a missing dependency is from a system project (e.g., _pypi), it attempts
|
||||||
to fetch the package from the corresponding upstream registry.
|
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:
|
Args:
|
||||||
db: Database session
|
db: Database session
|
||||||
project_name: Project name
|
project_name: Project name
|
||||||
@@ -900,43 +903,94 @@ async def resolve_dependencies_with_fetch(
|
|||||||
DependencyResolutionResponse with all resolved artifacts and fetch status
|
DependencyResolutionResponse with all resolved artifacts and fetch status
|
||||||
|
|
||||||
Raises:
|
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
|
CircularDependencyError: If circular dependencies are detected
|
||||||
DependencyConflictError: If conflicting versions are required
|
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()
|
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:
|
if not project:
|
||||||
raise DependencyNotFoundError(project_name, package_name, ref)
|
raise DependencyNotFoundError(project_name, package_name, ref)
|
||||||
|
|
||||||
|
# Check if package exists
|
||||||
package = db.query(Package).filter(
|
package = db.query(Package).filter(
|
||||||
Package.project_id == project.id,
|
Package.project_id == project.id,
|
||||||
Package.name == package_name,
|
Package.name == package_name,
|
||||||
).first()
|
).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
|
# Handle artifact: prefix for direct artifact ID references
|
||||||
if ref.startswith("artifact:"):
|
if ref.startswith("artifact:"):
|
||||||
artifact_id = ref[9:]
|
artifact_id = ref[9:]
|
||||||
artifact = db.query(Artifact).filter(Artifact.id == artifact_id).first()
|
artifact = db.query(Artifact).filter(Artifact.id == artifact_id).first()
|
||||||
if not artifact:
|
if artifact:
|
||||||
raise DependencyNotFoundError(project_name, package_name, ref)
|
|
||||||
root_artifact_id = artifact.id
|
root_artifact_id = artifact.id
|
||||||
root_version = artifact_id[:12]
|
root_version = artifact_id[:12]
|
||||||
root_size = artifact.size
|
root_size = artifact.size
|
||||||
else:
|
elif package:
|
||||||
|
# Try to resolve by version/constraint
|
||||||
resolved = _resolve_dependency_to_artifact(
|
resolved = _resolve_dependency_to_artifact(
|
||||||
db, project_name, package_name, ref
|
db, project_name, package_name, ref
|
||||||
)
|
)
|
||||||
if not resolved:
|
if resolved:
|
||||||
raise DependencyNotFoundError(project_name, package_name, ref)
|
|
||||||
root_artifact_id, root_version, root_size = 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
|
# Track state
|
||||||
resolved_artifacts: Dict[str, ResolvedArtifact] = {}
|
resolved_artifacts: Dict[str, ResolvedArtifact] = {}
|
||||||
missing_dependencies: List[MissingDependency] = []
|
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]]] = {}
|
version_requirements: Dict[str, List[Dict[str, Any]]] = {}
|
||||||
visiting: Set[str] = set()
|
visiting: Set[str] = set()
|
||||||
visited: Set[str] = set()
|
visited: Set[str] = set()
|
||||||
|
|||||||
Reference in New Issue
Block a user