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
data/houston-core.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
 
22
22
  # For Houston as a Web Application
23
- spec.add_dependency "rails", "~> 4.2.5.1"
23
+ spec.add_dependency "rails", "~> 4.2.5"
24
24
  spec.add_dependency "pg", "~> 0.18.3"
25
25
  # --------------------------------
26
26
  spec.add_dependency "activerecord-import"
@@ -0,0 +1,105 @@
1
+ require "thread_safe"
2
+
3
+ module Houston
4
+ class Actions
5
+
6
+ def initialize
7
+ @actions = ThreadSafe::Hash.new
8
+ end
9
+
10
+
11
+ def names
12
+ actions.keys
13
+ end
14
+
15
+ def count
16
+ actions.count
17
+ end
18
+
19
+ def exists?(name)
20
+ actions.key?(name)
21
+ end
22
+
23
+ def [](name)
24
+ actions[name]
25
+ end
26
+
27
+ def to_a
28
+ actions.values
29
+ end
30
+
31
+ def define(name, required_params=[], &block)
32
+ raise ArgumentError, "#{name.inspect} is already defined" if exists?(name)
33
+ redefine(name, required_params, &block)
34
+ end
35
+
36
+ def redefine(name, required_params=[], &block)
37
+ raise ArgumentError, "A block is required to define an action" unless block_given?
38
+ actions[name] = Action.new(name, required_params, block)
39
+ end
40
+
41
+ def undefine(name)
42
+ raise ArgumentError, "#{name.inspect} is not defined" unless exists?(name)
43
+ actions.delete name
44
+ end
45
+
46
+
47
+ def run(name, params={}, options={})
48
+ raise ArgumentError, "#{name.inspect} is not defined" unless exists?(name)
49
+ action = actions.fetch(name)
50
+
51
+ unless params.is_a?(Hash)
52
+ raise ArgumentError, "params must be a Hash" unless params.respond_to?(:to_h)
53
+ params = params.to_h
54
+ end
55
+
56
+ assert_required_params! action, params
57
+ assert_serializable! params
58
+
59
+ Houston.async(options.fetch(:async, true)) do
60
+ action.send :run!, params, options
61
+ end
62
+ end
63
+
64
+
65
+ private
66
+ attr_reader :actions
67
+
68
+
69
+ def assert_required_params!(action, params)
70
+ action.assert_required_params! params.keys.map(&:to_s)
71
+ end
72
+
73
+ def assert_serializable!(params)
74
+ Houston::Serializer.new.assert_serializable!(params)
75
+ end
76
+
77
+
78
+ class Action < Struct.new(:name, :required_params, :block)
79
+ def initialize(name, required_params, block)
80
+ super name, required_params.map(&:to_s), block
81
+ end
82
+
83
+ def assert_required_params!(params)
84
+ missing_params = required_params - params
85
+ if missing_params.any?
86
+ raise Houston::Observer::MissingParamError, "#{missing_params.first.inspect} is a required param of the action #{name.inspect}"
87
+ end
88
+ end
89
+
90
+ private
91
+
92
+ def run!(params, options={})
93
+ params = ReadonlyHash.new(params)
94
+ trigger = options.fetch(:trigger, "manual")
95
+
96
+ ::Action.record name, params, trigger do
97
+ Rails.logger.info "\e[34m[#{trigger} => #{name}] Running job\e[0m"
98
+ params.instance_eval(&block)
99
+ end
100
+ end
101
+ end
102
+
103
+
104
+ end
105
+ end
@@ -0,0 +1,24 @@
1
+ module Houston
2
+ class ActiveRecordSerializer
3
+
4
+ def applies_to?(object)
5
+ object.is_a?(ActiveRecord::Base)
6
+ end
7
+
8
+ def pack(record)
9
+ model = record.class
10
+ normal_attributes = record.attributes.each_with_object({}) do |(attribute, value), attributes|
11
+ attributes[attribute] = model.column_for_attribute(attribute).type_cast_for_database(value)
12
+ end
13
+ { "class" => model.name, "attributes" => normal_attributes }
14
+ end
15
+
16
+ def unpack(object)
17
+ klass, attributes = object.values_at("class", "attributes")
18
+ klass.constantize.instantiate(attributes)
19
+ end
20
+
21
+ end
22
+ end
23
+
24
+ Houston.add_serializer Houston::ActiveRecordSerializer.new
@@ -2,14 +2,25 @@ root = File.expand_path(File.join(File.dirname(__FILE__), "../../.."))
2
2
  require File.join(root, "lib/core_ext/hash")
