@@ -45,37 +45,49 @@ defmodule Console.Deployments.Flows.Preview do
45
45
end
46
46
end
47
47
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
49
51
case Repo . preload ( svc , [ :preview_instance , :preview_templates ] ) do
50
52
% Service { preview_instance: % PreviewEnvironmentInstance { } = inst } ->
51
53
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
59
63
_ -> :ok
60
64
end
61
65
end
66
+ def sync_service ( _ ) , do: :ok
62
67
63
68
defp post_comment ( % PreviewEnvironmentInstance { } = inst ) do
64
69
% PreviewEnvironmentInstance {
65
- pull_request: % PullRequest { url: url } = pr ,
70
+ pull_request: % PullRequest { url: url , commit_sha: sha } = pr ,
66
71
service: svc ,
67
72
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 ] )
69
74
70
75
with % ScmConnection { } = conn <- scm_connection ( tpl ) ,
71
76
message = EEx . eval_string ( @ preview_comment , assigns: [
72
77
url: Console . url ( "/cd/clusters/#{ svc . cluster_id } /services/#{ svc . id } /components" ) ,
73
78
comment_template: msg ,
74
79
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" )
76
86
] ) ,
77
87
{ :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 ) )
79
91
else
80
92
_ -> { :error , "could not create review comment for pr: #{ url } " }
81
93
end
@@ -90,7 +102,7 @@ defmodule Console.Deployments.Flows.Preview do
90
102
def delete_instance ( _ ) , do: :ok
91
103
92
104
defp create_instance (
93
- % PreviewEnvironmentTemplate { reference_service: ref } = template ,
105
+ % PreviewEnvironmentTemplate { reference_service: % Service { } = ref } = template ,
94
106
% PullRequest { } = pr
95
107
) do
96
108
with { :ok , attrs } <- build_attributes ( pr , template ) ,
@@ -123,7 +135,9 @@ defmodule Console.Deployments.Flows.Preview do
123
135
with { :ok , ns } <- render_liquid ( tpl . namespace || svc . namespace , ctx ) ,
124
136
{ :ok , name } <- render_liquid ( tpl . name || svc . name , ctx ) ,
125
137
{ :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 ( )
127
141
end
128
142
end
129
143
@@ -148,33 +162,58 @@ defmodule Console.Deployments.Flows.Preview do
148
162
defp scm_connection ( _ ) , do: Git . default_scm_connection ( )
149
163
150
164
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 ( ) ,
155
169
do: { :ok , put_in ( tpl . helm . values , vals ) }
156
170
end
157
171
defp template_helm_vals ( _ , % ServiceTemplate { } = tpl , _ ) , do: { :ok , tpl }
158
172
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
160
177
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
162
179
{ :ok , IO . iodata_to_binary ( res ) }
163
180
else
164
- { :parse , { :error , % Solid.TemplateError { message: message } } } -> { :error , message }
181
+ { :parse , { :error , % Solid.TemplateError { } = err } } -> { :error , Solid.TemplateError . message ( err ) }
165
182
{ :render , { :error , errs , _ } } -> { :error , Enum . map ( errs , & inspect / 1 ) |> Enum . join ( ", " ) }
166
183
end
167
184
end
185
+ defp render_liquid ( template , _ ) , do: { :ok , template }
168
186
169
187
defp color ( :healthy ) , do: :green
170
188
defp color ( :failed ) , do: :red
171
189
defp color ( _ ) , do: :yellow
172
190
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
+
173
199
defp bot ( ) , do: % { Users . get_bot! ( "console" ) | roles: % { admin: true } }
174
200
175
201
defp notify ( { :ok , % PreviewEnvironmentInstance { } = inst } , :create ) ,
176
202
do: handle_notify ( PubSub.PreviewEnvironmentInstanceCreated , inst )
177
203
defp notify ( { :ok , % PreviewEnvironmentInstance { } = inst } , :update ) ,
178
204
do: handle_notify ( PubSub.PreviewEnvironmentInstanceUpdated , inst )
179
205
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
180
219
end
0 commit comments