brycethornton-integrity 0.1.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/README.markdown +66 -0
  2. data/Rakefile +110 -0
  3. data/VERSION.yml +4 -0
  4. data/app.rb +137 -0
  5. data/bin/integrity +4 -0
  6. data/config/config.sample.ru +31 -0
  7. data/config/config.sample.yml +38 -0
  8. data/config/thin.sample.yml +13 -0
  9. data/integrity.gemspec +76 -0
  10. data/lib/integrity.rb +82 -0
  11. data/lib/integrity/build.rb +61 -0
  12. data/lib/integrity/core_ext/object.rb +6 -0
  13. data/lib/integrity/core_ext/string.rb +5 -0
  14. data/lib/integrity/helpers.rb +16 -0
  15. data/lib/integrity/helpers/authorization.rb +33 -0
  16. data/lib/integrity/helpers/breadcrumbs.rb +20 -0
  17. data/lib/integrity/helpers/forms.rb +28 -0
  18. data/lib/integrity/helpers/pretty_output.rb +45 -0
  19. data/lib/integrity/helpers/rendering.rb +14 -0
  20. data/lib/integrity/helpers/resources.rb +13 -0
  21. data/lib/integrity/helpers/urls.rb +47 -0
  22. data/lib/integrity/installer.rb +132 -0
  23. data/lib/integrity/migrations.rb +152 -0
  24. data/lib/integrity/notifier.rb +50 -0
  25. data/lib/integrity/notifier/base.rb +55 -0
  26. data/lib/integrity/project.rb +117 -0
  27. data/lib/integrity/project_builder.rb +47 -0
  28. data/lib/integrity/scm.rb +19 -0
  29. data/lib/integrity/scm/git.rb +91 -0
  30. data/lib/integrity/scm/git/uri.rb +57 -0
  31. data/public/buttons.css +82 -0
  32. data/public/reset.css +7 -0
  33. data/public/spinner.gif +0 -0
  34. data/test/helpers.rb +48 -0
  35. data/test/helpers/acceptance.rb +126 -0
  36. data/test/helpers/acceptance/git_helper.rb +99 -0
  37. data/test/helpers/acceptance/textfile_notifier.rb +26 -0
  38. data/test/helpers/expectations.rb +5 -0
  39. data/test/helpers/expectations/be_a.rb +23 -0
  40. data/test/helpers/expectations/change.rb +90 -0
  41. data/test/helpers/expectations/have.rb +105 -0
  42. data/test/helpers/expectations/have_tag.rb +128 -0
  43. data/test/helpers/expectations/predicates.rb +37 -0
  44. data/test/helpers/fixtures.rb +83 -0
  45. data/views/_build_info.haml +18 -0
  46. data/views/build.haml +2 -0
  47. data/views/error.haml +36 -0
  48. data/views/home.haml +23 -0
  49. data/views/integrity.sass +387 -0
  50. data/views/layout.haml +28 -0
  51. data/views/new.haml +51 -0
  52. data/views/not_found.haml +31 -0
  53. data/views/notifier.haml +7 -0
  54. data/views/project.builder +21 -0
  55. data/views/project.haml +28 -0
  56. data/views/unauthorized.haml +38 -0
  57. metadata +243 -0
