Skip to content

Commit

Permalink
refactor: updated compose onboarding installation (#4479)
Browse files Browse the repository at this point in the history
### What does this PR do?

* Installation is now Download which is more correct and files updated
  (installation.ts now download.ts)
* Onboarding compose process is more flowing and streamlined, the
  system-wide install is now it's own step as it's required for
  onboarding
* Updated documentation on how to use compose within the onboarding
  process

### Screenshot/screencast of this PR

<!-- Please include a screenshot or a screencast
explaining what is doing this PR -->

### What issues does this PR fix or reference?

<!-- Include any related issues from Podman Desktop
repository (or from another issue tracker). -->

Closes #4475
Closes #4476

### How to test this PR?

Go through the onboarding process on a non-linux machine. If you are on
a linux machine, you should NOT see the setup button anymore.

<!-- Please explain steps to reproduce -->

Signed-off-by: Charlie Drage <charlie@charliedrage.com>
  • Loading branch information
cdrage committed Oct 25, 2023
1 parent c200d2b commit 6e4877d
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 87 deletions.
89 changes: 56 additions & 33 deletions extensions/compose/package.json
Expand Up @@ -21,32 +21,32 @@
"title": "Compose: Checks..."
},
{
"command": "compose.onboarding.checkComposeInstalled",
"title": "Compose: Check Compose installation"
"command": "compose.onboarding.checkComposeDownloaded",
"title": "Compose: Check Compose Downloaded"
},
{
"command": "compose.onboarding.installCompose",
"title": "Compose: Install Compose"
"command": "compose.onboarding.downloadCompose",
"title": "Compose: Download Compose"
}
],
"onboarding": {
"title": "Compose Setup",
"enablement": "!compose.isComposeInstalledSystemWide",
"steps": [
{
"id": "checkComposeInstalled",
"id": "checkComposeDownloaded",
"label": "Check Compose",
"title": "Checking for Compose installation",
"command": "compose.onboarding.checkComposeInstalled",
"command": "compose.onboarding.checkComposeDownloaded",
"completionEvents": [
"onCommand:compose.onboarding.checkComposeInstalled"
"onCommand:compose.onboarding.checkComposeDownloaded"
]
},
{
"id": "startComposeInstallation",
"label": "Compose Installation",
"title": "Compose Installation",
"when": "onboardingContext:composeIsNotInstalled == true",
"id": "startComposeDownload",
"label": "Compose Download",
"title": "Compose Download",
"when": "onboardingContext:composeIsNotDownloaded == true",
"content": [
[
{
Expand All @@ -55,55 +55,78 @@
],
[
{
"value": "#### How to use Compose\nRun `podman compose up` (podman CLI v4.7.0+) in a directory with a `compose.yaml` for Podman to deploy the containers. Podman Desktop will automatically detect the Compose deployment and show it in the container list. \n\n> ℹ️ Note: If you would like to use docker tools such as: `docker compose up` or `docker-compose` with podman. Enable **Docker Compatibility** within Preferences.",
"value": "> ℹ️ Note: Want to use docker CLI tools such as: `docker compose up` or `docker-compose` with podman? Enable **Docker Compatibility** within Preferences.",
"highlight": true
}
],
[
{
"value": "Compose will be installed in the next step (Version ${onboardingContext:composeInstallVersion}). :link[Want to install a different version?]{command=compose.onboarding.promptUserForVersion}",
"when": "!onboardingContext:composeShowCustomInstallDialog"
"value": "Compose will be downloaded in the next step (Version ${onboardingContext:composeDownloadVersion}). :link[Want to download a different version?]{command=compose.onboarding.promptUserForVersion}",
"when": "!onboardingContext:composeShowCustomDownloadDialog"
}
]
]
},
{
"id": "installComposeView",
"title": "Installing Compose ${onboardingContext:composeInstallVersion}",
"description": "Downloading and installing the binary.\n\nOnce installed, we will enable and configure the extension.",
"when": "onboardingContext:composeIsNotInstalled == true",
"command": "compose.onboarding.installCompose",
"id": "downloadComposeView",
"title": "Downloading Compose ${onboardingContext:composeDownloadVersion}",
"description": "Downloading the binary.\n\nOnce downloaded, the next step will install Compose system-wide.",
"when": "onboardingContext:composeIsNotDownloaded == true",
"command": "compose.onboarding.downloadCompose",
"completionEvents": [
"onCommand:compose.onboarding.installCompose"
"onCommand:compose.onboarding.downloadCompose"
]
},
{
"id": "composeFailedInstallation",
"title": "Failed installing Compose",
"when": "onboardingContext:composeIsNotInstalled == true",
"id": "composeFailedDownload",
"title": "Failed Downloading Compose",
"when": "onboardingContext:composeIsNotDownloaded == true",
"state": "failed"
},
{
"id": "composeInstalled",
"title": "Compose successfully installed",
"when": "onboardingContext:composeIsNotInstalled == false",
"id": "composeDownloaded",
"title": "Compose Successfully Downloaded",
"when": "onboardingContext:composeIsNotDownloaded == false",
"state": "succeeded",
"content": [
[
{
"value": "Compose has been successfully installed! However, in order for `podman compose` (podman CLI v4.7.0+) to work correctly, it is required for Compose to be installed system-wide for `podman` to access the binary.",
"when": "!compose.isComposeInstalledSystemWide"
"value": "Compose has been successfully downloaded! In order for `podman compose` (podman CLI v4.7.0+) to work correctly, it is required for Compose to be installed system-wide for `podman` to access the binary.\n\nThe next step will install Compose system-wide. **You will be prompted for system privileges when enabling this.**"
}
],
]
]
},
{
"id": "installComposeSystemWide",
"title": "Install Compose",
"description": "Installing the binary system-wide.\n\n You may be prompted for elevated system privileges.",
"when": "compose.isComposeInstalledSystemWide == false",
"command": "compose.onboarding.installSystemWide",
"completionEvents": [
"onCommand:compose.onboarding.installSystemWide"
]
},
{
"id": "composeFailedInstalledSystemWide",
"title": "Failed Installing Compose",
"when": "compose.isComposeInstalledSystemWide == false",
"state": "failed"
},
{
"id": "composeInstalledSystemWide",
"title": "Compose Successfully Installed",
"when": "compose.isComposeInstalledSystemWide == true",
"state": "succeeded",
"content": [
[
{
"value": "${configuration:compose.binary.installComposeSystemWide}",
"when": "!compose.isComposeInstalledSystemWide"
"value": "Compose has been successfully installed system-wide!"
}
],
[
{
"value": "> ℹ️ Note on `docker`: If you are using docker CLI tools with a podman back-end you must enable **Docker Compatibility** within **Preferences -> Extension: Podman** or set the [DOCKER_HOST](https://podman-desktop.io/docs/migrating-from-docker/using-the-docker_host-environment-variable) environment variable before running `docker compose up` or `docker-compose up`."
"value": "#### How to use Compose\nRun `podman compose up` (podman CLI v4.7.0+) or `docker-compose` in a directory with a `compose.yaml`. Podman Desktop will automatically detect the Compose deployment and show it in the container list.'\n\n`$ podman compose up`",
"highlight": true
}
]
]
Expand All @@ -118,7 +141,7 @@
"default": false,
"scope": ["DEFAULT", "Onboarding"],
"hidden": true,
"description": "Install system-wide instead of just your user directory, so compose can be accessed on the command line. Note: You will be prompted for system privileges when enabling this. "
"description": "Install system-wide instead of just your user directory, so compose can be accessed on the command line. Note: You may be prompted for elevated system privileges when enabling this."
}
}
}
Expand Down
Expand Up @@ -20,7 +20,7 @@ import { afterEach, expect, test, vi } from 'vitest';
import type { ComposeGitHubReleases, ComposeGithubReleaseArtifactMetadata } from './compose-github-releases';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { ComposeInstallation } from './installation';
import { ComposeDownload } from './download';
import * as extensionApi from '@podman-desktop/api';
import { OS } from './os';
import * as utils from './utils';
Expand Down Expand Up @@ -87,8 +87,8 @@ test('expect getLatestVersionAsset to return the first release from a list of re
});

