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.
Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +56 -56
  3. data/app/assets/javascripts/houston/app/infinite_scroll.coffee +6 -2
  4. data/app/assets/javascripts/houston/app/models/ticket.coffee +0 -42
  5. data/app/assets/javascripts/houston/app/ticket_tracker_refresh.coffee +0 -2
  6. data/app/assets/javascripts/houston/app/views/keyboard_shortcuts_modal.coffee +0 -6
  7. data/app/assets/javascripts/houston/core/handlebars_helpers.coffee +0 -5
  8. data/app/assets/stylesheets/houston/application/actions.scss +15 -0
  9. data/app/assets/stylesheets/houston/application/layout.scss +3 -0
  10. data/app/assets/stylesheets/houston/application/markdown.scss +1 -1
  11. data/app/assets/stylesheets/houston/application/navigation.scss +3 -1
  12. data/app/assets/stylesheets/houston/application/project_banner_buttons.scss +2 -0
  13. data/app/assets/stylesheets/houston/application/tables.scss +0 -1
  14. data/app/assets/stylesheets/houston/application/timeline.scss +1 -1
  15. data/app/assets/stylesheets/houston/core/overrides.scss +2 -1
  16. data/app/concerns/houston/props.rb +11 -4
  17. data/app/concerns/project_adapter.rb +1 -1
  18. data/app/concerns/unique_add.rb +1 -1
  19. data/app/controllers/actions_controller.rb +39 -0
  20. data/app/controllers/commits_controller.rb +1 -1
  21. data/app/controllers/errors_controller.rb +10 -0
  22. data/app/controllers/hooks_controller.rb +1 -1
  23. data/app/controllers/omnibar_controller.rb +1 -11
  24. data/app/controllers/project_hooks_controller.rb +2 -2
  25. data/app/controllers/projects_controller.rb +2 -0
  26. data/app/controllers/test_runs_controller.rb +14 -3
  27. data/app/controllers/triggers_controller.rb +8 -0
  28. data/app/helpers/actions_helper.rb +7 -0
  29. data/app/helpers/application_helper.rb +1 -1
  30. data/app/interactors/cache_key_dependencies.rb +1 -1
  31. data/app/interactors/test_run_comparer.rb +1 -1
  32. data/app/mailers/project_notification.rb +0 -31
  33. data/app/models/ability.rb +0 -11
  34. data/app/models/{job.rb → action.rb} +19 -7
  35. data/app/models/commit.rb +2 -2
  36. data/app/models/deploy.rb +3 -3
  37. data/app/models/github/comment_event.rb +9 -3
  38. data/app/models/github/post_receive_event.rb +1 -1
  39. data/app/models/github/pull_request.rb +5 -5
  40. data/app/models/persistent_trigger.rb +46 -0
  41. data/app/models/project.rb +0 -1
  42. data/app/models/release.rb +1 -1
  43. data/app/models/run_tests_on_post_receive.rb +17 -17
  44. data/app/models/task.rb +4 -4
  45. data/app/models/test_run.rb +18 -5
  46. data/app/models/ticket.rb +2 -21
  47. data/app/models/ticket_antecedent.rb +3 -3
  48. data/app/models/user.rb +0 -1
  49. data/app/views/actions/index.html.erb +69 -0
  50. data/app/views/actions/show.html.erb +45 -0
  51. data/app/views/commits/show.html.erb +7 -8
  52. data/app/views/errors/_actions.html.erb +11 -0
  53. data/app/views/errors/index.html.erb +39 -0
  54. data/app/views/layouts/_mobile_navigation.html.erb +1 -9
  55. data/app/views/layouts/_navigation.html.erb +14 -8
  56. data/app/views/layouts/application.html.erb +1 -3
  57. data/app/views/project_notification/test_run.html.erb +13 -3
  58. data/app/views/projects/_form.html.erb +13 -7
  59. data/app/views/triggers/index.html.erb +39 -0
  60. data/config/initializers/add_navigation_renderers.rb +0 -6
  61. data/config/initializers/houston_async.rb +4 -2
  62. data/config/initializers/houston_scheduler_daemon.rb +6 -0
  63. data/config/initializers/load_persistent_triggers.rb +7 -0
  64. data/config/initializers/requirements.rb +2 -1
  65. data/config/initializers/sync_commits_on_post_receive.rb +2 -2
  66. data/config/routes.rb +17 -15
  67. data/db/migrate/20160711170921_rename_jobs_to_actions.rb +5 -0
  68. data/db/migrate/20160713204605_add_trigger_and_params_to_actions.rb +6 -0
  69. data/db/migrate/20160715173039_create_persistent_triggers.rb +10 -0
  70. data/db/structure.sql +197 -221
  71. data/houston-core.gemspec +1 -1
  72. data/lib/houston/boot/actions.rb +105 -0
  73. data/lib/houston/boot/active_record_serializer.rb +24 -0
  74. data/lib/houston/boot/configuration.rb +118 -49
  75. data/lib/houston/boot/events.rb +46 -0
  76. data/lib/houston/boot/extensions.rb +118 -14
  77. data/lib/houston/boot/observer.rb +122 -24
  78. data/lib/houston/boot/readonly_hash_serializer.rb +15 -0
  79. data/lib/houston/boot/serializer.rb +83 -0
  80. data/lib/houston/boot/ticket_antecedent_serializer.rb +21 -0
  81. data/lib/houston/boot/timer.rb +45 -0
  82. data/lib/houston/boot/triggers.rb +75 -0
  83. data/lib/houston/boot.rb +5 -0
  84. data/lib/houston/version.rb +1 -1
  85. data/lib/params_serializer.rb +18 -0
  86. data/lib/tasks/actions.rake +12 -0
  87. data/lib/tasks/events.rake +11 -0
  88. data/templates/new-instance/config/abilities.rb +0 -8
  89. data/templates/new-instance/config/{triggers → events}/alerts/slack_when_assigned.rb +1 -1
  90. data/templates/new-instance/config/{triggers → events}/alerts/slack_when_opened.rb +1 -1
  91. data/templates/new-instance/config/{triggers → events}/daemons/health.rb +6 -6
  92. data/templates/new-instance/config/{triggers → events}/deploy/autoresolve_errs.rb +1 -1
  93. data/templates/new-instance/config/{triggers → events}/deploy/checkout_mentioned_alerts.rb +1 -1
  94. data/templates/new-instance/config/{triggers → events}/deploy/notify_deployer_when_finished.rb +2 -2
  95. data/templates/new-instance/config/{triggers → events}/github/publish_comments_on_slack.rb +9 -9
  96. data/templates/new-instance/config/{triggers → events}/tests/slack_when_analyzed.rb +1 -1
  97. data/templates/new-instance/config/{triggers → events}/tests/slack_when_completed.rb +1 -1
  98. data/templates/new-instance/config/{triggers → events}/tickets/mark_tasks_completed_on_commit.rb +1 -1
  99. data/templates/new-instance/config/main.rb +8 -35
  100. data/templates/new-instance/config/{jobs → timers}/cache_key_dependencies.rb +0 -0
  101. data/templates/new-instance/config/{jobs → timers}/email_about_open_alerts.rb +0 -0
  102. data/templates/new-instance/config/{jobs → timers}/purge_jobs.rb +0 -0
  103. data/templates/new-instance/config/{jobs → timers}/slack_reminders_about_alerts.rb +0 -0
  104. data/templates/new-instance/config/{jobs → timers}/sync_commits.rb +0 -0
  105. data/templates/new-instance/config/{jobs → timers}/sync_pull_requests.rb +0 -0
  106. data/templates/new-instance/config/{jobs → timers}/sync_tickets.rb +0 -0
  107. data/templates/new-module/lib/houston/%name%.rb +13 -0
  108. data/test/integration/ci_integration_test.rb +5 -5
  109. data/test/integration/web_hook_test.rb +1 -1
  110. data/test/test_helper.rb +14 -0
  111. data/test/unit/controllers/hooks_controller_test.rb +2 -2
  112. data/test/unit/initializers/sync_commits_on_post_receive_test.rb +1 -1
  113. data/test/unit/models/actions_test.rb +107 -0
  114. data/test/unit/models/configuration_test.rb +108 -0
  115. data/test/unit/models/observer_test.rb +87 -3
  116. data/test/unit/models/persistent_trigger_test.rb +94 -0
  117. data/test/unit/models/serializer_test.rb +80 -0
  118. data/test/unit/models/triggers_test.rb +53 -0
  119. metadata +60 -60
  120. data/app/assets/javascripts/houston/app/models/testing_note.coffee +0 -18
  121. data/app/assets/javascripts/houston/app/views/commit_view.coffee +0 -13
  122. data/app/assets/javascripts/houston/app/views/testing_note_view.coffee +0 -85
  123. data/app/assets/javascripts/houston/app/views/testing_report_view.coffee +0 -29
  124. data/app/assets/javascripts/houston/app/views/testing_ticket_view.coffee +0 -203
  125. data/app/assets/stylesheets/houston/application/jobs.scss +0 -5
  126. data/app/assets/stylesheets/houston/application/testing_report.scss +0 -279
  127. data/app/assets/templates/commit.hbs +0 -9
  128. data/app/assets/templates/testing_notes/edit.hbs +0 -20
  129. data/app/assets/templates/testing_notes/new.hbs +0 -27
  130. data/app/assets/templates/testing_notes/show.hbs +0 -11
  131. data/app/assets/templates/testing_report/description.hbs +0 -12
  132. data/app/assets/templates/testing_report/ticket.hbs +0 -21
  133. data/app/assets/templates/testing_report/verdict.hbs +0 -4
  134. data/app/controllers/jobs_controller.rb +0 -42
  135. data/app/controllers/testing_notes_controller.rb +0 -50
  136. data/app/controllers/testing_report_controller.rb +0 -38
  137. data/app/models/testing_note.rb +0 -64
  138. data/app/presenters/testing_note_presenter.rb +0 -27
  139. data/app/presenters/testing_report_ticket_presenter.rb +0 -71
  140. data/app/views/jobs/index.html.erb +0 -72
  141. data/app/views/jobs/show.html.erb +0 -41
  142. data/app/views/project_notification/testing_note.html.erb +0 -9
  143. data/app/views/testing_report/_scripts.html.erb +0 -12
  144. data/app/views/testing_report/index.html.erb +0 -31
  145. data/app/views/testing_report/show.html.erb +0 -29
  146. data/config/initializers/houston_scheduler.rb +0 -23
  147. data/db/migrate/20120424212706_create_testing_notes.rb +0 -14
  148. data/db/migrate/20120501231817_add_expires_at_to_testing_notes.rb +0 -5
  149. data/db/migrate/20120501231948_add_unfuddle_id_to_testing_notes.rb +0 -5
  150. data/db/migrate/20120715230526_change_testing_notes_comment_to_text.rb +0 -9
  151. data/db/migrate/20130211015046_add_min_passing_verdicts_to_projects.rb +0 -5
  152. data/db/migrate/20130407220039_add_project_id_to_testing_notes.rb +0 -26
  153. data/db/migrate/20140511024021_rename_testing_notes_unfuddle_id_to_remote_id.rb +0 -5
  154. data/templates/new-instance/config/triggers/tickets/email_testing_notes.rb +0 -7
  155. data/templates/new-instance/log/development.log +0 -41253
  156. data/templates/new-instance/log/test.log +0 -545
  157. 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
