fix(compose): show error step when CLI version fetch fails during onboarding

When the GitHub API rate limit is hit (or any network error occurs),
checkDownloadedCommand now catches the failure, sets a
composeVersionCheckFailed context value, and the onboarding flow
displays a dedicated error step instead of proceeding with broken
placeholder text.

Fixes #13868

Signed-off-by: Simon Rey <simon.rey@outlook.com>
Co-authored-by: Claude <claude@anthropic.com>
Made-with: Cursor
Signed-off-by: Simon Rey <51708585+simonrey1@users.noreply.github.com>
Made-with: Cursor
This commit is contained in:
Simon Rey 2026-04-16 17:38:51 +02:00
parent 7259f66339
commit 08be405a60
3 changed files with 59 additions and 8 deletions

View file

@ -55,11 +55,24 @@
]
]
},
{
"id": "versionCheckFailedView",
"title": "Unable to retrieve Compose version",
"when": "onboardingContext:composeVersionCheckFailed",
"state": "failed",
"content": [
[
{
"value": "Podman Desktop was unable to retrieve the latest Compose version. This may be caused by a GitHub API rate limit or a network issue.\n\nPlease try again later or check your network connection."
}
]
]
},
{
"id": "welcomeDownloadView",
"label": "Compose Download",
"title": "Compose download",
"when": "!compose.isComposeInstalledSystemWide && !compose.isPodmanComposeInstalledSystemWide && onboardingContext:composeIsNotDownloaded",
"when": "!compose.isComposeInstalledSystemWide && !compose.isPodmanComposeInstalledSystemWide && onboardingContext:composeIsNotDownloaded && !onboardingContext:composeVersionCheckFailed",
"content": [
[
{
@ -84,7 +97,7 @@
"id": "downloadCommand",
"title": "Downloading Compose ${onboardingContext:composeDownloadVersion}",
"description": "Downloading the binary.\n\nOnce downloaded, the next step will install Compose system-wide.",
"when": "!compose.isComposeInstalledSystemWide && !compose.isPodmanComposeInstalledSystemWide && !compose.isPodmanComposeInstalledSystemWide && onboardingContext:composeIsNotDownloaded",
"when": "!compose.isComposeInstalledSystemWide && !compose.isPodmanComposeInstalledSystemWide && !compose.isPodmanComposeInstalledSystemWide && onboardingContext:composeIsNotDownloaded && !onboardingContext:composeVersionCheckFailed",
"command": "compose.onboarding.downloadCommand",
"completionEvents": [
"onCommand:compose.onboarding.downloadCommand"

View file

@ -477,6 +477,40 @@ describe('registerCLITool', () => {
});
});
test('checkDownloadedCommand sets composeVersionCheckFailed when version fetch fails', async () => {
vi.mocked(Detect.prototype.getStoragePath).mockResolvedValue('');
vi.mocked(Detect.prototype.checkSystemWideDockerCompose).mockResolvedValue(false);
vi.mocked(ComposeDownload.prototype.getLatestVersionAsset).mockRejectedValue(new Error('API rate limit exceeded'));
await activate(extensionContextMock);
const checkDownloadedHandler = vi.mocked(extensionApi.commands.registerCommand).mock.calls[1][1];
await checkDownloadedHandler();
expect(extensionApi.context.setValue).toHaveBeenCalledWith('composeVersionCheckFailed', true, 'onboarding');
expect(extensionApi.context.setValue).not.toHaveBeenCalledWith(
'composeDownloadVersion',
expect.anything(),
'onboarding',
);
});
test('checkDownloadedCommand sets composeDownloadVersion on success', async () => {
vi.mocked(Detect.prototype.getStoragePath).mockResolvedValue('');
vi.mocked(Detect.prototype.checkSystemWideDockerCompose).mockResolvedValue(false);
vi.mocked(ComposeDownload.prototype.getLatestVersionAsset).mockResolvedValue({
tag: 'v2.30.0',
} as unknown as ComposeGithubReleaseArtifactMetadata);
await activate(extensionContextMock);
const checkDownloadedHandler = vi.mocked(extensionApi.commands.registerCommand).mock.calls[1][1];
await checkDownloadedHandler();
expect(extensionApi.context.setValue).toHaveBeenCalledWith('composeDownloadVersion', 'v2.30.0', 'onboarding');
expect(extensionApi.context.setValue).toHaveBeenCalledWith('composeVersionCheckFailed', false, 'onboarding');
});
test('onboarding download command shows error message if version list cannot be obtained', async () => {
await activate(extensionContextMock);
const downloadCommandHandler = vi.mocked(extensionApi.commands.registerCommand).mock.calls[2][1];

View file

@ -115,12 +115,16 @@ export async function activate(extensionContext: extensionApi.ExtensionContext):
// we will run getLatestVersionAsset so we can show the user the latest
// latest version of compose that is available.
if (!isDownloaded) {
// Get the latest version and store the metadata in a local variable
const composeLatestVersion = await composeDownload.getLatestVersionAsset();
// Set the value in the context to the version we're downloading so it appears in the onboarding sequence
if (composeLatestVersion) {
composeVersionMetadata = composeLatestVersion;
extensionApi.context.setValue('composeDownloadVersion', composeVersionMetadata.tag, 'onboarding');
try {
const composeLatestVersion = await composeDownload.getLatestVersionAsset();
if (composeLatestVersion) {
composeVersionMetadata = composeLatestVersion;
extensionApi.context.setValue('composeDownloadVersion', composeVersionMetadata.tag, 'onboarding');
extensionApi.context.setValue('composeVersionCheckFailed', false, 'onboarding');
}
} catch (error: unknown) {
console.error('Failed to retrieve latest Compose version:', error);
extensionApi.context.setValue('composeVersionCheckFailed', true, 'onboarding');
}
}