ruby_raider 4.0.1 → 4.1.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +59 -1
  3. data/RELEASE.md +12 -0
  4. data/lib/commands/flow_commands.rb +104 -0
  5. data/lib/generators/templates/flows/flow_helper.tt +42 -0
  6. data/lib/generators/templates/flows/run.tt +332 -0
  7. data/lib/ruby_raider.rb +16 -0
  8. data/lib/utilities/flows/next_run.rb +61 -0
  9. data/lib/utilities/flows/notifier.rb +76 -0
  10. data/lib/utilities/flows/os/command_runner.rb +73 -0
  11. data/lib/utilities/flows/os/cron.rb +137 -0
  12. data/lib/utilities/flows/os/launchd.rb +164 -0
  13. data/lib/utilities/flows/os/linux.rb +63 -0
  14. data/lib/utilities/flows/os/systemd.rb +178 -0
  15. data/lib/utilities/flows/os/task_scheduler.rb +179 -0
  16. data/lib/utilities/flows/project.rb +170 -0
  17. data/lib/utilities/flows/run_log.rb +61 -0
  18. data/lib/utilities/flows/runner.rb +206 -0
  19. data/lib/utilities/flows/schedule.rb +221 -0
  20. data/lib/utilities/flows/schedule_store.rb +135 -0
  21. data/lib/utilities/flows/scheduler.rb +187 -0
  22. data/lib/version +1 -1
  23. data/sig/commands/flow_commands.rbs +13 -0
  24. data/sig/ruby_raider.rbs +2 -0
  25. data/sig/utilities/flows/next_run.rbs +15 -0
  26. data/sig/utilities/flows/notifier.rbs +29 -0
  27. data/sig/utilities/flows/os/command_runner.rbs +27 -0
  28. data/sig/utilities/flows/os/cron.rbs +34 -0
  29. data/sig/utilities/flows/os/launchd.rbs +45 -0
  30. data/sig/utilities/flows/os/linux.rbs +27 -0
  31. data/sig/utilities/flows/os/systemd.rbs +43 -0
  32. data/sig/utilities/flows/os/task_scheduler.rbs +53 -0
  33. data/sig/utilities/flows/project.rbs +46 -0
  34. data/sig/utilities/flows/run_log.rbs +22 -0
  35. data/sig/utilities/flows/runner.rbs +35 -0
  36. data/sig/utilities/flows/schedule.rbs +61 -0
  37. data/sig/utilities/flows/schedule_store.rbs +34 -0
  38. data/sig/utilities/flows/scheduler.rbs +42 -0
  39. data/spec/commands/flow_commands_spec.rb +128 -0
  40. data/spec/generators/flow_helper_spec.rb +40 -0
  41. data/spec/integration/content/gemfile_content_spec.rb +2 -2
  42. data/spec/integration/end_to_end_spec.rb +63 -0
  43. data/spec/integration/flows/flow_project.rb +62 -0
  44. data/spec/integration/flows/run_command_spec.rb +91 -0
  45. data/spec/integration/flows/run_lifecycle_spec.rb +383 -0
  46. data/spec/utilities/flows/next_run_spec.rb +119 -0
  47. data/spec/utilities/flows/notifier_spec.rb +121 -0
  48. data/spec/utilities/flows/os/command_runner_spec.rb +56 -0
  49. data/spec/utilities/flows/os/cron_spec.rb +287 -0
  50. data/spec/utilities/flows/os/launchd_spec.rb +293 -0
  51. data/spec/utilities/flows/os/linux_spec.rb +149 -0
  52. data/spec/utilities/flows/os/systemd_spec.rb +329 -0
  53. data/spec/utilities/flows/os/task_scheduler_spec.rb +505 -0
  54. data/spec/utilities/flows/project_spec.rb +178 -0
  55. data/spec/utilities/flows/run_log_spec.rb +47 -0
  56. data/spec/utilities/flows/runner_spec.rb +313 -0
  57. data/spec/utilities/flows/schedule_spec.rb +233 -0
  58. data/spec/utilities/flows/schedule_store_spec.rb +137 -0
  59. data/spec/utilities/flows/scheduler_spec.rb +329 -0
  60. metadata +53 -2
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'json'
5
+ require 'rbconfig'
6
+ require_relative 'next_run'
7
+ require_relative 'run_log'
8
+ require_relative 'schedule'
9
+ require_relative 'schedule_store'
10
+ require_relative 'os/command_runner'
11
+ require_relative 'os/launchd'
12
+ require_relative 'os/task_scheduler'
13
+ require_relative 'os/linux'
14
+
15
+ module RubyRaider
16
+ module Flows
17
+ # `raider flow schedule | unschedule | schedules`: keeps the OS scheduler entries and
18
+ # .raider/flows/schedules.yml in step. The OS entry is installed first and the yml written after,
19
+ # so the yml never names an entry the OS scheduler refused.
20
+ # :reek:TooManyInstanceVariables { max_instance_variables: 6 } -- the project, its store, the adapter and the injected streams and clock
21
+ class Scheduler
22
+ NOT_SET_UP = 'Flows are not set up in this project: run raider flow init'
23
+ RUBY_NOT_FOUND = 'Ruby not found: re-schedule'
24
+ FLOW_NOT_FOUND = 'flow not found: unschedule'
25
+ LAST = %w[status finished_at trigger failed_step results_dir].freeze
26
+ TIME = '%a %-d %b %H:%M'
27
+
28
+ # The OS scheduler for this machine; only Linux asks the system (is the user's systemd there?)
29
+ def self.adapter(runner: Os::CommandRunner.new, host_os: RbConfig::CONFIG['host_os'])
30
+ case host_os
31
+ when /darwin/ then Os::Launchd.new(runner: runner)
32
+ when /mswin|mingw|cygwin/ then Os::TaskScheduler.new(runner: runner)
33
+ when /linux/ then Os::Linux.pick(runner)
34
+ else raise Error, "Scheduling flows is not supported on #{host_os}"
35
+ end
36
+ end
37
+
38
+ # adapter: nil picks the OS scheduler on first use, so a command refused earlier never touches it
39
+ def initialize(project, adapter: nil, store: ScheduleStore.new(project), out: $stdout, err: $stderr, now: -> { Time.now })
40
+ @project = project
41
+ @adapter = adapter
42
+ @store = store
43
+ @out = out
44
+ @err = err
45
+ @now = now
46
+ end
47
+
48
+ def schedule(name, every:, at: nil, on: nil, retries: 0, inputs: [], notify: false)
49
+ @project.flow_file(name)
50
+ raise Error, NOT_SET_UP unless @project.set_up?
51
+
52
+ now = @now.call
53
+ schedule = Schedule.build(project: @project, name: name, every: every, at: at, on: on, retries: retries,
54
+ inputs: inputs, notify: notify, now: now)
55
+ flow_dir(name)
56
+ @store.writable!
57
+ old = @store.find(name)
58
+ adapter.install(schedule)
59
+ save(schedule)
60
+ prefix = old ? "Replaced the schedule for #{name}" : "Scheduled #{name}"
61
+ @out.puts("#{prefix}: #{rule(schedule)}. Next run #{NextRun.after(schedule, now).strftime(TIME)}.")
62
+ end
63
+
64
+ def unschedule(name)
65
+ raise Error, "Invalid flow name #{name.inspect}: use 1 to 60 of a-z, 0-9 and _ (not env)" unless Flows.valid_name?(name)
66
+
67
+ # The OS entry first: when the scheduler refuses, the yml entry stays to retry with.
68
+ # from_h is strict, so a stored entry's os_id is always this one.
69
+ label = adapter.label
70
+ was_there = adapter.remove(Schedule.os_id_for(@project.root, name))
71
+ removed = delete(name, label)
72
+ raise Error, "No schedule for #{name}" unless removed || was_there
73
+
74
+ @out.puts(was_there ? "Unscheduled #{name}" : "Unscheduled #{name} (it was already gone from #{label})")
75
+ return unless removed.is_a?(ScheduleStore::Removed)
76
+
77
+ @err.puts("The schedules.yml entry for #{name} could not be read: a #{label} entry made from a different project path may remain")
78
+ end
79
+
80
+ def schedules(json: false)
81
+ now = @now.call
82
+ listed = @store.all
83
+ rows = listed.map { |schedule| row(schedule, now) } + unlisted_rows(listed.map(&:name))
84
+ return @out.puts(JSON.generate(rows.map { |entry| entry[:json] })) if json
85
+ return @out.puts('No schedules yet: raider flow schedule <name> --every day --at 08:00') if rows.empty?
86
+
87
+ rows.each { |entry| @out.puts(Flows.printable(entry[:text])) }
88
+ note = adapter.respond_to?(:missed_runs_note) ? adapter.missed_runs_note : nil
89
+ @out.puts(note) if note
90
+ end
91
+
92
+ private
93
+
94
+ def adapter = @adapter ||= Scheduler.adapter
95
+
96
+ # Writes the yml; when that fails the OS entry just installed is removed, so neither names the flow
97
+ def save(schedule)
98
+ @store.save(schedule)
99
+ rescue Error, SystemCallError => e
100
+ label = adapter.label
101
+ begin
102
+ adapter.remove(schedule.os_id)
103
+ rescue Error => remove_error
104
+ raise Error, "#{e.message} (and removing the #{label} entry failed: #{remove_error.message})"
105
+ end
106
+ raise Error, "#{e.message}: the #{label} entry was removed too, so #{schedule.name} is not scheduled"
107
+ end
108
+
109
+ # The OS entry is gone by now: say so when the yml can't be written
110
+ def delete(name, label)
111
+ @store.delete(name)
112
+ rescue Error, SystemCallError => e
113
+ raise Error, "#{e.message}: the #{label} entry was already removed, but schedules.yml still lists #{name}"
114
+ end
115
+
116
+ # .raider/flows/<name>/ for scheduler.log: 0700 folders that are not links, as flows/support/run.rb makes them
117
+ def flow_dir(name)
118
+ [ScheduleStore::DIR, "#{ScheduleStore::DIR}/#{name}"].each { |relative| private_dir(relative) }
119
+ end
120
+
121
+ def private_dir(relative)
122
+ dir = @project.path(relative)
123
+ FileUtils.mkdir_p(dir)
124
+ raise Error, "#{relative} must be a folder, not a link" unless File.lstat(dir).directory?
125
+
126
+ File.chmod(0o700, dir)
127
+ rescue SystemCallError => e
128
+ raise Error, "Could not make #{relative}: #{e.message}"
129
+ end
130
+
131
+ def row(schedule, now)
132
+ name = schedule.name
133
+ next_run = NextRun.after(schedule, now)
134
+ state = os_state(schedule)
135
+ last = last_run(name)
136
+ json = { 'name' => name, 'every' => schedule.every, 'at' => schedule.at, 'on' => schedule.on,
137
+ 'retries' => schedule.retries, 'inputs' => schedule.inputs, 'notify' => schedule.notify, 'next_run_at' => next_run.iso8601,
138
+ 'os_state' => state, 'last' => last }
139
+ { json: json, text: line(name, rule(schedule), "next #{next_run.strftime(TIME)}", last, state) }
140
+ end
141
+
142
+ # Flows the OS scheduler still runs for this project although schedules.yml has no entry for them
143
+ def unlisted_rows(listed)
144
+ (@project.flow_names - listed).filter_map do |name|
145
+ next unless present?(Schedule.os_id_for(@project.root, name))
146
+
147
+ state = 'missing from schedules.yml'
148
+ last = last_run(name)
149
+ json = { 'name' => name, 'every' => nil, 'at' => nil, 'on' => nil, 'retries' => nil, 'inputs' => nil, 'notify' => nil,
150
+ 'next_run_at' => nil, 'os_state' => state, 'last' => last }
151
+ { json: json, text: line(name, '-', '-', last, state) }
152
+ end
153
+ end
154
+
155
+ # A flow whose state can't be read is left out: only a listed schedule gets an unknown row
156
+ def present?(os_id)
157
+ adapter.present?(os_id)
158
+ rescue Error
159
+ false
160
+ end
161
+
162
+ # The OS entry runs `<ruby> <bundle> ...`: ruby is executed, bundle is only read by it
163
+ def os_state(schedule)
164
+ ruby = schedule.ruby
165
+ bundle = schedule.bundle
166
+ return RUBY_NOT_FOUND unless File.file?(ruby) && File.executable?(ruby) && File.file?(bundle) && File.readable?(bundle)
167
+ return FLOW_NOT_FOUND unless File.file?(@project.path("flows/#{schedule.name}_flow.rb"))
168
+
169
+ adapter.present?(schedule.os_id) ? 'ok' : "missing from #{adapter.label}"
170
+ rescue Error => e
171
+ "unknown (#{e.message})"
172
+ end
173
+
174
+ def rule(schedule) = schedule.notify ? "#{schedule.rule_text} (notify)" : schedule.rule_text
175
+
176
+ def last_run(name)
177
+ last = RunLog.new(@project, name).last_result
178
+ last && LAST.to_h { |key| [key, last[key]] }
179
+ end
180
+
181
+ def line(name, rule, next_run, last, state)
182
+ result = last ? "#{last['status']} #{last['finished_at']}" : 'never run'
183
+ "#{name.ljust(30)} #{rule} #{next_run} #{result} #{state}"
184
+ end
185
+ end
186
+ end
187
+ end
data/lib/version CHANGED
@@ -1 +1 @@
1
- 4.0.1
1
+ 4.1.0
@@ -0,0 +1,13 @@
1
+ # Type definitions for FlowCommands
2
+ class FlowCommands < Thor
3
+ def init: () -> void
4
+ def run_flow: (String name) -> void
5
+ def list: () -> void
6
+ def schedule: (String name) -> void
7
+ def unschedule: (String name) -> void
8
+ def schedules: () -> void
9
+ def project: () -> RubyRaider::Flows::Project
10
+ def scheduler: () -> RubyRaider::Flows::Scheduler
11
+ def list_line: (Hash[String, untyped] flow) -> String
12
+ def stop: (RubyRaider::Flows::Error error) -> bot
13
+ end
data/sig/ruby_raider.rbs CHANGED
@@ -1,6 +1,8 @@
1
1
  # Type definitions for main RubyRaider entry point
