relevant-hudson 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ relevant*.gem
data/README.md ADDED
@@ -0,0 +1 @@
1
+ Hudson widget for Relevant
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require 'rake'
2
+ require File.dirname(__FILE__) + "/lib/relevant/hudson.rb"
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gemspec|
9
+ gemspec.version = Relevant::Hudson::Version
10
+ gemspec.name = "relevant-hudson"
11
+ gemspec.summary = "Hudson widget for Relevant"
12
+ gemspec.description = "Check the time"
13
+ gemspec.email = "opensource@thinkrelevance.com"
14
+ gemspec.homepage = "http://github.com/relevance/relevant-hudson"
15
+ gemspec.authors = ["Jared Pace", "Rob Sanheim"]
16
+ gemspec.add_dependency "relevant-widget", "~> 0.0.6"
17
+ gemspec.add_dependency "feedzirra"
18
+ gemspec.add_development_dependency "rspec", "~> 2.0.0.beta.22"
19
+ end
20
+ Jeweler::GemcutterTasks.new
21
+
22
+ rescue LoadError
23
+ puts "Jeweler not available. Install it with: gem install jeweler"
24
+ end
25
+
26
+ require 'rspec/core/rake_task'
27
+ RSpec::Core::RakeTask.new(:spec)
28
+ task :default => :spec
29
+
30
+ task :full_release => [:check_dependencies, :spec, :release]
@@ -0,0 +1,159 @@
1
+ require "relevant/widget"
2
+ require "feedzirra"
3
+
4
+ module Relevant
5
+ class Hudson
6
+ Version = "0.0.1"
7
+ include Relevant::Widget
8
+
9
+ available_options :title => :string,
10
+ :rss_feed => :string,
11
+ :ignore_projects => :string,
12
+ :http_auth_username => :string,
13
+ :http_auth_password => :password
14
+
15
+ refresh_every 1.minute
16
+
17
+ template_format :haml
18
+ template %q[
19
+ %h2 Hudson - #{@options[:title]}
20
+ %ul.hudson-builds
21
+ - builds.each do |build|
22
+ %li.build{:class => build.label}
23
+ %span.indicator
24
+ %h3= build.project.titleize
25
+ %em Build ##{build.number} - #{build.status}
26
+ :css
27
+ ul.hudson-builds li.failing { padding-left: 37%; height: 3em; margin-bottom: 0.5em; }
28
+ ul.hudson-builds li.failing .indicator {
29
+ display: block;
30
+ width: 50%;
31
+ height: 3em;
32
+ float: left;
33
+ margin-left: -58%;
34
+ background-color: #fc2015;
35
+ border-radius: 5px;
36
+ -moz-border-radius: 5px;
37
+ -webkit-border-radius: 5px;
38
+ }
39
+ ul.hudson-builds li.failing h3 { margin-bottom: 0}
40
+ ul.hudson-builds li.failing em { color: #BBB; font-size: 0.8em; }
41
+
42
+ ul.hudson-builds li.building { padding-left: 37%; height: 1.5em; margin-bottom: 0.5em; }
43
+ ul.hudson-builds li.building .indicator {
44
+ display: block;
45
+ width: 50%;
46
+ height: 1.5em;
47
+ float: left;
48
+ margin-left: -58%;
49
+ background-color: #fcce15;
50
+ border-radius: 5px;
51
+ -moz-border-radius: 5px;
52
+ -webkit-border-radius: 5px;
53
+ }
54
+ ul.hudson-builds li.building h3 { margin-bottom: 0}
55
+ ul.hudson-builds li.building em { display:none; }
56
+
57
+ ul.hudson-builds li.passing {
58
+ float: left;
59
+ margin-right: 1.5em;
60
+ padding: 5px 0 5px 18px;
61
+ }
62
+ ul.hudson-builds li.passing .indicator {
63
+ display: block;
64
+ width: 14px;
65
+ height: 14px;
66
+ float: left;
67
+ margin-left: -18px;
68
+ background-color: #4ad026;
69
+ border-radius: 7px;
70
+ -moz-border-radius: 7px;
71
+ -webkit-border-radius: 7px;
72
+ }
73
+ ul.hudson-builds li.passing h3 { font-size: 1.1em; margin: 0;}
74
+ ul.hudson-builds li.passing em { display: none }
75
+ ul.hudson-builds li .indicator {
76
+ box-shadow: 1px 1px 3px #222;
77
+ -moz-box-shadow: 1px 1px 3px #222;
78
+ -webkit-box-shadow: 1px 1px 3px #222;
79
+ }
80
+ :javascript
81
+ function animateHudsonBuilds() {
82
+ $('ul.hudson-builds li.building .indicator').animate({opacity:0.05},2000,function(){
83
+ $('ul.hudson-builds li.building .indicator').animate({opacity:1},2000,animateHudsonBuilds);
84
+ });
85
+ }
86
+ animateHudsonBuilds();
87
+ ]
88
+
89
+ def builds
90
+ return [] unless feed.respond_to?(:entries) # Error fetching feed
91
+
92
+ builds = feed.entries.map{|rss_entry| Build.new(rss_entry)}
93
+ builds.reject! {|build| build.project.match Regexp.new(@options[:ignore_projects], true)} if @options[:ignore_projects].present?
94
+ builds.sort
95
+ end
96
+
97
+ def feed
98
+ return unless @options[:rss_feed].present?
99
+
100
+ feed_options = {:timeout => 10}
101
+ feed_options[:http_authentication] = [@options[:http_auth_username], @options[:http_auth_password]] if @options[:http_auth_username].present?
102
+
103
+ @feed ||= Feedzirra::Feed.fetch_and_parse(@options[:rss_feed], feed_options)
104
+ end
105
+
106
+ class Build
107
+ TitleRegexp = /^(.*) #(\d+) \((.*)\)$/
108
+
109
+ attr_reader :rss_entry
110
+
111
+ def initialize(rss_entry)
112
+ @rss_entry = rss_entry
113
+ end
114
+
115
+ def passing?
116
+ status.match(/(stable|back to normal)/i)
117
+ end
118
+
119
+ def failing?
120
+ status.match(/broken/)
121
+ end
122
+
123
+ def building?
124
+ status.match(/^\?$/)
125
+ end
126
+
127
+ def project
128
+ rss_entry.title.match(TitleRegexp)[1]
129
+ end
130
+
131
+ def number
132
+ rss_entry.title.match(TitleRegexp)[2]
133
+ end
134
+
135
+ def status
136
+ rss_entry.title.match(TitleRegexp)[3]
137
+ end
138
+
139
+ def label
140
+ if passing?
141
+ 'passing'
142
+ elsif failing?
143
+ 'failing'
144
+ elsif building?
145
+ 'building'
146
+ end
147
+ end
148
+
149
+ def <=>(other_build)
150
+ order = ['failing','building','passing']
151
+ result = order.index(self.label) <=> order.index(other_build.label)
152
+ result = self.project <=> other_build.project if result.zero?
153
+ result
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ Relevant.register Relevant::Hudson
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+
3
+ describe Relevant::Hudson do
4
+
5
+ describe "#feed" do
6
+ it 'fetches and parses the RSS feed' do
7
+ hudson = Relevant::Hudson.setup(:rss_feed => 'http://hudson.example.com/rssLatest')
8
+
9
+ Feedzirra::Feed.expects(:fetch_and_parse).with('http://hudson.example.com/rssLatest', {:timeout => 10}).returns(:feed)
10
+ hudson.feed.should == :feed
11
+ end
12
+
13
+ it 'will pass basic auth credentials if provided' do
14
+ hudson = Relevant::Hudson.setup(
15
+ :rss_feed => 'http://hudson.example.com/rssLatest',
16
+ :http_auth_username => 'admin',
17
+ :http_auth_password => 'letmein'
18
+ )
19
+
20
+ Feedzirra::Feed.expects(:fetch_and_parse).with(
21
+ 'http://hudson.example.com/rssLatest', {
22
+ :timeout => 10,
23
+ :http_authentication => ['admin','letmein']
24
+ })
25
+ hudson.feed
26
+ end
27
+ end
28
+
29
+ describe '#builds' do
30
+ before do
31
+ @passing_entry = stub('entry', :title => 'Bar Project #15 (stable)')
32
+ @failing_entry = stub('entry', :title => 'Foo Project #99 (broken since build #85)')
33
+ @hudson = Relevant::Hudson.setup
34
+ @hudson.stubs(:feed).returns(stub('feed', :title => 'RSS Feed', :entries => [@passing_entry, @failing_entry]))
35
+ end
36
+
37
+ it 'translates rss entries into builds' do
38
+ @hudson.builds.all?{|build| build.is_a? Relevant::Hudson::Build}.should be_true
39
+ end
40
+
41
+ it 'sorts the builds to have failing ones first' do
42
+ @hudson.builds.first.should be_failing
43
+ end
44
+
45
+ it 'ignores projects by matching against its name' do
46
+ hudson = Relevant::Hudson.setup :ignore_projects => '^foo'
47
+ hudson.stubs(:feed).returns(stub('feed', :title => 'RSS Feed', :entries => [@passing_entry, @failing_entry]))
48
+
49
+ hudson.builds.map(&:project).should_not include('Foo Project')
50
+ end
51
+ end
52
+
53
+ describe Relevant::Hudson::Build do
54
+ it 'knows the project of the build' do
55
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (broken since build #85)')
56
+ build.project.should == 'Foo Project'
57
+ end
58
+
59
+ it 'knows the number of the build' do
60
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (broken since build #85)')
61
+ build.number.should == '99'
62
+ end
63
+
64
+ it 'knows the status of the build' do
65
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (broken since build #85)')
66
+ build.status.should == 'broken since build #85'
67
+ end
68
+
69
+ it 'is passing if the build is stable' do
70
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (stable)')
71
+ build.should be_passing
72
+ end
73
+
74
+ it 'is passing if the build is back to normal' do
75
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (back to normal)')
76
+ build.should be_passing
77
+ end
78
+
79
+ it 'is failing if the build is broken' do
80
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (broken since build #85)')
81
+ build.should_not be_passing
82
+ build.should be_failing
83
+ end
84
+
85
+ it 'is building if the status is unknown' do
86
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (?)')
87
+ build.should_not be_passing
88
+ build.should_not be_failing
89
+ build.should be_building
90
+ end
91
+
92
+ context 'label' do
93
+ it "is 'passing' if the build is passing?" do
94
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (stable)')
95
+ build.label.should == 'passing'
96
+ end
97
+
98
+ it "is 'building' if the build is building?" do
99
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (?)')
100
+ build.label.should == 'building'
101
+ end
102
+
103
+ it "is 'failing' if the build is failing?" do
104
+ build = Relevant::Hudson::Build.new stub('entry', :title => 'Foo Project #99 (broken)')
105
+ build.label.should == 'failing'
106
+ end
107
+ end
108
+ end
109
+
110
+ end
@@ -0,0 +1,15 @@
1
+ require 'rspec'
2
+
3
+ $LOAD_PATH.unshift "../lib"
4
+ require "relevant/hudson"
5
+
6
+ RSpec.configure do |config|
7
+ config.color_enabled = true
8
+ config.mock_with :mocha
9
+
10
+ config.formatter = :progress
11
+ config.color_enabled = true
12
+ config.filter_run :focused => true
13
+ config.run_all_when_everything_filtered = true
14
+ config.alias_example_to :fit, :focused => true
15
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: relevant-hudson
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Jared Pace
13
+ - Rob Sanheim
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-24 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: relevant-widget
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 0
31
+ - 0
32
+ - 6
33
+ version: 0.0.6
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: feedzirra
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 2
59
+ - 0
60
+ - 0
61
+ - beta
62
+ - 22
63
+ version: 2.0.0.beta.22
64
+ type: :development
65
+ version_requirements: *id003
66
+ description: Check the time
67
+ email: opensource@thinkrelevance.com
68
+ executables: []
69
+
70
+ extensions: []
71
+
72
+ extra_rdoc_files:
73
+ - README.md
74
+ files:
75
+ - .gitignore
76
+ - README.md
77
+ - Rakefile
78
+ - lib/relevant/hudson.rb
79
+ - spec/relevant/hudson_spec.rb
80
+ - spec/spec_helper.rb
81
+ has_rdoc: true
82
+ homepage: http://github.com/relevance/relevant-hudson
83
+ licenses: []
84
+
85
+ post_install_message:
86
+ rdoc_options:
87
+ - --charset=UTF-8
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ segments:
104
+ - 0
105
+ version: "0"
106
+ requirements: []
107
+
108
+ rubyforge_project:
109
+ rubygems_version: 1.3.7
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: Hudson widget for Relevant
113
+ test_files:
114
+ - spec/relevant/hudson_spec.rb
115
+ - spec/spec_helper.rb