feat: provide clear errors for missing required envs
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
f8a3cc4c47
commit
61952f986d
6 changed files with 146 additions and 27 deletions
|
|
@ -32,11 +32,91 @@ get_env_or_file = fn var_name, default ->
|
|||
end
|
||||
end
|
||||
|
||||
# Same as get_env_or_file but raises if the value is not set
|
||||
# Same as get_env_or_file but raises if the value is not set or empty (after trim).
|
||||
# Empty values lead to unclear runtime errors; failing at boot with a clear message is preferred.
|
||||
get_env_or_file! = fn var_name, error_message ->
|
||||
case get_env_or_file.(var_name, nil) do
|
||||
nil -> raise error_message
|
||||
value -> value
|
||||
nil ->
|
||||
raise error_message
|
||||
|
||||
value when is_binary(value) ->
|
||||
trimmed = String.trim(value)
|
||||
|
||||
if trimmed == "" do
|
||||
raise """
|
||||
#{error_message}
|
||||
(Variable #{var_name} or #{var_name}_FILE is set but the value is empty.)
|
||||
"""
|
||||
else
|
||||
trimmed
|
||||
end
|
||||
|
||||
value ->
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
# Returns default when env_value is nil, empty after trim, or not a valid positive integer.
|
||||
# Used for PORT, POOL_SIZE, SMTP_PORT to avoid ArgumentError on empty or invalid values.
|
||||
parse_positive_integer = fn env_value, default ->
|
||||
case env_value do
|
||||
nil ->
|
||||
default
|
||||
|
||||
v when is_binary(v) ->
|
||||
case String.trim(v) do
|
||||
"" ->
|
||||
default
|
||||
|
||||
trimmed ->
|
||||
case Integer.parse(trimmed) do
|
||||
{n, _} when n > 0 -> n
|
||||
_ -> default
|
||||
end
|
||||
end
|
||||
|
||||
_ ->
|
||||
default
|
||||
end
|
||||
end
|
||||
|
||||
# Returns default when the key is missing or the value is empty (after trim).
|
||||
# Use for optional string ENV vars (e.g. DATABASE_PORT) so empty string is treated as "unset".
|
||||
get_env_non_empty = fn key, default ->
|
||||
case System.get_env(key) do
|
||||
nil ->
|
||||
default
|
||||
|
||||
v when is_binary(v) ->
|
||||
trimmed = String.trim(v)
|
||||
if trimmed == "", do: default, else: trimmed
|
||||
|
||||
v ->
|
||||
v
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the trimmed value when set and non-empty; otherwise raises with error_message.
|
||||
# Use for required vars (DATABASE_HOST, etc.) so "set but empty" fails at boot with a clear message.
|
||||
get_env_required = fn key, error_message ->
|
||||
case System.get_env(key) do
|
||||
nil ->
|
||||
raise error_message
|
||||
|
||||
v when is_binary(v) ->
|
||||
trimmed = String.trim(v)
|
||||
|
||||
if trimmed == "" do
|
||||
raise """
|
||||
#{error_message}
|
||||
(Variable #{key} is set but empty.)
|
||||
"""
|
||||
else
|
||||
trimmed
|
||||
end
|
||||
|
||||
v ->
|
||||
v
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -49,12 +129,14 @@ build_database_url = fn ->
|
|||
nil ->
|
||||
# Build URL from separate components
|
||||
host =
|
||||
System.get_env("DATABASE_HOST") ||
|
||||
raise "DATABASE_HOST is required when DATABASE_URL is not set"
|
||||
get_env_required.("DATABASE_HOST", """
|
||||
DATABASE_HOST is required when DATABASE_URL is not set.
|
||||
""")
|
||||
|
||||
user =
|
||||
System.get_env("DATABASE_USER") ||
|
||||
raise "DATABASE_USER is required when DATABASE_URL is not set"
|
||||
get_env_required.("DATABASE_USER", """
|
||||
DATABASE_USER is required when DATABASE_URL is not set.
|
||||
""")
|
||||
|
||||
password =
|
||||
get_env_or_file!.("DATABASE_PASSWORD", """
|
||||
|
|
@ -62,10 +144,11 @@ build_database_url = fn ->
|
|||
""")
|
||||
|
||||
database =
|
||||
System.get_env("DATABASE_NAME") ||
|
||||
raise "DATABASE_NAME is required when DATABASE_URL is not set"
|
||||
get_env_required.("DATABASE_NAME", """
|
||||
DATABASE_NAME is required when DATABASE_URL is not set.
|
||||
""")
|
||||
|
||||
port = System.get_env("DATABASE_PORT", "5432")
|
||||
port = get_env_non_empty.("DATABASE_PORT", "5432")
|
||||
|
||||
# URL-encode the password to handle special characters
|
||||
encoded_password = URI.encode_www_form(password)
|
||||
|
|
@ -102,7 +185,7 @@ if config_env() == :prod do
|
|||
config :mv, Mv.Repo,
|
||||
# ssl: true,
|
||||
url: database_url,
|
||||
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
|
||||
pool_size: parse_positive_integer.(System.get_env("POOL_SIZE"), 10),
|
||||
socket_options: maybe_ipv6
|
||||
|
||||
# The secret key base is used to sign/encrypt cookies and other secrets.
|
||||
|
|
@ -120,11 +203,14 @@ if config_env() == :prod do
|
|||
# PHX_HOST or DOMAIN can be used to set the host for the application.
|
||||
# DOMAIN is commonly used in deployment environments (e.g., Portainer templates).
|
||||
host =
|
||||
System.get_env("PHX_HOST") ||
|
||||
System.get_env("DOMAIN") ||
|
||||
raise "Please define the PHX_HOST or DOMAIN environment variable."
|
||||
get_env_non_empty.("PHX_HOST", nil) ||
|
||||
get_env_non_empty.("DOMAIN", nil) ||
|
||||
raise """
|
||||
Please define the PHX_HOST or DOMAIN environment variable.
|
||||
(Variable may be set but empty.)
|
||||
"""
|
||||
|
||||
port = String.to_integer(System.get_env("PORT") || "4000")
|
||||
port = parse_positive_integer.(System.get_env("PORT"), 4000)
|
||||
|
||||
config :mv, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
|
||||
|
||||
|
|
@ -230,11 +316,7 @@ if config_env() == :prod do
|
|||
smtp_host_env = System.get_env("SMTP_HOST")
|
||||
|
||||
if smtp_host_env && String.trim(smtp_host_env) != "" do
|
||||
smtp_port_env =
|
||||
case System.get_env("SMTP_PORT") do
|
||||
nil -> 587
|
||||
v -> String.to_integer(String.trim(v))
|
||||
end
|
||||
smtp_port_env = parse_positive_integer.(System.get_env("SMTP_PORT"), 587)
|
||||
|
||||
smtp_password_env =
|
||||
case System.get_env("SMTP_PASSWORD") do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue