ductwork 0.11.2 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/app/assets/images/ductwork/logo.png +0 -0
- data/app/assets/images/ductwork/octagon-x.svg +1 -0
- data/app/assets/javascripts/ductwork/application.js +49 -0
- data/app/assets/stylesheets/ductwork/application.css +240 -0
- data/app/assets/stylesheets/ductwork/vendor/flexboxgrid.min.css +1 -0
- data/app/assets/stylesheets/ductwork/vendor/pico.min.css +4 -0
- data/app/controllers/ductwork/application_controller.rb +39 -0
- data/app/controllers/ductwork/dashboards_controller.rb +19 -0
- data/app/controllers/ductwork/pipelines_controller.rb +30 -0
- data/app/controllers/ductwork/step_errors_controller.rb +35 -0
- data/app/helpers/ductwork/application_helper.rb +39 -0
- data/app/views/ductwork/dashboards/show.html.erb +136 -0
- data/app/views/ductwork/pipelines/index.html.erb +105 -0
- data/app/views/ductwork/pipelines/show.html.erb +266 -0
- data/app/views/ductwork/step_errors/index.html.erb +101 -0
- data/app/views/layouts/ductwork/application.html.erb +49 -0
- data/config/routes.rb +8 -0
- data/lib/ductwork/cli.rb +19 -0
- data/lib/ductwork/engine.rb +13 -0
- data/lib/ductwork/models/job.rb +1 -1
- data/lib/ductwork/models/pipeline.rb +23 -9
- data/lib/ductwork/version.rb +1 -1
- data/lib/ductwork.rb +2 -0
- data/lib/generators/ductwork/install/install_generator.rb +6 -1
- data/lib/generators/ductwork/install/templates/db/create_ductwork_pipelines.rb +1 -0
- metadata +38 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ductwork
|
|
4
|
+
class StepErrorsController < Ductwork::ApplicationController
|
|
5
|
+
def index
|
|
6
|
+
@step_errors = query_step_errors
|
|
7
|
+
@klasses = Ductwork::Result
|
|
8
|
+
.failure
|
|
9
|
+
.joins(execution: { job: :step })
|
|
10
|
+
.group("ductwork_steps.klass")
|
|
11
|
+
.pluck("ductwork_steps.klass")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def query_step_errors
|
|
17
|
+
Ductwork::Result
|
|
18
|
+
.failure
|
|
19
|
+
.then(&method(:filter_by_step_klass))
|
|
20
|
+
.then(&method(:paginate))
|
|
21
|
+
.includes(execution: { job: :step })
|
|
22
|
+
.order(created_at: :desc)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def filter_by_step_klass(relation)
|
|
26
|
+
if params[:klass].present?
|
|
27
|
+
relation
|
|
28
|
+
.joins(execution: { job: :step })
|
|
29
|
+
.where(ductwork_steps: { klass: params[:klass] })
|
|
30
|
+
else
|
|
31
|
+
relation
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ductwork
|
|
4
|
+
module ApplicationHelper
|
|
5
|
+
def formatted_time_distance(started_at, completed_at)
|
|
6
|
+
elapsed = completed_at - started_at
|
|
7
|
+
hours = (elapsed / 3600).floor
|
|
8
|
+
minutes = ((elapsed % 3600) / 60).floor
|
|
9
|
+
seconds = (elapsed % 60).round(2)
|
|
10
|
+
hours_string = hours.zero? ? "" : "#{hours}h "
|
|
11
|
+
minutes_string = minutes.zero? ? "" : "#{minutes}m "
|
|
12
|
+
seconds_string = seconds.zero? ? "" : "#{seconds}s"
|
|
13
|
+
|
|
14
|
+
"#{hours_string}#{minutes_string}#{seconds_string}"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def first_page?
|
|
18
|
+
params[:page].to_i.zero?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def next_page_path
|
|
22
|
+
next_page = params[:page].to_i + 1
|
|
23
|
+
next_params = params
|
|
24
|
+
.permit(:controller, :action, :klass, :status, :page)
|
|
25
|
+
.merge(page: next_page)
|
|
26
|
+
|
|
27
|
+
url_for(**next_params)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def previous_page_path
|
|
31
|
+
previous_page = params[:page].to_i - 1
|
|
32
|
+
previous_params = params
|
|
33
|
+
.permit(:controller, :action, :klass, :status, :page)
|
|
34
|
+
.merge(page: previous_page)
|
|
35
|
+
|
|
36
|
+
url_for(**previous_params)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<div class="grid metrics">
|
|
3
|
+
<%= link_to(pipelines_path(status: "completed"), class: "stealthy-link") do %>
|
|
4
|
+
<article>
|
|
5
|
+
<div class="metric-heading">Completed Pipelines</div>
|
|
6
|
+
<h1 class="metric-value"><%= number_with_delimiter(@metrics[:completed]) %></h1>
|
|
7
|
+
</article>
|
|
8
|
+
<% end %>
|
|
9
|
+
|
|
10
|
+
<%= link_to(pipelines_path(status: "in_progress"), class: "stealthy-link") do %>
|
|
11
|
+
<article>
|
|
12
|
+
<div class="metric-heading">In-Progress Pipelines</div>
|
|
13
|
+
<h1 class="metric-value"><%= number_with_delimiter(@metrics[:in_progress]) %></h1>
|
|
14
|
+
</article>
|
|
15
|
+
<% end %>
|
|
16
|
+
|
|
17
|
+
<%= link_to(pipelines_path(status: "halted"), class: "stealthy-link") do %>
|
|
18
|
+
<article>
|
|
19
|
+
<div class="metric-heading">Halted Pipelines</div>
|
|
20
|
+
<h1 class="metric-value"><%= number_with_delimiter(@metrics[:halted]) %></h1>
|
|
21
|
+
</article>
|
|
22
|
+
<% end %>
|
|
23
|
+
|
|
24
|
+
<%= link_to(step_errors_path, class: "stealthy-link") do %>
|
|
25
|
+
<article>
|
|
26
|
+
<div class="metric-heading">Step Errors</div>
|
|
27
|
+
<h1 class="metric-value"><%= @metrics[:step_errors] %></h1>
|
|
28
|
+
</article>
|
|
29
|
+
<% end %>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div>
|
|
33
|
+
<h1>All Pipelines</h1>
|
|
34
|
+
<div class="separate-content">
|
|
35
|
+
<div class="filter-group">
|
|
36
|
+
<span class="filter-group-item">Filters:</span>
|
|
37
|
+
|
|
38
|
+
<details class="dropdown filter-group-item">
|
|
39
|
+
<summary>Class</summary>
|
|
40
|
+
<ul>
|
|
41
|
+
<% @klasses.each do |klass| %>
|
|
42
|
+
<li>
|
|
43
|
+
<%= link_to(klass, pipelines_path(klass:)) %>
|
|
44
|
+
</li>
|
|
45
|
+
<% end %>
|
|
46
|
+
</ul>
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<details class="dropdown filter-group-item">
|
|
50
|
+
<summary>Status</summary>
|
|
51
|
+
<ul>
|
|
52
|
+
<% @statuses.each do |status| %>
|
|
53
|
+
<li>
|
|
54
|
+
<%= link_to(status.gsub("_", "-"), pipelines_path(status:)) %>
|
|
55
|
+
</li>
|
|
56
|
+
<% end %>
|
|
57
|
+
</ul>
|
|
58
|
+
</details>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div role="group" style="width: auto;">
|
|
62
|
+
<button <%= first_page? && "disabled" %> data-href="<%= previous_page_path %>">
|
|
63
|
+
←
|
|
64
|
+
</button>
|
|
65
|
+
<button data-href="<%= next_page_path %>">
|
|
66
|
+
→
|
|
67
|
+
</button>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<table class="striped">
|
|
72
|
+
<thead>
|
|
73
|
+
<tr>
|
|
74
|
+
<th>ID</th>
|
|
75
|
+
<th>Class</th>
|
|
76
|
+
<th>Status</th>
|
|
77
|
+
<th>Errors</th>
|
|
78
|
+
<th>Started At</th>
|
|
79
|
+
<th>Runtime</th>
|
|
80
|
+
</tr>
|
|
81
|
+
</thead>
|
|
82
|
+
<tbody>
|
|
83
|
+
<% @pipelines.each do |pipeline| %>
|
|
84
|
+
<tr class="row-link" data-href="<%= pipeline_path(pipeline.id) %>">
|
|
85
|
+
<td>
|
|
86
|
+
<code>
|
|
87
|
+
<%= pipeline.id %>
|
|
88
|
+
</code>
|
|
89
|
+
</td>
|
|
90
|
+
<td>
|
|
91
|
+
<code>
|
|
92
|
+
<%= pipeline.klass %>
|
|
93
|
+
</code>
|
|
94
|
+
</td>
|
|
95
|
+
<td>
|
|
96
|
+
<div class="status-pill <%= pipeline.status %>">
|
|
97
|
+
<%= pipeline.status.gsub("_", "-") %>
|
|
98
|
+
</div>
|
|
99
|
+
</td>
|
|
100
|
+
<td>
|
|
101
|
+
<%
|
|
102
|
+
count = Ductwork::Result
|
|
103
|
+
.joins(execution: { job: { step: :pipeline }})
|
|
104
|
+
.failure
|
|
105
|
+
.where(ductwork_pipelines: { id: pipeline.id })
|
|
106
|
+
.count
|
|
107
|
+
%>
|
|
108
|
+
<% if count.zero? %>
|
|
109
|
+
0
|
|
110
|
+
<% else %>
|
|
111
|
+
<div class="errors">
|
|
112
|
+
<%= image_tag("ductwork/octagon-x.svg", class: "icon") %>
|
|
113
|
+
<%= count %>
|
|
114
|
+
</div>
|
|
115
|
+
<% end %>
|
|
116
|
+
</td>
|
|
117
|
+
<td>
|
|
118
|
+
<div class="tight-timestamp">
|
|
119
|
+
<%= pipeline.started_at.iso8601(3) %>
|
|
120
|
+
</div>
|
|
121
|
+
</td>
|
|
122
|
+
<td>
|
|
123
|
+
<% if pipeline.completed_at.nil? %>
|
|
124
|
+
<div data-started-at=<%= pipeline.started_at.iso8601 %>>
|
|
125
|
+
<span id="elapsed-timer">0h 0m 0s</span>
|
|
126
|
+
</div>
|
|
127
|
+
<% else %>
|
|
128
|
+
<%= formatted_time_distance(pipeline.started_at, pipeline.completed_at) %>
|
|
129
|
+
<% end %>
|
|
130
|
+
</td>
|
|
131
|
+
</tr>
|
|
132
|
+
<% end %>
|
|
133
|
+
</tbody>
|
|
134
|
+
</table>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<h1>All Pipelines</h1>
|
|
3
|
+
|
|
4
|
+
<div class="separate-content">
|
|
5
|
+
<div class="filter-group">
|
|
6
|
+
<span class="filter-group-item">Filters:</span>
|
|
7
|
+
|
|
8
|
+
<details class="dropdown filter-group-item">
|
|
9
|
+
<summary><%= params[:klass] || "Class" %></summary>
|
|
10
|
+
<ul>
|
|
11
|
+
<% @klasses.each do |klass| %>
|
|
12
|
+
<li>
|
|
13
|
+
<%= link_to(klass, pipelines_path(params.permit(:status).merge(klass: klass))) %>
|
|
14
|
+
</li>
|
|
15
|
+
<% end %>
|
|
16
|
+
</ul>
|
|
17
|
+
</details>
|
|
18
|
+
|
|
19
|
+
<details class="dropdown filter-group-item">
|
|
20
|
+
<summary><%= params[:status]&.gsub("_", "-") || "Status" %></summary>
|
|
21
|
+
<ul>
|
|
22
|
+
<% @statuses.each do |status| %>
|
|
23
|
+
<li>
|
|
24
|
+
<%= link_to(status.gsub("_", "-"), pipelines_path(params.permit(:klass).merge(status:))) %>
|
|
25
|
+
</li>
|
|
26
|
+
<% end %>
|
|
27
|
+
</ul>
|
|
28
|
+
</details>
|
|
29
|
+
|
|
30
|
+
<%= link_to("Clear", pipelines_path) %>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div role="group" style="width: auto;">
|
|
34
|
+
<button <%= first_page? && "disabled" %> data-href="<%= previous_page_path %>">
|
|
35
|
+
<%= link_to(previous_page_path, class: "stealthy-link") do %>
|
|
36
|
+
←
|
|
37
|
+
<% end %>
|
|
38
|
+
</button>
|
|
39
|
+
<button data-href="<%= next_page_path %>">
|
|
40
|
+
→
|
|
41
|
+
</button>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<table class="striped">
|
|
46
|
+
<thead>
|
|
47
|
+
<tr>
|
|
48
|
+
<th>ID</th>
|
|
49
|
+
<th>Class</th>
|
|
50
|
+
<th>Status</th>
|
|
51
|
+
<th>Errors</th>
|
|
52
|
+
<th>Started At</th>
|
|
53
|
+
<th>Runtime</th>
|
|
54
|
+
</tr>
|
|
55
|
+
</thead>
|
|
56
|
+
<tbody>
|
|
57
|
+
<% @pipelines.each do |pipeline| %>
|
|
58
|
+
<tr class="row-link" data-href="<%= pipeline_path(pipeline.id) %>">
|
|
59
|
+
<td>
|
|
60
|
+
<code><%= pipeline.id %></code>
|
|
61
|
+
</td>
|
|
62
|
+
<td>
|
|
63
|
+
<code><%= pipeline.klass %></code>
|
|
64
|
+
</td>
|
|
65
|
+
<td>
|
|
66
|
+
<div class="status-pill <%= pipeline.status %>">
|
|
67
|
+
<%= pipeline.status.gsub("_", "-") %>
|
|
68
|
+
</div>
|
|
69
|
+
</td>
|
|
70
|
+
<td>
|
|
71
|
+
<%
|
|
72
|
+
count = Ductwork::Result
|
|
73
|
+
.joins(execution: { job: { step: :pipeline }})
|
|
74
|
+
.failure
|
|
75
|
+
.where(ductwork_pipelines: { id: pipeline.id })
|
|
76
|
+
.count
|
|
77
|
+
%>
|
|
78
|
+
<% if count.zero? %>
|
|
79
|
+
0
|
|
80
|
+
<% else %>
|
|
81
|
+
<div class="errors">
|
|
82
|
+
<%= image_tag("ductwork/octagon-x.svg", class: "icon") %>
|
|
83
|
+
<%= count %>
|
|
84
|
+
</div>
|
|
85
|
+
<% end %>
|
|
86
|
+
</td>
|
|
87
|
+
<td>
|
|
88
|
+
<div class="tight-timestamp">
|
|
89
|
+
<%= pipeline.started_at.iso8601(3) %>
|
|
90
|
+
</div>
|
|
91
|
+
</td>
|
|
92
|
+
<td>
|
|
93
|
+
<% if pipeline.completed_at.nil? %>
|
|
94
|
+
<div data-started-at=<%= pipeline.started_at.iso8601 %>>
|
|
95
|
+
<span id="elapsed-timer">0h 0m 0s</span>
|
|
96
|
+
</div>
|
|
97
|
+
<% else %>
|
|
98
|
+
<%= formatted_time_distance(pipeline.started_at, pipeline.completed_at) %>
|
|
99
|
+
<% end %>
|
|
100
|
+
</td>
|
|
101
|
+
</tr>
|
|
102
|
+
<% end %>
|
|
103
|
+
</tbody>
|
|
104
|
+
</table>
|
|
105
|
+
</div>
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<div class="separate-content">
|
|
3
|
+
<h1>
|
|
4
|
+
Pipeline <code><%= @pipeline.id %></code>
|
|
5
|
+
</h1>
|
|
6
|
+
|
|
7
|
+
<h2>
|
|
8
|
+
<span class="status-pill big-pill <%= @pipeline.status %>">
|
|
9
|
+
<%= @pipeline.status.gsub("_", "-") %>
|
|
10
|
+
</span>
|
|
11
|
+
</h2>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<article>
|
|
15
|
+
<div class="separate-content">
|
|
16
|
+
<div>
|
|
17
|
+
<div class="metric-heading">
|
|
18
|
+
<label>ID</label>
|
|
19
|
+
<code><%= @pipeline.id %></code>
|
|
20
|
+
</div>
|
|
21
|
+
<div>
|
|
22
|
+
<label>Class</label>
|
|
23
|
+
<code>
|
|
24
|
+
<%= link_to(@pipeline.klass, pipelines_path(klass: @pipeline.klass)) %>
|
|
25
|
+
</code>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div>
|
|
30
|
+
<div class="metric-heading">
|
|
31
|
+
<label>Triggered At</label>
|
|
32
|
+
<span>
|
|
33
|
+
<%= @pipeline.triggered_at.iso8601(3) %>
|
|
34
|
+
</span>
|
|
35
|
+
</div>
|
|
36
|
+
<div>
|
|
37
|
+
<label>Step Count</label>
|
|
38
|
+
<span>
|
|
39
|
+
<%= @pipeline.steps.count %>
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div>
|
|
45
|
+
<div class="metric-heading">
|
|
46
|
+
<label>Last Advanced At</label>
|
|
47
|
+
<span>
|
|
48
|
+
<%= @pipeline.last_advanced_at.iso8601(3) %>
|
|
49
|
+
</span>
|
|
50
|
+
</div>
|
|
51
|
+
<div>
|
|
52
|
+
<label>Completed At</label>
|
|
53
|
+
<span>
|
|
54
|
+
<%= @pipeline.completed_at&.iso8601(3) %>
|
|
55
|
+
</span>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div style="margin-top: 1rem;">
|
|
61
|
+
<label>Definition</label>
|
|
62
|
+
<code>
|
|
63
|
+
<%= @pipeline.parsed_definition %>
|
|
64
|
+
</code>
|
|
65
|
+
</div>
|
|
66
|
+
</article>
|
|
67
|
+
|
|
68
|
+
<h3>Steps</h3>
|
|
69
|
+
|
|
70
|
+
<div class="separate-content">
|
|
71
|
+
<div class="filter-group">
|
|
72
|
+
<span class="filter-group-item">Filters:</span>
|
|
73
|
+
|
|
74
|
+
<details class="dropdown filter-group-item">
|
|
75
|
+
<summary><%= params[:klass] || "Class" %></summary>
|
|
76
|
+
<ul>
|
|
77
|
+
<% @klasses.each do |klass| %>
|
|
78
|
+
<li>
|
|
79
|
+
<%= link_to(klass, pipeline_path(@pipeline.id, **params.permit(:status).merge(klass: klass))) %>
|
|
80
|
+
</li>
|
|
81
|
+
<% end %>
|
|
82
|
+
</ul>
|
|
83
|
+
</details>
|
|
84
|
+
|
|
85
|
+
<details class="dropdown filter-group-item">
|
|
86
|
+
<summary><%= params[:status]&.gsub("_", "-") || "Status" %></summary>
|
|
87
|
+
<ul>
|
|
88
|
+
<% @statuses.each do |status| %>
|
|
89
|
+
<li>
|
|
90
|
+
<%= link_to(status.gsub("_", "-"), pipeline_path(@pipeline.id, **params.permit(:klass).merge(status:))) %>
|
|
91
|
+
</li>
|
|
92
|
+
<% end %>
|
|
93
|
+
</ul>
|
|
94
|
+
</details>
|
|
95
|
+
|
|
96
|
+
<%= link_to("Clear", pipeline_path(@pipeline.id)) %>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div role="group" style="width: auto;">
|
|
100
|
+
<button <%= first_page? && "disabled" %> data-href="<%= previous_page_path %>">
|
|
101
|
+
<%= link_to(previous_page_path, class: "stealthy-link") do %>
|
|
102
|
+
←
|
|
103
|
+
<% end %>
|
|
104
|
+
</button>
|
|
105
|
+
<button data-href="<%= next_page_path %>">
|
|
106
|
+
→
|
|
107
|
+
</button>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<article style="margin-bottom: 0px;">
|
|
112
|
+
<div>
|
|
113
|
+
<% @steps.each do |step| %>
|
|
114
|
+
<details>
|
|
115
|
+
<summary class="details-grid">
|
|
116
|
+
<div class="grid">
|
|
117
|
+
<div>
|
|
118
|
+
<label>ID</label>
|
|
119
|
+
<code>
|
|
120
|
+
<%= step.id %>
|
|
121
|
+
</code>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div>
|
|
125
|
+
<label>Status</label>
|
|
126
|
+
<div class="status-pill <%= step.status %>">
|
|
127
|
+
<%= step.status.gsub("_", "-") %>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div>
|
|
132
|
+
<label>Transition</label>
|
|
133
|
+
<code>
|
|
134
|
+
<%= step.to_transition == "default" ? "chain" : step.to_transition %>
|
|
135
|
+
</code>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<div>
|
|
139
|
+
<label>Errors</label>
|
|
140
|
+
<% if (step.job.executions.count - 1).zero? %>
|
|
141
|
+
0
|
|
142
|
+
<% else %>
|
|
143
|
+
<div class="errors">
|
|
144
|
+
<%= image_tag("ductwork/octagon-x.svg") %>
|
|
145
|
+
<%= step.job.executions.count - 1 %>
|
|
146
|
+
</div>
|
|
147
|
+
<% end %>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div>
|
|
151
|
+
<label>Total Runtime</label>
|
|
152
|
+
<% if step.completed_at.nil? %>
|
|
153
|
+
<div data-started-at=<%= step.started_at.iso8601 %>>
|
|
154
|
+
<span id="elapsed-timer">0h 0m 0s</span>
|
|
155
|
+
</div>
|
|
156
|
+
<% else %>
|
|
157
|
+
<%= formatted_time_distance(step.started_at, step.completed_at) %>
|
|
158
|
+
<% end %>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
</summary>
|
|
162
|
+
|
|
163
|
+
<div>
|
|
164
|
+
<div class="grid">
|
|
165
|
+
<div>
|
|
166
|
+
<label>Node</label>
|
|
167
|
+
<code>
|
|
168
|
+
<%= step.node %>
|
|
169
|
+
</code>
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<div>
|
|
173
|
+
<label>Class</label>
|
|
174
|
+
<code>
|
|
175
|
+
<%= step.klass %>
|
|
176
|
+
</code>
|
|
177
|
+
</div>
|
|
178
|
+
|
|
179
|
+
<div>
|
|
180
|
+
<label>Started At</label>
|
|
181
|
+
<div class="tight-timestamp">
|
|
182
|
+
<%= step.started_at.iso8601(3) %>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
<div>
|
|
187
|
+
<label>Completed At</label>
|
|
188
|
+
<div class="tight-timestamp">
|
|
189
|
+
<%= step.completed_at&.iso8601(3) %>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<div style="margin-top: 1rem;">
|
|
196
|
+
<label>Executions</label>
|
|
197
|
+
<table class="small-table">
|
|
198
|
+
<thead>
|
|
199
|
+
<tr>
|
|
200
|
+
<th>ID</th>
|
|
201
|
+
<th>Attempt</th>
|
|
202
|
+
<th>Available At</th>
|
|
203
|
+
<th>Claimed At</th>
|
|
204
|
+
<th>Ran At</th>
|
|
205
|
+
<th>Completed At</th>
|
|
206
|
+
<th>Error</th>
|
|
207
|
+
</tr>
|
|
208
|
+
</thead>
|
|
209
|
+
|
|
210
|
+
<tbody>
|
|
211
|
+
<% step.job.executions.each do |execution| %>
|
|
212
|
+
<tr class="not-clickable">
|
|
213
|
+
<td>
|
|
214
|
+
<code>
|
|
215
|
+
<%= execution.id %>
|
|
216
|
+
</code>
|
|
217
|
+
</td>
|
|
218
|
+
<td><%= execution.retry_count + 1 %></td>
|
|
219
|
+
<td><%= execution.started_at.strftime("%H:%M:%S.%3N") %></td>
|
|
220
|
+
<td><%= execution.availability.completed_at&.strftime("%H:%M:%S.%3N") %></td>
|
|
221
|
+
<td><%= execution.run&.started_at&.strftime("%H:%M:%S.%3N") %></td>
|
|
222
|
+
<td><%= execution.completed_at&.strftime("%H:%M:%S.%3N") %></td>
|
|
223
|
+
<td>
|
|
224
|
+
<% if execution.result.present? && execution.result.failure? %>
|
|
225
|
+
<button data-open-modal="modal-<%= execution.result.id %>" class="tight-timestamp secondary">
|
|
226
|
+
Open
|
|
227
|
+
</button>
|
|
228
|
+
|
|
229
|
+
<dialog id="modal-<%= execution.result.id %>">
|
|
230
|
+
<article>
|
|
231
|
+
<header>
|
|
232
|
+
<button aria-label="Close" rel="prev" data-close-modal="modal-<%= execution.result.id %>"></button>
|
|
233
|
+
<p>
|
|
234
|
+
<strong>Error Backtrace</strong>
|
|
235
|
+
</p>
|
|
236
|
+
</header>
|
|
237
|
+
<div>
|
|
238
|
+
<h2>
|
|
239
|
+
<%= execution.result.error_klass %>
|
|
240
|
+
</h2>
|
|
241
|
+
<h5>
|
|
242
|
+
<%= execution.result.error_message %>
|
|
243
|
+
</h5>
|
|
244
|
+
<code>
|
|
245
|
+
<%= execution.result.error_backtrace.split("\n").each do |line| %>
|
|
246
|
+
<div><%= line %></div>
|
|
247
|
+
<% end %>
|
|
248
|
+
</code>
|
|
249
|
+
</div>
|
|
250
|
+
</article>
|
|
251
|
+
</dialog>
|
|
252
|
+
<% end %>
|
|
253
|
+
</td>
|
|
254
|
+
</tr>
|
|
255
|
+
<% end %>
|
|
256
|
+
</tbody>
|
|
257
|
+
</table>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
</details>
|
|
261
|
+
|
|
262
|
+
<hr/>
|
|
263
|
+
<% end %>
|
|
264
|
+
</div>
|
|
265
|
+
</article>
|
|
266
|
+
</div>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<h3>Step Errors</h3>
|
|
3
|
+
|
|
4
|
+
<div class="separate-content">
|
|
5
|
+
<div class="filter-group">
|
|
6
|
+
<span class="filter-group-item">Filters:</span>
|
|
7
|
+
|
|
8
|
+
<details class="dropdown filter-group-item">
|
|
9
|
+
<summary><%= params[:klass] || "Step Class" %></summary>
|
|
10
|
+
<ul>
|
|
11
|
+
<% @klasses.each do |klass| %>
|
|
12
|
+
<li>
|
|
13
|
+
<%= link_to(klass, step_errors_path(**params.permit(:status).merge(klass: klass))) %>
|
|
14
|
+
</li>
|
|
15
|
+
<% end %>
|
|
16
|
+
</ul>
|
|
17
|
+
</details>
|
|
18
|
+
|
|
19
|
+
<%= link_to("Clear", step_errors_path) %>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div role="group" style="width: auto;">
|
|
23
|
+
<button <%= first_page? && "disabled" %> data-href="<%= previous_page_path %>">
|
|
24
|
+
<%= link_to(previous_page_path, class: "stealthy-link") do %>
|
|
25
|
+
←
|
|
26
|
+
<% end %>
|
|
27
|
+
</button>
|
|
28
|
+
<button data-href="<%= next_page_path %>">
|
|
29
|
+
→
|
|
30
|
+
</button>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
<table class="striped">
|
|
34
|
+
<thead>
|
|
35
|
+
<tr>
|
|
36
|
+
<th>Step ID</th>
|
|
37
|
+
<th>Step Class</th>
|
|
38
|
+
<th>Pipeline ID</th>
|
|
39
|
+
<th>Error Message</th>
|
|
40
|
+
<th>Error Backtrace</th>
|
|
41
|
+
</tr>
|
|
42
|
+
</thead>
|
|
43
|
+
|
|
44
|
+
<tbody>
|
|
45
|
+
<% @step_errors.each do |result| %>
|
|
46
|
+
<tr class="not-clickable">
|
|
47
|
+
<td>
|
|
48
|
+
<code>
|
|
49
|
+
<%= result.execution.job.step.id %>
|
|
50
|
+
</code>
|
|
51
|
+
</td>
|
|
52
|
+
<td>
|
|
53
|
+
<code>
|
|
54
|
+
<%= result.execution.job.step.klass %>
|
|
55
|
+
</code>
|
|
56
|
+
</td>
|
|
57
|
+
<td>
|
|
58
|
+
<code>
|
|
59
|
+
<%= link_to(result.execution.job.step.pipeline_id, pipeline_path(result.execution.job.step.pipeline_id)) %>
|
|
60
|
+
</code>
|
|
61
|
+
</td>
|
|
62
|
+
<td>
|
|
63
|
+
<code>
|
|
64
|
+
<%= [result.error_klass, result.error_message].join(": ") %>
|
|
65
|
+
</code>
|
|
66
|
+
</td>
|
|
67
|
+
<td>
|
|
68
|
+
<button data-open-modal="modal-<%= result.id %>" class="tight-timestamp secondary">
|
|
69
|
+
Open
|
|
70
|
+
</button>
|
|
71
|
+
|
|
72
|
+
<dialog id="modal-<%= result.id %>">
|
|
73
|
+
<article>
|
|
74
|
+
<header>
|
|
75
|
+
<button aria-label="Close" rel="prev" data-close-modal="modal-<%= result.id %>"></button>
|
|
76
|
+
<p>
|
|
77
|
+
<strong>Error Backtrace</strong>
|
|
78
|
+
</p>
|
|
79
|
+
</header>
|
|
80
|
+
<div>
|
|
81
|
+
<h2>
|
|
82
|
+
<%= result.error_klass %>
|
|
83
|
+
</h2>
|
|
84
|
+
<h5>
|
|
85
|
+
<%= result.error_message %>
|
|
86
|
+
</h5>
|
|
87
|
+
<code>
|
|
88
|
+
<%= result.error_backtrace.split("\n").each do |line| %>
|
|
89
|
+
<div><%= line %></div>
|
|
90
|
+
<% end %>
|
|
91
|
+
</code>
|
|
92
|
+
</div>
|
|
93
|
+
</article>
|
|
94
|
+
</dialog>
|
|
95
|
+
|
|
96
|
+
</td>
|
|
97
|
+
</tr>
|
|
98
|
+
<% end %>
|
|
99
|
+
</tbody>
|
|
100
|
+
</table>
|
|
101
|
+
</div>
|