2
2
  module RubyRaider
3
3
  class Raider < Thor
4
+ def self.start: (?Array[String] given_args, ?Hash[Symbol, untyped] config) -> void
5
+
4
6
  def current_version: () -> String
5
7
 
6
8
  def new: (String project_name) -> void
@@ -0,0 +1,15 @@
1
+ module RubyRaider
2
+ module Flows
3
+ module NextRun
4
+ WDAYS: Array[String]
5
+ SEARCH_DAYS: Integer
6
+ SEARCH_MINUTES: Integer
7
+
8
+ def self?.after: (Schedule schedule, Time now) -> Time
9
+ def self?.next_minute: (Integer minute, Time now) -> Time
10
+ def self?.next_day: (Schedule schedule, Time now) -> Time
11
+ def self?.local: (Date date, Integer hour, Integer minute) -> Time
12
+ def self?.wall: (Time time) -> Array[Integer]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ module RubyRaider
2
+ module Flows
3
+ class Notifier
4
+ MAX: Integer
5
+ TIMEOUT: Integer
6
+ OSASCRIPT: Array[String]
7
+ NOTIFY_SEND: Array[String]
8
+ MARKUP: Hash[String, String]
9
+ TOAST_SCRIPT: String
10
+ POWERSHELL_ARGS: Array[String]
11
+
12
+ @runner: Os::CommandRunner
13
+ @host_os: String
14
+ @err: IO | StringIO
15
+ @warned: bool
16
+ @powershell: String
17
+
18
+ def self.powershell: () -> String
19
+
20
+ def initialize: (?runner: Os::CommandRunner, ?host_os: String, ?err: IO | StringIO, ?powershell: String) -> void
21
+ def notify: (String title, String message) -> bool
22
+
23
+ private
24
+
25
+ def clean: (untyped text) -> String
26
+ def failed: (String reason) -> false
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,27 @@
1
+ module RubyRaider
2
+ module Flows
3
+ module Os
4
+ class CommandRunner
5
+ MISSING: Integer
6
+ TIMED_OUT: Integer
7
+
8
+ class Result
9
+ attr_reader stdout: String
10
+ attr_reader stderr: String
11
+ attr_reader exitstatus: Integer
12
+
13
+ def initialize: (stdout: String, stderr: String, exitstatus: Integer) -> void
14
+ def success?: () -> bool
15
+ end
16
+
17
+ def call: (*String argv, ?stdin_data: String?, ?env: Hash[String, String], ?timeout: Numeric?) -> Result
18
+
19
+ private
20
+
21
+ def reader: (IO io) -> Thread
22
+ def feed: (IO stdin, String? data) -> void
23
+ def timed_out: (String command, Numeric? timeout, untyped wait) -> Result
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ module RubyRaider
2
+ module Flows
3
+ module Os
4
+ class Cron
5
+ CRONTAB: String
6
+ TAG: String
7
+ MAX_LINE: Integer
8
+ OS_ID: Regexp
9
+
10
+ @runner: CommandRunner
11
+
12
+ def initialize: (?runner: CommandRunner) -> void
13
+ def label: () -> String
14
+ def missed_runs_note: () -> String
15
+ def line: (Schedule schedule) -> String
16
+ def install: (Schedule schedule) -> true
17
+ def remove: (String os_id) -> bool
18
+ def present?: (String os_id) -> bool
19
+ def usable?: () -> bool
20
+
21
+ private
22
+
23
+ def fields: (Schedule schedule) -> String
24
+ def weekday: (String day) -> Integer
25
+ def escape: (String word) -> String
26
+ def without: (String table, String os_id) -> [String, bool]
27
+ def our_command?: (String text, String? name) -> bool
28
+ def read: () -> String
29
+ def save: (String table) -> void
30
+ def checked_os_id: (untyped os_id) -> String
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,45 @@
1
+ module RubyRaider
2
+ module Flows
3
+ module Os
4
+ class Launchd
5
+ LAUNCHCTL: String
6
+ PLUTIL: String
7
+ NOFOLLOW: Integer
8
+ ESCAPES: Hash[String, String]
9
+ HEADER: String
10
+ OS_ID: Regexp
11
+
12
+ @runner: CommandRunner
13
+ @home: String
14
+ @uid: Integer
15
+
16
+ def initialize: (?runner: CommandRunner, ?home: String, ?uid: Integer) -> void
17
+ def label: () -> String
18
+ def plist: (Schedule schedule) -> String
19
+ def plist_path: (String os_id) -> String
20
+ def install: (Schedule schedule) -> true
21
+ def remove: (String os_id) -> bool
22
+ def present?: (String os_id) -> bool
23
+
24
+ private
25
+
26
+ def launchctl: (*String args) -> CommandRunner::Result
27
+ def domain: () -> String
28
+ def service: (String os_id) -> String
29
+ def unlink: (String path) -> bool
30
+ def agents_dir: () -> String
31
+ def checked_os_id: (untyped os_id) -> String
32
+ def escape: (untyped text) -> String
33
+ def string: (untyped text) -> Array[String]
34
+ def integer: (Integer number) -> Array[String]
35
+ def array: (Array[Array[String]] items) -> Array[String]
36
+ def dict: (Array[[String, Array[String]]] pairs) -> Array[String]
37
+ def indent: (Array[String] lines) -> Array[String]
38
+ def calendar: (Schedule schedule) -> Array[String]
39
+ def weekday: (String day) -> Integer
40
+ def discard: (String path) -> String
41
+ def write: (String path, String text) -> void
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,27 @@
1
+ module RubyRaider
2
+ module Flows
3
+ module Os
4
+ class Linux
5
+ @primary: Systemd | Cron
6
+ @other: Cron?
7
+ @systemd: Systemd
8
+
9
+ def self.pick: (?CommandRunner runner) -> Linux
10
+
11
+ def initialize: (?runner: CommandRunner, ?systemd: Systemd, ?cron: Cron) -> void
12
+ def label: () -> String
13
+ def missed_runs_note: () -> String?
14
+ def install: (Schedule schedule) -> true
15
+ def remove: (String os_id) -> bool
16
+ def present?: (String os_id) -> bool
17
+
18
+ private
19
+
20
+ def stranded?: (String os_id) -> bool
21
+ def refuse_stranded: (String os_id) -> void
22
+
23
+ def other_present?: (String os_id) -> bool
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ module RubyRaider
2
+ module Flows
3
+ module Os
4
+ class Systemd
5
+ SYSTEMCTL: String
6
+ NOFOLLOW: Integer
7
+ QUOTED: Hash[String, String]
8
+ CALENDAR: Hash[String, String]
9
+ OS_ID: Regexp
10
+ UNSAFE_PATH: Regexp
11
+
12
+ @runner: CommandRunner
13
+ @home: String
14
+ @config_home: String?
15
+
16
+ def initialize: (?runner: CommandRunner, ?home: String, ?config_home: String?) -> void
17
+ def label: () -> String
18
+ def missed_runs_note: () -> nil
19
+ def service: (Schedule schedule) -> String
20
+ def timer: (Schedule schedule) -> String
21
+ def unit_path: (String os_id, String kind) -> String
22
+ def install: (Schedule schedule) -> true
23
+ def remove: (String os_id) -> bool
24
+ def present?: (String os_id) -> bool
25
+ def usable?: () -> bool
26
+ def unit_files?: (String os_id) -> bool
27
+
28
+ private
29
+
30
+ def systemctl: (*String args) -> CommandRunner::Result
31
+ def units_dir: () -> String
32
+ def checked_os_id: (untyped os_id) -> String
33
+ def checked_path: (String path) -> void
34
+ def quote: (String text) -> String
35
+ def specifiers: (String text) -> String
36
+ def unlink: (String path) -> bool
37
+ def discard: (String os_id) -> String
38
+ def write: (Hash[String, String] texts) -> void
39
+ def temp_file: (String path, String text) -> String
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,53 @@
1
+ module RubyRaider
2
+ module Flows
3
+ module Os
4
+ class TaskScheduler
5
+ interface _Clock
6
+ def now: () -> Time
7
+ end
8
+
9
+ FOLDER: String
10
+ ESCAPES: Hash[String, String]
11
+ NAMESPACE: String
12
+ OS_ID: Regexp
13
+ NEEDS_QUOTES: Regexp
14
+ GLOB: Regexp
15
+ EXPANDS: Regexp
16
+ DAY_NAMES: Array[String]
17
+
18
+ @runner: CommandRunner
19
+ @clock: _Clock
20
+ @schtasks: String
21
+
22
+ def self.quote: (String arg) -> String
23
+ def self.glob_quote: (String arg) -> String
24
+ def self.odd_doubled: (String slashes) -> String
25
+ def self.join: (Array[String] args) -> String
26
+
27
+ def initialize: (?runner: CommandRunner, ?clock: _Clock, ?schtasks: String) -> void
28
+ def label: () -> String
29
+ def task_name: (untyped os_id) -> String
30
+ def task_xml: (Schedule schedule) -> String
31
+ def install: (Schedule schedule) -> true
32
+ def remove: (String os_id) -> bool
33
+ def present?: (String os_id) -> bool
34
+
35
+ private
36
+
37
+ def schtasks: (*String args) -> CommandRunner::Result
38
+ def list: () -> CommandRunner::Result
39
+ def listed?: (CommandRunner::Result listing, String name) -> bool
40
+ def refuse_expansion: (Schedule schedule) -> void
41
+ def checked_os_id: (untyped os_id) -> String
42
+ def escape: (untyped value) -> String
43
+ def text: (String name, untyped value) -> Array[String]
44
+ def element: (String tag, Array[untyped] children) -> Array[String]
45
+ def indent: (Array[String] lines) -> Array[String]
46
+ def trigger: (Schedule schedule) -> Array[untyped]
47
+ def calendar: (Schedule schedule, String every) -> Array[String]
48
+ def settings: () -> Array[Array[String]]
49
+ def action: (Schedule schedule) -> Array[Array[String]]
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,46 @@
1
+ module RubyRaider
2
+ module Flows
3
+ NAME: Regexp
4
+ RESERVED: Array[String]
5
+
6
+ def self.valid_name?: (untyped name) -> bool
7
+ def self.printable: (untyped text) -> String
8
+
9
+ class Error < StandardError
10
+ attr_reader exit_code: Integer
11
+
12
+ def initialize: (String message, ?exit_code: Integer) -> void
13
+ end
14
+
15
+ class Project
16
+ UNSUPPORTED: String
17
+ GITIGNORE_LINES: Array[String]
18
+ TEMPLATES: Hash[String, String]
19
+ PIN: Regexp
20
+ FLOWS_PIN: Array[Integer]
21
+
22
+ attr_reader root: String
23
+
24
+ def initialize: (String path) -> void
25
+ def path: (String relative) -> String
26
+ def flow_file: (String name) -> String
27
+ def flow_names: () -> Array[String]
28
+ def set_up?: () -> bool
29
+ def unsupported_reason: () -> String?
30
+ def init: (?out: IO | StringIO, ?err: IO | StringIO) -> Integer
31
+
32
+ private
33
+
34
+ def template_dir: () -> String
35
+ def read: (String relative) -> String?
36
+ def selenium?: (String gemfile) -> bool
37
+ def runtime?: () -> bool
38
+ def old_pin?: (String gemfile) -> bool
39
+ def write_templates: () -> Array[String]
40
+ def add_gitignore_lines: () -> Array[String]
41
+ def pin_gem: () -> bool
42
+ def warn_unknown_pin: (IO | StringIO err) -> void
43
+ def report: (IO | StringIO out, Array[String] created, Array[String] updated, bool pinned) -> void
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,22 @@
1
+ module RubyRaider
2
+ module Flows
3
+ class RunLog
4
+ MAX_BYTES: Integer
5
+ NOFOLLOW: Integer
6
+ NONBLOCK: Integer
7
+ SUMMARY: Array[String]
8
+
9
+ def self.summaries: (Project project) -> Array[Hash[String, untyped]]
10
+
11
+ def initialize: (Project project, String name) -> void
12
+ def lines: () -> Array[Hash[String, untyped]]
13
+ def last: () -> Hash[String, untyped]?
14
+ def last_result: () -> Hash[String, untyped]?
15
+ def find: (String run_id) -> Hash[String, untyped]?
16
+
17
+ private
18
+
19
+ def tail: () -> String
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,35 @@
1
+ module RubyRaider
2
+ module Flows
3
+ class Runner
4
+ EXIT_CODES: Hash[String, Integer]
5
+ INPUT: Regexp
6
+ INPUT_RULE: String
7
+ TRIGGERS: Array[String]
8
+ RETRY_WAIT: Integer
9
+
10
+ def self.spawn: (Hash[String, String?] env, Array[String] argv, String chdir) -> Integer?
11
+ def self.stopped: () -> bool?
12
+ def self.stopped=: (bool) -> bool
13
+ def self.interrupt: (Integer pid) -> void
14
+
15
+ def initialize: (Project project, ?out: IO | StringIO, ?spawner: untyped, ?sleeper: untyped, ?notifier: untyped) -> void
16
+ def run: (String name, ?headed: bool?, ?retries: untyped, ?inputs: Array[String]?, ?trigger: String, ?notify: bool) -> Integer
17
+
18
+ private
19
+
20
+ def attempt_runs: (String name, Integer attempts, Hash[Symbol, untyped] options) -> String
21
+ def notify_failure: (String name, String status, String trigger) -> bool
22
+ def start_output: (String name, String trigger) -> String
23
+ def stopped: (String name, String status) -> String
24
+ def attempt_run: (String name, Integer attempt, Hash[Symbol, untyped] options) -> String
25
+ def run_env: (String name, Integer attempt, String run_id, Hash[Symbol, untyped] options) -> Hash[String, String?]
26
+ def input_env: (Array[String]? inputs) -> Hash[String, String]
27
+ def checked_trigger: (String trigger) -> String
28
+ def checked_retries: (untyped retries) -> Integer
29
+ def report: (String name, Hash[String, untyped]? line, Integer? code) -> void
30
+ def outcome: (Hash[String, untyped] line) -> String
31
+ def failed_step: (untyped step) -> String
32
+ def duration: (Hash[String, untyped] line) -> (Float | String)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,61 @@
1
+ module RubyRaider
2
+ module Flows
3
+ class Schedule
4
+ EVERY: Array[String]
5
+ DAYS: Array[String]
6
+ DAYS_RULE: String
7
+ CLOCK: Regexp
8
+ MINUTE: Regexp
9
+ GEM_ENV: Array[String]
10
+ SYSTEM_PATH: Array[String]
11
+ OS_ID_PREFIX: String
12
+ KEYS: Array[String]
13
+
14
+ attr_reader name: String
15
+ attr_reader every: String
16
+ attr_reader at: String
17
+ attr_reader on: String?
18
+ attr_reader retries: Integer
19
+ attr_reader inputs: Array[String]
20
+ attr_reader notify: bool
21
+ attr_reader os_id: String
22
+ attr_reader ruby: String
23
+ attr_reader bundle: String
24
+ attr_reader gem_env: Hash[String, String]
25
+ attr_reader project_root: String
26
+ attr_reader created_at: String
27
+
28
+ def self.build: (project: Project, name: String, every: String, ?at: String?, ?on: String?, ?retries: untyped, ?inputs: Array[String], ?notify: bool, ?now: Time) -> Schedule
29
+ def self.from_h: (untyped hash, String project_root) -> Schedule
30
+ def self.os_id_for: (String project_root, String name) -> String
31
+ def self.bundle_path: () -> String
32
+ def self.captured_gem_env: () -> Hash[String, String]
33
+
34
+ def initialize: (name: untyped, every: untyped, at: untyped, on: untyped, retries: untyped, inputs: untyped, os_id: untyped, ruby: untyped, bundle: untyped, gem_env: untyped, project_root: untyped, created_at: untyped, ?notify: untyped) -> void
35
+ def hour: () -> Integer
36
+ def minute: () -> Integer
37
+ def days: () -> Array[String]
38
+ def argv: () -> Array[String]
39
+ def env: () -> Hash[String, String]
40
+ def working_directory: () -> String
41
+ def log_path: () -> String
42
+ def rule_text: () -> String
43
+ def to_h: () -> Hash[String, untyped]
44
+
45
+ private
46
+
47
+ def checked_name: (untyped name) -> String
48
+ def checked_every: (untyped every) -> String
49
+ def checked_at: (untyped at) -> String
50
+ def clock: (untyped at) -> String
51
+ def checked_on: (untyped on) -> String?
52
+ def checked_retries: (untyped retries) -> Integer
53
+ def checked_inputs: (untyped inputs) -> Array[String]
54
+ def checked_notify: (untyped notify) -> bool
55
+ def checked_os_id: (untyped os_id) -> String
56
+ def checked_path: (String label, untyped path) -> String
57
+ def checked_gem_env: (untyped gem_env) -> Hash[String, String]
58
+ def checked_text: (String label, untyped text) -> String
59
+ end
60
+ end
61
+ end