Skip to content

Commit 84119c2

Browse files
Fixes for preview environments (#2191)
1 parent 83992ef commit 84119c2

File tree

17 files changed

+223
-82
lines changed

17 files changed

+223
-82
lines changed

lib/console.ex

+19-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ defmodule Console do
44
@ttl :timer.minutes(30)
55

66
@type error :: {:error, term}
7+
@cache Application.compile_env(:console, :cache_adapter)
78

89
def version(), do: conf(:version)
910

@@ -16,14 +17,30 @@ defmodule Console do
1617
def coalesce(val, _), do: val
1718

1819
def debounce(scope, fun, opts \\ []) do
19-
case conf(:cache_adapter).get({:plrl_debounce, scope}) do
20+
case @cache.get({:plrl_debounce, scope}) do
2021
nil ->
21-
conf(:cache_adapter).put({:plrl_debounce, scope}, opts[:placeholder] || :ok, opts ++ [ttl: @ttl])
22+
@cache.put({:plrl_debounce, scope}, opts[:placeholder] || :ok, opts ++ [ttl: @ttl])
2223
fun.()
2324
res -> res
2425
end
2526
end
2627

28+
@doc """
29+
Executes a function only once, even if the function is called multiple times, within a given time frame.
30+
31+
If ignored, just returns ok
32+
"""
33+
@spec nonce(term, term, (() -> term), keyword()) :: term | :ok
34+
def nonce(scope, input, fun, opts \\ []) when is_function(fun, 0) do
35+
sha = :erlang.phash2(input)
36+
case @cache.get({:plrl_nonce, scope}) do
37+
^sha -> :ok
38+
_ ->
39+
@cache.put({:plrl_nonce, scope}, sha, opts ++ [ttl: @ttl])
40+
fun.()
41+
end
42+
end
43+
2744
def rate_limit(), do: {"global", :timer.seconds(1), Console.conf(:qps)}
2845

2946
def provider(), do: Console.conf(:provider)

lib/console/ai/chat.ex

+4-3
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,13 @@ defmodule Console.AI.Chat do
226226
|> ChatThread.changeset(Map.merge(Console.mapify(thread), %{summary: "Clone of #{thread.summary}"}))
227227
|> Repo.insert()
228228
end)
229-
|> add_operation(:chats, fn %{thread: thread} ->
230-
Chat.for_thread(thread_id)
229+
|> add_operation(:chats, fn %{thread: thread, clone: clone} ->
230+
Chat.for_thread(thread.id)
231231
|> Chat.before(seq)
232232
|> Repo.all()
233+
|> Enum.map(&Map.take(&1, ~w(content role confirm confirmed_at attributes server_id pull_request_id)a))
233234
|> Enum.map(&Console.mapify/1)
234-
|> save_messages(thread.id, user)
235+
|> save_messages(clone.id, user)
235236
end)
236237
|> execute(extract: :clone)
237238
end

lib/console/deployments/flows/preview.ex

+60-21
Original file line numberDiff line numberDiff line change
@@ -45,37 +45,49 @@ defmodule Console.Deployments.Flows.Preview do
4545
end
4646
end
4747

48-
def sync_service(%Service{} = svc) do
48+
def fresh?(updated_at), do: Timex.after?(updated_at || Timex.now(), Timex.shift(Timex.now(), minutes: -1))
49+
50+
def sync_service(%Service{deleted_at: nil} = svc) do
4951
case Repo.preload(svc, [:preview_instance, :preview_templates]) do
5052
%Service{preview_instance: %PreviewEnvironmentInstance{} = inst} ->
5153
post_comment(inst)
52-
%Service{preview_templates: [_ | _], id: id} ->
53-
PreviewEnvironmentInstance.for_service(id)
54-
|> PreviewEnvironmentInstance.preloaded()
55-
|> PreviewEnvironmentInstance.ordered(asc: :id)
56-
|> Repo.stream(method: :keyset)
57-
|> Console.throttle()
58-
|> Enum.each(&update_instance(&1, &1.pull_request))
54+
%Service{preview_templates: [_ | _], id: id, updated_at: updated_at} ->
55+
if fresh?(updated_at) do
56+
PreviewEnvironmentInstance.for_service(id)
57+
|> PreviewEnvironmentInstance.preloaded()
58+
|> PreviewEnvironmentInstance.ordered(asc: :id)
59+
|> Repo.stream(method: :keyset)
60+
|> Console.throttle()
61+
|> Enum.each(&update_instance(&1, &1.pull_request))
62+
end
5963
_ -> :ok
6064
end
6165
end
66+
def sync_service(_), do: :ok
6267

6368
defp post_comment(%PreviewEnvironmentInstance{} = inst) do
6469
%PreviewEnvironmentInstance{
65-
pull_request: %PullRequest{url: url} = pr,
70+
pull_request: %PullRequest{url: url, commit_sha: sha} = pr,
6671
service: svc,
6772
template: %PreviewEnvironmentTemplate{comment_template: msg} = tpl,
68-
} = inst = Repo.preload(inst, [:service, :template, :pull_request])
73+
} = inst = Repo.preload(inst, [:template, :pull_request, service: :cluster])
6974

