GeezerVison is showing github.com — feat(marketplace): load live local catalogs directly from apm.yml by Nadeesha-D-Shalom · Pull Request #3367 · microsoft/apm
Conversation
add(marketplace): load live local catalogs directly from apm.yml
TL;DR
Allow apm marketplace add ./apm.yml --name alice-dev to register an explicitly selected local authoring catalog without generating JSON first.
Later explicit operations reread that file, while each invocation uses one configuration snapshot.
Selected installs retain the actual package dependency and existing lockfile semantics.
Issue and approved scope
Fixes #2729.
Human approval: #2729 (comment)
Review contact: Daniel Meppiel (@danielmeppiel).
This implements the bounded local-authoring change.
Registry-backed authoring, durable catalog-following intent, and the separate enterprise API conformance scenario remain with their respective issues.
Important Registration creates a local discovery source. It does not publish packages, install inventory, activate plugins, or run package hooks.
Local paths and hashes remain local dependencies; they do not distribute files to other machines.
Problem (WHY)
Approach (WHAT)
- Recognize only an explicitly selected local
apm.yml; retain existing source classification for JSON, Git and hosted JSON.
- Reuse canonical authoring validation, ref resolution, catalog mapping and path containment.
- Cache the successful in-memory catalog only in the current Click invocation.
- Expose bounded
--offline behavior on marketplace add and marketplace browse.
Implementation (HOW)
| Area |
Change |
src/apm_cli/marketplace/authoring_source.py |
Coordinates existing owners, validates author-relative paths, retains the invocation snapshot, and translates failures into actionable marketplace errors. |
src/apm_cli/marketplace/client.py |
Routes explicitly selected local authoring files to that adapter; preserves the existing catalog cache/fetch paths for other sources. |
src/apm_cli/marketplace/builder.py |
Composes a discovery view using local metadata and existing mappers; keeps native output configuration intact and avoids credential initialization for local-only resolution. |
src/apm_cli/commands/marketplace/__init__.py |
Adds examples and bounded offline options; validates offline source eligibility before probing. Existing registration still occurs only after a successful fetch. |
.apm/architecture/owners/marketplace-plugins.json and scripts/architecture_linter/checks/marketplace_catalog_and_contract.py |
Register and enforce canonical routing and the no-writing boundary. |
tests/unit/marketplace/test_authoring_source.py |
Covers snapshots, containment, offline resolution, native-output stability, metadata and local-only credential avoidance. |
tests/integration/test_marketplace_authoring_lifecycle.py |
Exercises the installed CLI and packaged executable using owned local packages and Git origins. Included in the existing lifecycle_smoke selection. |
tests/integration/test_architecture_authoring_source.py |
Confirms the registered guard rejects an injected packing call. |
Marketplace CLI, producer and consumer documentation; packages/apm-guide/.apm/skills/apm-usage/commands.md |
Document live-source behavior, offline limits, side effects and portability boundaries. |
The dashed nodes identify the new local input and its in-memory discovery view; existing consumer and lockfile owners remain downstream.
flowchart LR
A[Explicit local apm.yml] --> B[Canonical authoring parser]
B --> C[Canonical ref resolver]
C --> D[In-memory discovery composer]
D --> E[Existing marketplace consumer]
E --> F[Browse or view]
E --> G[Install selected actual dependency]
G --> H[Existing manifest and lockfile]
I[JSON or Git or HTTPS catalog] --> E
classDef added stroke-dasharray:5 5
class A,D added
Loading
The diagram was rendered successfully with mmdc.
Trade-offs
- Discovery does not fetch cosmetic manifests for every remote package. Explicit curator fields and existing local metadata remain available; remote ref resolution is still explicit and can require network access.
--offline is limited to this local YAML path. Full commit SHAs and local entries work without network; tags and ranges are not persisted for later offline invocations.
- Native
pluginRoot layout hints are omitted from the temporary discovery view so authored paths remain relative to the selected file. Native generated catalogs retain their original representation, verified before and after discovery composition.
- Snapshots are invocation-local, with no watcher or persistent generated preview. A later explicit operation validates the current file again and reports edits or deletion.
Benefits
- Register and browse a valid local authoring file without running
apm pack.
- Install one selected package without installing an unselected package's inventory or executable hooks.
- Replay a remote dependency from its lock in a fresh configuration scope after removing the author's preview directory.
Validation
Python 3.12.15 and dependencies installed from the unchanged uv.lock with uv sync --frozen --extra dev --extra build.
Marketplace regression suite and new architecture guard:
1785 passed, 5 deselected in 90.29s (0:01:30)
The five deselections are symlink-related cases requiring privileges unavailable to this Windows account. They are not disabled in the committed suite.
PyInstaller 6.17.0 packaged executable, selected through APM_BINARY_PATH:
Full Ruff lint and formatting:
All checks passed!
2095 files already formatted
Full duplication check (pylint R0801):
Your code has been rated at 10.00/10
Architecture linter exited 0. Auth and assertion/duplicate ratchets:
[+] auth-signal lint clean
[+] assertion-quality ratchet clean: AQ001=4, AQ002=12
[+] exact test duplicate ratchet clean: 1418 files, 0 allowed duplicate group(s)
Documentation build and generated-page link checks:
20:55:52 [build] 126 page(s) built in 43.50s
[+] Checked 1113 relative link(s) across generated pages. No broken relative links found.
git diff --check passed. These are local Windows results; required GitHub checks and maintainer review still apply.
Scenario Evidence
| # |
Scenario (user promise) |
Principle(s) |
Test(s) proving it |
Type |
| 1 |
Register, browse and view the authoring file from another directory without changing author or consumer files. |
DevX (pragmatic as npm), Secure by default |
tests/integration/test_marketplace_authoring_lifecycle.py::test_live_local_catalog_register_browse_view_install_and_edit |
e2e |
| 2 |
See an edited catalog on the next operation and install only the selected nested local package. |
DevX (pragmatic as npm), Portability by manifest |
Same installed-CLI lifecycle scenario as row 1. |
e2e |
| 3 |
Reject missing, malformed or unusable YAML without replacing an existing registration; reject later broken live reads. |
Secure by default |
tests/integration/test_marketplace_authoring_lifecycle.py::test_failed_reregistration_preserves_registered_source |
e2e |
| 4 |
Install the actual remote Git package and replay without the preview directory or its registration. |
Vendor-neutral, Governed by policy |
tests/integration/test_marketplace_authoring_lifecycle.py::test_remote_entry_records_real_source_and_replays_without_preview |
e2e |
| 5 |
Continue registering existing JSON files and Git catalogs without authoring ref resolution. |
Vendor-neutral, DevX (pragmatic as npm) |
tests/integration/test_marketplace_authoring_lifecycle.py::test_existing_catalog_sources_still_register_without_authoring_resolution |
e2e |
| 6 |
Keep nested and bare authored package paths anchored to the authoring file (#2729 regression trap). |
Secure by default, Portability by manifest |
tests/unit/marketplace/test_authoring_source.py::test_plugin_root_never_rebases_authored_package_paths |
component |
| 7 |
Preserve native generated-output semantics after browsing a local authoring preview. |
Multi-harness support |
tests/unit/marketplace/test_authoring_source.py::test_discovery_composition_does_not_change_native_output |
component |
| 8 |
Avoid remote credential lookup for a local-only catalog and avoid network ref lookup for pinned offline commits. |
Secure by default, DevX (pragmatic as npm) |
tests/unit/marketplace/test_authoring_source.py::test_local_catalog_does_not_resolve_remote_credentials; ::test_pinned_remote_commit_needs_no_ref_or_metadata_network |
component |
| 9 |
Keep one configuration snapshot within an invocation, then reread next time. |
Governed by policy |
tests/unit/marketplace/test_authoring_source.py::test_invocation_snapshot_is_shared_but_next_invocation_rereads |
component |
How to test
- Install the locked development environment:
uv sync --frozen --extra dev --extra build.
- Run
uv run --frozen pytest tests/unit/marketplace tests/integration/test_architecture_authoring_source.py; expect the marketplace suite to pass on the CI platform.
- Run
uv run --frozen pytest tests/integration/test_marketplace_authoring_lifecycle.py; expect all eight scenarios to pass using the installed CLI. For packaged validation, build with build/apm.spec, set APM_BINARY_PATH to the resulting executable, and repeat.
- Register a valid local catalog with
apm marketplace add ./apm.yml --name alice-dev, edit it, and browse again. Expect current entries with no generated catalog writes; a malformed edit must fail without replacing registration.
- Run the repository Ruff, pylint duplication, auth/architecture and test-quality guards, then
cd docs && npm ci && npm run build; expect clean checks and valid relative links.
Type of change and testing
- New feature
- Documentation
- Tested locally, including the packaged executable
- Added behavioral and architecture regression tests
- Required GitHub checks and maintainer review completed
Spec conformance
- N/A: no normative requirement, public schema or lockfile format changes. This adds a local authoring input to existing registration and package-source contracts.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟢 Approval recommended
No blocking issues were identified, and focused regression coverage supports the canonical routing, containment, snapshot and compatibility behavior.
No open issues 🎉
What changed in this PR
Implements #2729 by allowing explicitly selected local apm.yml files to serve as live marketplace catalogs, reusing existing authoring and installation machinery without generating JSON.
Changes:
- Adds invocation-local catalog snapshots, canonical validation and path containment, with fresh reads on later operations.
- Adds bounded
--offline support for registration and browsing while preserving existing catalog and dependency workflows.
- Adds regression tests, architecture guards and documentation for local previews.
| File |
Description |
| tests/unit/marketplace/test_authoring_source.py |
Tests snapshots, containment, offline behavior and native-output preservation. |
| tests/integration/test_marketplace_authoring_lifecycle.py |
Covers discovery, selected installation, replay and existing-source compatibility. |
| tests/integration/test_architecture_authoring_source.py |
Tests rejection of packing calls in the read-only adapter. |
| src/apm_cli/marketplace/client.py |
Routes explicitly selected local YAML catalogs to the adapter. |
| src/apm_cli/marketplace/builder.py |
Composes discovery catalogs and avoids local-only credential initialization. |
| src/apm_cli/marketplace/authoring_source.py |
Coordinates validation, resolution, containment and invocation snapshots. |
| src/apm_cli/commands/marketplace/__init__.py |
Adds local YAML examples and bounded offline options. |
| scripts/architecture_linter/checks/marketplace_catalog_and_contract.py |
Enforces canonical routing and the adapter's no-writing boundary. |
| packages/apm-guide/.apm/skills/apm-usage/commands.md |
Documents live previews and offline limits. |
| docs/src/content/docs/reference/cli/marketplace.md |
Explains command behavior, snapshots and dependency portability. |
| docs/src/content/docs/producer/publish-to-a-marketplace.md |
Adds the producer's direct local-preview workflow. |
| docs/src/content/docs/consumer/installing-from-marketplaces.md |
Explains discovery and installation from local authoring catalogs. |
| .apm/architecture/owners/marketplace-plugins.json |
Registers ownership and the guard for live authoring catalogs. |
Review effort: Balanced
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sergio Sisternes (sergio-sisternes-epam)
added
area/marketplace
marketplace.json schema, federation, authoring suite, source parity.
theme/portability
One manifest, every target. Multi-target deploy, marketplace, packaging, install.
triage/recommended
Automated advice completed; not human scope approval.
type/feature
New capability, new flag, new primitive.
labels
Nov 3, 2026
|
@microsoft-github-policy-service agree
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This branch has not been deployed
No deployments
Reviewers
At least 0 approving reviews are required to merge this pull request.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
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.
|