Add aliases to Kamal

Aliases are defined in the configuration file under the `aliases` key.

The configuration is a map of alias name to command. When we run the
command the we just do a literal replacement of the alias with the
string.

So if we have:

```yaml
aliases:
  console: app exec -r console -i --reuse "rails console"
```

Then running `kamal console -r workers` will run the command

```sh
$ kamal app exec -r console -i --reuse "rails console" -r workers
```

Because of the order Thor parses the arguments, this allows us to
override the role from the alias command.

There might be cases where we need to munge the command a bit more but
that would involve getting into Thor command parsing internals,
which are complicated and possibly subject to change.

There's a chance that your aliases could conflict with future built-in
commands, but there's not likely to be many of those and if it happens
you'll get a validation error when you upgrade.

Thanks to @dhnaranjo for the idea!
This commit is contained in:
Donal McBreen
2024-06-18 16:11:01 +01:00
committed by Donal McBreen
parent f48987aa03
commit b8af719bb7
19 changed files with 204 additions and 46 deletions

View File

@@ -63,4 +63,12 @@ class CliTestCase < ActiveSupport::TestCase
assert_match expected, output
end
def with_argv(*argv)
old_argv = ARGV
ARGV.replace(*argv)
yield
ensure
ARGV.replace(old_argv)
end
end

View File

@@ -537,9 +537,40 @@ class CliMainTest < CliTestCase
assert_equal Kamal::VERSION, version
end
test "run an alias for details" do
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:traefik:details")
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:details")
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:details", [ "all" ])
run_command("info", config_file: "deploy_with_aliases")
end
test "run an alias for a console" do
run_command("console", config_file: "deploy_with_aliases").tap do |output|
assert_match "docker exec app-console-999 bin/console on 1.1.1.5", output
assert_match "App Host: 1.1.1.5", output
end
end
test "run an alias for a console overriding role" do
run_command("console", "-r", "workers", config_file: "deploy_with_aliases").tap do |output|
assert_match "docker exec app-workers-999 bin/console on 1.1.1.3", output
assert_match "App Host: 1.1.1.3", output
end
end
test "run an alias for a console passing command" do
run_command("exec", "bin/job", config_file: "deploy_with_aliases").tap do |output|
assert_match "docker exec app-console-999 bin/job on 1.1.1.5", output
assert_match "App Host: 1.1.1.5", output
end
end
private
def run_command(*command, config_file: "deploy_simple")
stdouted { Kamal::Cli::Main.start([ *command, "-c", "test/fixtures/#{config_file}.yml" ]) }
with_argv([ *command, "-c", "test/fixtures/#{config_file}.yml" ]) do
stdouted { Kamal::Cli::Main.start }
end
end
def with_test_dotenv(**files)

20
test/fixtures/deploy_with_aliases.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
service: app
image: dhh/app
servers:
web:
- 1.1.1.1
- 1.1.1.2
workers:
hosts:
- 1.1.1.3
- 1.1.1.4
console:
hosts:
- 1.1.1.5
registry:
username: user
password: pw
aliases:
info: details
console: app exec --reuse -p -r console "bin/console"
exec: app exec --reuse -p -r console

View File

@@ -1,8 +1,4 @@
#!/bin/sh
echo "About to lock..."
if [ "$KAMAL_HOSTS" != "vm1,vm2" ]; then
echo "Expected hosts to be 'vm1,vm2', got $KAMAL_HOSTS"
exit 1
fi
mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-connect

View File

@@ -1,8 +1,4 @@
#!/bin/sh
echo "About to lock..."
if [ "$KAMAL_HOSTS" != "vm1,vm2,vm3" ]; then
echo "Expected hosts to be 'vm1,vm2,vm3', got $KAMAL_HOSTS"
exit 1
fi
mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-connect

View File

@@ -37,3 +37,6 @@ accessories:
- web
stop_wait_time: 1
readiness_delay: 0
aliases:
whome: version
worker_hostname: app exec -r workers -q --reuse hostname

View File

@@ -82,6 +82,19 @@ class MainTest < IntegrationTest
assert_equal({ "cmd"=>"wget -qO- http://localhost > /dev/null || exit 1", "interval"=>"1s", "max_attempts"=>3, "port"=>3000, "path"=>"/up", "cord"=>"/tmp/kamal-cord", "log_lines"=>50 }, config[:healthcheck])
end
test "aliases" do
@app = "app_with_roles"
kamal :envify
kamal :deploy
output = kamal :whome, capture: true
assert_equal Kamal::VERSION, output
output = kamal :worker_hostname, capture: true
assert_match /App Host: vm3\nvm3-[0-9a-f]{12}$/, output
end
test "setup and remove" do
# Check remove completes when nothing has been setup yet
kamal :remove, "-y"