7075
with %ScmConnection{} = conn <- scm_connection(tpl),
7176
message = EEx.eval_string(@preview_comment, assigns: [
7277
url: Console.url("/cd/clusters/#{svc.cluster_id}/services/#{svc.id}/components"),
7378
comment_template: msg,
7479
service: svc,
75-
status_color: color(svc.status)
80+
sha: sha,
81+
status_color: color(svc.status),
82+
status_emoji: emoji(svc.status),
83+
status_text: status(svc.status),
84+
logs_url: Console.url("/cd/clusters/#{svc.cluster_id}/services/#{svc.id}/logs"),
85+
flow_url: Console.url("/flows/#{tpl.flow_id}/services")
7686
]),
7787
{:ok, message} <- render_liquid(message, liquid_context(pr, tpl)) do
78-
Pr.Dispatcher.review(conn, %{pr | comment_id: Console.deep_get(inst, ~w(status comment_id)a)}, message)
88+
Console.nonce({:svc_review, svc.id}, message, fn ->
89+
Pr.Dispatcher.review(conn, %{pr | comment_id: Console.deep_get(inst, ~w(status comment_id)a)}, message)
90+
end, ttl: :timer.seconds(15))
7991
else
8092
_ -> {:error, "could not create review comment for pr: #{url}"}
8193
end
@@ -90,7 +102,7 @@ defmodule Console.Deployments.Flows.Preview do
90102
def delete_instance(_), do: :ok
91103

92104
defp create_instance(
93-
%PreviewEnvironmentTemplate{reference_service: ref} = template,
105+
%PreviewEnvironmentTemplate{reference_service: %Service{} = ref} = template,
94106
%PullRequest{} = pr
95107
) do
96108
with {:ok, attrs} <- build_attributes(pr, template),
@@ -123,7 +135,9 @@ defmodule Console.Deployments.Flows.Preview do
123135
with {:ok, ns} <- render_liquid(tpl.namespace || svc.namespace, ctx),
124136
{:ok, name} <- render_liquid(tpl.name || svc.name, ctx),
125137
{:ok, tpl} <- template_helm_vals(svc,tpl, ctx) do
126-
{:ok, ServiceTemplate.attributes(tpl, ns, name)}
138+
ServiceTemplate.attributes(tpl, ns, name)
139+
|> drop_nils_recursive()
140+
|> ok()
127141
end
128142
end
129143

@@ -148,33 +162,58 @@ defmodule Console.Deployments.Flows.Preview do
148162
defp scm_connection(_), do: Git.default_scm_connection()
149163

