ductwork 1.3.0 → 1.4.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 +4 -0
- data/lib/ductwork/cli.rb +47 -8
- data/lib/ductwork/version.rb +1 -1
- data/lib/ductwork.rb +20 -19
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 01b3ce0336857fcaf0dcaf6beb6b02f002186bd5a94df0c05761cfcd49e8a7e9
|
|
4
|
+
data.tar.gz: cbef9120711ddf5a42819f68dd44871965681317695c6244e732e8e0228b4218
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 315615bb86d68fdcb29bf8dd96d987c79be645a551a85e45825f1a623de9099a8a8ec6e9ef64465eaab259406aa82151a5f76959d10cde2f43bfd7381d5b34bd
|
|
7
|
+
data.tar.gz: 11b3af06290fa9c3261ef1cdc5ee98e45e2e103988c3b2b11fe07dc9d873c441b82ddfe3a091f1e5da6b487d0af1343e1d3b021049e01705f1c7f2bb94788050
|
|
@@ -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
data/lib/ductwork/cli.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "optparse"
|
|
|
5
5
|
module Ductwork
|
|
6
6
|
class CLI
|
|
7
7
|
DEFAULT_COMMAND = "start"
|
|
8
|
+
BACKTRACE_FRAME_LIMIT = 5
|
|
8
9
|
|
|
9
10
|
def self.start!(args)
|
|
10
11
|
new(args).start!
|
|
@@ -31,8 +32,9 @@ module Ductwork
|
|
|
31
32
|
|
|
32
33
|
def start!
|
|
33
34
|
parse!
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
configure
|
|
36
|
+
validate!
|
|
37
|
+
execute
|
|
36
38
|
end
|
|
37
39
|
|
|
38
40
|
private
|
|
@@ -44,9 +46,9 @@ module Ductwork
|
|
|
44
46
|
top_level_parser.order(raw_args)
|
|
45
47
|
@command = raw_args.shift || DEFAULT_COMMAND
|
|
46
48
|
|
|
47
|
-
if
|
|
49
|
+
if start_command?
|
|
48
50
|
start_command_parser.parse!(raw_args)
|
|
49
|
-
elsif
|
|
51
|
+
elsif health_check_command?
|
|
50
52
|
health_command_parser.parse!(raw_args)
|
|
51
53
|
else
|
|
52
54
|
warn "Unknown command: #{command}"
|
|
@@ -55,7 +57,15 @@ module Ductwork
|
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
59
|
|
|
58
|
-
def
|
|
60
|
+
def start_command?
|
|
61
|
+
command == "start"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def health_check_command?
|
|
65
|
+
command == "health"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def configure
|
|
59
69
|
configuration_options[:role] = ENV.fetch("DUCTWORK_ROLE", nil)
|
|
60
70
|
Ductwork.configuration = Configuration.new(**configuration_options)
|
|
61
71
|
Ductwork.logger = if Ductwork.configuration.logger_source == "rails"
|
|
@@ -82,10 +92,39 @@ module Ductwork
|
|
|
82
92
|
BANNER
|
|
83
93
|
end
|
|
84
94
|
|
|
85
|
-
def
|
|
86
|
-
if
|
|
95
|
+
def validate!
|
|
96
|
+
if start_command?
|
|
97
|
+
Ductwork.validate!
|
|
98
|
+
end
|
|
99
|
+
rescue StandardError => e
|
|
100
|
+
report_invalid_definitions(e)
|
|
101
|
+
exit 1
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def report_invalid_definitions(error)
|
|
105
|
+
warn "ductwork failed to validate your step and pipeline definitions"
|
|
106
|
+
warn ""
|
|
107
|
+
warn " #{error.class}: #{error.message}"
|
|
108
|
+
|
|
109
|
+
definition_frames(error).each do |frame|
|
|
110
|
+
warn " #{frame}"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def definition_frames(error)
|
|
115
|
+
frames = error.backtrace.to_a
|
|
116
|
+
|
|
117
|
+
return frames if Ductwork.logger.debug?
|
|
118
|
+
|
|
119
|
+
application_frames = frames.grep(/\A#{Regexp.escape(Rails.root.to_s)}/)
|
|
120
|
+
|
|
121
|
+
(application_frames.presence || frames).first(BACKTRACE_FRAME_LIMIT)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def execute
|
|
125
|
+
if start_command?
|
|
87
126
|
launch_processes
|
|
88
|
-
elsif
|
|
127
|
+
elsif health_check_command?
|
|
89
128
|
check_health
|
|
90
129
|
end
|
|
91
130
|
end
|
data/lib/ductwork/version.rb
CHANGED
data/lib/ductwork.rb
CHANGED
|
@@ -10,6 +10,14 @@ require "securerandom"
|
|
|
10
10
|
require "zeitwerk"
|
|
11
11
|
|
|
12
12
|
module Ductwork
|
|
13
|
+
DEFINITION_DIRECTORIES = %w[
|
|
14
|
+
app/steps
|
|
15
|
+
app/pipelines
|
|
16
|
+
app/workflows
|
|
17
|
+
].freeze
|
|
18
|
+
|
|
19
|
+
class LoadPathError < StandardError; end
|
|
20
|
+
|
|
13
21
|
class << self
|
|
14
22
|
attr_accessor :app_executor, :loader, :logger
|
|
15
23
|
attr_writer :configuration, :defined_pipelines, :hooks
|
|
@@ -67,25 +75,18 @@ module Ductwork
|
|
|
67
75
|
end
|
|
68
76
|
|
|
69
77
|
def validate!
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if pipeline_directory.exist?
|
|
84
|
-
loader.eager_load_dir(pipeline_directory)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
if workflow_directory.exist?
|
|
88
|
-
loader.eager_load_dir(workflow_directory)
|
|
78
|
+
loader = Rails.autoloaders.main
|
|
79
|
+
|
|
80
|
+
DEFINITION_DIRECTORIES.each do |relative|
|
|
81
|
+
directory = Rails.root.join(relative)
|
|
82
|
+
|
|
83
|
+
if directory.exist?
|
|
84
|
+
begin
|
|
85
|
+
loader.eager_load_dir(directory)
|
|
86
|
+
rescue Zeitwerk::Error => e
|
|
87
|
+
raise LoadPathError, "#{directory} exists but is not autoloadable: #{e.message}"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
89
90
|
end
|
|
90
91
|
|
|
91
92
|
true
|