houston-core 0.7.0.beta3 → 0.7.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +56 -56
- data/app/assets/javascripts/houston/app/infinite_scroll.coffee +6 -2
- data/app/assets/javascripts/houston/app/models/ticket.coffee +0 -42
- data/app/assets/javascripts/houston/app/ticket_tracker_refresh.coffee +0 -2
- data/app/assets/javascripts/houston/app/views/keyboard_shortcuts_modal.coffee +0 -6
- data/app/assets/javascripts/houston/core/handlebars_helpers.coffee +0 -5
- data/app/assets/stylesheets/houston/application/actions.scss +15 -0
- data/app/assets/stylesheets/houston/application/layout.scss +3 -0
- data/app/assets/stylesheets/houston/application/markdown.scss +1 -1
- data/app/assets/stylesheets/houston/application/navigation.scss +3 -1
- data/app/assets/stylesheets/houston/application/project_banner_buttons.scss +2 -0
- data/app/assets/stylesheets/houston/application/tables.scss +0 -1
- data/app/assets/stylesheets/houston/application/timeline.scss +1 -1
- data/app/assets/stylesheets/houston/core/overrides.scss +2 -1
- data/app/concerns/houston/props.rb +11 -4
- data/app/concerns/project_adapter.rb +1 -1
- data/app/concerns/unique_add.rb +1 -1
- data/app/controllers/actions_controller.rb +39 -0
- data/app/controllers/commits_controller.rb +1 -1
- data/app/controllers/errors_controller.rb +10 -0
- data/app/controllers/hooks_controller.rb +1 -1
- data/app/controllers/omnibar_controller.rb +1 -11
- data/app/controllers/project_hooks_controller.rb +2 -2
- data/app/controllers/projects_controller.rb +2 -0
- data/app/controllers/test_runs_controller.rb +14 -3
- data/app/controllers/triggers_controller.rb +8 -0
- data/app/helpers/actions_helper.rb +7 -0
- data/app/helpers/application_helper.rb +1 -1
- data/app/interactors/cache_key_dependencies.rb +1 -1
- data/app/interactors/test_run_comparer.rb +1 -1
- data/app/mailers/project_notification.rb +0 -31
- data/app/models/ability.rb +0 -11
- data/app/models/{job.rb → action.rb} +19 -7
- data/app/models/commit.rb +2 -2
- data/app/models/deploy.rb +3 -3
- data/app/models/github/comment_event.rb +9 -3
- data/app/models/github/post_receive_event.rb +1 -1
- data/app/models/github/pull_request.rb +5 -5
- data/app/models/persistent_trigger.rb +46 -0
- data/app/models/project.rb +0 -1
- data/app/models/release.rb +1 -1
- data/app/models/run_tests_on_post_receive.rb +17 -17
- data/app/models/task.rb +4 -4
- data/app/models/test_run.rb +18 -5
- data/app/models/ticket.rb +2 -21
- data/app/models/ticket_antecedent.rb +3 -3
- data/app/models/user.rb +0 -1
- data/app/views/actions/index.html.erb +69 -0
- data/app/views/actions/show.html.erb +45 -0
- data/app/views/commits/show.html.erb +7 -8
- data/app/views/errors/_actions.html.erb +11 -0
- data/app/views/errors/index.html.erb +39 -0
- data/app/views/layouts/_mobile_navigation.html.erb +1 -9
- data/app/views/layouts/_navigation.html.erb +14 -8
- data/app/views/layouts/application.html.erb +1 -3
- data/app/views/project_notification/test_run.html.erb +13 -3
- data/app/views/projects/_form.html.erb +13 -7
- data/app/views/triggers/index.html.erb +39 -0
- data/config/initializers/add_navigation_renderers.rb +0 -6
- data/config/initializers/houston_async.rb +4 -2
- data/config/initializers/houston_scheduler_daemon.rb +6 -0
- data/config/initializers/load_persistent_triggers.rb +7 -0
- data/config/initializers/requirements.rb +2 -1
- data/config/initializers/sync_commits_on_post_receive.rb +2 -2
- data/config/routes.rb +17 -15
- data/db/migrate/20160711170921_rename_jobs_to_actions.rb +5 -0
- data/db/migrate/20160713204605_add_trigger_and_params_to_actions.rb +6 -0
- data/db/migrate/20160715173039_create_persistent_triggers.rb +10 -0
- data/db/structure.sql +197 -221
- data/houston-core.gemspec +1 -1
- data/lib/houston/boot/actions.rb +105 -0
- data/lib/houston/boot/active_record_serializer.rb +24 -0
- data/lib/houston/boot/configuration.rb +118 -49
- data/lib/houston/boot/events.rb +46 -0
- data/lib/houston/boot/extensions.rb +118 -14
- data/lib/houston/boot/observer.rb +122 -24
- data/lib/houston/boot/readonly_hash_serializer.rb +15 -0
- data/lib/houston/boot/serializer.rb +83 -0
- data/lib/houston/boot/ticket_antecedent_serializer.rb +21 -0
- data/lib/houston/boot/timer.rb +45 -0
- data/lib/houston/boot/triggers.rb +75 -0
- data/lib/houston/boot.rb +5 -0
- data/lib/houston/version.rb +1 -1
- data/lib/params_serializer.rb +18 -0
- data/lib/tasks/actions.rake +12 -0
- data/lib/tasks/events.rake +11 -0
- data/templates/new-instance/config/abilities.rb +0 -8
- data/templates/new-instance/config/{triggers → events}/alerts/slack_when_assigned.rb +1 -1
- data/templates/new-instance/config/{triggers → events}/alerts/slack_when_opened.rb +1 -1
- data/templates/new-instance/config/{triggers → events}/daemons/health.rb +6 -6
- data/templates/new-instance/config/{triggers → events}/deploy/autoresolve_errs.rb +1 -1
- data/templates/new-instance/config/{triggers → events}/deploy/checkout_mentioned_alerts.rb +1 -1
- data/templates/new-instance/config/{triggers → events}/deploy/notify_deployer_when_finished.rb +2 -2
- data/templates/new-instance/config/{triggers → events}/github/publish_comments_on_slack.rb +9 -9
- data/templates/new-instance/config/{triggers → events}/tests/slack_when_analyzed.rb +1 -1
- data/templates/new-instance/config/{triggers → events}/tests/slack_when_completed.rb +1 -1
- data/templates/new-instance/config/{triggers → events}/tickets/mark_tasks_completed_on_commit.rb +1 -1
- data/templates/new-instance/config/main.rb +8 -35
- data/templates/new-instance/config/{jobs → timers}/cache_key_dependencies.rb +0 -0
- data/templates/new-instance/config/{jobs → timers}/email_about_open_alerts.rb +0 -0
- data/templates/new-instance/config/{jobs → timers}/purge_jobs.rb +0 -0
- data/templates/new-instance/config/{jobs → timers}/slack_reminders_about_alerts.rb +0 -0
- data/templates/new-instance/config/{jobs → timers}/sync_commits.rb +0 -0
- data/templates/new-instance/config/{jobs → timers}/sync_pull_requests.rb +0 -0
- data/templates/new-instance/config/{jobs → timers}/sync_tickets.rb +0 -0
- data/templates/new-module/lib/houston/%name%.rb +13 -0
- data/test/integration/ci_integration_test.rb +5 -5
- data/test/integration/web_hook_test.rb +1 -1
- data/test/test_helper.rb +14 -0
- data/test/unit/controllers/hooks_controller_test.rb +2 -2
- data/test/unit/initializers/sync_commits_on_post_receive_test.rb +1 -1
- data/test/unit/models/actions_test.rb +107 -0
- data/test/unit/models/configuration_test.rb +108 -0
- data/test/unit/models/observer_test.rb +87 -3
- data/test/unit/models/persistent_trigger_test.rb +94 -0
- data/test/unit/models/serializer_test.rb +80 -0
- data/test/unit/models/triggers_test.rb +53 -0
- metadata +60 -60
- data/app/assets/javascripts/houston/app/models/testing_note.coffee +0 -18
- data/app/assets/javascripts/houston/app/views/commit_view.coffee +0 -13
- data/app/assets/javascripts/houston/app/views/testing_note_view.coffee +0 -85
- data/app/assets/javascripts/houston/app/views/testing_report_view.coffee +0 -29
- data/app/assets/javascripts/houston/app/views/testing_ticket_view.coffee +0 -203
- data/app/assets/stylesheets/houston/application/jobs.scss +0 -5
- data/app/assets/stylesheets/houston/application/testing_report.scss +0 -279
- data/app/assets/templates/commit.hbs +0 -9
- data/app/assets/templates/testing_notes/edit.hbs +0 -20
- data/app/assets/templates/testing_notes/new.hbs +0 -27
- data/app/assets/templates/testing_notes/show.hbs +0 -11
- data/app/assets/templates/testing_report/description.hbs +0 -12
- data/app/assets/templates/testing_report/ticket.hbs +0 -21
- data/app/assets/templates/testing_report/verdict.hbs +0 -4
- data/app/controllers/jobs_controller.rb +0 -42
- data/app/controllers/testing_notes_controller.rb +0 -50
- data/app/controllers/testing_report_controller.rb +0 -38
- data/app/models/testing_note.rb +0 -64
- data/app/presenters/testing_note_presenter.rb +0 -27
- data/app/presenters/testing_report_ticket_presenter.rb +0 -71
- data/app/views/jobs/index.html.erb +0 -72
- data/app/views/jobs/show.html.erb +0 -41
- data/app/views/project_notification/testing_note.html.erb +0 -9
- data/app/views/testing_report/_scripts.html.erb +0 -12
- data/app/views/testing_report/index.html.erb +0 -31
- data/app/views/testing_report/show.html.erb +0 -29
- data/config/initializers/houston_scheduler.rb +0 -23
- data/db/migrate/20120424212706_create_testing_notes.rb +0 -14
- data/db/migrate/20120501231817_add_expires_at_to_testing_notes.rb +0 -5
- data/db/migrate/20120501231948_add_unfuddle_id_to_testing_notes.rb +0 -5
- data/db/migrate/20120715230526_change_testing_notes_comment_to_text.rb +0 -9
- data/db/migrate/20130211015046_add_min_passing_verdicts_to_projects.rb +0 -5
- data/db/migrate/20130407220039_add_project_id_to_testing_notes.rb +0 -26
- data/db/migrate/20140511024021_rename_testing_notes_unfuddle_id_to_remote_id.rb +0 -5
- data/templates/new-instance/config/triggers/tickets/email_testing_notes.rb +0 -7
- data/templates/new-instance/log/development.log +0 -41253
- data/templates/new-instance/log/test.log +0 -545
- data/templates/new-module/config/initializers/add_navigation_renderer.rb +0 -3
@@ -2,35 +2,53 @@ require "thread_safe"
|
|
2
2
|
|
3
3
|
module Houston
|
4
4
|
class Observer
|
5
|
+
attr_accessor :async
|
6
|
+
|
7
|
+
class UnregisteredEventError < ArgumentError; end
|
8
|
+
class MissingParamError < ArgumentError; end
|
9
|
+
class UnregisteredParamError < ArgumentError; end
|
5
10
|
|
6
11
|
def initialize
|
7
12
|
@async = true
|
8
13
|
clear!
|
9
14
|
end
|
10
15
|
|
11
|
-
|
16
|
+
def on(event, options={}, &block)
|
17
|
+
assert_registered! event
|
18
|
+
observers_of(event).push Callback.new(self, event, options, block)
|
19
|
+
nil
|
20
|
+
end
|
12
21
|
|
13
|
-
def
|
14
|
-
|
22
|
+
def once(event, options={}, &block)
|
23
|
+
assert_registered! event
|
24
|
+
observers_of(event).push CallbackOnce.new(self, event, options, block)
|
15
25
|
nil
|
16
26
|
end
|
17
27
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
observers_of(event).delete wrapped_block
|
22
|
-
end
|
23
|
-
on(event, &wrapped_block)
|
28
|
+
def off(callback)
|
29
|
+
observers_of(callback.event).delete callback
|
30
|
+
nil
|
24
31
|
end
|
25
32
|
|
26
33
|
def observed?(event)
|
34
|
+
assert_registered! event
|
27
35
|
observers_of(event).any?
|
28
36
|
end
|
29
37
|
|
30
|
-
def fire(event,
|
31
|
-
|
32
|
-
|
33
|
-
|
38
|
+
def fire(event, params={})
|
39
|
+
assert_registered! event
|
40
|
+
|
41
|
+
unless params.is_a?(Hash)
|
42
|
+
raise ArgumentError, "params must be a Hash" unless params.respond_to?(:to_h)
|
43
|
+
params = params.to_h
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_registered_params! event, params
|
47
|
+
assert_serializable! params
|
48
|
+
params = ReadonlyHash.new(params)
|
49
|
+
|
50
|
+
observers_of(event).each do |callback|
|
51
|
+
callback.call params
|
34
52
|
end
|
35
53
|
nil
|
36
54
|
end
|
@@ -40,25 +58,105 @@ module Houston
|
|
40
58
|
end
|
41
59
|
|
42
60
|
private
|
61
|
+
attr_reader :observers
|
62
|
+
|
63
|
+
def observers_of(event)
|
64
|
+
observers[event] ||= ThreadSafe::Array.new
|
65
|
+
end
|
43
66
|
|
44
|
-
def
|
45
|
-
Houston.
|
46
|
-
|
67
|
+
def assert_registered!(event_name)
|
68
|
+
return if Houston.registered_event?(event_name)
|
69
|
+
raise UnregisteredEventError, "#{event_name.inspect} is not a registered event"
|
70
|
+
end
|
71
|
+
|
72
|
+
def assert_registered_params!(event_name, params)
|
73
|
+
event = Houston.get_registered_event(event_name)
|
74
|
+
|
75
|
+
missing_params = event.params - params.keys.map(&:to_s)
|
76
|
+
unregistered_params = params.keys.map(&:to_s) - event.params
|
77
|
+
if missing_params.any?
|
78
|
+
raise MissingParamError, "#{missing_params.first.inspect} is a required param of the event #{event_name.inspect}"
|
79
|
+
end
|
80
|
+
if unregistered_params.any?
|
81
|
+
raise UnregisteredParamError, "#{unregistered_params.first.inspect} is a not a registered param of the event #{event_name.inspect}"
|
47
82
|
end
|
48
83
|
end
|
49
84
|
|
50
|
-
def
|
51
|
-
|
52
|
-
rescue Exception # rescues StandardError by default; but we want to rescue and report all errors
|
53
|
-
$!.additional_information[:event] = event
|
54
|
-
Houston.report_exception($!)
|
85
|
+
def assert_serializable!(params)
|
86
|
+
Houston::Serializer.new.assert_serializable!(params)
|
55
87
|
end
|
56
88
|
|
57
|
-
|
58
|
-
|
89
|
+
|
90
|
+
|
91
|
+
class Callback
|
92
|
+
attr_reader :observer, :event
|
93
|
+
|
94
|
+
def initialize(observer, event, options, block)
|
95
|
+
@observer = observer
|
96
|
+
@event = event
|
97
|
+
@invoke_async = options.fetch(:async, nil)
|
98
|
+
@raise_exceptions = options.fetch(:raise, false)
|
99
|
+
@block = block
|
100
|
+
end
|
101
|
+
|
102
|
+
def invoke_async?
|
103
|
+
return @invoke_async unless @invoke_async.nil?
|
104
|
+
Houston.observer.async
|
105
|
+
end
|
106
|
+
|
107
|
+
def raise_exceptions?
|
108
|
+
@raise_exceptions
|
109
|
+
end
|
110
|
+
|
111
|
+
def call(params)
|
112
|
+
Houston.async(invoke_async?) do
|
113
|
+
begin
|
114
|
+
@block.call(params)
|
115
|
+
|
116
|
+
rescue Exception # rescues StandardError by default; but we want to rescue and report all errors
|
117
|
+
raise if raise_exceptions?
|
118
|
+
|
119
|
+
$!.additional_information[:event] = event
|
120
|
+
$!.additional_information[:async] = invoke_async?
|
121
|
+
$!.additional_information[:raise_exceptions] = raise_exceptions?
|
122
|
+
Houston.report_exception($!)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
59
127
|
end
|
60
128
|
|
61
|
-
|
129
|
+
class CallbackOnce < Callback
|
130
|
+
def call(params)
|
131
|
+
observer.off self
|
132
|
+
super
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
class ReadonlyHash
|
141
|
+
|
142
|
+
def initialize(hash)
|
143
|
+
@hash = hash.symbolize_keys
|
144
|
+
@hash.keys.each do |key|
|
145
|
+
define_singleton_method(key) { @hash[key] }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def [](key)
|
150
|
+
@hash[key.to_sym]
|
151
|
+
end
|
152
|
+
|
153
|
+
def count
|
154
|
+
@hash.count
|
155
|
+
end
|
156
|
+
|
157
|
+
def to_h
|
158
|
+
@hash.dup
|
159
|
+
end
|
62
160
|
|
63
161
|
end
|
64
162
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "oj"
|
2
|
+
|
3
|
+
Oj.register_odd(Date, Date, :iso8601, :iso8601)
|
4
|
+
Oj.register_odd(DateTime, DateTime, :iso8601, :iso8601)
|
5
|
+
|
6
|
+
module Houston
|
7
|
+
class Serializer
|
8
|
+
class UnserializableError < ArgumentError; end
|
9
|
+
|
10
|
+
def load(string)
|
11
|
+
unpack Oj.load(string, nilnil: true, auto_define: false)
|
12
|
+
end
|
13
|
+
|
14
|
+
def dump(object)
|
15
|
+
Oj.dump pack(object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def assert_serializable!(object)
|
19
|
+
pack(object); nil
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def unpack(object)
|
25
|
+
if object.is_a?(Array)
|
26
|
+
object.map { |item| unpack(item) }
|
27
|
+
elsif object.is_a?(Hash)
|
28
|
+
object = object.each_with_object({}) { |(key, value), new_object| new_object[key] = unpack(value) }
|
29
|
+
if serializer = object["^S"]
|
30
|
+
object = serializer.constantize.new.unpack(object)
|
31
|
+
end
|
32
|
+
object
|
33
|
+
else
|
34
|
+
object
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def pack(object)
|
39
|
+
case object
|
40
|
+
when Array
|
41
|
+
object.map { |item| pack(item) }
|
42
|
+
when Hash
|
43
|
+
object.each_with_object({}) do |(key, value), new_object|
|
44
|
+
unless key.is_a?(String) || key.is_a?(Symbol)
|
45
|
+
raise UnserializableError, "Hash keys must be either strings or symbols"
|
46
|
+
end
|
47
|
+
new_object[key] = pack(value)
|
48
|
+
end
|
49
|
+
when ActiveSupport::TimeWithZone
|
50
|
+
object.to_datetime
|
51
|
+
when *SERIALIZABLE_TYPES
|
52
|
+
object
|
53
|
+
else
|
54
|
+
Houston.serializers.each do |serializer|
|
55
|
+
next unless serializer.applies_to?(object)
|
56
|
+
packed_object = serializer.pack(object)
|
57
|
+
packed_object.merge!("^S" => serializer.class.name) if serializer.respond_to?(:unpack)
|
58
|
+
return pack(packed_object)
|
59
|
+
end
|
60
|
+
|
61
|
+
raise UnserializableError, <<-STR.squish
|
62
|
+
Unable to serialize a #{object.class} (#{object.inspect})
|
63
|
+
You can add a serializer for it with `Houston.add_serializer`
|
64
|
+
STR
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
SERIALIZABLE_TYPES = [
|
69
|
+
BigDecimal,
|
70
|
+
Date,
|
71
|
+
DateTime,
|
72
|
+
FalseClass,
|
73
|
+
Fixnum,
|
74
|
+
Float,
|
75
|
+
NilClass,
|
76
|
+
String,
|
77
|
+
Symbol,
|
78
|
+
Time,
|
79
|
+
TrueClass
|
80
|
+
].freeze
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Houston
|
2
|
+
class TicketAntecedentSerializer
|
3
|
+
|
4
|
+
def applies_to?(object)
|
5
|
+
object.is_a?(TicketAntecedent)
|
6
|
+
end
|
7
|
+
|
8
|
+
def pack(antecedent)
|
9
|
+
{ "ticket_or_commit" => antecedent.ticket_or_commit,
|
10
|
+
"kind" => antecedent.kind,
|
11
|
+
"id" => antecedent.id }
|
12
|
+
end
|
13
|
+
|
14
|
+
def unpack(object)
|
15
|
+
TicketAntecedent.new *object.values_at("ticket_or_commit", "kind", "id")
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Houston.add_serializer Houston::TicketAntecedentSerializer.new
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "thread_safe"
|
2
|
+
|
3
|
+
module Houston
|
4
|
+
class Timer
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@queued_timers = ThreadSafe::Array.new
|
8
|
+
|
9
|
+
Houston.observer.on "daemon:scheduler:start", raise: true do
|
10
|
+
schedule_queued_timers!
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def at(time, &block)
|
15
|
+
return schedule_later :at, time, block unless $scheduler
|
16
|
+
|
17
|
+
days_of_the_week = :day
|
18
|
+
days_of_the_week, time = *time if time.is_a?(Array)
|
19
|
+
cronline = Whenever::Output::Cron.new(days_of_the_week, nil, time)
|
20
|
+
$scheduler.cron cronline.time_in_cron_syntax, &block
|
21
|
+
end
|
22
|
+
|
23
|
+
def every(interval, &block)
|
24
|
+
return schedule_later :every, interval, block unless $scheduler
|
25
|
+
|
26
|
+
$scheduler.every interval, &block
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :queued_timers
|
32
|
+
|
33
|
+
def schedule_later(*args)
|
34
|
+
queued_timers.push args
|
35
|
+
end
|
36
|
+
|
37
|
+
def schedule_queued_timers!
|
38
|
+
while timer = queued_timers.pop
|
39
|
+
method_name, value, block = timer
|
40
|
+
public_send method_name, value, &block
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "thread_safe"
|
2
|
+
require "delegate"
|
3
|
+
|
4
|
+
module Houston
|
5
|
+
class DuplicateTriggerError < ArgumentError; end
|
6
|
+
|
7
|
+
|
8
|
+
class Triggers < SimpleDelegator
|
9
|
+
attr_reader :config
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
super ThreadSafe::Array.new
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def at(value, action, params={})
|
18
|
+
push build(:at, value, action, params)
|
19
|
+
end
|
20
|
+
|
21
|
+
def every(value, action, params={})
|
22
|
+
push build(:every, value, action, params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def on(event, action, params={})
|
26
|
+
push build(:on, event, action, params)
|
27
|
+
end
|
28
|
+
|
29
|
+
def build(method_name, value, action, params)
|
30
|
+
Trigger.new(self, method_name, value, action, params)
|
31
|
+
end
|
32
|
+
|
33
|
+
def push(trigger)
|
34
|
+
raise DuplicateTriggerError, "That exact trigger has already been defined" if member?(trigger)
|
35
|
+
super trigger
|
36
|
+
trigger.register!
|
37
|
+
trigger
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class Trigger < Struct.new(:method_name, :value, :action, :params)
|
44
|
+
|
45
|
+
def initialize(triggers, *args)
|
46
|
+
@triggers = triggers
|
47
|
+
super *args
|
48
|
+
end
|
49
|
+
|
50
|
+
def register!
|
51
|
+
case method_name
|
52
|
+
when :at then config.timer.at(value, &method(:call))
|
53
|
+
when :every then config.timer.every(value, &method(:call))
|
54
|
+
when :on then config.observer.on(value, &method(:call))
|
55
|
+
else raise NotImplementedError, "Unrecognized method name: #{method_name.inspect}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def call(params={})
|
60
|
+
config.actions.run action, self.params.merge(params.to_h), trigger: to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
"#{method_name}(#{value})"
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
attr_reader :triggers
|
69
|
+
|
70
|
+
def config
|
71
|
+
triggers.config
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
data/lib/houston/boot.rb
CHANGED
@@ -2,3 +2,8 @@ require "houston/boot/configuration"
|
|
2
2
|
require "houston/boot/server"
|
3
3
|
require "houston/boot/daemonize"
|
4
4
|
require "houston/boot/extensions"
|
5
|
+
require "houston/boot/events"
|
6
|
+
|
7
|
+
require "houston/boot/active_record_serializer"
|
8
|
+
require "houston/boot/readonly_hash_serializer"
|
9
|
+
require "houston/boot/ticket_antecedent_serializer"
|
data/lib/houston/version.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "houston/boot/serializer"
|
2
|
+
|
3
|
+
module Houston
|
4
|
+
class ParamsSerializer < Serializer
|
5
|
+
|
6
|
+
def load(string)
|
7
|
+
super(string || "{}")
|
8
|
+
end
|
9
|
+
|
10
|
+
def dump(object)
|
11
|
+
object = {} if object.nil?
|
12
|
+
object = object.to_h if !object.is_a?(Hash) && object.respond_to?(:to_h)
|
13
|
+
raise ArgumentError, "params must be a Hash, but it is a #{object.class}" unless object.is_a?(Hash)
|
14
|
+
super object
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
namespace :houston do
|
2
|
+
desc "Lists actions"
|
3
|
+
task :actions do
|
4
|
+
actions = Houston.actions.to_a
|
5
|
+
longest_name = actions.map { |action| action.name.length }.max
|
6
|
+
longest_params = actions.map { |action| action.required_params.join(", ").length }.max
|
7
|
+
actions.sort_by(&:name).each do |action|
|
8
|
+
params = "#{action.required_params.join(", ")}" if action.required_params.any?
|
9
|
+
puts " \e[36m#{action.name.ljust(longest_name)}\e[0m \e[96m#{params.to_s.ljust(longest_params)}\e[0m"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
namespace :houston do
|
2
|
+
desc "Lists registered events and their descriptions"
|
3
|
+
task :events do
|
4
|
+
longest_name = Houston.events.map { |event| event.name.length }.max
|
5
|
+
longest_params = Houston.events.map { |event| event.params.join(", ").length }.max
|
6
|
+
Houston.events.sort_by(&:name).each do |event|
|
7
|
+
params = "#{event.params.join(", ")}" if event.params.any?
|
8
|
+
puts " \e[36m#{event.name.ljust(longest_name)}\e[0m \e[96m#{params.to_s.ljust(longest_params)}\e[0m #{event.description}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -39,9 +39,6 @@ Houston.config.abilities do |user|
|
|
39
39
|
# Everyone can remove themselves from a role
|
40
40
|
can :destroy, Role, user_id: user.id
|
41
41
|
|
42
|
-
# Everyone can edit their own testing notes
|
43
|
-
can [:update, :destroy], TestingNote, user_id: user.id
|
44
|
-
|
45
42
|
# Developers can
|
46
43
|
# - create tickets
|
47
44
|
# - see other kinds of Release Changes (like Refactors)
|
@@ -54,12 +51,10 @@ Houston.config.abilities do |user|
|
|
54
51
|
end
|
55
52
|
|
56
53
|
# Testers and Developers can
|
57
|
-
# - see and comment on all testing notes
|
58
54
|
# - create tickets
|
59
55
|
# - see and manage alerts
|
60
56
|
if user.tester? or user.developer?
|
61
57
|
can :create, Ticket
|
62
|
-
can [:create, :read], TestingNote
|
63
58
|
can :manage, Houston::Alerts::Alert
|
64
59
|
end
|
65
60
|
|
@@ -67,9 +62,6 @@ Houston.config.abilities do |user|
|
|
67
62
|
roles = user.roles.participants
|
68
63
|
if roles.any?
|
69
64
|
|
70
|
-
# Everyone can see and comment on Testing Reports for projects they are involved in
|
71
|
-
can [:create, :read], TestingNote, project_id: roles.pluck(:project_id)
|
72
|
-
|
73
65
|
# Maintainers can manage Releases, close Tickets, and update Projects
|
74
66
|
roles.maintainers.pluck(:project_id).tap do |project_ids|
|
75
67
|
can :manage, Release, project_id: project_ids
|
@@ -1,5 +1,5 @@
|
|
1
1
|
Houston.config do
|
2
|
-
on "alert:assign"
|
2
|
+
on "alert:assign" => "alert:slack-assignee-of-assignment" do
|
3
3
|
if alert.checked_out_by && alert.updated_by && alert.checked_out_by != alert.updated_by
|
4
4
|
Rails.logger.info "\e[34m[slack] #{alert.type} assigned to \e[1m#{alert.checked_out_by.first_name}\e[0m"
|
5
5
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Houston.config do
|
2
2
|
# Notify #alerts of new alerts
|
3
|
-
on "alert:create"
|
3
|
+
on "alert:create" => "alert:announce-in-slack" do
|
4
4
|
message = "There's a new *#{alert.type}*"
|
5
5
|
message << " for #{alert.project.slug}" if alert.project
|
6
6
|
slack_send_message_to message, "#alerts", attachments: [slack_alert_attachment(alert)]
|
@@ -1,21 +1,21 @@
|
|
1
1
|
Houston.config do
|
2
|
-
on "daemon:scheduler:restart" do
|
2
|
+
on "daemon:scheduler:restart" => "daemon:announce-scheduler-restarted-in-slack" do
|
3
3
|
slack_send_message_to "The thread running Rufus::Scheduler errored out and is attempting to recover", "general"
|
4
4
|
end
|
5
5
|
|
6
|
-
on "daemon:scheduler:stop" do
|
6
|
+
on "daemon:scheduler:stop" => "daemon:announce-scheduler-stopped-in-slack" do
|
7
7
|
slack_send_message_to ":rotating_light: The thread running Rufus::Scheduler has terminated", "general"
|
8
8
|
end
|
9
9
|
|
10
|
-
on "daemon:slack:restart" do
|
10
|
+
on "daemon:slack:restart" => "daemon:announce-slack-restarted-in-slack" do
|
11
11
|
slack_send_message_to "The thread running Slack errored out and is attempting to recover", "general"
|
12
12
|
end
|
13
13
|
|
14
|
-
on "daemon:slack:stop" do
|
14
|
+
on "daemon:slack:stop" => "daemon:announce-slack-stopped-in-slack" do
|
15
15
|
slack_send_message_to ":rotating_light: The thread running Slack has terminated", "general"
|
16
16
|
end
|
17
17
|
|
18
|
-
on "slack:error" do
|
19
|
-
slack_send_message_to "An error occurred\n#{
|
18
|
+
on "slack:error" => "slack:announce-error-in-slack" do
|
19
|
+
slack_send_message_to "An error occurred\n#{message}", "general"
|
20
20
|
end
|
21
21
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
Houston.config do
|
2
|
-
on "github:comment:
|
2
|
+
on "github:comment:commit:create" => "github:slack-when-commit-comment-created" do
|
3
3
|
channel = "##{comment["project"].slug}" if comment["project"]
|
4
4
|
channel = "developers" unless Houston::Slack.connection.channels.include? channel
|
5
5
|
body, url = comment.values_at "body", "html_url"
|
6
6
|
|
7
7
|
message = "#{comment["user"]["login"]} commented on #{slack_link_to(comment["commit_id"][0...7], url)}"
|
8
8
|
|
9
|
-
|
10
|
-
slack_send_message_to message, channel, as: :github, attachments: [
|
9
|
+
attachment = { fallback: body, text: body }
|
10
|
+
slack_send_message_to message, channel, as: :github, attachments: [attachment]
|
11
11
|
end
|
12
12
|
|
13
|
-
on "github:comment:
|
13
|
+
on "github:comment:diff:create" => "github:slack-when-diff-comment-created" do
|
14
14
|
channel = "##{comment["project"].slug}" if comment["project"]
|
15
15
|
channel = "developers" unless Houston::Slack.connection.channels.include? channel
|
16
16
|
body, url = comment.values_at "body", "html_url"
|
@@ -18,11 +18,11 @@ Houston.config do
|
|
18
18
|
message = "#{comment["user"]["login"]} commented on #{slack_link_to(comment["path"], url)}"
|
19
19
|
message << "\n```\n#{comment["diff_hunk"]}\n```\n"
|
20
20
|
|
21
|
-
|
22
|
-
slack_send_message_to message, channel, as: :github, attachments: [
|
21
|
+
attachment = { fallback: body, text: body }
|
22
|
+
slack_send_message_to message, channel, as: :github, attachments: [attachment]
|
23
23
|
end
|
24
24
|
|
25
|
-
on "github:comment:
|
25
|
+
on "github:comment:pull:create" => "github:slack-when-issue-comment-created" do
|
26
26
|
channel = "##{comment["project"].slug}" if comment["project"]
|
27
27
|
channel = "developers" unless Houston::Slack.connection.channels.include? channel
|
28
28
|
body, url = comment.values_at "body", "html_url"
|
@@ -30,7 +30,7 @@ Houston.config do
|
|
30
30
|
issue = comment["issue"]
|
31
31
|
message = "#{comment["user"]["login"]} commented on #{slack_link_to("##{issue["number"]} #{issue["title"]}", url)}"
|
32
32
|
|
33
|
-
|
34
|
-
slack_send_message_to message, channel, as: :github, attachments: [
|
33
|
+
attachment = { fallback: body, text: body }
|
34
|
+
slack_send_message_to message, channel, as: :github, attachments: [attachment]
|
35
35
|
end
|
36
36
|
end
|