// Expect the test to return the first release from the list (as the function simply returns the first one)
const composeInstallation = new ComposeInstallation(extensionContext, composeGitHubReleasesMock, os);
const result = await composeInstallation.getLatestVersionAsset();
const composeDownload = new ComposeDownload(extensionContext, composeGitHubReleasesMock, os);
const result = await composeDownload.getLatestVersionAsset();
expect(result).toBeDefined();
expect(result).toEqual(releases[0]);
});
Expand All @@ -103,13 +103,13 @@ test('pick the 4th option option in the quickpickmenu and expect it to return th
showQuickPickMock.mockResolvedValue({ id: 86626999, label: 'v2.14.2', tag: 'v2.14.2' } as any);

// Expect the test to return the first release from the list (as the function simply returns the first one)
const composeInstallation = new ComposeInstallation(extensionContext, composeGitHubReleasesMock, os);
const result = await composeInstallation.promptUserForVersion();
const composeDownload = new ComposeDownload(extensionContext, composeGitHubReleasesMock, os);
const result = await composeDownload.promptUserForVersion();
expect(result).toBeDefined();
expect(result).toEqual(releases[3]); // "4th" option was picked
});

test('test installation of compose passes and that mkdir and executable mocks are called', async () => {
test('test download of compose passes and that mkdir and executable mocks are called', async () => {
const makeExecutableMock = vi.spyOn(utils, 'makeExecutable');
const mkdirMock = vi.spyOn(fs.promises, 'mkdir');
const getReleaseAssetIdMock = vi.spyOn(composeGitHubReleasesMock, 'getReleaseAssetId');
Expand All @@ -128,9 +128,9 @@ test('test installation of compose passes and that mkdir and executable mocks ar
getReleaseAssetIdMock.mockResolvedValue(123456789);
downloadReleaseAssetMock.mockResolvedValue(undefined);

// Simply install the first release from the example json list
const composeInstallation = new ComposeInstallation(extensionContext, composeGitHubReleasesMock, os);
await composeInstallation.install(releases[0]);
// Simply download the first release from the example json list
const composeDownload = new ComposeDownload(extensionContext, composeGitHubReleasesMock, os);
await composeDownload.download(releases[0]);

// Expect the mkdir and executables to have been called
expect(mkdirMock).toHaveBeenCalled();
Expand Down
Expand Up @@ -24,7 +24,7 @@ import type { OS } from './os';
import { platform, arch } from 'node:os';
import { makeExecutable } from './utils';

export class ComposeInstallation {
export class ComposeDownload {
constructor(
private readonly extensionContext: extensionApi.ExtensionContext,
private readonly composeGitHubReleases: ComposeGitHubReleases,
Expand All @@ -38,14 +38,14 @@ export class ComposeInstallation {
return latestReleases[0];
}

// Create a "quickpick" prompt to ask the user which version of Compose they want to install
// Create a "quickpick" prompt to ask the user which version of Compose they want to download
async promptUserForVersion(): Promise<ComposeGithubReleaseArtifactMetadata> {
// Get the latest releases
const lastReleasesMetadata = await this.composeGitHubReleases.grabLatestsReleasesMetadata();

// Show the quickpick
const selectedRelease = await extensionApi.window.showQuickPick(lastReleasesMetadata, {
placeHolder: 'Select Compose version to install',
placeHolder: 'Select Compose version to download',
});

if (selectedRelease) {
Expand All @@ -55,12 +55,13 @@ export class ComposeInstallation {
}
}

// Install compose from the artifact metadata: ComposeGithubReleaseArtifactMetadata
async install(release: ComposeGithubReleaseArtifactMetadata): Promise<void> {
// Download compose from the artifact metadata: ComposeGithubReleaseArtifactMetadata
// this will download it to the storage bin folder as well as make it executeable
async download(release: ComposeGithubReleaseArtifactMetadata): Promise<void> {
// Get asset id
const assetId = await this.composeGitHubReleases.getReleaseAssetId(release.id, platform(), arch());

// Get the storage and check to see if it exists before we install Compose
// Get the storage and check to see if it exists before we download Compose
const storageData = this.extensionContext.storagePath;
const storageBinFolder = path.resolve(storageData, 'bin');
if (!existsSync(storageBinFolder)) {
Expand Down

0 comments on commit 6e4877d

Please sign in to comment.