Files
renovate/lib/modules/manager/apm/readme.md
Victor Sollerhed 6d747ea8ff feat(manager): add apm manager for Agent Package Manager (#44390)
* feat(manager): add apm manager for Agent Package Manager

Add a new `apm` manager that updates git-pinned dependencies in APM
(Agent Package Manager) `apm.yml` manifests, as requested in
renovatebot/renovate#42507.

The manager parses the string entries under `dependencies.apm` and
`devDependencies.apm` (`[host/]owner/repo[/subpath]#<ref>`) and selects
the datasource dynamically from the git host, reusing the existing
github-tags, gitlab-tags and git-tags datasources. MCP entries carry no
pinnable version and are ignored.

When an `apm.lock.yaml` lockfile is present, it is refreshed by running
`apm install` via a new `apm` tool constraint (pypi `apm-cli`).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vfjt3BpqDriiVsvwqVe9M9

* fix(manager/apm): resolve apm tool from github releases

APM ships self-contained binaries as GitHub release assets
(apm-linux-<arch>.tar.gz under vX.Y.Z tags), not as the PyPI apm-cli
wheel. Point the apm tool constraint at the github-releases datasource so
the version Renovate resolves matches the artifact that actually gets
installed, stripping the leading `v` from the tag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vfjt3BpqDriiVsvwqVe9M9

* docs(manager/apm): point to canonical microsoft/apm repository

The APM project's canonical home is github.com/microsoft/apm (originally
danielmeppiel/apm). Update the manager URL and readme accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vfjt3BpqDriiVsvwqVe9M9

* refactor(manager/apm): validate manifest with zod schema

Address review feedback on the apm manager:

- parse `apm.yml` with a dedicated zod schema via
  `parseSingleYaml(content, { customSchema })` instead of casting the
  parsed YAML to `ApmManifest`
- `LooseArray(z.string())` keeps only the string dependency entries, so
  MCP objects and other non-string values are dropped by the schema and
  the manual `Array.isArray`/`is.string` guards are no longer needed
- drop the `as SkipReason` casts now that the literals are inferred
- remove the now-unused `types.ts`

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UbMAQBiMRNkCNxc8EGQw1C

* Update schema.ts

Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>

* Update readme.md

Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>

* Update readme.md

Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>

* refactor(manager/apm): simplify manifest schema and host detection

Address review feedback:

- default the `apm` array to `[]` in the schema (`LooseArray(...).catch([])`)
  since LooseArray already discards non-string entries, so downstream code
  no longer needs to handle `undefined`
- use `coerceArray` when mapping the optional dependency sections
- drop the redundant `host === 'github.com'` / `host === 'gitlab.com'`
  checks in datasource selection; `detectPlatform` already resolves those
  hosts (the explicit host comparison is only kept to decide registryUrls
  for self-hosted instances)
- document that APM only supports remote git references and that dots in
  repo names / subpaths are handled, with a regression test

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UbMAQBiMRNkCNxc8EGQw1C

* docs(manager/apm): fix readme trailing newline

Remove the trailing blank line left after the readme edits so it passes
`prettier` and `markdown-lint`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UbMAQBiMRNkCNxc8EGQw1C

* refactor(manager/apm): parse dependency path with named capture groups

Replace the manual host/owner/repo splitting (and the standalone dot
regex) with a single named-capture regex, as suggested in review. `owner`
excludes dots so the optional hostname segment is unambiguous, while repo
names and subpaths may still contain dots.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UbMAQBiMRNkCNxc8EGQw1C

* test(manager/apm): align admin config with InternalGlobalConfigOptions

`localDir` moved out of `RepoGlobalConfig` into `InternalGlobalConfigOptions`
on main, so annotate the test admin config as
`RepoGlobalConfig & InternalGlobalConfigOptions`, matching the other
manager artifacts specs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UbMAQBiMRNkCNxc8EGQw1C

* fix(manager/apm): resolve GitLab nested groups and recognize SHA-pinned refs

- resolve nested GitLab project slugs (e.g. `group/subgroup/project`)
  instead of capping at `owner/repo`, splitting the project from any
  virtual-package subpath using APM's primitive-dir / virtual-file markers
- recognize the documented SHA-pinned form and skip it
  (`unversioned-reference`) rather than treating the SHA as a version or
  rewriting it

* feat(manager/apm): support digest pinning for SHA-pinned deps

Recover the release tag from the trailing YAML comment of a SHA-pinned
entry (`owner/repo#<sha> # v2.0.0`) - which the structured parse strips -
so it extracts as a digest (`currentDigest` + `currentValue`) and updates
both via `pinDigests`, mirroring the github-actions manager. A bare SHA
with no tag comment (or a quoted form we can't rewrite verbatim) is left
skipped.

* fix(manager/apm): map SHA-pin tag recovery per line to handle duplicates

The raw-manifest scan matched the first line for the entry regardless of
section, so the same `owner/repo#<sha>` pinned in both `dependencies` and
`devDependencies` resolved to the first line's tag/replaceString. Consume
each line at most once (in file order) so duplicate pins map to distinct
lines.

* fix(manager/apm): recognize `.chatmode.md` virtual files

APM's VIRTUAL_FILE_EXTENSIONS includes `.chatmode.md`; add it to the
subpath-boundary regex so a `*.chatmode.md` virtual dependency on a
nested-group host (GitLab, Azure DevOps) is not folded into the repo path.

* test(manager/apm): cover SHA-pin digest updates on git-tags hosts

Lock in that a SHA-pinned dep on a non-github/gitlab host resolves via the
git-tags datasource (which supports `getDigest` through `git ls-remote`),
so the commit is preserved on a bump rather than dropped.

* fix(manager/apm): commit regenerated harness files, not just the lockfile

`apm install` re-deploys the harness directories APM consumers commit
(`.github/`, `.claude/`, ...), but updateArtifacts only returned
`apm.lock.yaml`, leaving instruction files stale after a bump. Capture
every file the install changed via `getRepoStatus` (additions +
deletions); the gitignored `apm_modules/` cache is excluded, and the
manifest stays with `updatedPackageFiles`.

* fix(manager/apm): declare lockFileMaintenanceIsDelegatedToPackageManager

main now requires managers with `supportsLockFileMaintenance` to set this
field. apm regenerates the lockfile via `apm install`, so it delegates to
the package manager (`true`).

* refactor(manager/apm): reuse shared regex and git-sha helpers

Adopt the shared utilities per review:

- use the exported `newlineRegex` from `util/regex` instead of a local copy
- use `isLongCommitSha` from `util/schema-utils/git` instead of a bespoke
  SHA regex
- filter path segments with `isTruthy` instead of `Boolean`

* test(manager/apm): align docker exec snapshot with current base-image wrapper

The shared `util/exec` docker wrapper now injects `-e CI` and single-quotes
the `bash -l -c` payload. Update the docker-mode expectation to match, so the
snapshot tracks the current wrapper output.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
2026-09-02 16:17:15 +00:00

1.2 KiB

The apm manager keeps APM (Agent Package Manager) dependencies up to date.

Renovate reads the apm.yml manifest and updates the git-pinned entries under dependencies.apm and devDependencies.apm. Each entry uses the form [host/]owner/repo[/subpath]#<ref>, for example:

name: your-project
version: 1.0.0
dependencies:
  apm:
    - microsoft/apm-sample-package#v1.0.0
    - gitlab.com/team/project#v2.3.0
devDependencies:
  apm:
    - owner/repo#v1.2.3

Only entries that pin an exact #<ref> are updated. Entries without a #<ref> are skipped because there is no version to bump.

APM also documents pinning to a commit SHA with the release tag kept as a trailing comment (owner/repo#<sha> # v2.0.0). With pinDigests enabled (part of the config:best-practices preset) Renovate keeps both the SHA and the tag comment current, the same way it does for github-actions (uses: owner/action@<sha> # v4). A SHA pin without a tag comment is skipped, as there is no version to track.

When an apm.lock.yaml lockfile is present, Renovate refreshes it by running apm install after updating the manifest. This requires the apm CLI to be available (for example, with binarySource=global).