3
3
  require File.join(root, "lib/core_ext/kernel")
4
4
  require File.join(root, "lib/core_ext/exception")
5
+ require File.join(root, "lib/houston/boot/triggers")
5
6
  require File.join(root, "lib/houston/boot/observer")
7
+ require File.join(root, "lib/houston/boot/actions")
8
+ require File.join(root, "lib/houston/boot/timer")
6
9
 
7
10
  $:.unshift File.expand_path(File.join(root, "app/adapters"))
8
11
  require "houston/adapters"
9
12
 
10
13
  module Houston
14
+ module_function
15
+ def deprecation_notice(message, stack_offset=1)
16
+ message = message.gsub /<b>(.*)<\/b>/, "\e[1m\\1\e[0;34m"
17
+ puts "\e[34mDEPRECATION: #{message}\e[0;90m\n#{caller[stack_offset]}\e[0m\n\n"
18
+ end
19
+
20
+
21
+
11
22
  class Configuration
12
- attr_reader :timers
23
+ attr_reader :observer, :actions, :timer
13
24
 
14
25
  def initialize
15
26
  @root = Rails.root
@@ -21,9 +32,27 @@ module Houston
21
32
  @ticket_tracker_configuration = {}
22
33
  @ci_server_configuration = {}
23
34
  @error_tracker_configuration = {}
24
- @timers = []
25
35
  end
26
36
 
37
+ def triggers
38
+ return @triggers if defined?(@triggers)
39
+ @triggers = Houston::Triggers.new(self)
40
+ end
41
+
42
+ def observer
43
+ return @observer if defined?(@observer)
44
+ @observer = Houston::Observer.new
45
+ end
46
+
47
+ def actions
48
+ return @actions if defined?(@actions)
49
+ @actions = Houston::Actions.new
50
+ end
51
+
52
+ def timer
53
+ return @timer if defined?(@timer)
54
+ @timer = Houston::Timer.new
55
+ end
27
56
 
28
57
 
29
58
 
@@ -342,18 +371,86 @@ module Houston
342
371
 
343
372
 
344
373
 
345
- # Events
374
+ # Actions and Triggers
346
375
 
347
- def on(event, &block)
348
- Houston.observer.on(event, &block)
376
+ def action(name, required_params=[], &block)
377
+ actions.define(name, required_params, &block)
349
378
  end
350
379
 
351
- def at(time, name, options={}, &block)
352
- @timers.push [:cron, time, name, options, block]
380
+ def on(*args, &block)
381
+ event_name, action_name = extract_trigger_and_action!(args)
382
+ event = Houston.get_registered_event(event_name)
383
+ action = assert_action! action_name, event.params, &block
384
+ action.assert_required_params! event.params
385
+
386
+ triggers.on event_name, action_name
387
+ action
353
388
  end
354
389
 
