Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ defaults:
workdir: /app
interactive: false
remove: true
network: app-tier # optional; shared with `dependencies` so containers can resolve each other by name
env:
RAILS_ENV: development
PORT: "3000"
Expand All @@ -60,6 +61,15 @@ defaults:
up:
command: server # command `wip up` passes to the image when it creates the container
# (omit to use the image's default CMD)
dependencies:
redis:
image: redis:latest
development.mysql:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
env:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: development
commands:
rails:
type: exec
Expand Down Expand Up @@ -91,6 +101,16 @@ commands:
credential, or auth. Keep real secrets out of the config file and in your runtime environment
instead.

### Dependency containers

If your app needs sidecar services (a database, Redis, ...), declare them under `dependencies`
and set `defaults.network`. `wip up` creates the network first (if it doesn't exist), then brings
up each dependency by name before the main container — so `bin/rails c` (or anything else run
inside the main container) can reach `development.mysql`/`redis`/etc. by their dependency name,
the same way Compose's service names resolve. `wip down` tears the main container and all
dependencies down (the network itself is left in place). Each dependency entry accepts `image`
(required), `command`, `env`, `ports`, `volumes`, and `workdir` — the same shape as `defaults`.

## Commands

| Command | Description |
Expand All @@ -99,8 +119,8 @@ instead.
| `wip doctor` | Diagnose WSL2, interop, WSLC, config, architecture, and Git |
| `wip config` | Print the effective configuration (secrets masked) |
| `wip build -- --no-cache` | Build the image from the `build` definition |
| `wip up [-d]` | Start `defaults.container` (creating it with `up.command` if missing). `-d` runs it in the background |
| `wip down` | Stop and remove `defaults.container` |
| `wip up [-d]` | Start `defaults.container` and its `dependencies` (creating any that are missing, on `defaults.network` if set). `-d` runs the main container in the background |
| `wip down` | Stop and remove `defaults.container` and its `dependencies` |
| `wip exec [--no-interactive] COMMAND...` | Run a command in the existing container |
| `wip run [--no-interactive] COMMAND...` | Run a command in a new `--rm` container |
| `wip shell` | Open the configured shell, falling back to `bash` then `sh` |
Expand Down Expand Up @@ -165,10 +185,10 @@ checklist.

## Not in the initial release

Compose compatibility, a resident/daemon process, a GUI, PowerShell-specific tuning, direct
registry API/manifest parsing, self-update, and plugins are all unimplemented. Likely future
additions: a richer config schema, lifecycle hooks, multi-container support, platform selection,
and more detailed diagnostics.
Full Compose compatibility (multiple networks, `depends_on` ordering/health checks, profiles), a
resident/daemon process, a GUI, PowerShell-specific tuning, direct registry API/manifest parsing,
self-update, and plugins are all unimplemented. Likely future additions: a richer config schema,
lifecycle hooks, platform selection, and more detailed diagnostics.

## License

Expand Down
65 changes: 52 additions & 13 deletions lib/wip/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,22 @@ def build(*extra)
execute(builder.build(settings: load_config.command('build') || {}, extra: extra))
end

desc 'up', 'Start the configured container, creating it if necessary'
desc 'up', 'Start the configured container and its dependencies, creating them if necessary'
option :detach, type: :boolean, default: false, aliases: '-d'
def up
container = load_config.defaults['container']
interactive = builder.tty?(!options[:detach])
if container_exists?
warn "wip: starting existing container '#{container}'"
execute(builder.start(detach: options[:detach]), interactive: interactive)
else
warn "wip: container '#{container}' not found, creating it"
execute(builder.up(detach: options[:detach]), interactive: interactive)
end
ensure_network
load_config.dependencies.each_key { |name| ensure_dependency(name) }
ensure_container
end

desc 'down', 'Stop and remove the configured container'
desc 'down', 'Stop and remove the configured container and its dependencies'
def down
execute(builder.down, exit_on_failure: false)
execute(builder.remove, exit_on_failure: false)
load_config.dependencies.each_key do |name|
execute(builder.dependency_down(name), exit_on_failure: false)
execute(builder.dependency_remove(name), exit_on_failure: false)
end
end

desc 'exec COMMAND...', 'Execute a command in the running container'
Expand Down Expand Up @@ -126,12 +124,53 @@ def execute(command, interactive: false, exit_on_failure: true)
code
end

def container_exists?
def resource_exists?(find_command)
out = StringIO.new
code = CommandRunner.new(stdout: out, stderr: StringIO.new).run(builder.find)
code = CommandRunner.new(stdout: out, stderr: StringIO.new).run(find_command)
code.zero? && !JSON.parse(out.string).empty?
rescue JSON::ParserError
false
end

def ensure_network
network = load_config.network
return unless network
return if network_exists?(network)

warn "wip: creating network '#{network}'"
execute(builder.network_create, exit_on_failure: false)
end

def network_exists?(network)
out = StringIO.new
code = CommandRunner.new(stdout: out, stderr: StringIO.new).run(builder.network_list)
return false unless code.zero?

JSON.parse(out.string).any? { |entry| entry['Name'] == network }
rescue JSON::ParserError
false
end

def ensure_dependency(name)
if resource_exists?(builder.dependency_find(name))
warn "wip: starting existing dependency '#{name}'"
execute(builder.dependency_start(name))
Comment on lines +154 to +157

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline lib/wip/command_builder.rb --items all

rg -nP -C 4 \
  'def\s+(up|start|dependency_up|dependency_start|network_\w+)|network\s+(connect|inspect)|\binspect\b' \
  lib/wip/command_builder.rb lib/wip/cli.rb spec/wip/cli_spec.rb

Repository: slidict/wip

Length of output: 3899


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,190p' lib/wip/cli.rb
printf '\n--- spec snippet ---\n'
sed -n '1,140p' spec/wip/cli_spec.rb
printf '\n--- relevant builder methods ---\n'
sed -n '20,115p' lib/wip/command_builder.rb

Repository: slidict/wip

Length of output: 13733


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- all network-related occurrences ---'
rg -n -C 3 '"network"|network|Network|networks|container.*network|Containers' lib spec

printf '%s\n' '--- CLI test coverage around existing containers/networks ---'
rg -n -C 3 "existing|network|dependency|connect|start app|start redis|app-tier" spec/lib spec/wip lib/wip/cli.rb spec/wip/cli_spec.rb

Repository: slidict/wip

Length of output: 25675


🌐 Web query:

wslc net container inspect networks JSON

💡 Result:

In the WSL container feature (WSL Containers), the command to inspect a container's networking configuration is: wslc container inspect <container_id_or_name> The wslc CLI (available in Windows Subsystem for Linux public preview as of July 2026) outputs container information in JSON format [1]. When you run the inspect command, the output includes a NetworkSettings object within the container's inspection data [2]. The InspectContainer schema, which dictates the structure of this JSON output, is defined in the WSL codebase [2]. The NetworkSettings section contains details about the networks the container is connected to, specifically mapping network names to endpoint settings (represented as an InspectEndpointSettings object) [2]. Because wslc commands like container inspect are designed to output structured JSON directly to the console [1], you can pipe or redirect this output as needed for parsing or further processing. [1].

Citations:


🌐 Web query:

Microsoft WSL wslc container inspect NetworkSettings endpoints configuration

💡 Result:

In the Microsoft Windows Subsystem for Linux (WSL) container feature, the wslc CLI tool uses an inspection mechanism to retrieve detailed information about containers, which includes their network configurations [1][2]. ### Inspecting Network Settings To view the network configuration of a container, you use the wslc container inspect command (or the Inspect method in the WSL container API) [1][2]. The output is a JSON-formatted structure that maps to an internal schema [2]. The NetworkSettings configuration within this inspection data is defined by an InspectNetworkSettings object [3]. This object primarily contains a map of InspectEndpointSettings keyed by the network name [3]: - InspectNetworkSettings: Contains a collection (std::map) of network endpoints associated with the container [3]. - InspectEndpointSettings: Represents the configuration for a specific network endpoint, which may include settings such as IP addresses, network aliases, links, and driver-specific options [3][4][5]. ### Context and Usage - CLI Interaction: The wslc binary allows you to manage containers with a familiar interface, supporting commands like wslc container inspect <container_id> [6][7]. This command triggers the backend Inspect logic, which gathers the container state, configuration, and network settings, then outputs the result as JSON [1][2]. - API Layer: For developers using the WSL container API (available via NuGet), the Container object provides an Inspect method that returns an InspectContainer structure [8][7]. This structure includes the NetworkSettings field, allowing programmatic access to the container's network topology, including endpoints created via wslc container run or wslc network connect [1][4]. - Network Capabilities: Recent updates have extended the endpoint configuration to support Docker-style settings such as --network-alias, --ip, --link, --link-local-ip, and --driver-opt [4][5]. These endpoint configurations are persisted and surfaced through the inspection flow, enabling the retrieval of detailed network state [4][5]. For further details on the exact schema structure, you can refer to the wslc_schema.h file in the official Microsoft WSL repository [3].

Citations:


既存コンテナの共有ネットワーク接続を保証してください。

up は配置ネットワークを作成/存在確認するだけで、既存の依存コンテナ・メインコンテナがそのネットワークに接続済みであるとは限りません。

  • lib/wip/cli.rbensure_dependencyensure_container は、既存リソースに対して start だけを実行します。
  • 配置ネットワークが存在する既存コンテナの場合、start 前に wslc container inspectNetworkSettings にそのネットワークのエンターポイントがあるか確認し、未接続なら network connect するか再作成してください。
  • spec/wip/cli_spec.rb にも既存かつ未接続の依存コンテナ・メインコンテナのケースを追加し、接続または再作成が最初に実行されることを検証してください。
📍 Affects 2 files
  • lib/wip/cli.rb#L154-L157 (this comment)
  • lib/wip/cli.rb#L164-L169
  • spec/wip/cli_spec.rb#L63-L110
🤖 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 `@lib/wip/cli.rb` around lines 154 - 157,
既存コンテナを開始する前に配置ネットワークへの接続を保証するよう、lib/wip/cli.rb の ensure_dependency(154-157行)と
ensure_container(164-169行)を更新してください。wslc container inspect の NetworkSettings
を確認し、未接続なら network connect または再作成を start
より先に実行してください。spec/wip/cli_spec.rb(63-110行)には、未接続の既存依存コンテナとメインコンテナで接続処理または再作成が最初に呼ばれるケースを追加してください。

else
warn "wip: dependency '#{name}' not found, creating it"
execute(builder.dependency_up(name))
end
end

def ensure_container
container = load_config.defaults['container']
interactive = builder.tty?(!options[:detach])
if resource_exists?(builder.find)
warn "wip: starting existing container '#{container}'"
execute(builder.start(detach: options[:detach]), interactive: interactive)
else
warn "wip: container '#{container}' not found, creating it"
execute(builder.up(detach: options[:detach]), interactive: interactive)
end
end
end
end
46 changes: 46 additions & 0 deletions lib/wip/command_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def run(arguments, settings: {}, interactive: true)
def up(detach: false)
values = @config.defaults
command = [@wslc, 'run', '--name', required(values, 'container')]
command.push('--network', @config.network) if @config.network
command << '-d' if detach
command << '-it' if !detach && tty?(true)
command.concat(options(values)).push(required(values, 'image'))
Expand All @@ -55,6 +56,40 @@ def remove
[@wslc, 'remove', '-f', required(@config.defaults, 'container')]
end

def network_create
[@wslc, 'network', 'create', required_network]
end

def network_list
[@wslc, 'network', 'list', '--format', 'json']
end

def dependency_up(name, detach: true)
values = dependency_values(name)
command = [@wslc, 'run', '--name', name.to_s]
command.push('--network', @config.network) if @config.network
command << '-d' if detach
command.concat(options(values)).push(required(values, 'image'))
command.concat(Shellwords.split(values['command'].to_s)) unless values['command'].to_s.empty?
command
end

def dependency_start(name)
[@wslc, 'start', name.to_s]
end
Comment on lines +77 to +79

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 4 --glob '*.rb' \
  '\b(network\s+(connect|disconnect)|dependency_start|ensure_dependency|ensure_container|start\s*\()' \
  lib spec

Repository: slidict/wip

Length of output: 7251


🌐 Web query:

Does Microsoft WSLC start attach an existing container to a newly configured network? If not, what command connects an existing container to a network?

💡 Result:

The wslc start command is used to start an existing container, but it does not connect a container to a new network [1]. To connect an existing container to a network, you should use the wslc network connect command [2][3]. The wslc network connect command allows you to add an existing container to a specified network [2][3]. It supports various flags to configure the connection, including: - --network-alias: Defines a network alias for the container [3]. - --ip: Assigns a static IP address on the network [3]. - --link: Adds network links [3]. - --link-local-ip: Specifies link-local IP addresses [3]. - --driver-opt: Provides arbitrary driver options [3]. The WSL container feature, introduced in 2026, provides the wslc.exe CLI for managing containers, images, and networks [4][5]. While container networking configuration (such as the initial network) is often handled during the create or run phases [6][3], wslc network connect provides the mechanism for modifying the network membership of an existing, provisioned container [2][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- command_builder.rb relevant ---\n'
sed -n '1,140p' lib/wip/command_builder.rb

printf '\n--- cli.rb ensure dependency/container/network ---\n'
sed -n '1,240p' lib/wip/cli.rb

printf '\n--- tests around existing containers and network ordering ---\n'
sed -n '30,120p' spec/wip/cli_spec.rb

Repository: slidict/wip

Length of output: 240


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- command_builder.rb relevant ---'
sed -n '1,140p' lib/wip/command_builder.rb

echo
echo '--- cli.rb ensure dependency/container/network ---'
sed -n '1,240p' lib/wip/cli.rb

echo
echo '--- tests around existing containers and network ordering ---'
sed -n '30,120p' spec/wip/cli_spec.rb

Repository: slidict/wip

Length of output: 14269


既存コンテナを network に接続してください。

up では ensure_network を先に実行していますが、既存の main container と dependency container はそれぞれ start / dependency_start のみで起動されます。wslc start は既存コンテナの network 配置を変更しないため、defaults.network を後から追加した既存コンテナは shared network に入っていません。network の再適用で両方を接続するか、古い network 配置を持つ場合は再作成して --network を渡してください。

🤖 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 `@lib/wip/command_builder.rb` around lines 77 - 79, Update dependency_start and
the corresponding main-container start flow so existing containers are connected
to the configured defaults.network after ensure_network runs. Reapply the
network to both containers, or recreate containers with the network option when
their existing network configuration is stale, while preserving normal start
behavior.


def dependency_find(name)
[@wslc, 'list', '--all', '--filter', "name=#{name}", '--format', 'json']
end

def dependency_down(name)
[@wslc, 'stop', name.to_s]
end

def dependency_remove(name)
[@wslc, 'remove', '-f', name.to_s]
end

def build(settings:, extra: [])
values = @config.defaults.merge(settings)
context = values['context'] || '.'
Expand Down Expand Up @@ -95,5 +130,16 @@ def required(values, key)

value
end

def required_network
network = @config.network
raise ConfigError, 'Configured network must not be empty' if network.to_s.empty?

network
end

def dependency_values(name)
@config.dependency(name) || raise(ConfigError, "Unknown dependency: #{name}")
end
end
end
32 changes: 30 additions & 2 deletions lib/wip/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ def wslc_command = @raw.dig('wslc', 'command') || 'auto'
def commands = @raw['commands'] || {}
def defaults = DEFAULTS.merge(@raw['defaults'] || {})
def up_command = @raw.dig('up', 'command')
def dependencies = @raw['dependencies'] || {}
def network = defaults['network']

def command(name)
entry = commands[name.to_s]
Expand All @@ -26,9 +28,16 @@ def command(name)
defaults.merge('type' => 'exec').merge(entry)
end

def dependency(name)
entry = dependencies[name.to_s]
return unless entry

{ 'workdir' => nil, 'env' => {}, 'ports' => [], 'volumes' => [] }.merge(entry)
end

def to_h(redact: true)
value = { 'version' => 1, 'wslc' => { 'command' => wslc_command }, 'defaults' => defaults,
'up' => { 'command' => up_command },
'up' => { 'command' => up_command }, 'dependencies' => dependencies,
'commands' => commands.transform_values { |entry| defaults.merge('type' => 'exec').merge(entry) } }
redact ? redact_secrets(value) : value
end
Expand All @@ -37,12 +46,24 @@ def to_h(redact: true)

def validate!
raise ConfigError, "Unsupported configuration version: #{@raw['version']}" unless (@raw['version'] || 1) == 1
raise ConfigError, 'commands must be a mapping' unless commands.is_a?(Hash)
raise ConfigError, 'up must be a mapping' if @raw.key?('up') && !@raw['up'].is_a?(Hash)

validate_commands!
validate_dependencies!
Comment on lines +51 to +52

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

defaults.network を構成読み込み時に検証してください。

defaults.network: "" は現在通過します。Ruby では空文字列が真値なので、CLI はネットワーク作成を試み、後で required_networkConfigError を送出します。空白だけの値も拒否してください。無効な値は wip up ではなく構成読み込み時に報告してください。

修正案
 def validate!
   raise ConfigError, "Unsupported configuration version: #{`@raw`['version']}" unless (`@raw`['version'] || 1) == 1
   raise ConfigError, 'up must be a mapping' if `@raw.key`?('up') && !`@raw`['up'].is_a?(Hash)

   validate_commands!
   validate_dependencies!
+  validate_network!
 end
+
+def validate_network!
+  network = `@raw.dig`('defaults', 'network')
+  return if network.nil?
+
+  unless network.is_a?(String) && !network.strip.empty?
+    raise ConfigError, 'defaults.network must be a non-empty string'
+  end
+end

defaults.network: "" と空白文字列の構成例も追加してください。

🤖 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 `@lib/wip/config.rb` around lines 51 - 52, 構成読み込み時の検証フロー(validate_commands! と
validate_dependencies! の呼び出し箇所)に defaults.network の検証を追加し、空文字列および空白のみの値を無効として
ConfigError を即時に報告してください。これにより無効なネットワーク値が wip up
まで通過しないようにし、空文字列と空白文字列の構成例も追加してください。

end

def validate_commands!
raise ConfigError, 'commands must be a mapping' unless commands.is_a?(Hash)

commands.each { |name, entry| validate_command!(name, entry) }
end

def validate_dependencies!
raise ConfigError, 'dependencies must be a mapping' unless dependencies.is_a?(Hash)

dependencies.each { |name, entry| validate_dependency!(name, entry) }
Comment on lines +61 to +64

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

依存コンテナ名と defaults.container の重複を拒否してください。

依存名が main container 名と同じ場合、up は先に依存コンテナを作成します。その後、main container の検索が同じコンテナを検出します。結果として main container は作成されず、down は同じコンテナを複数回停止・削除しようとします。

修正案
 def validate_dependencies!
   raise ConfigError, 'dependencies must be a mapping' unless dependencies.is_a?(Hash)

-  dependencies.each { |name, entry| validate_dependency!(name, entry) }
+  dependencies.each do |name, entry|
+    if name == defaults['container'].to_s
+      raise ConfigError, "dependencies.#{name} must not match defaults.container"
+    end
+
+    validate_dependency!(name, entry)
+  end
 end

dependenciesdefaults.container と同じ名前を設定した場合の仕様も追加してください。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def validate_dependencies!
raise ConfigError, 'dependencies must be a mapping' unless dependencies.is_a?(Hash)
dependencies.each { |name, entry| validate_dependency!(name, entry) }
def validate_dependencies!
raise ConfigError, 'dependencies must be a mapping' unless dependencies.is_a?(Hash)
dependencies.each do |name, entry|
if name == defaults['container'].to_s
raise ConfigError, "dependencies.#{name} must not match defaults.container"
end
validate_dependency!(name, entry)
end
🤖 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 `@lib/wip/config.rb` around lines 61 - 64, Update validate_dependencies! to
reject any dependency name that matches defaults.container before validating
dependency entries, raising the existing configuration error with a clear
message. Add or update the configuration specification to document that
dependency names must not duplicate defaults.container.

end

def validate_command!(name, entry)
raise ConfigError, "commands.#{name} must be a mapping" unless entry.is_a?(Hash)

Expand All @@ -52,6 +73,13 @@ def validate_command!(name, entry)
entry['env']&.transform_values!(&:to_s)
end

def validate_dependency!(name, entry)
raise ConfigError, "dependencies.#{name} must be a mapping" unless entry.is_a?(Hash)
raise ConfigError, "dependencies.#{name} must set image" if entry['image'].to_s.empty?

entry['env']&.transform_values!(&:to_s)
end

def stringify(object)
case object
when Hash then object.to_h { |key, value| [key.to_s, stringify(value)] }
Expand Down
2 changes: 1 addition & 1 deletion lib/wip/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Wip
VERSION = '0.3.1'
VERSION = '0.4.0'
end
50 changes: 50 additions & 0 deletions spec/wip/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,54 @@

described_class.start(%w[up])
end

it 'creates the network and dependencies before bringing up the main container' do
File.write('wip.yml', <<~YAML)
version: 1
defaults:
container: app
image: example:dev
network: app-tier
dependencies:
redis:
image: redis:latest
YAML

fake_runner = Class.new do
class << self
attr_accessor :calls, :responses
end
self.calls = []
self.responses = {
%w[wslc.exe network list --format json] => '[]',
%w[wslc.exe list --all --filter name=redis --format json] => '[]',
%w[wslc.exe list --all --filter name=app --format json] => '[]'
}

def initialize(stdout: nil, **_kwargs)
@stdout = stdout
end

def run(command, interactive: false, **_kwargs)
self.class.calls << [command, interactive]
@stdout&.write(self.class.responses.fetch(command, ''))
0
end
end
stub_const('Wip::CommandRunner', fake_runner)
allow(Wip::CommandResolver).to receive(:new).and_return(instance_double(Wip::CommandResolver,
resolve: 'wslc.exe'))

described_class.start(%w[up -d])

expected_commands = [
%w[wslc.exe network list --format json],
%w[wslc.exe network create app-tier],
%w[wslc.exe list --all --filter name=redis --format json],
%w[wslc.exe run --name redis --network app-tier -d redis:latest],
%w[wslc.exe list --all --filter name=app --format json],
%w[wslc.exe run --name app --network app-tier -d -w /app example:dev]
]
expect(fake_runner.calls.map(&:first)).to eq(expected_commands)
end
end
Loading
Loading