150164
defp template_helm_vals(%Service{} = svc, %ServiceTemplate{helm: %{values: v}} = tpl, ctx) do
151-
with {:ok, svc_values} <- Console.deep_get(svc, ~w(helm values)a, "{}") |> YamlElixir.read_from_string(),
152-
{:ok, new_str} <- render_liquid(v, ctx),
153-
{:ok, new_values} <- YamlElixir.read_from_string(new_str),
154-
{:ok, vals} <- DeepMerge.deep_merge(svc_values, new_values) |> Jason.encode(),
165+
with {:ok, svc_values} <- safe_yaml(Console.deep_get(svc, ~w(helm values)a)),
166+
{:ok, tpl_values} <- render_liquid(v, ctx),
167+
{:ok, new_values} <- safe_yaml(tpl_values),
168+
{:ok, vals} <- DeepMerge.deep_merge(svc_values, new_values) |> Jason.encode(),
155169
do: {:ok, put_in(tpl.helm.values, vals)}
156170
end
157171
defp template_helm_vals(_, %ServiceTemplate{} = tpl, _), do: {:ok, tpl}
158172

159-
defp render_liquid(template, ctx) do
173+
defp safe_yaml(val) when is_binary(val), do: YamlElixir.read_from_string(val)
174+
defp safe_yaml(nil), do: {:ok, %{}}
175+
176+
defp render_liquid(template, ctx) when is_binary(template) do
160177
with {:parse, {:ok, tpl}} <- {:parse, Solid.parse(template)},
161-
{:render, {:ok, res}} <- {:render, Solid.render(tpl, ctx, strict_variables: true)} do
178+
{:render, {:ok, res, _}} <- {:render, Solid.render(tpl, ctx, strict_variables: true)} do
162179
{:ok, IO.iodata_to_binary(res)}
163180
else
164-
{:parse, {:error, %Solid.TemplateError{message: message}}} -> {:error, message}
181+
{:parse, {:error, %Solid.TemplateError{} = err}} -> {:error, Solid.TemplateError.message(err)}
165182
{:render, {:error, errs, _}} -> {:error, Enum.map(errs, &inspect/1) |> Enum.join(", ")}
166183
end
167184
end
185+
defp render_liquid(template, _), do: {:ok, template}
168186

169187
defp color(:healthy), do: :green
170188
defp color(:failed), do: :red
171189
defp color(_), do: :yellow
172190

191+
defp emoji(:healthy), do: ":white_check_mark:"
192+
defp emoji(:failed), do: ":x:"
193+
defp emoji(_), do: ":wrench:"
194+
195+
defp status(:healthy), do: "ready!"
196+
defp status(:failed), do: "failed to deploy (check Plural to see details)"
197+
defp status(_), do: "building..."
198+
173199
defp bot(), do: %{Users.get_bot!("console") | roles: %{admin: true}}
174200

175201
defp notify({:ok, %PreviewEnvironmentInstance{} = inst}, :create),
176202
do: handle_notify(PubSub.PreviewEnvironmentInstanceCreated, inst)
177203
defp notify({:ok, %PreviewEnvironmentInstance{} = inst}, :update),
178204
do: handle_notify(PubSub.PreviewEnvironmentInstanceUpdated, inst)
179205
defp notify(pass, _), do: pass
206+
207+
defp drop_nils_recursive(%{__struct__: _} = struct) do
208+
Map.from_struct(struct)
209+
|> drop_nils_recursive()
210+
end
211+
212+
defp drop_nils_recursive(%{} = map) do
213+
Enum.filter(map, &elem(&1, 1) != nil)
214+
|> Map.new(fn {k, v} -> {k, drop_nils_recursive(v)} end)
215+
end
216+
217+
defp drop_nils_recursive(list) when is_list(list), do: Enum.map(list, &drop_nils_recursive/1)
218+
defp drop_nils_recursive(v), do: v
180219
end

