Skip to content

Commit 3a350a2

Browse files
committed
fix: update podman api and replace local runCliCommand with process.exec
Signed-off-by: lstocchi <[email protected]>
1 parent 60eae96 commit 3a350a2

10 files changed

+43
-237
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"publisher": "podman-desktop",
88
"license": "Apache-2.0",
99
"engines": {
10-
"podman-desktop": "^1.0.0"
10+
"podman-desktop": ">=1.10.0"
1111
},
1212
"main": "./dist/extension.js",
1313
"contributes": {
@@ -80,7 +80,7 @@
8080
},
8181
"devDependencies": {
8282
"7zip-min": "^1.4.4",
83-
"@podman-desktop/api": "^1.6.4",
83+
"@podman-desktop/api": "^1.10.0",
8484
"@typescript-eslint/eslint-plugin": "^6.19.1",
8585
"@typescript-eslint/parser": "^6.19.1",
8686
"@vitest/coverage-v8": "^1.2.1",

src/create-cluster.spec.ts

+10-11
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import { beforeEach, expect, test, vi } from 'vitest';
2020
import type { Mock } from 'vitest';
2121
import { createCluster } from './create-cluster';
22-
import { runCliCommand } from './util';
2322
import type { TelemetryLogger } from '@podman-desktop/api';
2423
import * as extensionApi from '@podman-desktop/api';
2524

@@ -29,12 +28,14 @@ vi.mock('@podman-desktop/api', async () => {
2928
kubernetes: {
3029
createResources: vi.fn(),
3130
},
31+
process: {
32+
exec: vi.fn(),
33+
},
3234
};
3335
});
3436

