Skip to content

Commit

Permalink
feat: image checker extension API (podman-desktop#4662)
Browse files Browse the repository at this point in the history
* feat: add image checker to api
Signed-off-by: Philippe Martin <[email protected]>

* feat: image checker api implementation
Signed-off-by: Philippe Martin <[email protected]>

* feat: image checker extension
Signed-off-by: Philippe Martin <[email protected]>

* feat: use image checker in UI
Signed-off-by: Philippe Martin <[email protected]>

* test: fix unit tests
Signed-off-by: Philippe Martin <[email protected]>

* refactor: move id initialization to internal
Signed-off-by: Philippe Martin <[email protected]>

* refactor: remove categories
Signed-off-by: Philippe Martin <[email protected]>

* refactor: move label to metadata
Signed-off-by: Philippe Martin <[email protected]>

* refactor: use ProviderResult
Signed-off-by: Philippe Martin <[email protected]>

* Apply suggestions from code review

Co-authored-by: Florent BENOIT <[email protected]>
Signed-off-by: Philippe Martin <[email protected]>

* refactor: use async + fix return type
Signed-off-by: Philippe Martin <[email protected]>

* refactor: remove extension sample implementation
Signed-off-by: Philippe Martin <[email protected]>

* refactor: revert UI changes
Signed-off-by: Philippe Martin <[email protected]>

* feat: implement cancellation
Signed-off-by: Philippe Martin <[email protected]>

* test: unit tests
Signed-off-by: Philippe Martin <[email protected]>

---------

Signed-off-by: Philippe Martin <[email protected]>
Co-authored-by: Florent BENOIT <[email protected]>
  • Loading branch information
feloy and benoitf authored Nov 17, 2023
1 parent 83630c2 commit bdcaff1
Show file tree
Hide file tree
Showing 10 changed files with 447 additions and 0 deletions.
55 changes: 55 additions & 0 deletions packages/extension-api/src/extension-api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,35 @@ declare module '@podman-desktop/api' {
readonly storagePath: string;
}

/**
* A provider result represents the values a provider, like the {@linkcode ImageCheckerProvider},
* may return. For once this is the actual result type `T`, like `ImageChecks`, or a Promise that resolves
* to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a
* Promise.
*
* The snippets below are all valid implementations of the {@linkcode ImageCheckerProvider}:
*
* ```ts
* let a: ImageCheckerProvider = {
* check(image: ImageInfo, token?: CancellationToken): ProviderResult<ImageChecks> {
* return new ImageChecks();
* }
*
* let b: ImageCheckerProvider = {
* async check(image: ImageInfo, token?: CancellationToken): ProviderResult<ImageChecks> {
* return new ImageChecks();
* }
* }
*
* let c: ImageCheckerProvider = {
* check(image: ImageInfo, token?: CancellationToken): ProviderResult<ImageChecks> {
* return; // undefined
* }
* }
* ```
*/
export type ProviderResult<T> = T | undefined | Promise<T | undefined>;

export type ProviderStatus =
| 'not-installed'
| 'installed'
Expand Down Expand Up @@ -2488,4 +2517,30 @@ declare module '@podman-desktop/api' {
*/
export function createCliTool(options: CliToolOptions): CliTool;
}

export interface ImageCheck {
name: string;
status: 'success' | 'failed';
severity?: 'low' | 'medium' | 'high' | 'critical';
markdownDescription?: string;
}

export interface ImageChecks {
checks: ImageCheck[];
}

export interface ImageCheckerProvider {
check(image: ImageInfo, token?: CancellationToken): ProviderResult<ImageChecks>;
}

export interface ImageCheckerProviderMetadata {
readonly label: string;
}

export namespace imageChecker {
export function registerImageCheckerProvider(
imageCheckerProvider: ImageCheckerProvider,
metadata?: ImageCheckerProviderMetadata,
): Disposable;
}
}
9 changes: 9 additions & 0 deletions packages/main/src/plugin/api/image-checker-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type ImageCheckerExtensionInfo = {
id: string;
label: string;
};

export interface ImageCheckerInfo {
id: string;
label: string;
}
2 changes: 2 additions & 0 deletions packages/main/src/plugin/authentication.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import type { Exec } from './util/exec.js';
import type { KubeGeneratorRegistry } from '/@/plugin/kube-generator-registry.js';
import type { CliToolRegistry } from './cli-tool-registry.js';
import type { NotificationRegistry } from './notification-registry.js';
import type { ImageCheckerImpl } from './image-checker.js';

