Skip to content

refactor(compose): use ContainerRuntime for compose detection ordering#282

Merged
skevetter merged 3 commits into
mainfrom
skevetter/devsy-099-compose-abstraction
May 14, 2026
Merged

refactor(compose): use ContainerRuntime for compose detection ordering#282
skevetter merged 3 commits into
mainfrom
skevetter/devsy-099-compose-abstraction

Conversation

@skevetter

@skevetter skevetter commented May 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Refactored NewComposeHelper() to use dockerHelper.GetRuntime().Name() to determine compose detection order — Podman runtimes try podman compose first, Docker/nerdctl runtimes try docker compose V2 first
  • Removed hardcoded podmanCmd and composeArg package-level constants
  • Renamed tryPodmanCompose() to tryComposeSubcommand() — now accepts docker command as parameter for generalized compose subcommand detection
  • Non-Podman fallback preserves original behavior of independently probing for podman in PATH
  • Added 7 new unit tests covering runtime-aware detection ordering with a stubRuntime test double (22 total tests pass)

Closes DEVSY-099

Summary by CodeRabbit

  • Refactor

    • Improved compose helper detection to better support different container runtimes.
  • Tests

    • Enhanced test coverage for compose helper detection across various runtime configurations.

Review Change Stack

skevetter added 2 commits May 13, 2026 21:41
…on ordering

NewComposeHelper now queries dockerHelper.GetRuntime().Name() to determine
the compose detection order — Podman runtimes try podman compose first,
while Docker/nerdctl runtimes try docker compose V2 first.

Removes hardcoded podmanCmd and composeArg constants. tryPodmanCompose now
accepts the docker command as a parameter instead of using a hardcoded
"podman" string, using dockerHelper.DockerCommand consistently throughout.
The non-Podman detection path now passes "podman" (hardcoded) to the
fallback detector instead of re-using dockerCmd, preserving the original
behavior of independently probing for podman in PATH.

Renames tryPodmanCompose to tryComposeSubcommand to reflect that the
function generically probes `<cmd> compose` for any docker command.
@netlify

netlify Bot commented May 14, 2026

Copy link
Copy Markdown

Deploy Preview for devsydev canceled.

Name Link
🔨 Latest commit 28c204b
🔍 Latest deploy log https://app.netlify.com/projects/devsydev/deploys/6a053a2135d32e000809bcd1

@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The pull request refactors compose command detection in pkg/compose/helper.go to generalize the probing logic beyond Podman-specific approaches. A new generic tryComposeSubcommand(dockerCmd) helper validates binary availability and version, replacing prior specialized code. NewComposeHelper is rewritten to build runtime-aware detection function lists and iterate until finding a working Compose helper. Tests are expanded with runtime mocks and comprehensive cases covering selection logic across different runtimes and fallback scenarios.

Changes

Compose command detection refactor

Layer / File(s) Summary
Generic compose subcommand detection helper
pkg/compose/helper.go
A new generic tryComposeSubcommand(dockerCmd) helper validates the binary is on PATH, checks compose availability, captures compose version --short, logs stderr warnings, and returns a configured ComposeHelper or error. Private compose constants removed.
Runtime-aware NewComposeHelper
pkg/compose/helper.go
NewComposeHelper is rewritten to build an ordered list of detection functions based on container runtime (Podman tries podman compose first; others try Docker Compose V2 first), then iterates through detectors until one succeeds, assigning the provided DockerHelper on success.
Compose helper test suite
pkg/compose/helper_test.go
Test constants added for command names; stubRuntime mock implemented; comprehensive test cases validate runtime-to-command selection (Podman/Docker passthrough, default behavior, nerdctl fallback), fallback probing without re-trying, and tryComposeSubcommand behavior with existent/nonexistent binaries.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • devsy-org/devsy#274: Both PRs modify pkg/compose/helper.go's NewComposeHelper and compose-subcommand detection logic to handle Podman compose probing with accompanying test adjustments.
  • devsy-org/devsy#281: Main PR refactors pkg/compose/helper.go to use the newly introduced docker.ContainerRuntime interface via runtime-aware detection and a stubRuntime mock.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(compose): use ContainerRuntime for compose detection ordering' directly and clearly summarizes the main change: using ContainerRuntime to determine the order of compose detection methods.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Resolves goconst lint violations flagged by golangci-lint.
@skevetter
skevetter marked this pull request as ready for review May 14, 2026 10:01
@skevetter
skevetter enabled auto-merge (squash) May 14, 2026 10:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
pkg/compose/helper.go (2)

93-93: 💤 Low value

Error message could mention docker-compose V1.

