ductwork 1.3.0 → 1.5.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/.claude/skills/audit-common/accepted-tradeoffs.md +0 -5
- data/CHANGELOG.md +19 -0
- data/app/assets/javascripts/ductwork/application.js +50 -41
- data/app/assets/stylesheets/ductwork/application.css +859 -146
- data/app/controllers/ductwork/application_controller.rb +39 -8
- data/app/controllers/ductwork/dashboards_controller.rb +44 -11
- data/app/controllers/ductwork/pipelines_controller.rb +47 -7
- data/app/controllers/ductwork/step_errors_controller.rb +9 -5
- data/app/helpers/ductwork/application_helper.rb +107 -18
- data/app/views/ductwork/dashboards/show.html.erb +75 -126
- data/app/views/ductwork/pipelines/_graph.html.erb +37 -0
- data/app/views/ductwork/pipelines/_step.html.erb +76 -0
- data/app/views/ductwork/pipelines/index.html.erb +11 -101
- data/app/views/ductwork/pipelines/show.html.erb +62 -285
- data/app/views/ductwork/shared/_error.html.erb +7 -0
- data/app/views/ductwork/shared/_filter_menu.html.erb +13 -0
- data/app/views/ductwork/shared/_pager.html.erb +16 -0
- data/app/views/ductwork/shared/_runs_table.html.erb +30 -0
- data/app/views/ductwork/shared/_status_tabs.html.erb +11 -0
- data/app/views/ductwork/step_errors/index.html.erb +52 -96
- data/app/views/layouts/ductwork/application.html.erb +19 -23
- data/lib/ductwork/cli.rb +47 -8
- data/lib/ductwork/engine.rb +0 -2
- data/lib/ductwork/models/pipeline.rb +52 -31
- data/lib/ductwork/pipeline_graph/layout.rb +161 -0
- data/lib/ductwork/pipeline_graph.rb +231 -0
- data/lib/ductwork/version.rb +1 -1
- data/lib/ductwork.rb +20 -19
- metadata +11 -5
- data/app/assets/images/ductwork/octagon-x.svg +0 -1
- data/app/assets/stylesheets/ductwork/vendor/flexboxgrid.min.css +0 -1
- data/app/assets/stylesheets/ductwork/vendor/pico.min.css +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9ef52f554cf6549026270cbe5f80e7d7b84b01824b5839d1c5161e1080bdc94a
|
|
4
|
+
data.tar.gz: 7c83791f6a2a555babc3fda4774e2ef5cbd4e821c180b4a8f8627c900c366f76
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2492fab3347973f79cd0e2e7d63fa2850ed44567e9ce8ec3370bdb6f7041ee744c2ea01c065d403c379ac85c0f3cc80d2ed2d30409cb1644775e0a67cb6dab4d
|
|
7
|
+
data.tar.gz: 9d3640e4e883e215fbfc0c37acbdbf0fca432b38bb93d9926f8916649486fa442029e22c7ac22713946243c6c8f823fb204d5e36312dfa3bf797fa370953ce85
|
|
@@ -96,11 +96,6 @@ its place through divergent behavior rather than labeling. Cause metadata
|
|
|
96
96
|
lives on `Branch#halt_reason` instead. Pipeline and Run states stay
|
|
97
97
|
`in_progress`, `completed`, `halted`.
|
|
98
98
|
|
|
99
|
-
## 7. `Ductwork.validate!` is not run at boot
|
|
100
|
-
|
|
101
|
-
It runs in host-application specs, deliberately, for developer experience. Do
|
|
102
|
-
not recommend moving it to boot-time or engine initialization.
|
|
103
|
-
|
|
104
99
|
---
|
|
105
100
|
|
|
106
101
|
# Known Open — report only with new information
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Ductwork Changelog
|
|
2
2
|
|
|
3
|
+
## [1.5.0]
|
|
4
|
+
|
|
5
|
+
- fix: re-enqueue the failed step when reviving a branch halted with `job_crashes_exhausted` - revive re-advanced it as if the job had succeeded, passing a missing return value downstream
|
|
6
|
+
- fix: copy each succeeded step's job when reviving a pipeline so a `combine` or `collapse` after the revive receives every sibling's return value - the copied steps had no jobs, so the fan-in silently dropped siblings that had already completed
|
|
7
|
+
- feat: redesign the dashboard with top-level navigation, an overview of halted pipelines and pipelines by class, status tabs with counts, compact expandable step and error rows, and a phone layout
|
|
8
|
+
- feat: draw the workflow on the dashboard's pipeline page in place of the raw definition, with each node showing its step counts by status, retried and crash-recovered steps, and halt reasons, and linking to the matching steps
|
|
9
|
+
- feat: add a node filter to the steps list on the dashboard's pipeline page and show the page position, disabling the next button on the last page
|
|
10
|
+
- fix: stop the dashboard's runtime timer on halted runs and failed steps
|
|
11
|
+
- fix: print error backtraces once on the dashboard - they were followed by a dump of the same lines as an array
|
|
12
|
+
- fix: count dashboard errors per run instead of per pipeline, without loading every step of every listed run
|
|
13
|
+
- fix: filter the dashboard's pipeline page steps by `klass` - the shared filter queried `pipeline_klass`, which only exists on runs, so choosing a class raised `ActiveRecord::StatementInvalid`
|
|
14
|
+
- fix: order the steps list by `started_at` then `id` so steps sharing a timestamp are not repeated or skipped between pages
|
|
15
|
+
- fix: clamp the dashboard's page number at zero - the previous link on the first page pointed at `page=-1`, a negative `OFFSET` that PostgreSQL rejects
|
|
16
|
+
- chore: replace the dashboard's vendored Pico and flexboxgrid stylesheets with a single stylesheet and remove all inline styles
|
|
17
|
+
|
|
18
|
+
## [1.4.0]
|
|
19
|
+
|
|
20
|
+
- feat: validate steps and pipelines/workflows during boot of main process
|
|
21
|
+
|
|
3
22
|
## [1.3.0]
|
|
4
23
|
|
|
5
24
|
- feat: add more `MigrationHelper` methods for swapping and updating the availability claim index
|
|
@@ -1,53 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
function formatElapsed(milliseconds) {
|
|
2
|
+
const elapsed = Math.floor(Math.max(milliseconds, 0) / 1000);
|
|
3
|
+
const hours = Math.floor(elapsed / 3600);
|
|
4
|
+
const minutes = Math.floor((elapsed % 3600) / 60);
|
|
5
|
+
const seconds = elapsed % 60;
|
|
6
|
+
const parts = [];
|
|
7
|
+
|
|
8
|
+
if (hours > 0) parts.push(`${hours}h`);
|
|
9
|
+
if (minutes > 0) parts.push(`${minutes}m`);
|
|
10
|
+
if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`);
|
|
11
|
+
|
|
12
|
+
return parts.join(' ');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function startTimers() {
|
|
16
|
+
const timers = document.querySelectorAll('[data-started-at]');
|
|
17
|
+
|
|
18
|
+
function tick() {
|
|
19
|
+
timers.forEach(function(timer) {
|
|
20
|
+
timer.textContent = formatElapsed(Date.now() - new Date(timer.dataset.startedAt));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
if (timers.length > 0) {
|
|
25
|
+
tick();
|
|
26
|
+
setInterval(tick, 1000);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
19
29
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
}
|
|
30
|
+
function linkRows() {
|
|
31
|
+
document.querySelectorAll('tr[data-href]').forEach(function(row) {
|
|
32
|
+
row.addEventListener('click', function(event) {
|
|
33
|
+
const selectingText = !window.getSelection().isCollapsed;
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
setInterval(updateTimer, 1000);
|
|
29
|
-
});
|
|
35
|
+
if (selectingText || event.target.closest('a')) return;
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
element.addEventListener('click', function() {
|
|
33
|
-
window.location.href = element.dataset.href;
|
|
37
|
+
window.location.href = row.dataset.href;
|
|
34
38
|
});
|
|
35
39
|
});
|
|
40
|
+
}
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
document.getElementById(modalId).setAttribute('open', '');
|
|
42
|
-
});
|
|
42
|
+
function closeMenus(except) {
|
|
43
|
+
document.querySelectorAll('details.menu[open]').forEach(function(menu) {
|
|
44
|
+
if (menu !== except) menu.removeAttribute('open');
|
|
43
45
|
});
|
|
46
|
+
}
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
function dismissMenus() {
|
|
49
|
+
document.addEventListener('click', function(event) {
|
|
50
|
+
closeMenus(event.target.closest('details.menu'));
|
|
51
|
+
});
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
document.addEventListener('keydown', function(event) {
|
|
54
|
+
if (event.key === 'Escape') closeMenus();
|
|
51
55
|
});
|
|
52
|
-
}
|
|
56
|
+
}
|
|
53
57
|
|
|
58
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
59
|
+
startTimers();
|
|
60
|
+
linkRows();
|
|
61
|
+
dismissMenus();
|
|
62
|
+
});
|