vi.mock('../util.js', async () => {
return {
Expand Down Expand Up @@ -276,6 +277,7 @@ suite('Authentication', () => {
vi.fn() as unknown as KubeGeneratorRegistry,
vi.fn() as unknown as CliToolRegistry,
vi.fn() as unknown as NotificationRegistry,
vi.fn() as unknown as ImageCheckerImpl,
);
providerMock = {
onDidChangeSessions: vi.fn(),
Expand Down
2 changes: 2 additions & 0 deletions packages/main/src/plugin/cli-tool-registry.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import type { Proxy } from './proxy.js';
import { afterEach } from 'node:test';
import type { CliToolOptions } from '@podman-desktop/api';
import type { NotificationRegistry } from './notification-registry.js';
import type { ImageCheckerImpl } from './image-checker.js';

const apiSender: ApiSenderType = {
send: vi.fn(),
Expand Down Expand Up @@ -92,6 +93,7 @@ suite('cli module', () => {
vi.fn() as unknown as KubeGeneratorRegistry,
cliToolRegistry,
vi.fn() as unknown as NotificationRegistry,
vi.fn() as unknown as ImageCheckerImpl,
);
});

Expand Down
4 changes: 4 additions & 0 deletions packages/main/src/plugin/extension-loader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { Exec } from './util/exec.js';
import type { KubeGeneratorRegistry } from '/@/plugin/kube-generator-registry.js';
import type { CliToolRegistry } from './cli-tool-registry.js';
import type { NotificationRegistry } from './notification-registry.js';
import type { ImageCheckerImpl } from './image-checker.js';

class TestExtensionLoader extends ExtensionLoader {
public async setupScanningDirectory(): Promise<void> {
Expand Down Expand Up @@ -150,6 +151,8 @@ const exec = new Exec(proxy);

const notificationRegistry: NotificationRegistry = {} as unknown as NotificationRegistry;

const imageCheckerImpl: ImageCheckerImpl = {} as unknown as ImageCheckerImpl;

/* eslint-disable @typescript-eslint/no-empty-function */
beforeAll(() => {
extensionLoader = new TestExtensionLoader(
Expand Down Expand Up @@ -180,6 +183,7 @@ beforeAll(() => {
kubernetesGeneratorRegistry,
cliToolRegistry,
notificationRegistry,
imageCheckerImpl,
);
});

Expand Down
14 changes: 14 additions & 0 deletions packages/main/src/plugin/extension-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import { ExtensionLoaderSettings } from './extension-loader-settings.js';
import type { KubeGeneratorRegistry, KubernetesGeneratorProvider } from '/@/plugin/kube-generator-registry.js';
import type { CliToolRegistry } from './cli-tool-registry.js';
import type { NotificationRegistry } from './notification-registry.js';
import type { ImageCheckerImpl } from './image-checker.js';

/**
* Handle the loading of an extension
Expand Down Expand Up @@ -158,6 +159,7 @@ export class ExtensionLoader {
private kubeGeneratorRegistry: KubeGeneratorRegistry,
private cliToolRegistry: CliToolRegistry,
private notificationRegistry: NotificationRegistry,
private imageCheckerProvider: ImageCheckerImpl,
) {
this.pluginsDirectory = directories.getPluginsDirectory();
this.pluginsScanDirectory = directories.getPluginsScanDirectory();
Expand Down Expand Up @@ -1036,6 +1038,17 @@ export class ExtensionLoader {
},
};

const imageCheckerProvider = this.imageCheckerProvider;
console.log('imageCheckerProvider', this.imageCheckerProvider);
const imageChecker: typeof containerDesktopAPI.imageChecker = {
registerImageCheckerProvider: (
provider: containerDesktopAPI.ImageCheckerProvider,
metadata?: containerDesktopAPI.ImageCheckerProviderMetadata,
): containerDesktopAPI.Disposable => {
return imageCheckerProvider.registerImageCheckerProvider(extensionInfo, provider, metadata);
},
};

return <typeof containerDesktopAPI>{
// Types
Disposable: Disposable,
Expand Down Expand Up @@ -1064,6 +1077,7 @@ export class ExtensionLoader {
authentication,
context: contextAPI,
cli,
imageChecker,
};
}

Expand Down
Loading

0 comments on commit bdcaff1

Please sign in to comment.