3537
vi.mock('./util', async () => {
3638
return {
37-
runCliCommand: vi.fn(),
3839
getMinikubePath: vi.fn(),
3940
};
4041
});
@@ -52,7 +53,7 @@ const telemetryLoggerMock = {
5253

5354
test('expect error is cli returns non zero exit code', async () => {
5455
try {
55-
(runCliCommand as Mock).mockReturnValue({ exitCode: -1, error: 'error' });
56+
(extensionApi.process.exec as Mock).mockReturnValue({ exitCode: -1, error: 'error' });
5657
await createCluster({}, undefined, '', telemetryLoggerMock, undefined);
5758
} catch (err) {
5859
expect(err).to.be.a('Error');
@@ -62,7 +63,7 @@ test('expect error is cli returns non zero exit code', async () => {
6263
});
6364

6465
test('expect cluster to be created', async () => {
65-
(runCliCommand as Mock).mockReturnValue({ exitCode: 0 });
66+
(extensionApi.process.exec as Mock).mockReturnValue({ exitCode: 0 });
6667
await createCluster({}, undefined, '', telemetryLoggerMock, undefined);
6768
expect(telemetryLogUsageMock).toHaveBeenNthCalledWith(
6869
1,
@@ -75,7 +76,7 @@ test('expect cluster to be created', async () => {
7576

7677
test('expect error if Kubernetes reports error', async () => {
7778
try {
78-
(runCliCommand as Mock).mockReturnValue({ exitCode: 0 });
79+
(extensionApi.process.exec as Mock).mockReturnValue({ exitCode: 0 });
7980
const logger = {
8081
log: vi.fn(),
8182
error: vi.fn(),
@@ -95,7 +96,7 @@ test('expect error if Kubernetes reports error', async () => {
9596
});
9697

9798
test('expect cluster to be created with custom base image', async () => {
98-
(runCliCommand as Mock).mockReturnValue({ exitCode: 0 });
99+
(extensionApi.process.exec as Mock).mockReturnValue({ exitCode: 0 });
99100
await createCluster(
100101
{ 'minikube.cluster.creation.base-image': 'myCustomImage' },
101102
undefined,
@@ -110,7 +111,7 @@ test('expect cluster to be created with custom base image', async () => {
110111
);
111112
expect(telemetryLogErrorMock).not.toBeCalled();
112113
expect(extensionApi.kubernetes.createResources).not.toBeCalled();
113-
expect(runCliCommand).toBeCalledWith(
114+
expect(extensionApi.process.exec).toBeCalledWith(
114115
'',
115116
[
116117
'start',
@@ -124,12 +125,11 @@ test('expect cluster to be created with custom base image', async () => {
124125
'myCustomImage',
125126
],
126127
expect.anything(),
127-
undefined,
128128
);
129129
});
130130

131131
test('expect cluster to be created with custom mount', async () => {
132-
(runCliCommand as Mock).mockReturnValue({ exitCode: 0 });
132+
(extensionApi.process.exec as Mock).mockReturnValue({ exitCode: 0 });
133133
await createCluster(
134134
{ 'minikube.cluster.creation.mount-string': '/foo:/bar' },
135135
undefined,
@@ -144,7 +144,7 @@ test('expect cluster to be created with custom mount', async () => {
144144
);
145145
expect(telemetryLogErrorMock).not.toBeCalled();
146146
expect(extensionApi.kubernetes.createResources).not.toBeCalled();
147-
expect(runCliCommand).toBeCalledWith(
147+
expect(extensionApi.process.exec).toBeCalledWith(
148148
'',
149149
[
150150
'start',
@@ -159,6 +159,5 @@ test('expect cluster to be created with custom mount', async () => {
159159
'/foo:/bar',
160160
],
161161
expect.anything(),
162-
undefined,
163162
);
164163
});

src/create-cluster.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
*
1616
* SPDX-License-Identifier: Apache-2.0
1717
***********************************************************************/
18-
import { getMinikubePath, runCliCommand } from './util';
18+
import { getMinikubePath } from './util';
1919

2020
import type { Logger, TelemetryLogger, CancellationToken } from '@podman-desktop/api';
21+
import { process as processApi } from '@podman-desktop/api';
2122

2223
export async function createCluster(
2324
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -52,7 +53,7 @@ export async function createCluster(
5253

5354
// now execute the command to create the cluster
5455
try {
55-
await runCliCommand(minikubeCli, startArgs, { env, logger }, token);
56+
await processApi.exec(minikubeCli, startArgs, { env, logger, token });
5657
telemetryLogger.logUsage('createCluster', { driver, runtime });
5758
} catch (error) {
5859
const errorMessage = error instanceof Error ? error.message : error;

src/extension.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
***********************************************************************/
1818

1919
import * as extensionApi from '@podman-desktop/api';
20-
import { detectMinikube, getMinikubePath, runCliCommand } from './util';
20+
import { detectMinikube, getMinikubePath } from './util';
2121
import { MinikubeInstaller } from './minikube-installer';
2222
import type { CancellationToken, Logger } from '@podman-desktop/api';
2323
import { window } from '@podman-desktop/api';
@@ -123,7 +123,7 @@ async function updateClusters(provider: extensionApi.Provider, containers: exten
123123
delete: async (logger): Promise<void> => {
124124
const env = Object.assign({}, process.env);
125125
env.PATH = getMinikubePath();
126-
await runCliCommand(minikubeCli, ['delete', '--profile', cluster.name], { env, logger });
126+
await extensionApi.process.exec(minikubeCli, ['delete', '--profile', cluster.name], { env, logger });
127127
},
128128
};
129129
// create a new connection

src/image-handler.spec.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@ import type { Mock } from 'vitest';
2121
import { ImageHandler } from './image-handler';
2222
import * as extensionApi from '@podman-desktop/api';
2323
import * as fs from 'node:fs';
24-
import { getMinikubePath, runCliCommand } from './util';
24+
import { getMinikubePath } from './util';
2525

2626
let imageHandler: ImageHandler;
2727
vi.mock('@podman-desktop/api', async () => {
2828
return {
2929
containerEngine: {
3030
saveImage: vi.fn(),
3131
},
32+
process: {
33+
exec: vi.fn(),
34+
},
3235
window: {
3336
showNotification: vi.fn(),
3437
showInformationMessage: vi.fn(),
@@ -38,7 +41,6 @@ vi.mock('@podman-desktop/api', async () => {
3841

3942
vi.mock('./util', async () => {
4043
return {
41-
runCliCommand: vi.fn().mockReturnValue({ exitCode: 0 }),
4244
getMinikubePath: vi.fn(),
4345
};
4446
});
@@ -119,9 +121,9 @@ test('expect cli is called with right PATH', async () => {
119121
);
120122
expect(getMinikubePath).toBeCalled();
121123

122-
expect(runCliCommand).toBeCalledTimes(1);
123-
// grab the env parameter of the first call to runCliCommand
124-
const props = (runCliCommand as Mock).mock.calls[0][2];
124+
expect(extensionApi.process.exec).toBeCalledTimes(1);
125+
// grab the env parameter of the first call to process.Exec
126+
const props = (extensionApi.process.exec as Mock).mock.calls[0][2];
125127
expect(props).to.have.property('env');
126128
const env = props.env;
127129
expect(env).to.have.property('PATH');

src/image-handler.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import type { MinikubeCluster } from './extension';
1919
import * as extensionApi from '@podman-desktop/api';
2020
import { tmpName } from 'tmp-promise';
21-
import { getMinikubePath, runCliCommand } from './util';
21+
import { getMinikubePath } from './util';
2222
import * as fs from 'node:fs';
2323

2424
type ImageInfo = { engineId: string; name?: string; tag?: string };
@@ -71,7 +71,7 @@ export class ImageHandler {
7171
await extensionApi.containerEngine.saveImage(image.engineId, name, filename);
7272

7373
// Run the minikube image load command to push the image to the cluster
74-
await runCliCommand(minikubeCli, ['-p', selectedCluster.label, 'image', 'load', filename], {
74+
await extensionApi.process.exec(minikubeCli, ['-p', selectedCluster.label, 'image', 'load', filename], {
7575
env: env,
7676
});
7777

src/minikube-installer.spec.ts

-4
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,6 @@ const telemetryLoggerMock = {
6060
logError: telemetryLogErrorMock,
6161
} as unknown as extensionApi.TelemetryLogger;
6262

63-
vi.mock('runCliCommand', async () => {
64-
return vi.fn();
65-
});
66-
6763
beforeEach(() => {
6864
installer = new MinikubeInstaller('.', telemetryLoggerMock);
6965
vi.clearAllMocks();

src/util.spec.ts

+11-111
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@
2020

2121
import * as extensionApi from '@podman-desktop/api';
2222
import { afterEach, beforeEach, expect, test, vi } from 'vitest';
23-
import { detectMinikube, getMinikubePath, installBinaryToSystem, runCliCommand } from './util';
24-
import * as childProcess from 'node:child_process';
23+
import { detectMinikube, getMinikubePath, installBinaryToSystem } from './util';
2524
import type { MinikubeInstaller } from './minikube-installer';
2625
import * as fs from 'node:fs';
2726
import * as path from 'node:path';
@@ -86,126 +85,27 @@ test('getMinikubePath on macOS with existing PATH', async () => {
8685
expect(computedPath).toEqual(`${existingPATH}:/usr/local/bin:/opt/homebrew/bin:/opt/local/bin:/opt/podman/bin`);
8786
});
8887

89-
test.each([
90-
['macOS', true, false],
91-
['windows', false, true],
92-
])('detectMinikube on %s', async (operatingSystem, isMac, isWindows) => {
93-
vi.mocked(extensionApi.env).isMac = isMac;
94-
vi.mocked(extensionApi.env).isWindows = isWindows;
95-
96-
// spy on runCliCommand
97-
const spawnSpy = vi.spyOn(childProcess, 'spawn');
98-
99-
const onEventMock = vi.fn();
100-
101-
onEventMock.mockImplementation((event: string, callback: (data: string) => void) => {
102-
// delay execution
103-
if (event === 'close') {
104-
setTimeout(() => {
105-
callback(0 as unknown as string);
106-
}, 500);
107-
}
108-
});
109-
110-
spawnSpy.mockReturnValue({
111-
on: onEventMock,
112-
stdout: { setEncoding: vi.fn(), on: vi.fn() },
113-
stderr: { setEncoding: vi.fn(), on: vi.fn() },
114-
} as unknown as childProcess.ChildProcessWithoutNullStreams);
115-
88+
test('detectMinikube', async () => {
11689
const fakeMinikubeInstaller = {
11790
getAssetInfo: vi.fn(),
11891
} as unknown as MinikubeInstaller;
11992

93+
const execMock = vi.spyOn(extensionApi.process, 'exec').mockResolvedValue({
94+
command: '',
95+
stderr: '',
96+
stdout: '',
97+
});
98+
12099
const result = await detectMinikube('', fakeMinikubeInstaller);
121100
expect(result).toEqual('minikube');
122101

123102
// expect not called getAssetInfo
124103
expect(fakeMinikubeInstaller.getAssetInfo).not.toBeCalled();
125104

126-
expect(spawnSpy).toBeCalled();
105+
expect(execMock).toBeCalled();
127106
// expect right parameters
128-
if (isMac) {
129-
expect(spawnSpy.mock.calls[0][0]).toEqual('minikube');
130-
} else if (isWindows) {
131-
expect(spawnSpy.mock.calls[0][0]).toEqual('"minikube"');
132-
}
133-
expect(spawnSpy.mock.calls[0][1]).toEqual(['version']);
134-
});
135-
136-
test('runCliCommand/killProcess on macOS', async () => {
137-
vi.mocked(extensionApi.env).isMac = true;
138-
vi.mocked(extensionApi.env).isWindows = false;
139-
140-
// spy on runCliCommand
141-
const spawnSpy = vi.spyOn(childProcess, 'spawn');
142-
143-
const killMock = vi.fn();
144-
145-
spawnSpy.mockReturnValue({
146-
kill: killMock,
147-
on: vi.fn(),
148-
stdout: { setEncoding: vi.fn(), on: vi.fn() },
149-
stderr: { setEncoding: vi.fn(), on: vi.fn() },
150-
} as unknown as childProcess.ChildProcessWithoutNullStreams);
151-
152-
const fakeToken = {
153-
onCancellationRequested: vi.fn(),
154-
} as unknown as extensionApi.CancellationToken;
155-
156-
vi.mocked(fakeToken.onCancellationRequested).mockImplementation((callback: any): extensionApi.Disposable => {
157-
// abort execution after 500ms
158-
setTimeout(() => {
159-
callback();
160-
}, 500);
161-
162-
return extensionApi.Disposable.from({ dispose: vi.fn() });
163-
});
164-
165-
await expect(runCliCommand('fooCommand', [], undefined, fakeToken)).rejects.toThrow('Execution cancelled');
166-
167-
expect(spawnSpy.mock.calls[0][0]).toEqual('fooCommand');
168-
169-
expect(killMock).toBeCalled();
170-
});
171-
172-
test('runCliCommand/killProcess on Windows', async () => {
173-
vi.mocked(extensionApi.env).isMac = false;
174-
vi.mocked(extensionApi.env).isWindows = true;
175-
176-
// spy on runCliCommand
177-
const spawnSpy = vi.spyOn(childProcess, 'spawn');
178-
179-
const killMock = vi.fn();
180-
181-
spawnSpy.mockReturnValue({
182-
kill: killMock,
183-
pid: 'pid123',
184-
on: vi.fn(),
185-
stdout: { setEncoding: vi.fn(), on: vi.fn() },
186-
stderr: { setEncoding: vi.fn(), on: vi.fn() },
187-
} as unknown as childProcess.ChildProcessWithoutNullStreams);
188-
189-
const fakeToken = {
190-
onCancellationRequested: vi.fn(),
191-
} as unknown as extensionApi.CancellationToken;
192-
193-
vi.mocked(fakeToken.onCancellationRequested).mockImplementation((callback: any): extensionApi.Disposable => {
194-
// abort execution after 500ms
195-
setTimeout(() => {
196-
callback();
197-
}, 500);
198-
199-
return extensionApi.Disposable.from({ dispose: vi.fn() });
200-
});
201-
202-
await expect(runCliCommand('fooCommand', [], undefined, fakeToken)).rejects.toThrow('Execution cancelled');
203-
204-
expect(spawnSpy.mock.calls[0][0]).toEqual('"fooCommand"');
205-
// on windows we don't use killProcess but run taskkill
206-
expect(killMock).not.toBeCalled();
207-
208-
expect(spawnSpy.mock.calls[1]).toEqual(['taskkill', ['/pid', 'pid123', '/f', '/t']]);
107+
expect(execMock.mock.calls[0][0]).toEqual('minikube');
108+
expect(execMock.mock.calls[0][1]).toEqual(['version']);
209109
});
210110

211111
test('error: expect installBinaryToSystem to fail with a non existing binary', async () => {

0 commit comments

Comments
 (0)