fix: preserve DependencyReference through download pipeline (#382)#383
Merged
danielmeppiel merged 3 commits intomicrosoft:mainfrom Mar 20, 2026
Conversation
…t#382) Subdirectory packages on non-GitHub/ADO hosts (e.g. GitLab, Gitea) failed because the download pipeline converted DependencyReference to a string via str() and re-parsed it in download_package(). The str() → parse() round-trip lost the repo_url / virtual_path boundary on generic hosts where _detect_virtual_package() uses a dynamic min_base_segments heuristic. Fix: pass the structured DependencyReference object through the pipeline instead of flattening to string. Specifically: - download_package() and resolve_git_reference() now accept Union[str, DependencyReference], skipping the parse when already structured - build_download_ref() returns a DependencyReference (via dataclasses.replace) instead of a flat string - All call sites in install.py and _utils.py updated to pass the object directly Closes microsoft#382 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes installs of subdirectory (virtual) packages on non-GitHub/ADO git hosts by preserving the structured DependencyReference object through the download pipeline, avoiding a lossy str() → parse() round-trip that could collapse repo_url and virtual_path.
Changes:
build_download_ref()now returns aDependencyReference(withreferenceoverridden viadataclasses.replace()when using a locked SHA).GitHubPackageDownloader.download_package()and.resolve_git_reference()now acceptUnion[str, DependencyReference]and skip parsing when already structured.- Call sites updated to pass
DependencyReferencedirectly; tests updated/added for the new object-based behavior.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/apm_cli/deps/github_downloader.py |
Accepts structured refs in download_package/resolve_git_reference to avoid re-parsing and preserve virtual_path. |
src/apm_cli/drift.py |
Changes build_download_ref() to return DependencyReference instead of a flattened string. |
src/apm_cli/commands/install.py |
Updates transitive download callback + cache pre-resolution to pass DependencyReference objects. |
src/apm_cli/commands/deps/_utils.py |
Updates deps update commands to stop wrapping deps with str() before download. |
tests/test_apm_package_models.py |
Adds regression tests related to generic-host subdirectory refs. |
tests/unit/test_install_update.py |
Updates existing tests to assert on DependencyReference fields rather than string formatting. |
- Normalize original_ref to string in resolve_git_reference() to avoid leaking DependencyReference objects into ResolvedReference.original_ref - Replace shallow test with one that verifies DependencyReference.parse() is NOT called when passing a structured object to download_package() - Update test_resolve_git_reference_branch to match normalized original_ref Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #382 — Subdirectory packages fail on non-GitHub/ADO hosts (generic git hosts like GitLab, Gitea, Bitbucket Server).
Root Cause
The download pipeline converted
DependencyReferenceto a string viastr()and re-parsed it indownload_package(). Thestr()→parse()round-trip lost therepo_url/virtual_pathboundary on generic hosts, where_detect_virtual_package()usesmin_base_segments = len(path_segments). This caused APM to clone an invalid URL with the subdirectory baked into the repo path:Reproduced end-to-end against a self-hosted GitLab instance.
Fix
Pass the structured
DependencyReferenceobject through the pipeline instead of flattening to string (Option A from the issue):download_package()andresolve_git_reference()now acceptUnion[str, DependencyReference], skipping the parse when already structuredbuild_download_ref()returns aDependencyReference(viadataclasses.replace()) instead of a flat stringinstall.pyand_utils.pyupdated to pass the object directlyChanges
src/apm_cli/deps/github_downloader.pydownload_package()andresolve_git_reference()acceptUnion[str, DependencyReference]src/apm_cli/drift.pybuild_download_ref()returnsDependencyReferenceviadataclasses.replace()src/apm_cli/commands/install.pysrc/apm_cli/commands/deps/_utils.pystr()wrapping in update commandstests/test_apm_package_models.pytests/unit/test_install_update.pybuild_download_reftests to assert on object propertiesTesting
TestGenericHostSubdirectoryRoundTripclass with parametrized tests covering GitLab, Gitea, Bitbucket, and the reporter's exact scenariovirtual_pathfor the reporter's exact case (git.example.com/ai/grandpa-s-skillswithdist/brain-council)