- attr_accessor :async
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 on(event, &block)
14
- observers_of(event).push(block)
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 once(event, &block)
19
- wrapped_block = Proc.new do |*args|
20
- block.call(*args)
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, *args)
31
- invoker = async ? method(:invoke_callback_async) : method(:invoke_callback)
32
- observers_of(event).each do |block|
33
- invoker.call(event, block, *args)
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 invoke_callback_async(event, block, *args)
45
- Houston.async do
46
- invoke_callback(event, block, *args)
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 invoke_callback(event, block, *args)
51
- block.call(*args)
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
- def observers_of(event)
58
- observers[event] ||= ThreadSafe::Array.new
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
- attr_reader :observers
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,15 @@
1
+ module Houston
2
+ class ReadonlyHashSerializer
3
+
4
+ def applies_to?(object)
5
+ object.is_a?(Houston::ReadonlyHash)
6
+ end
7
+
8
+ def pack(object)
9
+ object.to_h
10
+ end
11
+
12
+ end
13
+ end
14
+
15
+ Houston.add_serializer Houston::ReadonlyHashSerializer.new
@@ -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"
@@ -1,3 +1,3 @@
1
1
  module Houston
2
- VERSION = "0.7.0.beta3"
2
+ VERSION = "0.7.0.beta4"
3
3
  end