lib/console/deployments/observer/poller.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ defmodule Console.Deployments.Observer.Poller do
4343
defp poll_oci(%{oci: %{url: url} = oci} = target, last) do
4444
client = OCI.Client.new(url)
4545
with {:ok, oci} <- OCI.Auth.authenticate(client, oci.provider, oci.auth),
46-
{:ok, %OCI.Tags{tags: [_ | _] = tags}} <- OCI.Client.tags(oci),
46+
{:ok, %OCI.Tags{tags: [_ | _] = tags}} <- OCI.Client.tags(oci, &is_semver?/1),
4747
{:tag, [vsn | _]} <- {:tag, sorted(tags, target)},
4848
{:vsn, :gt} <- {:vsn, compare(vsn, last, target)} do
4949
{:ok, vsn}

lib/console/deployments/pr/utils.ex

+6-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ defmodule Console.Deployments.Pr.Utils do
1313
@flow_regex [~r/plrl\/flow\/([[:alnum:]_\-]+)\/?/, ~r/plrl\(flow:([[:alnum:]_\-]*)\)/, ~r/Plural [fF]low:\s+([[:alnum:]_\-]+)/]
1414
@preview_regex [~r/plrl\/preview\/([[:alnum:]_\-]+)\/?/, ~r/plrl\(preview:([[:alnum:]_\-]*)\)/, ~r/Plural [pP]review:\s+([[:alnum:]_\-]+)/]
1515

16+
@solid_opts [strict_variables: true, strict_filters: true]
17+
1618
def filter_ansi(text), do: String.replace(text, @ansi_code, "")
1719

1820
def pr_associations(content, scopes \\ ~w(stack service cluster flow)a) do
@@ -64,20 +66,20 @@ defmodule Console.Deployments.Pr.Utils do
6466

6567
def render_solid_raw(template, ctx) do
6668
with {:parse, {:ok, tpl}} <- {:parse, Solid.parse(template)},
67-
{:render, {:ok, res}} <- {:render, Solid.render(tpl, %{"context" => ctx})} do
69+
{:render, {:ok, res, _}} <- {:render, Solid.render(tpl, %{"context" => ctx}, @solid_opts)} do
6870
{:ok, IO.iodata_to_binary(res)}
6971
else
70-
{:parse, {:error, %Solid.TemplateError{message: message}}} -> {:error, message}
72+
{:parse, {:error, %Solid.TemplateError{} = err}} -> {:error, Solid.TemplateError.message(err)}
7173
{:render, {:error, errs, _}} -> {:error, Enum.map(errs, &inspect/1) |> Enum.join(", ")}
7274
end
7375
end
7476

7577
def render_solid(template, ctx) do
7678
with {:parse, {:ok, tpl}} <- {:parse, Solid.parse(template)},
77-
{:render, {:ok, res}} <- {:render, Solid.render(tpl, %{"context" => ctx})} do
79+
{:render, {:ok, res, _}} <- {:render, Solid.render(tpl, %{"context" => ctx}, @solid_opts)} do
7880
{:ok, IO.iodata_to_binary(res)}
7981
else
80-
{:parse, {:error, %Solid.TemplateError{message: message}}} -> {:error, message}
82+
{:parse, {:error, %Solid.TemplateError{} = err}} -> {:error, Solid.TemplateError.message(err)}
8183
{:render, {:error, errs, _}} -> {:error, "encountered #{length(errs)} while rendering pr description"}
8284
end
8385
end

lib/console/deployments/pubsub/protocols/previewable.ex

+9-6
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,32 @@ defimpl Console.Deployments.PubSub.Previewable, for: [
1717
Console.PubSub.PullRequestUpdated
1818
] do
1919
alias Console.Schema.PullRequest
20+
alias Console.Deployments.Notifications.Utils
2021
alias Console.Deployments.Flows.Preview
2122

2223
def reconcile(%@for{item: %PullRequest{status: s} = pr}) when s in ~w(merged closed)a,
2324
do: Preview.delete_instance(pr)
24-
def reconcile(%@for{item: %PullRequest{} = pr}), do: Preview.sync_instance(pr)
25+
def reconcile(%@for{item: %PullRequest{} = pr}) do
26+
Utils.deduplicate({:pr_updated, pr.id}, fn ->
27+
Preview.sync_instance(pr)
28+
end, ttl: :timer.seconds(15))
29+
end
2530
end
2631