The fallback logic includes tryDockerComposeV1, but the error message only mentions "docker compose or podman compose". Consider updating it to reflect all three options (e.g., "docker compose, podman compose, or docker-compose not installed").

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/compose/helper.go` at line 93, The error return in the function that
falls back through tryDockerCompose, tryPodmanCompose, and tryDockerComposeV1
currently says "docker compose or podman compose not installed"; update that
fmt.Errorf message to include docker-compose V1 as well (e.g., "docker compose,
podman compose, or docker-compose not installed") so the error accurately
reflects all three attempted options; locate the failing return in
pkg/compose/helper.go near the fallback logic that calls tryDockerCompose,
tryPodmanCompose, and tryDockerComposeV1 and replace the error string
accordingly.

72-84: ⚖️ Poor tradeoff

Redundant detection in Podman runtime branch.

When dockerHelper.GetRuntime().Name() returns RuntimePodman, the first two detectors both invoke compose subcommand checks on dockerCmd:

  1. tryComposeSubcommand(dockerCmd) — checks if dockerCmd binary exists, validates compose availability, and parses version
  2. tryDockerComposeV2(dockerCmd) — validates compose availability without checking binary existence or parsing version

If dockerCmd is "podman" (the typical case for Podman runtimes), both detectors probe podman compose. The second detector only succeeds if the first fails due to version parsing errors, which could mask parsing issues rather than surfacing them.

Consider revising the Podman branch to avoid redundant probing. For example, remove the second detector entirely, or replace it with a fallback to a different command (e.g., tryDockerComposeV2("docker")):

♻️ Proposed fix to eliminate redundancy

Option 1: Remove redundant detector

 if dockerHelper.GetRuntime().Name() == docker.RuntimePodman {
     detectors = []tryFunc{
         func() (*ComposeHelper, error) { return tryComposeSubcommand(dockerCmd) },
-        func() (*ComposeHelper, error) { return tryDockerComposeV2(dockerCmd) },
         tryDockerComposeV1,
     }

Option 2: Use explicit docker fallback

 if dockerHelper.GetRuntime().Name() == docker.RuntimePodman {
     detectors = []tryFunc{
         func() (*ComposeHelper, error) { return tryComposeSubcommand(dockerCmd) },
-        func() (*ComposeHelper, error) { return tryDockerComposeV2(dockerCmd) },
+        func() (*ComposeHelper, error) { return tryDockerComposeV2("docker") },
         tryDockerComposeV1,
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/compose/helper.go` around lines 72 - 84, When runtime is Podman
(dockerHelper.GetRuntime().Name() == RuntimePodman) the detectors slice
redundantly calls tryComposeSubcommand(dockerCmd) and then
tryDockerComposeV2(dockerCmd) which both probe the same podman compose; remove
the middle redundant detector so the Podman branch uses only
tryComposeSubcommand(dockerCmd) followed by tryDockerComposeV1, or if you prefer
an explicit Docker fallback replace the middle entry with func()
(*ComposeHelper, error) { return tryDockerComposeV2("docker") } — update the
detectors slice in the Podman branch accordingly (referencing dockerCmd,
tryComposeSubcommand, tryDockerComposeV2, tryDockerComposeV1 and RuntimePodman).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/compose/helper.go`:
- Line 93: The error return in the function that falls back through
tryDockerCompose, tryPodmanCompose, and tryDockerComposeV1 currently says
"docker compose or podman compose not installed"; update that fmt.Errorf message
to include docker-compose V1 as well (e.g., "docker compose, podman compose, or
docker-compose not installed") so the error accurately reflects all three
attempted options; locate the failing return in pkg/compose/helper.go near the
fallback logic that calls tryDockerCompose, tryPodmanCompose, and
tryDockerComposeV1 and replace the error string accordingly.
- Around line 72-84: When runtime is Podman (dockerHelper.GetRuntime().Name() ==
RuntimePodman) the detectors slice redundantly calls
tryComposeSubcommand(dockerCmd) and then tryDockerComposeV2(dockerCmd) which
both probe the same podman compose; remove the middle redundant detector so the
Podman branch uses only tryComposeSubcommand(dockerCmd) followed by
tryDockerComposeV1, or if you prefer an explicit Docker fallback replace the
middle entry with func() (*ComposeHelper, error) { return
tryDockerComposeV2("docker") } — update the detectors slice in the Podman branch
accordingly (referencing dockerCmd, tryComposeSubcommand, tryDockerComposeV2,
tryDockerComposeV1 and RuntimePodman).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 09e70735-4049-4f52-9862-f0465d992c8e

📥 Commits

Reviewing files that changed from the base of the PR and between d74b492 and 28c204b.

📒 Files selected for processing (2)
  • pkg/compose/helper.go
  • pkg/compose/helper_test.go

@skevetter
skevetter merged commit 1eaf03d into main May 14, 2026
100 of 104 checks passed
@skevetter
skevetter deleted the skevetter/devsy-099-compose-abstraction branch May 14, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant