From 5a20e819d2bfaf04a6b3141b07c4ee09187260ce Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Thu, 17 Apr 2025 13:21:14 +0200 Subject: [PATCH] regctl: manifestGet Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- __tests__/regclient/regctl.test.ts | 20 ++++++++++++++++++++ src/regclient/regctl.ts | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/__tests__/regclient/regctl.test.ts b/__tests__/regclient/regctl.test.ts index 94ea0b0..cd647b8 100644 --- a/__tests__/regclient/regctl.test.ts +++ b/__tests__/regclient/regctl.test.ts @@ -20,6 +20,26 @@ import * as semver from 'semver'; import {Exec} from '../../src/exec'; import {Regctl} from '../../src/regclient/regctl'; +describe('manifestGet', () => { + // prettier-ignore + test.each([ + ['moby/moby-bin:latest'], + ['crazymax/undock:latest'], + ['crazymax/diun:4.17.0'], + ])('given %p', async image => { + const regctl = new Regctl(); + const manifest = await regctl.manifestGet({ + image: image, + }); + console.log(`${image}: ${JSON.stringify(manifest, null, 2)}`); + expect(manifest).not.toBeNull(); + expect(manifest?.config).toBeDefined(); + expect(manifest?.config.digest).not.toEqual(''); + expect(manifest?.layers).toBeDefined(); + expect(manifest?.layers.length).toBeGreaterThan(0); + }); +}); + describe('isAvailable', () => { it('checks regctl is available', async () => { const execSpy = jest.spyOn(Exec, 'getExecOutput'); diff --git a/src/regclient/regctl.ts b/src/regclient/regctl.ts index 0c80808..2e2dc9f 100644 --- a/src/regclient/regctl.ts +++ b/src/regclient/regctl.ts @@ -19,10 +19,17 @@ import * as semver from 'semver'; import {Exec} from '../exec'; +import {Manifest} from '../types/oci/manifest'; + export interface RegctlOpts { binPath?: string; } +export interface RegctlManifestGetOpts { + image: string; + platform?: string; +} + export class Regctl { private readonly binPath: string; private _version: string; @@ -34,6 +41,18 @@ export class Regctl { this._versionOnce = false; } + public async manifestGet(opts: RegctlManifestGetOpts): Promise { + return await Exec.getExecOutput(this.binPath, ['manifest', 'get', opts.image, `--platform=${opts.platform ?? 'local'}`, `--format={{json .}}`], { + ignoreReturnCode: true, + silent: true + }).then(res => { + if (res.stderr.length > 0 && res.exitCode != 0) { + throw new Error(res.stderr.trim()); + } + return JSON.parse(res.stdout.trim()); + }); + } + public async isAvailable(): Promise { const ok: boolean = await Exec.getExecOutput(this.binPath, [], { ignoreReturnCode: true,