27-
defimpl Console.Deployments.PubSub.Previewable, for: [
28-
Console.PubSub.PreviewEnvironmentInstanceCreated,
29-
] do
32+
defimpl Console.Deployments.PubSub.Previewable, for: Console.PubSub.PreviewEnvironmentInstanceCreated do
3033
alias Console.Deployments.Flows.Preview
3134

3235
def reconcile(%@for{item: inst}), do: Preview.pr_comment(inst)
3336
end
3437

3538
defimpl Console.Deployments.PubSub.Previewable, for: [
3639
Console.PubSub.ServiceUpdated,
40+
Console.PubSub.ServiceComponentsUpdated
3741
] do
3842
alias Console.Deployments.Flows.Preview
3943

4044
def reconcile(%@for{item: svc}) do
41-
fresh = Timex.now() |> Timex.shift(seconds: -10)
42-
case Timex.after?(svc.updated_at || Timex.now(), fresh) do
45+
case Preview.fresh?(svc.updated_at) do
4346
true -> Preview.sync_service(svc)
4447
false -> :ok
4548
end

lib/console/deployments/services.ex

+3-2
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ defmodule Console.Deployments.Services do
395395
start_transaction()
396396
|> add_operation(:source, fn _ ->
397397
get_service!(service_id)
398-
|> Repo.preload([:dependencies, :context_bindings])
398+
|> Repo.preload([:dependencies, :context_bindings, :imports])
399399
|> allow(user, :write)
400400
end)
401401
|> add_operation(:config, fn %{source: source} ->
@@ -407,9 +407,10 @@ defmodule Console.Deployments.Services do
407407
|> Console.dedupe(:git, Console.mapify(source.git))
408408
|> Console.dedupe(:helm, Console.mapify(source.helm))
409409
|> Console.dedupe(:kustomize, Console.mapify(source.kustomize))
410+
|> Console.dedupe(:imports, Enum.map(source.imports, & %{service_id: &1.service_id, stack_id: &1.stack_id}))
410411
|> Console.dedupe(:dependencies, Enum.map(source.dependencies, & %{name: &1.name}))
411412
|> Console.dedupe(:sync_config, Console.clean(source.sync_config))
412-
|> Map.merge(attrs)
413+
|> DeepMerge.deep_merge(attrs)
413414
|> Map.put(:configuration, config)
414415
|> create_service(cluster_id, user)
415416
end)

lib/console/schema/pull_request.ex

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ defmodule Console.Schema.PullRequest do
8787
flow_id
8888
creator
8989
labels
90+
preview
9091
)a
9192

9293
def changeset(model, attrs \\ %{}) do

lib/oci/client.ex

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ defmodule Console.OCI.Client do
2828
put_in(client.client.options.dkr_repo, "#{repo}/#{suffix}")
2929
end
3030

31-
def tags(client, query \\ "", acc \\ %Tags{}) do
31+
def tags(client, filter \\ fn _ -> true end, query \\ "", acc \\ %Tags{}) do
3232
case authed_get(client, "/v2/:repo/tags/list?n=1000#{query}") do
3333
{:ok, %Req.Response{status: 200, body: body, headers: %{"link" => _}}} ->
34-
new = Tags.new(body)
35-
tags(client, "&last=#{List.last(new.tags)}", merge_tags(acc, new))
34+
new = Tags.new(body, filter)
35+
tags(client, filter, "&last=#{List.last(new.tags)}", merge_tags(acc, new))
3636
{:ok, %Req.Response{status: 200, body: body}} ->
37-
{:ok, merge_tags(acc, Tags.new(body))}
37+
{:ok, merge_tags(acc, Tags.new(body, filter))}
3838
err -> handle_error(err)
3939
end
4040
end

lib/oci/schema.ex

+7
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ defmodule Console.OCI.Tags do
5252
@type t :: %__MODULE__{}
5353
defstruct [:name, tags: []]
5454

