Skip to content
This repository has been archived by the owner on Dec 5, 2019. It is now read-only.

Commit

Permalink
Project#notify raises an exception if you try to notify plugins of an…
Browse files Browse the repository at this point in the history
… event that hasn't been documented in BuilderPlugin. Not coincidentally, BuilderPlugin now provides documentation and an interface for all event callbacks.
  • Loading branch information
bguthrie committed Jul 1, 2009
1 parent 6731b7a commit de819e6
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 4 deletions.
9 changes: 6 additions & 3 deletions app/models/project.rb
Expand Up @@ -298,9 +298,8 @@ def build_without_serialization(revision, reasons)
log_changeset(build.artifacts_directory, reasons)
update_project_to_revision(build, revision)

if config_tracker.config_modified?
if config_modified?
build.abort
notify(:configuration_modified)
throw :reload_project
end

Expand All @@ -324,10 +323,14 @@ def build_without_serialization(revision, reasons)
end

def notify(event, *event_parameters)
unless BuilderPlugin.known_event? event
raise "You attempted to notify the project of the #{event} event, but the plugin architecture does not understand this event. Add a method to BuilderPlugin, and document it."
end

errors = []
results = @plugins.collect do |plugin|
begin
plugin.send(event, *event_parameters) if plugin.respond_to?(event)
plugin.send(event, *event_parameters) if plugin.respond_to? event
rescue => plugin_error
CruiseControl::Log.error(plugin_error)
if (event_parameters.first and event_parameters.first.respond_to? :artifacts_directory)
Expand Down
83 changes: 83 additions & 0 deletions lib/builder_plugins/builder_plugin.rb
@@ -1,8 +1,91 @@
# BuilderPlugin is the superclass of all CC.rb plugins. It does not provide any functionality
# except a basic initializer that accepts as an argument the current project.
#
# CC.rb plugins offer a rich notification system for tracking every aspect of the build lifecycle. In rough order,
# they are:
#
# * polling_source_control
# * no_new_revisions_detected OR new_revisions_detected(revisions)
# * build_requested
# * queued
# * timed_out
# * build_initiated
# * configuration_modified
# * build_started
# * build_finished
# * build_broken OR build_fixed
# * build_loop_failed
# * sleeping
class BuilderPlugin
attr_reader :project

def initialize(project)
@project = project
end

class << self
def known_event?(event_name)
self.instance_methods(false).include? event_name.to_s
end
end

# Called by ChangeInSourceControlTrigger to indicate that it is about to poll source control.
def polling_source_control
end

# Called by ChangeInSourceControlTrigger to indicate that no new revisions have been detected.
def no_new_revisions_detected
end

# Called by ChangeInSourceControlTrigger to indicate that new revisions were detected.
def new_revisions_detected(revisions)
end

# Called by Project to indicate that a build has explicitly been requested by the user.
def build_requested
end

# Called by BuildSerializer if it another build is still running and it cannot acquire the build serialization lock.
# It will retry until it times out. Occurs only if build serialization is enabled in your CC.rb configuration.
def queued
end

# Called by BuildSerializer if it times out attempting to acquire the build serialization lock due to another build
# still running. Occurs only if build serialization is enabled in your CC.rb configuration.
def timed_out
end

# Called by Project at the start of a new build before any other build events.
def build_initiated
end

# Called by Project at the start of a new build to indicate that the configuration has been modified,
# after which the build is aborted.
def configuration_modified
end

# Called by Project after some basic logging and the configuration_modified check and just before the build begins running,
def build_started(build)
end

# Called by Project immediately after the build has finished running.
def build_finished(build)
end

# Called by Project after the completion of a build if the previous build was successful and this one is a failure.
def build_broken(build, previous_build)
end

# Called by Project after the completion of a build if the previous build was a failure and this one was successful.
def build_fixed(build, previous_build)
end

# Called by Project if the build fails internally with a CC.rb exception.
def build_loop_failed(exception)
end

# Called by Project at the end of a build to indicate that the build loop is once again sleeping.
def sleeping
end

end
10 changes: 10 additions & 0 deletions test/unit/plugins/builder_plugin_test.rb
@@ -0,0 +1,10 @@
require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')

class BuilderPluginTest < Test::Unit::TestCase

def test_builder_plugin_should_maintain_list_of_known_events
assert BuilderPlugin.known_event? :build_requested
assert_false BuilderPlugin.known_event? :some_random_event
end

end
11 changes: 10 additions & 1 deletion test/unit/project_test.rb
Expand Up @@ -227,6 +227,7 @@ def test_notify_should_not_fail_if_plugin_fails_and_notify_has_no_build_or_no_ar
listener = Object.new
listener.expects(:sleeping).raises(StandardError.new("Listener failed"))
listener.expects(:doing_something).with(:foo).raises(StandardError.new("Listener failed with :foo"))
BuilderPlugin.stubs(:known_event?).returns true

@project.add_plugin listener

Expand Down Expand Up @@ -313,8 +314,8 @@ def test_either_rake_task_or_build_command_can_be_set_but_not_both
end

def test_notify_should_handle_plugin_error
BuilderPlugin.expects(:known_event?).with(:hey_you).returns true
plugin = Object.new

@project.plugins << plugin

plugin.expects(:hey_you).raises("Plugin talking")
Expand All @@ -323,6 +324,7 @@ def test_notify_should_handle_plugin_error
end

def test_notify_should_handle_multiple_plugin_errors
BuilderPlugin.stubs(:known_event?).with(:hey_you).returns true
plugin1 = Object.new
plugin2 = Object.new

Expand Down Expand Up @@ -647,6 +649,13 @@ def test_adding_a_plugin_should_raise_exception_if_already_configured
end
end

def test_notifying_project_of_an_unknown_event_raises_exception
BuilderPlugin.expects(:known_event?).returns false
assert_raises RuntimeError do
@project.notify :some_random_event
end
end

private

def stub_build(label)
Expand Down

0 comments on commit de819e6

Please sign in to comment.