@@ -0,0 +1,26 @@
1
+ module Integrity
2
+ class Notifier
3
+ class Textfile < Notifier::Base
4
+ def self.to_haml
5
+ <<-haml
6
+ %p.normal
7
+ %label{ :for => "textfile_notifier_file" } File
8
+ %input.text#textfile_notifier_file{ :name => "notifiers[Textfile][file]", :type => "text", :value => config["file"] }
9
+ haml
10
+ end
11
+
12
+ def initialize(build, config={})
13
+ super
14
+ @file = @config["file"]
15
+ end
16
+
17
+ def deliver!
18
+ File.open(@file, "a") do |f|
19
+ f.puts "=== #{short_message} ==="
20
+ f.puts
21
+ f.puts full_message
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + "/expectations/be_a"
2
+ require File.dirname(__FILE__) + "/expectations/change"
3
+ require File.dirname(__FILE__) + "/expectations/have"
4
+ require File.dirname(__FILE__) + "/expectations/predicates"
5
+ require File.dirname(__FILE__) + "/expectations/have_tag"
@@ -0,0 +1,23 @@
1
+ module Matchy::Expectations
2
+ class BeAExpectation < Base
3
+ def matches?(receiver)
4
+ @receiver = receiver
5
+ @receiver.is_a?(@expected)
6
+ end
7
+
8
+ def failure_message
9
+ "Expected #{@receiver.inspect} to be a #{@expected.inspect}."
10
+ end
11
+
12
+ def negative_failure_message
13
+ "Expected #{@receiver.inspect} to not be a #{@expected.inspect}."
14
+ end
15
+ end
16
+
17
+ module TestCaseExtensions
18
+ def be_a(obj)
19
+ Matchy::Expectations::BeAExpectation.new(obj, self)
20
+ end
21
+ alias :be_an :be_a
22
+ end
23
+ end
@@ -0,0 +1,90 @@
1
+ module Matchy::Expectations
2
+ class ChangeExpectation < Base
3
+ def initialize(receiver=nil, message=nil, test_case=nil, &block)
4
+ @message = message || "result"
5
+ @value_proc = block || lambda {
6
+ receiver.__send__(message)
7
+ }
8
+ @test_case = test_case
9
+ end
10
+
11
+ def matches?(event_proc)
12
+ raise_block_syntax_error if block_given?
13
+
14
+ @before = evaluate_value_proc
15
+ event_proc.call
16
+ @after = evaluate_value_proc
17
+
18
+ return false if @from unless @from == @before
19
+ return false if @to unless @to == @after
20
+ return (@before + @amount == @after) if @amount
21
+ return ((@after - @before) >= @minimum) if @minimum
22
+ return ((@after - @before) <= @maximum) if @maximum
23
+ return @before != @after
24
+ end
25
+
26
+ def raise_block_syntax_error
27
+ raise ArgumentError, "block passed to should or should_not change must use {} instead of do/end"
28
+ end
29
+
30
+ def evaluate_value_proc
31
+ @value_proc.call
32
+ end
33
+
34
+ def failure_message
35
+ if @to
36
+ "#{@message} should have been changed to #{@to.inspect}, but is now #{@after.inspect}"
37
+ elsif @from
38
+ "#{@message} should have initially been #{@from.inspect}, but was #{@before.inspect}"
39
+ elsif @amount
40
+ "#{@message} should have been changed by #{@amount.inspect}, but was changed by #{actual_delta.inspect}"
41
+ elsif @minimum
42
+ "#{@message} should have been changed by at least #{@minimum.inspect}, but was changed by #{actual_delta.inspect}"
43
+ elsif @maximum
44
+ "#{@message} should have been changed by at most #{@maximum.inspect}, but was changed by #{actual_delta.inspect}"
45
+ else
46
+ "#{@message} should have changed, but is still #{@before.inspect}"
47
+ end
48
+ end
49
+
50
+ def actual_delta
51
+ @after - @before
52
+ end
53
+
54
+ def negative_failure_message
55
+ "#{@message} should not have changed, but did change from #{@before.inspect} to #{@after.inspect}"
56
+ end
57
+
58
+ def by(amount)
59
+ @amount = amount
60
+ self
61
+ end
62
+
63
+ def by_at_least(minimum)
64
+ @minimum = minimum
65
+ self
66
+ end
67
+
68
+ def by_at_most(maximum)
69
+ @maximum = maximum
70
+ self
71
+ end
72
+
73
+ def to(to)
74
+ @to = to
75
+ self
76
+ end
77
+
78
+ def from (from)
79
+ @from = from
80
+ self
81
+ end
82
+ end
83
+
84
+
85
+ module TestCaseExtensions
86
+ def change(receiver=nil, message=nil, &block)
87
+ Matchy::Expectations::ChangeExpectation.new(receiver, message, self, &block)
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,105 @@
1
+ module Matchy::Expectations
2
+ class HaveExpectation < Base
3
+ def initialize(expected, relativity=:exactly, test_case = nil)
4
+ @expected = (expected == :no ? 0 : expected)
5
+ @relativity = relativity
6
+ @test_case = test_case
7
+ end
8
+
9
+ def relativities
10
+ @relativities ||= {
11
+ :exactly => "",
12
+ :at_least => "at least ",
13
+ :at_most => "at most "
14
+ }
15
+ end
16
+
17
+ def matches?(collection_owner)
18
+ if collection_owner.respond_to?(@collection_name)
19
+ collection = collection_owner.__send__(@collection_name, *@args, &@block)
20
+ elsif (@plural_collection_name && collection_owner.respond_to?(@plural_collection_name))
21
+ collection = collection_owner.__send__(@plural_collection_name, *@args, &@block)
22
+ elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
23
+ collection = collection_owner
24
+ else
25
+ collection_owner.__send__(@collection_name, *@args, &@block)
26
+ end
27
+ @given = collection.size if collection.respond_to?(:size)
28
+ @given = collection.length if collection.respond_to?(:length)
29
+ raise not_a_collection if @given.nil?
30
+ return @given >= @expected if @relativity == :at_least
31
+ return @given <= @expected if @relativity == :at_most
32
+ return @given == @expected
33
+ end
34
+
35
+ def not_a_collection
36
+ "expected #{@collection_name} to be a collection but it does not respond to #length or #size"
37
+ end
38
+
39
+ def failure_message
40
+ "expected #{relative_expectation} #{@collection_name}, got #{@given}"
41
+ end
42
+
43
+ def negative_failure_message
44
+ if @relativity == :exactly
45
+ return "expected target not to have #{@expected} #{@collection_name}, got #{@given}"
46
+ elsif @relativity == :at_most
47
+ return <<-EOF
48
+ Isn't life confusing enough?
49
+ Instead of having to figure out the meaning of this:
50
+ should_not have_at_most(#{@expected}).#{@collection_name}
51
+ We recommend that you use this instead:
52
+ should have_at_least(#{@expected + 1}).#{@collection_name}
53
+ EOF
54
+ elsif @relativity == :at_least
55
+ return <<-EOF
56
+ Isn't life confusing enough?
57
+ Instead of having to figure out the meaning of this:
58
+ should_not have_at_least(#{@expected}).#{@collection_name}
59
+ We recommend that you use this instead:
60
+ should have_at_most(#{@expected - 1}).#{@collection_name}
61
+ EOF
62
+ end
63
+ end
64
+
65
+ def description
66
+ "have #{relative_expectation} #{@collection_name}"
67
+ end
68
+
69
+ def respond_to?(sym)
70
+ @expected.respond_to?(sym) || super
71
+ end
72
+
73
+ private
74
+
75
+ def method_missing(sym, *args, &block)
76
+ @collection_name = sym
77
+ if inflector = (defined?(ActiveSupport::Inflector) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
78
+ @plural_collection_name = inflector.pluralize(sym.to_s)
79
+ end
80
+ @args = args
81
+ @block = block
82
+ self
83
+ end
84
+
85
+ def relative_expectation
86
+ "#{relativities[@relativity]}#{@expected}"
87
+ end
88
+ end
89
+
90
+
91
+ module TestCaseExtensions
92
+ def have(n)
93
+ HaveExpectation.new(n, :exactly, self)
94
+ end
95
+ alias :have_exactly :have
96
+
97
+ def have_at_least(n)
98
+ HaveExpectation.new(n, :at_least, self)
99
+ end
100
+
101
+ def have_at_most(n)
102
+ HaveExpectation.new(n, :at_most, self)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,128 @@
1
+ require 'hpricot'
2
+
3
+ # evil hack to duck-type CgiResponse so that nested shoulds can use
4
+ # +rspec_on_rails+ matchers without remembering to call to_s on it
5
+ #
6
+ # e.g.
7
+ #
8
+ # response.should have_tag("li") do |ul|
9
+ # ul.should have_text("List Item") # with hack
10
+ # ul.to_s.should have_text("List Item") # without hack
11
+ # end
12
+ class Hpricot::Elem
13
+ alias body to_s
14
+ end
15
+
16
+ module Matchy::Expectations
17
+ class HaveTag < Base
18
+ def initialize(test_case, selector, inner_text_or_options, options, &block)
19
+ #@expected = expected
20
+ @test_case = test_case
21
+ @selector = selector
22
+
23
+ if Hash === inner_text_or_options
24
+ @inner_text = nil
25
+ @options = inner_text_or_options
26
+ else
27
+ @inner_text = inner_text_or_options
28
+ @options = options
29
+ end
30
+ end
31
+
32
+ def matches?(actual, &block)
33
+ @actual = actual
34
+ @doc = hpricot_document(@actual)
35
+
36
+ matched_elements = @doc.search(@selector)
37
+
38
+ return @options[:count] == 0 if matched_elements.empty?
39
+
40
+ matched_elements = filter_on_inner_text(matched_elements) if @inner_text
41
+ matched_elements = filter_on_nested_expectations(matched_elements, block) if block
42
+
43
+ @actual_count = matched_elements.length
44
+
45
+ return false unless acceptable_count?(@actual_count)
46
+
47
+ !matched_elements.empty?
48
+ end
49
+
50
+ def failure_message
51
+ explanation = @actual_count ? "but found #{@actual_count}" : "but did not"
52
+ "expected\n#{@doc.to_s}\nto have #{failure_count_phrase} #{failure_selector_phrase}, #{explanation}"
53
+ end
54
+
55
+ def negative_failure_message
56
+ explanation = @actual_count ? "but found #{@actual_count}" : "but did"
57
+ "expected\n#{@doc.to_s}\nnot to have #{failure_count_phrase} #{failure_selector_phrase}, #{explanation}"
58
+ end
59
+
60
+ private
61
+ def hpricot_document(input)
62
+ if Hpricot === input
63
+ input
64
+ elsif input.respond_to?(:body)
65
+ Hpricot(input.body)
66
+ else
67
+ Hpricot(input.to_s)
68
+ end
69
+ end
70
+
71
+ def filter_on_inner_text(elements)
72
+ elements.select do |element|
73
+ next(element.inner_text =~ @inner_text) if @inner_text.is_a?(Regexp)
74
+ element.inner_text == @inner_text
75
+ end
76
+ end
77
+
78
+ def filter_on_nested_expectations(elements, block)
79
+ elements.select do |el|
80
+ begin
81
+ block.call(el)
82
+ rescue NoMethodError
83
+ false
84
+ else
85
+ true
86
+ end
87
+ end
88
+ end
89
+
90
+ def acceptable_count?(actual_count)
91
+ if @options[:count]
92
+ return false unless @options[:count] === actual_count
93
+ end
94
+ if @options[:minimum]
95
+ return false unless actual_count >= @options[:minimum]
96
+ end
97
+ if @options[:maximum]
98
+ return false unless actual_count <= @options[:maximum]
99
+ end
100
+
101
+ true
102
+ end
103
+
104
+ def failure_count_phrase
105
+ if @options[:count]
106
+ "#{@options[:count]} elements matching"
107
+ elsif @options[:minimum] || @options[:maximum]
108
+ count_explanations = []
109
+ count_explanations << "at least #{@options[:minimum]}" if @options[:minimum]
110
+ count_explanations << "at most #{@options[:maximum]}" if @options[:maximum]
111
+ "#{count_explanations.join(' and ')} elements matching"
112
+ else
113
+ "an element matching"
114
+ end
115
+ end
116
+
117
+ def failure_selector_phrase
118
+ phrase = @selector.inspect
119
+ phrase << (@inner_text ? " with inner text #{@inner_text.inspect}" : "")
120
+ end
121
+ end
122
+
123
+ module TestCaseExtensions
124
+ def have_tag(selector, inner_text_or_options = nil, options = {}, &block)
125
+ Matchy::Expectations::HaveTag.new(self, selector, inner_text_or_options, options, &block)
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,37 @@
1
+ module Matchy::Expectations
2
+ class PredicateExpectation < Base
3
+ def initialize(predicate, *arguments)
4
+ @test_case = arguments.pop
5
+ @predicate = predicate
6
+ @arguments = arguments
7
+ end
8
+
9
+ def matches?(receiver)
10
+ @receiver = receiver
11
+ @receiver.send("#{@predicate}?", *@arguments)
12
+ end
13
+
14
+ def failure_message
15
+ message = "Expected #{@receiver.inspect} to be #{@predicate}"
16
+ message << " with #{@arguments.map {|e| e.inspect }.join(", ")}" unless @arguments.empty?
17
+ message
18
+ end
19
+
20
+ def negative_failure_message
21
+ message = "Expected #{@receiver.inspect} not to be #{@predicate}"
22
+ message << " with #{@arguments.map {|e| e.inspect }.join(", ")}" unless @arguments.empty?
23
+ message
24
+ end
25
+ end
26
+
27
+ module TestCaseExtensions
28
+ def method_missing(method, *args, &block)
29
+ if method.to_s =~ /^be_(.*)/
30
+ args << self
31
+ Matchy::Expectations::PredicateExpectation.new($1, *args)
32
+ else
33
+ super
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,83 @@
1
+ require 'rubygems'
2
+ require 'dm-sweatshop'
3
+
4
+ include DataMapper::Sweatshop::Unique
5
+
6
+ class Array
7
+ def pick
8
+ self[rand(self.length)]
9
+ end
10
+ end
11
+
12
+ def commit_metadata
13
+ meta_data = <<-EOS
14
+ ---
15
+ :author: #{/\w+ \w+ <\w+@example.org>/.gen}
16
+ :message: >-
17
+ #{/\w+/.gen}
18
+ :date: #{unique {|i| Time.mktime(2008, 12, 15, 18, (59 - i) % 60) }}
19
+ EOS
20
+ end
21
+
22
+ def create_notifier!(name)
23
+ klass = Class.new(Integrity::Notifier::Base) do
24
+ def self.to_haml; ""; end
25
+ def deliver!; nil; end
26
+ end
27
+
28
+ unless Integrity::Notifier.const_defined?(name)
29
+ Integrity::Notifier.const_set(name, klass)
30
+ end
31
+ end
32
+
33
+
34
+ Integrity::Project.fixture do
35
+ { :name => (name = unique { /\w+/.gen }),
36
+ :uri => "git://github.com/#{/\w+/.gen}/#{name}.git",
37
+ :branch => ["master", "test-refactoring", "lh-34"].pick,
38
+ :command => ["rake", "make", "ant -buildfile test.xml"].pick,
39
+ :public => [true, false].pick,
40
+ :building => [true, false].pick }
41
+ end
42
+
43
+ Integrity::Project.fixture(:integrity) do
44
+ { :name => "Integrity",
45
+ :uri => "git://github.com/foca/integrity.git",
46
+ :branch => "master",
47
+ :command => "rake",
48
+ :public => true,
49
+ :building => false }
50
+ end
51
+
52
+ Integrity::Project.fixture(:my_test_project) do
53
+ { :name => "My Test Project",
54
+ :uri => Integrity.root / "my-test-project",
55
+ :branch => "master",
56
+ :command => "./test",
57
+ :public => true,
58
+ :building => false }
59
+ end
60
+
61
+ Integrity::Build.fixture do
62
+ { :output => /[:paragraph:]/.gen,
63
+ :successful => true,
64
+ :created_at => unique {|i| Time.mktime(2008, 12, 15, 18, (59 - i) % 60) },
65
+ :commit_identifier => Digest::SHA1.hexdigest(/[:paragraph:]/.gen),
66
+ :commit_metadata => commit_metadata }
67
+ end
68
+
69
+ Integrity::Notifier.fixture(:irc) do
70
+ create_notifier! "IRC"
71
+
72
+ { :project => Integrity::Project.generate,
73
+ :name => "IRC",
74
+ :config => { :uri => "irc://irc.freenode.net/integrity" }}
75
+ end
76
+
77
+ Integrity::Notifier.fixture(:twitter) do
78
+ create_notifier! "Twitter"
79
+
80
+ { :project => Integrity::Project.generate,
81
+ :name => "Twitter",
82
+ :config => { :email => "foo@example.org", :pass => "secret" }}
83
+ end