55+
def new(body, filter) when is_function(filter, 1) do
56+
%__MODULE__{
57+
tags: Enum.filter(body["tags"], filter),
58+
name: body["name"]
59+
}
60+
end
61+
5562
def new(%{"tags" => tags, "name" => name}),
5663
do: %__MODULE__{tags: tags, name: name}
5764

mix.exs

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ defmodule Console.MixProject do
160160
{:briefly, "~> 0.5.0"},
161161
{:libring, "~> 1.7"},
162162
{:http_stream, "~> 1.0.0"},
163-
{:solid, "~> 0.15"},
163+
{:solid, "~> 1.0.0-rc.0"},
164164
{:x509, "~> 0.8.5"},
165165
{:bamboo_phoenix, "~> 1.0"},
166166
{:slipstream, "~> 1.0"},

mix.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
"slipstream": {:hex, :slipstream, "1.2.0", "f4e820752339d86d2f15f4103e163f538e3bb9c7fe353225afd1255178e1f051", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mint_web_socket, "~> 0.2 or ~> 1.0", [hex: :mint_web_socket, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.1 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f2fceddbb3c97331d348586e77c6425f4d150242dfaf392d22e8bd22f93d1f1e"},
124124
"snap": {:hex, :snap, "0.11.3", "12488b227929d340254bd3dc198f4819b134a361a57c367c1dce6a06ef192005", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3b80caf4f1bb11a505fee0c646c13687e4d87fda36a39b3bdc879265dabb8d0e"},
125125
"sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"},
126-
"solid": {:hex, :solid, "0.15.2", "6921af98a3a862041bb6af72b5f6e094dbf0242366b142f98a92cabe4ed30d2a", [:mix], [{:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "18b062b04948b7f7b99ac4a9360681dac7e0bd142df5e62a7761696c7384be45"},
126+
"solid": {:hex, :solid, "1.0.0-rc.0", "57af6fd1c3defadad1a951ca56a27f612f290b2965a3a5f7b5a8cfe6012b11bd", [:mix], [], "hexpm", "135250f7f1fb849ac9554110628afea40cc41e4c457e670fe40cb22247190d99"},
127127
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
128128
"swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm", "94884f84783fc1ba027aba8fe8a7dae4aad78c98e9f9c76667ec3471585c08c6"},
129129
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},

priv/pr/preview_env.md.eex

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
Plural has deployed a preview environment for this PR.
1+
### <%= @status_emoji %> Deploy preview for <%= @service.name %> is <%= @status_text %>
22

3-
Service Name: <%= @service.name %>
4-
Service Status: <%= @service.component_status %> ![](https://img.shields.io/badge/<%= @service.status %>-<%= @status_color %>)
5-
<%= if @comment_template do %>
6-
7-
<details>
8-
<summary>Preview Environment details</summary>
9-
<%= @comment_template %>
10-
</details>
3+
| Name | Details |
4+
| :---: | ------- |
5+
| :zap: Service | <%= @service.name %> (<%= @service.component_status %> ready) |
6+
| :cloud: Cluster | <%= @service.cluster.name %> (<%= @service.cluster.distro %>) |
7+
| :octocat: Commit sha | <%= @sha %> |
8+
| ![](https://docs.plural.sh/favicon-16.png) Plural URL | [<%= Solid.StandardFilter.truncate(@url, 75) %>](<%= @url %>) |
9+
| :mag: Logs URL | [<%= Solid.StandardFilter.truncate(@logs_url, 75) %>](<%= @logs_url %>) |
10+
| :ocean: Flow URL | [<%= Solid.StandardFilter.truncate(@flow_url, 75) %>](<%= @flow_url %>) |<%= if @comment_template do %>
11+
<%= @comment_template %>
1112
<% end %>
12-
View your preview environment in the Plural Console [here](<%= @url %>)
13+
14+
---
15+
16+
You can learn more about preview environments and Plural Flows [here](https://docs.plural.sh/plural-features/flows)

0 commit comments

Comments
 (0)