basecamp / kamal

Deploy web apps anywhere.
https://kamal-deploy.org
MIT License
11.65k stars 468 forks source link

Enable Environment Variable Expansion in Alias Commands for Dynamic Configuration #1167

Open muthuishere opened 1 month ago

muthuishere commented 1 month ago

Issue Summary

The current alias configuration in the codebase only supports basic shortcuts. It doesn't allow for environment variable expansion or parameter passing. This limitation prevents users from utilizing dynamic values through environment variables, impacting tasks like database exports that rely on such configurations.

Problem

Currently, the alias configuration does not expand environment variables. For instance, when trying to use an environment variable for a database export:

aliases:
  db-export: accessory exec --quiet  --interactive --reuse db "pg_dumpall -U $DB_USER"

The $DB_USER variable is not being expanded because the code does not handle environment variable substitution. This makes it impossible to use dynamic values set in the environment for the alias commands.

Use Case

Consider a scenario where the user wants to use an alias to run a database export using a user defined by the environment variable DB_USER. The current alias setup doesn't expand $DB_USER, leading to the command not functioning as intended.

Current Code

The existing code in Kamal::Cli::Alias::Command looks like this:

class Kamal::Cli::Alias::Command < Thor::DynamicCommand
  def run(instance, args = [])
    if (_alias = KAMAL.config.aliases[name])
      Kamal::Cli::Main.start(Shellwords.split(_alias.command) + ARGV[1..-1])
    else
      super
    end
  end
end

This implementation does not expand environment variables, leading to the inability to pass dynamic values via the environment.

Proposed Fix

To handle environment variable substitution, the code can be modified to expand any environment variables found in the alias command before executing it:

class Kamal::Cli::Alias::Command < Thor::DynamicCommand
  def run(instance, args = [])
    if (_alias = KAMAL.config.aliases[name])
      # Expand environment variables in the command
      expanded_command = _alias.command.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}/) do
        ENV[$1 || $2]
      end
      Kamal::Cli::Main.start(Shellwords.split(expanded_command) + ARGV[1..-1])
    else
      super
    end
  end
end

Explanation of the Fix

  1. Environment Variable Expansion:
    • The proposed change introduces a regular expression that searches for environment variables in two formats: $VAR_NAME and ${VAR_NAME}.
    • It uses ENV[$1 || $2] to retrieve the value from the environment, ensuring that any specified variables are substituted with their actual values.

Benefits of the Fix

Current work around

db.export: kamal accessory exec --quiet --interactive --reuse db "pg_dumpall -U $(DB_USER)" > $(DB_NAME).sql

djmb commented 3 days ago

Hey @muthuishere,

You should be able to do this with ERB:

aliases:
  db-export: accessory exec --quiet  --interactive --reuse db "pg_dumpall -U <=% ENV["DB_USER"] %>"

Let me know if that works.