@@ -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" do |alert|
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" do |alert|
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 |args|
19
- slack_send_message_to "An error occurred\n#{args.inspect}", "general"
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,4 +1,4 @@
1
- Houston.config.on "alert:err:deployed" do |alert, deploy, commit|
1
+ Houston.config.on "alert:err:deployed" => "alert:autoresolve-err" do
2
2
  error_tracker = deploy.project.error_tracker
3
3
 
4
4
  message = "Resolved by Houston when "
@@ -1,4 +1,4 @@
1
- Houston.config.on "alert:deployed" do |alert, deploy, commit|
1
+ Houston.config.on "alert:deployed" => "alert:assign-alert-to-committer" do
2
2
  next if alert.checked_out_by
3
3
  next unless committer = commit.committers.first
4
4
  alert.update_attribute :checked_out_by, committer
@@ -1,6 +1,6 @@
1
1
  Houston.config do
2
- on "deploy:completed" do |deploy|
3
- next if deploy.build_release.ignore?
2
+ on "deploy:completed" => "deploy:slack-deployer-of-finished-deploy" do
3
+ next if deploy.build_releasignore?
4
4
 
5
5
  deployer = deploy.user
6
6
  if deployer
@@ -1,16 +1,16 @@
1
1
  Houston.config do
2
- on "github:comment:created:commit" do |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
- comment = { fallback: body, text: body }
10
- slack_send_message_to message, channel, as: :github, attachments: [comment], test: true
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:created:diff" do |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
- comment = { fallback: body, text: body }
22
- slack_send_message_to message, channel, as: :github, attachments: [comment], test: true
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:created:pull" do |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
- comment = { fallback: body, text: body }
34
- slack_send_message_to message, channel, as: :github, attachments: [comment], test: true
33
+ attachment = { fallback: body, text: body }
34
+ slack_send_message_to message, channel, as: :github, attachments: [attachment]
35
35
  end
36
36
  end
@@ -1,5 +1,5 @@
1
1
  Houston.config do
2
- on "test_run:compared" do |test_run|
2
+ on "test_run:compared" => "test_run:slack-about-commits-that-introduced-regressions" do
3
3
  regressions = test_run.test_results.where(different: true, status: "fail").to_a
4
4
  next if regressions.none?
5
5
 
@@ -1,5 +1,5 @@
1
1
  Houston.config do
2
- on "test_run:complete" do |test_run|
2
+ on "test_run:complete" => "test_run:slack-results" do
3
3
  # When branch is nil, the test run was requested by Houston
4
4
  # not triggered by a developer pushing changes to GitHub.
5
5
  next if test_run.branch.nil?
@@ -1,7 +1,7 @@
1
1
  # Treat tasks as completed when a commit mentioning them is pushed
2
2
 
3
3
  Houston.config do
4
- on "task:committed" do |task|
4
+ on "task:committed" => "task:mark-completed" do
5
5
  task.completed!
6
6
  end
7
7
  end