mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-09-20 10:05:57 +08:00
New LivebookProto messages and minor improvements (#2503)
This commit is contained in:
parent
ca46b3eab6
commit
db41c99735
|
@ -396,12 +396,10 @@ defmodule Livebook.Hubs.TeamClient do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_event(:deployment_group_deleted, deployment_group_deleted, state) do
|
defp handle_event(:deployment_group_deleted, deployment_group_deleted, state) do
|
||||||
if deployment_group =
|
with {:ok, deployment_group} <- fetch_deployment_group(deployment_group_deleted.id, state) do
|
||||||
Enum.find(state.deployment_groups, &(&1.id == deployment_group_deleted.id)) do
|
|
||||||
Teams.Broadcasts.deployment_group_deleted(deployment_group)
|
Teams.Broadcasts.deployment_group_deleted(deployment_group)
|
||||||
|
|
||||||
remove_deployment_group(state, deployment_group)
|
remove_deployment_group(state, deployment_group)
|
||||||
else
|
|
||||||
state
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -423,26 +421,18 @@ defmodule Livebook.Hubs.TeamClient do
|
||||||
defp handle_event(:agent_key_created, agent_key_created, state) do
|
defp handle_event(:agent_key_created, agent_key_created, state) do
|
||||||
agent_key = build_agent_key(agent_key_created)
|
agent_key = build_agent_key(agent_key_created)
|
||||||
|
|
||||||
if deployment_group =
|
with {:ok, deployment_group} <- fetch_deployment_group(agent_key.deployment_group_id, state) do
|
||||||
find_deployment_group(agent_key.deployment_group_id, state.deployment_groups) do
|
deployment_group = put_agent_key(deployment_group, agent_key)
|
||||||
handle_event(:deployment_group_updated, put_agent_key(deployment_group, agent_key), state)
|
handle_event(:deployment_group_updated, deployment_group, state)
|
||||||
else
|
|
||||||
state
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_event(:agent_key_deleted, agent_key_deleted, state) do
|
defp handle_event(:agent_key_deleted, agent_key_deleted, state) do
|
||||||
agent_key = build_agent_key(agent_key_deleted)
|
agent_key = build_agent_key(agent_key_deleted)
|
||||||
|
|
||||||
if deployment_group =
|
with {:ok, deployment_group} <- fetch_deployment_group(agent_key.deployment_group_id, state) do
|
||||||
find_deployment_group(agent_key.deployment_group_id, state.deployment_groups) do
|
deployment_group = remove_agent_key(deployment_group, agent_key)
|
||||||
handle_event(
|
handle_event(:deployment_group_updated, deployment_group, state)
|
||||||
:deployment_group_updated,
|
|
||||||
remove_agent_key(deployment_group, agent_key),
|
|
||||||
state
|
|
||||||
)
|
|
||||||
else
|
|
||||||
state
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -528,6 +518,14 @@ defmodule Livebook.Hubs.TeamClient do
|
||||||
defp find_deployment_group(nil, _), do: nil
|
defp find_deployment_group(nil, _), do: nil
|
||||||
defp find_deployment_group(id, groups), do: Enum.find(groups, &(&1.id == id))
|
defp find_deployment_group(id, groups), do: Enum.find(groups, &(&1.id == id))
|
||||||
|
|
||||||
|
defp fetch_deployment_group(id, state) do
|
||||||
|
if deployment_group = find_deployment_group(id, state.deployment_groups) do
|
||||||
|
{:ok, deployment_group}
|
||||||
|
else
|
||||||
|
state
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# We cannot use to_existing_atom because the atoms
|
# We cannot use to_existing_atom because the atoms
|
||||||
# may not have been loaded. Luckily, we can trust
|
# may not have been loaded. Luckily, we can trust
|
||||||
# on Livebook Teams as a source.
|
# on Livebook Teams as a source.
|
||||||
|
|
|
@ -96,7 +96,7 @@ defmodule Livebook.Teams.Requests do
|
||||||
Send a request to Livebook Team API to delete a secret.
|
Send a request to Livebook Team API to delete a secret.
|
||||||
"""
|
"""
|
||||||
@spec delete_secret(Team.t(), Secret.t()) ::
|
@spec delete_secret(Team.t(), Secret.t()) ::
|
||||||
{:ok, String.t()} | {:error, map() | String.t()} | {:transport_error, String.t()}
|
{:ok, map()} | {:error, map() | String.t()} | {:transport_error, String.t()}
|
||||||
def delete_secret(team, %{deployment_group_id: nil} = secret) do
|
def delete_secret(team, %{deployment_group_id: nil} = secret) do
|
||||||
delete("/api/v1/org/secrets", %{name: secret.name}, team)
|
delete("/api/v1/org/secrets", %{name: secret.name}, team)
|
||||||
end
|
end
|
||||||
|
@ -156,7 +156,7 @@ defmodule Livebook.Teams.Requests do
|
||||||
Send a request to Livebook Team API to delete a file system.
|
Send a request to Livebook Team API to delete a file system.
|
||||||
"""
|
"""
|
||||||
@spec delete_file_system(Team.t(), FileSystem.t()) ::
|
@spec delete_file_system(Team.t(), FileSystem.t()) ::
|
||||||
{:ok, String.t()} | {:error, map() | String.t()} | {:transport_error, String.t()}
|
{:ok, map()} | {:error, map() | String.t()} | {:transport_error, String.t()}
|
||||||
def delete_file_system(team, file_system) do
|
def delete_file_system(team, file_system) do
|
||||||
delete("/api/v1/org/file-systems", %{id: file_system.external_id}, team)
|
delete("/api/v1/org/file-systems", %{id: file_system.external_id}, team)
|
||||||
end
|
end
|
||||||
|
@ -210,7 +210,7 @@ defmodule Livebook.Teams.Requests do
|
||||||
Send a request to Livebook Team API to delete an agent key.
|
Send a request to Livebook Team API to delete an agent key.
|
||||||
"""
|
"""
|
||||||
@spec delete_agent_key(Team.t(), AgentKey.t()) ::
|
@spec delete_agent_key(Team.t(), AgentKey.t()) ::
|
||||||
{:ok, String.t()} | {:error, map() | String.t()} | {:transport_error, String.t()}
|
{:ok, map()} | {:error, map() | String.t()} | {:transport_error, String.t()}
|
||||||
def delete_agent_key(team, agent_key) do
|
def delete_agent_key(team, agent_key) do
|
||||||
params = %{id: agent_key.id, deployment_group_id: agent_key.deployment_group_id}
|
params = %{id: agent_key.id, deployment_group_id: agent_key.deployment_group_id}
|
||||||
delete("/api/v1/org/deployment-groups/agent-keys", params, team)
|
delete("/api/v1/org/deployment-groups/agent-keys", params, team)
|
||||||
|
|
|
@ -37,6 +37,11 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupFormComponent do
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
<%= @subtitle %>
|
<%= @subtitle %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div :if={@error_message} class="error-box">
|
||||||
|
<%= @error_message %>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-columns gap-4">
|
<div class="flex flex-columns gap-4">
|
||||||
<.form
|
<.form
|
||||||
:let={f}
|
:let={f}
|
||||||
|
|
|
@ -3,7 +3,7 @@ defmodule LivebookProto do
|
||||||
AgentConnected,
|
AgentConnected,
|
||||||
AgentKeyCreated,
|
AgentKeyCreated,
|
||||||
AgentKeyDeleted,
|
AgentKeyDeleted,
|
||||||
Event,
|
AppDeploymentCreated,
|
||||||
FileSystemCreated,
|
FileSystemCreated,
|
||||||
FileSystemDeleted,
|
FileSystemDeleted,
|
||||||
FileSystemUpdated,
|
FileSystemUpdated,
|
||||||
|
@ -16,7 +16,7 @@ defmodule LivebookProto do
|
||||||
UserConnected
|
UserConnected
|
||||||
}
|
}
|
||||||
|
|
||||||
@event_mapping (for {_id, field_prop} <- Event.__message_props__().field_props,
|
@event_mapping (for {_id, field_prop} <- LivebookProto.Event.__message_props__().field_props,
|
||||||
into: %{} do
|
into: %{} do
|
||||||
{field_prop.type, field_prop.name_atom}
|
{field_prop.type, field_prop.name_atom}
|
||||||
end)
|
end)
|
||||||
|
@ -25,6 +25,7 @@ defmodule LivebookProto do
|
||||||
AgentConnected.t()
|
AgentConnected.t()
|
||||||
| AgentKeyCreated.t()
|
| AgentKeyCreated.t()
|
||||||
| AgentKeyDeleted.t()
|
| AgentKeyDeleted.t()
|
||||||
|
| AppDeploymentCreated.t()
|
||||||
| FileSystemCreated.t()
|
| FileSystemCreated.t()
|
||||||
| FileSystemDeleted.t()
|
| FileSystemDeleted.t()
|
||||||
| FileSystemUpdated.t()
|
| FileSystemUpdated.t()
|
||||||
|
@ -39,9 +40,9 @@ defmodule LivebookProto do
|
||||||
@doc """
|
@doc """
|
||||||
Builds an event with given data.
|
Builds an event with given data.
|
||||||
"""
|
"""
|
||||||
@spec build_event(event_proto()) :: Event.t()
|
@spec build_event(event_proto()) :: LivebookProto.Event.t()
|
||||||
def build_event(%struct{} = data) do
|
def build_event(%struct{} = data) do
|
||||||
%Event{type: {event_type(struct), data}}
|
%LivebookProto.Event{type: {event_type(struct), data}}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp event_type(module), do: Map.fetch!(@event_mapping, module)
|
defp event_type(module), do: Map.fetch!(@event_mapping, module)
|
||||||
|
|
13
proto/lib/livebook_proto/app_deployment_created.pb.ex
Normal file
13
proto/lib/livebook_proto/app_deployment_created.pb.ex
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
defmodule LivebookProto.AppDeploymentCreated do
|
||||||
|
use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0"
|
||||||
|
|
||||||
|
field :id, 1, type: :string
|
||||||
|
field :title, 2, type: :string
|
||||||
|
field :sha, 3, type: :string
|
||||||
|
field :archive_url, 4, type: :string, json_name: "archiveUrl"
|
||||||
|
field :app_id, 5, type: :string, json_name: "appId"
|
||||||
|
field :slug, 6, type: :string
|
||||||
|
field :deployment_group_id, 7, type: :string, json_name: "deploymentGroupId"
|
||||||
|
field :deployed_by, 8, type: :string, json_name: "deployedBy"
|
||||||
|
field :deployed_at, 9, type: :string, json_name: "deployedAt"
|
||||||
|
end
|
13
proto/lib/livebook_proto/deployed_app.pb.ex
Normal file
13
proto/lib/livebook_proto/deployed_app.pb.ex
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
defmodule LivebookProto.DeployedApp do
|
||||||
|
use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0"
|
||||||
|
|
||||||
|
field :id, 1, type: :string
|
||||||
|
field :title, 2, type: :string
|
||||||
|
field :sha, 3, type: :string
|
||||||
|
field :archive_url, 4, type: :string, json_name: "archiveUrl"
|
||||||
|
field :app_id, 5, type: :string, json_name: "appId"
|
||||||
|
field :slug, 6, type: :string
|
||||||
|
field :deployment_group_id, 7, type: :string, json_name: "deploymentGroupId"
|
||||||
|
field :deployed_by, 8, type: :string, json_name: "deployedBy"
|
||||||
|
field :deployed_at, 9, type: :string, json_name: "deployedAt"
|
||||||
|
end
|
|
@ -9,4 +9,9 @@ defmodule LivebookProto.DeploymentGroup do
|
||||||
field :zta_provider, 6, type: :string, json_name: "ztaProvider"
|
field :zta_provider, 6, type: :string, json_name: "ztaProvider"
|
||||||
field :zta_key, 7, type: :string, json_name: "ztaKey"
|
field :zta_key, 7, type: :string, json_name: "ztaKey"
|
||||||
field :agent_keys, 8, repeated: true, type: LivebookProto.AgentKey, json_name: "agentKeys"
|
field :agent_keys, 8, repeated: true, type: LivebookProto.AgentKey, json_name: "agentKeys"
|
||||||
|
|
||||||
|
field :deployed_apps, 9,
|
||||||
|
repeated: true,
|
||||||
|
type: LivebookProto.DeployedApp,
|
||||||
|
json_name: "deployedApps"
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,4 +9,9 @@ defmodule LivebookProto.DeploymentGroupCreated do
|
||||||
field :zta_provider, 6, type: :string, json_name: "ztaProvider"
|
field :zta_provider, 6, type: :string, json_name: "ztaProvider"
|
||||||
field :zta_key, 7, type: :string, json_name: "ztaKey"
|
field :zta_key, 7, type: :string, json_name: "ztaKey"
|
||||||
field :agent_keys, 8, repeated: true, type: LivebookProto.AgentKey, json_name: "agentKeys"
|
field :agent_keys, 8, repeated: true, type: LivebookProto.AgentKey, json_name: "agentKeys"
|
||||||
|
|
||||||
|
field :deployed_apps, 9,
|
||||||
|
repeated: true,
|
||||||
|
type: LivebookProto.DeployedApp,
|
||||||
|
json_name: "deployedApps"
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,4 +9,9 @@ defmodule LivebookProto.DeploymentGroupUpdated do
|
||||||
field :zta_provider, 6, type: :string, json_name: "ztaProvider"
|
field :zta_provider, 6, type: :string, json_name: "ztaProvider"
|
||||||
field :zta_key, 7, type: :string, json_name: "ztaKey"
|
field :zta_key, 7, type: :string, json_name: "ztaKey"
|
||||||
field :agent_keys, 8, repeated: true, type: LivebookProto.AgentKey, json_name: "agentKeys"
|
field :agent_keys, 8, repeated: true, type: LivebookProto.AgentKey, json_name: "agentKeys"
|
||||||
|
|
||||||
|
field :deployed_apps, 9,
|
||||||
|
repeated: true,
|
||||||
|
type: LivebookProto.DeployedApp,
|
||||||
|
json_name: "deployedApps"
|
||||||
end
|
end
|
||||||
|
|
|
@ -67,4 +67,9 @@ defmodule LivebookProto.Event do
|
||||||
type: LivebookProto.AgentKeyDeleted,
|
type: LivebookProto.AgentKeyDeleted,
|
||||||
json_name: "agentKeyDeleted",
|
json_name: "agentKeyDeleted",
|
||||||
oneof: 0
|
oneof: 0
|
||||||
|
|
||||||
|
field :app_deployment_created, 14,
|
||||||
|
type: LivebookProto.AppDeploymentCreated,
|
||||||
|
json_name: "appDeploymentCreated",
|
||||||
|
oneof: 0
|
||||||
end
|
end
|
||||||
|
|
|
@ -63,6 +63,7 @@ message DeploymentGroup {
|
||||||
string zta_provider = 6;
|
string zta_provider = 6;
|
||||||
string zta_key = 7;
|
string zta_key = 7;
|
||||||
repeated AgentKey agent_keys = 8;
|
repeated AgentKey agent_keys = 8;
|
||||||
|
repeated DeployedApp deployed_apps = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeploymentGroupCreated {
|
message DeploymentGroupCreated {
|
||||||
|
@ -74,6 +75,7 @@ message DeploymentGroupCreated {
|
||||||
string zta_provider = 6;
|
string zta_provider = 6;
|
||||||
string zta_key = 7;
|
string zta_key = 7;
|
||||||
repeated AgentKey agent_keys = 8;
|
repeated AgentKey agent_keys = 8;
|
||||||
|
repeated DeployedApp deployed_apps = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeploymentGroupUpdated {
|
message DeploymentGroupUpdated {
|
||||||
|
@ -85,6 +87,7 @@ message DeploymentGroupUpdated {
|
||||||
string zta_provider = 6;
|
string zta_provider = 6;
|
||||||
string zta_key = 7;
|
string zta_key = 7;
|
||||||
repeated AgentKey agent_keys = 8;
|
repeated AgentKey agent_keys = 8;
|
||||||
|
repeated DeployedApp deployed_apps = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeploymentGroupDeleted {
|
message DeploymentGroupDeleted {
|
||||||
|
@ -126,6 +129,30 @@ message AgentConnected {
|
||||||
repeated DeploymentGroup deployment_groups = 7;
|
repeated DeploymentGroup deployment_groups = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message DeployedApp {
|
||||||
|
string id = 1;
|
||||||
|
string title = 2;
|
||||||
|
string sha = 3;
|
||||||
|
string archive_url = 4;
|
||||||
|
string app_id = 5;
|
||||||
|
string slug = 6;
|
||||||
|
string deployment_group_id = 7;
|
||||||
|
string deployed_by = 8;
|
||||||
|
string deployed_at = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AppDeploymentCreated {
|
||||||
|
string id = 1;
|
||||||
|
string title = 2;
|
||||||
|
string sha = 3;
|
||||||
|
string archive_url = 4;
|
||||||
|
string app_id = 5;
|
||||||
|
string slug = 6;
|
||||||
|
string deployment_group_id = 7;
|
||||||
|
string deployed_by = 8;
|
||||||
|
string deployed_at = 9;
|
||||||
|
}
|
||||||
|
|
||||||
message Event {
|
message Event {
|
||||||
oneof type {
|
oneof type {
|
||||||
SecretCreated secret_created = 1;
|
SecretCreated secret_created = 1;
|
||||||
|
@ -141,5 +168,6 @@ message Event {
|
||||||
AgentConnected agent_connected = 11;
|
AgentConnected agent_connected = 11;
|
||||||
AgentKeyCreated agent_key_created = 12;
|
AgentKeyCreated agent_key_created = 12;
|
||||||
AgentKeyDeleted agent_key_deleted = 13;
|
AgentKeyDeleted agent_key_deleted = 13;
|
||||||
|
AppDeploymentCreated app_deployment_created = 14;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,65 @@ defmodule LivebookWeb.Integration.Hub.DeploymentGroupLiveTest do
|
||||||
assert updated_deployment_group in Livebook.Teams.get_deployment_groups(hub)
|
assert updated_deployment_group in Livebook.Teams.get_deployment_groups(hub)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "returns error if something goes wrong", %{conn: conn, hub: hub, node: node} do
|
||||||
|
name = "TEAMS_ERROR_DEPLOYMENT_GROUP"
|
||||||
|
mode = :online
|
||||||
|
insert_deployment_group(name: name, mode: mode, hub_id: hub.id)
|
||||||
|
|
||||||
|
assert_receive {:deployment_group_created,
|
||||||
|
%DeploymentGroup{name: ^name, mode: ^mode} = deployment_group}
|
||||||
|
|
||||||
|
attrs = %{
|
||||||
|
deployment_group: %{
|
||||||
|
id: deployment_group.id,
|
||||||
|
name: deployment_group.name,
|
||||||
|
mode: deployment_group.mode,
|
||||||
|
hub_id: deployment_group.hub_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_name = "FOO"
|
||||||
|
|
||||||
|
{:ok, view, html} =
|
||||||
|
live(conn, ~p"/hub/#{hub.id}/deployment-groups/edit/#{deployment_group.id}")
|
||||||
|
|
||||||
|
assert html =~ "Edit deployment group"
|
||||||
|
|
||||||
|
assert html =~
|
||||||
|
"Manage the #{deployment_group.name} (#{deployment_group.mode}) deployment group"
|
||||||
|
|
||||||
|
view
|
||||||
|
|> element("#deployment-groups-form")
|
||||||
|
|> render_change(attrs)
|
||||||
|
|
||||||
|
refute view
|
||||||
|
|> element("#deployment-groups-form button[disabled]")
|
||||||
|
|> has_element?()
|
||||||
|
|
||||||
|
# Forces the server to delete the deployment group
|
||||||
|
teams_deployment_group =
|
||||||
|
erpc_call(node, :get_deployment_group!, [String.to_integer(deployment_group.id)])
|
||||||
|
|
||||||
|
{:ok, _} = erpc_call(node, :delete_deployment_group, [teams_deployment_group])
|
||||||
|
|
||||||
|
view
|
||||||
|
|> element("#deployment-groups-form")
|
||||||
|
|> render_submit(put_in(attrs.deployment_group.name, new_name))
|
||||||
|
|
||||||
|
updated_deployment_group = %{deployment_group | name: new_name}
|
||||||
|
|
||||||
|
refute_receive {:deployment_group_updated, ^updated_deployment_group}
|
||||||
|
|
||||||
|
assert render(view) =~
|
||||||
|
"Something went wrong, try again later or please file a bug if it persists"
|
||||||
|
|
||||||
|
refute updated_deployment_group in Livebook.Teams.get_deployment_groups(hub)
|
||||||
|
|
||||||
|
# In this case, we aren't expecting the delete message,
|
||||||
|
# so the old deployment group remains in the list
|
||||||
|
assert deployment_group in Livebook.Teams.get_deployment_groups(hub)
|
||||||
|
end
|
||||||
|
|
||||||
test "creates a secret", %{conn: conn, hub: hub} do
|
test "creates a secret", %{conn: conn, hub: hub} do
|
||||||
insert_deployment_group(
|
insert_deployment_group(
|
||||||
name: "TEAMS_EDIT_DEPLOYMENT_GROUP",
|
name: "TEAMS_EDIT_DEPLOYMENT_GROUP",
|
||||||
|
|
|
@ -206,14 +206,6 @@ defmodule Livebook.TeamsServer do
|
||||||
System.get_env("TEAMS_PORT", "4123")
|
System.get_env("TEAMS_PORT", "4123")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp debug do
|
|
||||||
System.get_env("TEAMS_DEBUG", "false")
|
|
||||||
end
|
|
||||||
|
|
||||||
defp proto do
|
|
||||||
System.get_env("TEAMS_LIVEBOOK_PROTO_PATH")
|
|
||||||
end
|
|
||||||
|
|
||||||
defp wait_on_start(state, port) do
|
defp wait_on_start(state, port) do
|
||||||
url = state.url || fetch_url(state)
|
url = state.url || fetch_url(state)
|
||||||
|
|
||||||
|
@ -253,13 +245,16 @@ defmodule Livebook.TeamsServer do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp env(app_port, state_env) do
|
defp env(app_port, state_env) do
|
||||||
env = %{
|
env =
|
||||||
"MIX_ENV" => "livebook",
|
Map.filter(
|
||||||
"PORT" => to_string(app_port),
|
%{
|
||||||
"DEBUG" => debug()
|
"MIX_ENV" => "livebook",
|
||||||
}
|
"PORT" => to_string(app_port),
|
||||||
|
"DEBUG" => System.get_env("TEAMS_DEBUG", "false"),
|
||||||
env = if proto(), do: Map.merge(env, %{"LIVEBOOK_PROTO_PATH" => proto()}), else: env
|
"LIVEBOOK_PROTO_PATH" => System.get_env("TEAMS_LIVEBOOK_PROTO_PATH")
|
||||||
|
},
|
||||||
|
fn {_key, value} -> value not in ["", nil] end
|
||||||
|
)
|
||||||
|
|
||||||
if state_env do
|
if state_env do
|
||||||
Map.merge(env, state_env)
|
Map.merge(env, state_env)
|
||||||
|
|
Loading…
Reference in a new issue