Skip to content

Commit ff9360b

Browse files
MPVclaude
andauthored
feat: add apm (Agent Package Manager) install support (#7038)
* feat: add apm (Agent Package Manager) install support Add an install service for APM (Agent Package Manager) which downloads the self-contained native binary bundle from the `microsoft/apm` GitHub releases, verifies the published `.sha256` checksum, extracts the PyInstaller `onedir` layout (the `apm` binary plus its sibling `_internal` directory), and wraps the binary onto PATH. This is a prerequisite for adding APM (`apm.yml`) support to Renovate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UbMAQBiMRNkCNxc8EGQw1C * test: install apm on arm64 and document download urls Address review feedback on the apm install support: - add the `apm` install check to `test/latest/Dockerfile.arm64` so the binary is exercised on aarch64 as well as x86_64 - document the `apm` download urls in `docs/custom-registries.md` Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UbMAQBiMRNkCNxc8EGQw1C --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6e02460 commit ff9360b

6 files changed

Lines changed: 90 additions & 1 deletion

File tree

docs/custom-registries.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,21 @@ https://github.com/chainguard-dev/apko/releases/download/v0.30.11/apko_0.30.11_l
4444
https://github.com/chainguard-dev/apko/releases/download/v0.30.11/checksums.txt
4545
```
4646

47+
## `apm`
48+
49+
APM (Agent Package Manager) releases are downloaded from:
50+
51+
- `https://github.com/microsoft/apm/releases`
52+
53+
Samples:
54+
55+
```txt
56+
https://github.com/microsoft/apm/releases/download/v0.24.0/apm-linux-x86_64.tar.gz
57+
https://github.com/microsoft/apm/releases/download/v0.24.0/apm-linux-x86_64.tar.gz.sha256
58+
https://github.com/microsoft/apm/releases/download/v0.24.0/apm-linux-arm64.tar.gz
59+
https://github.com/microsoft/apm/releases/download/v0.24.0/apm-linux-arm64.tar.gz.sha256
60+
```
61+
4762
## `bazelisk`
4863

4964
Bazelisk releases are downloaded from:

src/cli/install-tool/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
createContainer,
99
} from '../services/index.ts';
1010
import { ApkoInstallService } from '../tools/apko.ts';
11+
import { ApmInstallService } from '../tools/apm.ts';
1112
import { BazeliskInstallService } from '../tools/bazelisk.ts';
1213
import { BufInstallService } from '../tools/buf.ts';
1314
import { BunInstallService } from '../tools/bun.ts';
@@ -134,6 +135,7 @@ async function prepareInstallContainer(): Promise<Container> {
134135
// modern tool services
135136
container.bind(INSTALL_TOOL_TOKEN).to(AndroidSdkCmdlineToolsInstallService);
136137
container.bind(INSTALL_TOOL_TOKEN).to(ApkoInstallService);
138+
container.bind(INSTALL_TOOL_TOKEN).to(ApmInstallService);
137139
container.bind(INSTALL_TOOL_TOKEN).to(ComposerInstallService);
138140
container.bind(INSTALL_TOOL_TOKEN).to(BazeliskInstallService);
139141
container.bind(INSTALL_TOOL_TOKEN).to(BuildxInstallService);

src/cli/tools/apm.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import fs from 'node:fs/promises';
2+
import { injectFromHierarchy, injectable } from 'inversify';
3+
import { BaseInstallService } from '../install-tool/base-install.service.ts';
4+
5+
@injectable()
6+
@injectFromHierarchy()
7+
export class ApmInstallService extends BaseInstallService {
8+
readonly name = 'apm';
9+
10+
private get ghArch(): string {
11+
switch (this.envSvc.arch) {
12+
case 'arm64':
13+
return 'arm64';
14+
case 'amd64':
15+
return 'x86_64';
16+
}
17+
}
18+
19+
override async install(version: string): Promise<void> {
20+
/**
21+
* APM (Agent Package Manager) ships self-contained PyInstaller `onedir`
22+
* bundles (an `apm` binary next to an `_internal` directory) as
23+
* `apm-<os>-<arch>.tar.gz` release assets, each accompanied by a
24+
* `.sha256` sidecar.
25+
* @see {@link https://github.com/microsoft/apm/releases}
26+
*/
27+
const baseUrl = `https://github.com/microsoft/apm/releases/download/v${version}/`;
28+
const filename = `apm-linux-${this.ghArch}.tar.gz`;
29+
const url = `${baseUrl}${filename}`;
30+
31+
const checksumFile = await this.http.download({ url: `${url}.sha256` });
32+
const expectedChecksum = (await fs.readFile(checksumFile, 'utf-8'))
33+
.split('\n')
34+
.find((l) => l.includes(filename))
35+
?.split(/\s+/)[0];
36+
37+
const file = await this.http.download({
38+
url,
39+
checksumType: 'sha256',
40+
expectedChecksum,
41+
});
42+
43+
await this.pathSvc.ensureToolPath(this.name);
44+
45+
const path = await this.pathSvc.createVersionedToolPath(this.name, version);
46+
// strip the top-level `apm-linux-<arch>` directory so the `apm` binary and
47+
// its sibling `_internal` bundle end up directly in the versioned path.
48+
await this.compress.extract({ file, cwd: path, strip: 1 });
49+
}
50+
51+
override async link(version: string): Promise<void> {
52+
const src = this.pathSvc.versionedToolPath(this.name, version);
53+
await this.shellwrapper({ srcDir: src });
54+
}
55+
56+
override async test(_version: string): Promise<void> {
57+
await this._spawn(this.name, ['--version']);
58+
}
59+
}

src/cli/tools/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { InstallToolType } from '../utils';
33
export const NoPrepareTools = [
44
'android-sdk-cmdline-tools',
55
'apko',
6+
'apm',
67
'bazelisk',
78
'bower',
89
'buf',

test/latest/Dockerfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ RUN prepare-tool all
212212
RUN set -ex; [ -d /usr/local/erlang ] && echo "works" || exit 1;
213213

214214
#--------------------------------------
215-
# test: bazelisk, buf, bun, deno, devbox, helmfile, kustomize, skopeo, tofu, vendir
215+
# test: apm, bazelisk, buf, bun, deno, devbox, helmfile, kustomize, skopeo, tofu, vendir
216216
#--------------------------------------
217217
FROM base AS teste
218218

@@ -231,6 +231,9 @@ RUN install-tool deno 2.9.2
231231
# renovate: datasource=github-releases packageName=chainguard-dev/apko
232232
RUN install-tool apko 1.2.25
233233

234+
# renovate: datasource=github-releases packageName=microsoft/apm
235+
RUN install-tool apm 0.24.0
236+
234237
# renovate: datasource=github-releases packageName=jetify-com/devbox
235238
RUN install-tool devbox 0.17.5
236239

test/latest/Dockerfile.arm64

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ FROM base AS test-apko
6464
# renovate: datasource=github-releases packageName=chainguard-dev/apko
6565
RUN install-tool apko 1.2.25
6666

67+
#--------------------------------------
68+
# Image: apm
69+
#--------------------------------------
70+
FROM base AS test-apm
71+
72+
# renovate: datasource=github-releases packageName=microsoft/apm
73+
RUN install-tool apm 0.24.0
74+
6775
#--------------------------------------
6876
# Image: devbox
6977
#--------------------------------------
@@ -206,6 +214,7 @@ COPY --from=test-bazelisk /.dummy /.dummy
206214
COPY --from=test-bun /.dummy /.dummy
207215
COPY --from=test-deno /.dummy /.dummy
208216
COPY --from=test-apko /.dummy /.dummy
217+
COPY --from=test-apm /.dummy /.dummy
209218
COPY --from=test-devbox /.dummy /.dummy
210219
COPY --from=test-docker /.dummy /.dummy
211220
COPY --from=test-git /.dummy /.dummy

0 commit comments

Comments
 (0)