355
- def every(interval, name, options={}, &block)
356
- @timers.push [:every, interval, name, options, block]
390
+ def at(*args, &block)
391
+ time, action_name = extract_trigger_and_action!(args)
392
+ action = assert_action! action_name, &block
393
+ action.assert_required_params! []
394
+
395
+ # Passing options to Houston.config.at is deprecated
396
+ # -------------------------------------------------------------- #
397
+ if args.first.is_a?(Hash)
398
+ options = args.first
399
+ if days_of_the_week = options.delete(:every)
400
+ Houston.deprecation_notice "Instead of passing every: #{days_of_the_week.inspect} to Houston.config.at, use Houston.config.at [#{days_of_the_week.inspect}, #{time}], ..."
401
+ time = [days_of_the_week, time]
402
+ end
403
+ options.keys.each do |key|
404
+ Houston.deprecation_notice "#{key.inspect} is an unknown option for Houston.config.at. In the next version of houston-core, Houston.config.at will no longer accept options"
405
+ end
406
+ end
407
+ # -------------------------------------------------------------- #
408
+
409
+ triggers.at time, action_name
410
+ action
411
+ end
412
+
413
+ def every(*args, &block)
414
+ interval, action_name = extract_trigger_and_action!(args)
415
+ action = assert_action! action_name, &block
416
+ action.assert_required_params! []
417
+
418
+ # Passing options to Houston.config.every is deprecated
419
+ # -------------------------------------------------------------- #
420
+ if args.first.is_a?(Hash)
421
+ options = args.first
422
+ options.keys.each do |key|
423
+ Houston.deprecation_notice "#{key.inspect} is an unknown option for Houston.config.at. In the next version of houston-core, Houston.config.at will no longer accept options"
424
+ end
425
+ end
426
+ # -------------------------------------------------------------- #
427
+
428
+ triggers.every interval, action_name
429
+ action
430
+ end
431
+
432
+ private def extract_trigger_and_action!(args)
433
+ if args.first.is_a?(Hash)
434
+ return args.shift.to_a[0] if args.first.one?
435
+ raise ArgumentError, "Unrecognized trigger: #{args.inspect}"
436
+ end
437
+ return args.shift(2) if args.length >= 2
438
+ if args.length == 1
439
+ method_name = caller[0][/in `(.*)'/, 1]
440
+ Houston.deprecation_notice "<b>Houston.config.#{method_name}(#{args[0].inspect})</b> does not specify an action name\nIn a future version of Houston <b>Houston.config.#{method_name}(#{args[0]} => \"do-something\")</b> will be required", 2
441
+ return [args[0], "#{args[0]}:#{SecureRandom.hex}"]
442
+ end
443
+ raise NotImplementedError, "I haven't been programmed to extract trigger and action_name from #{args.inspect}"
444
+ end
445
+
446
+ private def assert_action!(name, required_params=[], &block)
447
+ if block_given?
448
+ action name, required_params, &block
449
+ elsif action = actions[name]
450
+ action
451
+ else
452
+ raise ArgumentError, "An action named #{name.inspect} is not defined"
453
+ end
357
454
  end
358
455
 
359
456
 
@@ -490,40 +587,6 @@ module Houston
490
587
 
491
588
 
492
589
 
493
-
494
-
495
- class Jobs
496
-
497
- def run(job)
498
- trigger = "manual"
499
- job, trigger = [job.tags.first, job.original] if job.is_a? Rufus::Scheduler::Job
500
- block = find_timer_block!(job)
501
- Houston.async do
502
- run! job, trigger, block
503
- end
504
- end
505
-
506
- private
507
-
508
- def find_timer_block!(job_name)
509
- timer = Houston.config.timers.detect { |(_, _, name, _, _)| name == job_name }
510
- raise ArgumentError, "#{job_name} is not a job" unless timer
511
- timer.last
512
- end
513
-
514
- def run!(job_name, trigger, block)
515
- Job.record job_name do
516
- Rails.logger.info "\e[34m[#{job_name}/#{trigger}] Running job\e[0m"
517
- block.call
518
- end
519
- rescue Exception # rescues StandardError by default; but we want to rescue and report all errors
520
- Houston.report_exception($!, parameters: {job_name: job_name})
521
- end
522
-
523
- end
524
-
525
-
526
-
527
590
  class NotConfigured < RuntimeError
528
591
  def initialize(message = "Houston has not been configured. Please load config/config.rb before calling Houston.config")
529
592
  super
@@ -544,18 +607,24 @@ module_function
544
607
  @configuration
545
608
  end
546
609
 
610
+ def triggers
611
+ config.triggers
612
+ end
547
613
 
548
- def self.root
549
- config.root
614
+ def observer
615
+ config.observer
550
616
  end
551
617
 
618
+ def actions
619
+ config.actions
620
+ end
552
621
 
553
- def observer
554
- @observer ||= Observer.new
622
+ def timer
623
+ config.timer
555
624
  end
556
625
 
557
- def jobs
558
- @jobs ||= Jobs.new
626
+ def root
627
+ config.root
559
628
  end
560
629
 
561
630
  def github
@@ -0,0 +1,46 @@
1
+ Houston.register_events {{
2
+
3
+ "antecedent:{type}:released" => params("antecedent").desc("A ticket or commit with an antecedent of {type} was released"),
4
+ "antecedent:{type}:resolved" => params("antecedent").desc("A ticket with an antecedent of {type} was resolved"),
5
+ "antecedent:{type}:closed" => params("antecedent").desc("A ticket with an antecedent of {type} was closed"),
6
+
7
+ "commit:create" => params("commit").desc("A new commit was created"),
8
+
9
+ "daemon:{type}:start" => desc("Daemon {type} has started"),
10
+ "daemon:{type}:restart" => desc("Daemon {type} has restarted"),
11
+ "daemon:{type}:stop" => desc("Daemon {type} has stopped"),
12
+
13
+ "deploy:completed" => params("deploy").desc("A deploy just finished"),
14
+ "deploy:succeeded" => params("deploy").desc("A deploy succeeded"),
15
+ "deploy:failed" => params("deploy").desc("A deploy failed"),
16
+
17
+ "github:comment:create" => params("comment").desc("A comment was added to a commit, diff, or issue on GitHub"),
18
+ "github:comment:{type}:create" => params("comment").desc("A comment was added to a {type} on GitHub"),
19
+ "github:comment:update" => params("comment").desc("A comment on a commit, diff, or issue was updated on GitHub"),
20
+ "github:comment:{type}:update" => params("comment").desc("A comment on a {type} was updated on GitHub"),
21
+ "github:comment:delete" => params("comment").desc("A comment on a commit, diff, or issue was deleted on GitHub"),
22
+ "github:comment:{type}:delete" => params("comment").desc("A comment on a {type} was deleted on GitHub"),
23
+
24
+ "github:pull:opened" => params("pull_request").desc("A pull request was opened"),
25
+ "github:pull:updated" => params("pull_request", "changes").desc("A pull request was updated"),
26
+ "github:pull:closed" => params("pull_request").desc("A pull request was closed"),
27
+ "github:pull:reopened" => params("pull_request").desc("A pull request was reopened"),
28
+ "github:pull:synchronize" => params("pull_request").desc("Commits where pushed to a pull request"),
29
+
30
+ "hooks:{type}" => params("params").desc("/hooks/{type} was invoked"),
31
+ "hooks:project:{type}" => params("project", "params").desc("/hooks/project/:slug/{type} was invoked"),
32
+
33
+ "release:create" => params("release").desc("A new release was created"),
34
+
35
+ "task:released" => params("task").desc("A commit mentioning this task was released"),
36
+ "task:committed" => params("task").desc("A commit mentioning this task was created"),
37
+ "task:completed" => params("task").desc("A task was completed"),
38
+ "task:reopened" => params("task").desc("A task was reopened"),
39
+
40
+ "test_run:start" => params("test_run").desc("A test run was started on the CI server"),
41
+ "test_run:complete" => params("test_run").desc("A test run was completed on the CI server"),
42
+ "test_run:compared" => params("test_run").desc("The test results for a commit were compared to the results for its parent"),
43
+
44
+ "ticket:release" => params("ticket", "release").desc("A ticket was released")
45
+
46
+ }}
@@ -1,5 +1,9 @@
1
+ require "houston/boot/serializer"
2
+
3
+
1
4
  module Houston
2
5
  module Extensions
6
+ attr_reader :events, :serializers
3
7
 
4
8
 
5
9
 
@@ -13,6 +17,29 @@ module Houston
13
17
 
14
18
 
15
19
 
20
+
21
+ def available_project_features
22
+ @available_project_features.keys
23
+ end
24
+
25
+ def get_project_feature(slug)
26
+ @available_project_features[slug]
27
+ end
28
+
29
+ def add_project_feature(slug, &block)
30
+ dsl = ProjectFeatureDsl.new
31
+ dsl.instance_eval(&block)
32
+ feature = dsl.feature
33
+ feature.slug = slug
34
+ raise ArgumentError, "Project Feature must supply name, but #{slug.inspect} doesn't" unless feature.name
35
+ raise ArgumentError, "Project Feature must supply icon, but #{slug.inspect} doesn't" unless feature.icon
36
+ raise ArgumentError, "Project Feature must supply path lambda, but #{slug.inspect} doesn't" unless feature.path_block
37
+
38
+ @available_project_features[slug] = feature
39
+ end
40
+
41
+
42
+
16
43
  def add_user_option(slug, &block)
17
44
  dsl = FormBuilderDsl.new
18
45
  dsl.instance_eval(&block)
@@ -28,24 +55,50 @@ module Houston
28
55
 
29
56
 
30
57
 
31
- def available_project_features
32
- @available_project_features.keys
58
+ def add_project_option(slug, &block)
59
+ dsl = FormBuilderDsl.new
60
+ dsl.instance_eval(&block)
61
+ form = dsl.form
62
+ form.slug = slug
63
+
64
+ @project_options[slug] = form
33
65
  end
34
66
 
35
- def get_project_feature(slug)
36
- @available_project_features[slug]
67
+ def project_options
68
+ @project_options.values
37
69
  end
38
70
 
39
- def add_project_feature(slug, &block)
40
- dsl = ProjectFeatureDsl.new
41
- dsl.instance_eval(&block)
42
- feature = dsl.feature
43
- feature.slug = slug
44
- raise ArgumentError, "Project Feature must supply name, but #{slug.inspect} doesn't" unless feature.name
45
- raise ArgumentError, "Project Feature must supply icon, but #{slug.inspect} doesn't" unless feature.icon
46
- raise ArgumentError, "Project Feature must supply path lambda, but #{slug.inspect} doesn't" unless feature.path_block
47
71
 
48
- @available_project_features[slug] = feature
72
+
73
+ def registered_event?(event_name)
74
+ events.any? { |event| event.matches? event_name }
75
+ end
76
+
77
+ def get_registered_event(event_name)
78
+ events.find { |event| event.matches? event_name }
79
+ end
80
+
81
+ def register_event(name, description)
82
+ events.push Event.new(name, description)
83
+ end
84
+
85
+ def register_events(&block)
86
+ dsl = RegisterEventsDsl.new
87
+ hash = dsl.instance_eval(&block)
88
+ hash.each do |name, description|
89
+ register_event(name, description.to_h)
90
+ end
91
+ end
92
+
93
+
94
+
95
+ def add_serializer(serializer)
96
+ [:applies_to?, :pack].each do |method|
97
+ next if serializer.respond_to?(method)
98
+ raise ArgumentError, "`serializer` must respond to `#{method}`"
99
+ end
100
+
101
+ @serializers.push serializer
49
102
  end
50
103
 
51
104
 
@@ -125,12 +178,63 @@ module Houston
125
178
  end
126
179
  end
127
180
 
181
+ class RegisterEventsDsl
182
+ def params(*params)
183
+ RegisterEventDsl.new.params(*params)
184
+ end
185
+
186
+ def description(value)
187
+ RegisterEventDsl.new.description(value)
188
+ end
189
+ alias :desc :description
190
+ end
191
+
192
+ class RegisterEventDsl
193
+ def initialize
194
+ @hash = {}
195
+ end
196
+
197
+ def params(*params)
198
+ @hash[:params] = params
199
+ self
200
+ end
201
+
202
+ def description(value)
203
+ @hash[:description] = value
204
+ self
205
+ end
206
+ alias :desc :description
207
+
208
+ def to_h
209
+ @hash
210
+ end
211
+ end
212
+
213
+ class Event
214
+ attr_reader :name, :description, :params
215
+
216
+ def initialize(name, options)
217
+ @name = name
218
+ @description = options.fetch(:description)
219
+ @params = options.fetch(:params, [])
220
+ @matcher = Regexp.new("\\A#{name.gsub /\{([^:}]+)\}/, "(?<\\1>[^:]+)"}\\z")
221
+ end
222
+
223
+ def matches?(event_name)
224
+ @matcher === event_name
225
+ end
226
+ end
227
+
128
228
  end
129
229
 
130
230
 
131
231
 
132
232
  @navigation_renderers = {}
133
- @user_options = {}
134
233
  @available_project_features = {}
234
+ @user_options = {}
235
+ @project_options = {}
236
+ @events = []
237
+ @event_matchers = []
238
+ @serializers = []
135
239
  extend Houston::Extensions
136
240
  end