Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don't worry, you can still create the pull request.
  • 17 commits
  • 19 files changed
  • 0 commit comments
  • 2 contributors
View
6 Gemfile.lock
@@ -1,13 +1,14 @@
PATH
remote: .
specs:
- chicanery (0.0.6)
+ chicanery (0.0.7)
nokogiri (~> 1)
GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.1.3)
+ fakeweb (1.3.0)
multi_json (1.3.7)
nokogiri (1.5.5)
rake (0.9.2.2)
@@ -25,13 +26,16 @@ GEM
simplecov-gem-adapter (1.0.1)
simplecov
simplecov-html (0.7.1)
+ vcr (2.3.0)
PLATFORMS
ruby
DEPENDENCIES
chicanery!
+ fakeweb
rake (~> 0)
rspec (~> 2)
simplecov
simplecov-gem-adapter
+ vcr
View
8 README.md
@@ -56,12 +56,16 @@ Now you can schedule the following command with cron:
chicanery myconfiguration
-Or continuously poll every 10 seconds:
+Or to continuously poll every 10 seconds, add the following line to the configuration:
- chicanery myconfiguration 10
+ poll_period 10
You'll notice a file called 'state' is created which represents the state at the last execution. This is then restored during the next execution to detect events such as a new build succeeding/failing.
+If you want to specify an alternate location for this state file, add the following line to your configuration file:
+
+ persist_state_to '/tmp/build_state'
+
## Supported CI servers
Currently only ci servers that can provide [cctray reporting format](http://confluence.public.thoughtworks.org/display/CI/Multiple+Project+Summary+Reporting+Standard) are supported.
View
2  chicanery.gemspec
@@ -23,4 +23,6 @@ Gem::Specification.new do |gem|
gem.add_development_dependency 'rspec', '~>2'
gem.add_development_dependency 'simplecov'
gem.add_development_dependency 'simplecov-gem-adapter'
+ gem.add_development_dependency 'vcr'
+ gem.add_development_dependency 'fakeweb'
end
View
4 examples/baby_steps.rb
@@ -2,7 +2,9 @@
include Chicanery::Git
-git_repo 'chicanery', '.', branches: [:master]
+git 'chicanery', '.', branches: [:master]
+
+poll_period 10
def now
Time.now.to_i
View
14 examples/blinky.rb
@@ -0,0 +1,14 @@
+require 'blinky'
+require 'chicanery/cctray'
+
+include Chicanery::Cctray
+
+cctray 'travis', 'https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml'
+
+when_run do |state|
+ if state.has_failure?
+ Blinky.new.light.failure!
+ else
+ Blinky.new.light.success!
+ end
+end
View
7 examples/chicanery.rb
@@ -2,12 +2,15 @@
require 'chicanery/git'
include Chicanery::Git
+include Chicanery::Cctray
-git_repo 'chicanery', '.', branches: [:master], remotes: {
+git 'chicanery', '.', branches: [:master], remotes: {
github: { url: 'git://github.com/markryall/chicanery.git' }
}
-server Chicanery::Cctray.new 'travis', 'https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml'
+cctray 'travis', 'https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml'
+
+poll_period 10
def growlnotify message
`growlnotify -t "some new chicanery ..." --image ~/icons/chicanery.png -m \"#{message}\"`
View
54 fixtures/vcr_cassettes/broken.yml
@@ -0,0 +1,54 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ accept:
+ - ! '*/*'
+ user-agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ access-control-allow-credentials:
+ - 'true'
+ access-control-allow-origin:
+ - ! '*'
+ access-control-expose-headers:
+ - Content-Type, Cache-Control, Expires, Etag, Last-Modified
+ cache-control:
+ - no-cache
+ content-type:
+ - application/json;charset=utf-8
+ date:
+ - Sat, 15 Dec 2012 02:41:37 GMT
+ etag:
+ - ! '"715c01a97e6124876f63088110deeafd"'
+ status:
+ - 200 OK
+ strict-transport-security:
+ - max-age=31536000
+ vary:
+ - Accept,Accept-Encoding
+ x-accepted-oauth-scopes:
+ - public
+ x-oauth-scopes:
+ - public
+ content-length:
+ - '245'
+ connection:
+ - keep-alive
+ body:
+ encoding: US-ASCII
+ string: ! "<Projects>\n <Project\n name=\"markryall/chicanery\"\n activity=\"Sleeping\"\n
+ \ lastBuildStatus=\"Failure\"\n lastBuildLabel=\"50\"\n lastBuildTime=\"2012-12-15T02:41:20.000+0000\"\n
+ \ webUrl=\"api.travis-ci.org/markryall/chicanery\" />\n</Projects>"
+ http_version: '1.1'
+ recorded_at: Sat, 15 Dec 2012 02:41:42 GMT
+recorded_with: VCR 2.3.0
View
54 fixtures/vcr_cassettes/idle.yml
@@ -0,0 +1,54 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ accept:
+ - ! '*/*'
+ user-agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ access-control-allow-credentials:
+ - 'true'
+ access-control-allow-origin:
+ - ! '*'
+ access-control-expose-headers:
+ - Content-Type, Cache-Control, Expires, Etag, Last-Modified
+ cache-control:
+ - no-cache
+ content-type:
+ - application/json;charset=utf-8
+ date:
+ - Sat, 15 Dec 2012 02:36:15 GMT
+ etag:
+ - ! '"0bb76c5892b2ce7a7efafc2b41bc2512"'
+ status:
+ - 200 OK
+ strict-transport-security:
+ - max-age=31536000
+ vary:
+ - Accept,Accept-Encoding
+ x-accepted-oauth-scopes:
+ - public
+ x-oauth-scopes:
+ - public
+ content-length:
+ - '245'
+ connection:
+ - keep-alive
+ body:
+ encoding: US-ASCII
+ string: ! "<Projects>\n <Project\n name=\"markryall/chicanery\"\n activity=\"Sleeping\"\n
+ \ lastBuildStatus=\"Success\"\n lastBuildLabel=\"48\"\n lastBuildTime=\"2012-12-15T02:18:28.000+0000\"\n
+ \ webUrl=\"api.travis-ci.org/markryall/chicanery\" />\n</Projects>"
+ http_version: '1.1'
+ recorded_at: Sat, 15 Dec 2012 02:36:20 GMT
+recorded_with: VCR 2.3.0
View
52 fixtures/vcr_cassettes/no_projects.yml
@@ -0,0 +1,52 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ accept:
+ - ! '*/*'
+ user-agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ access-control-allow-credentials:
+ - 'true'
+ access-control-allow-origin:
+ - ! '*'
+ access-control-expose-headers:
+ - Content-Type, Cache-Control, Expires, Etag, Last-Modified
+ cache-control:
+ - no-cache
+ content-type:
+ - application/json;charset=utf-8
+ date:
+ - Sat, 15 Dec 2012 02:39:04 GMT
+ etag:
+ - ! '"aa451983b94cbec99aa94346f358b5b0"'
+ status:
+ - 200 OK
+ strict-transport-security:
+ - max-age=31536000
+ vary:
+ - Accept,Accept-Encoding
+ x-accepted-oauth-scopes:
+ - public
+ x-oauth-scopes:
+ - public
+ content-length:
+ - '217'
+ connection:
+ - keep-alive
+ body:
+ encoding: US-ASCII
+ string: ! "Nothing here but us chickens"
+ http_version: '1.1'
+ recorded_at: Sat, 15 Dec 2012 02:39:09 GMT
+recorded_with: VCR 2.3.0
View
52 fixtures/vcr_cassettes/redirect.yml
@@ -0,0 +1,52 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ accept:
+ - ! '*/*'
+ user-agent:
+ - Ruby
+ response:
+ status:
+ code: 301
+ message: Redirect
+ headers:
+ access-control-allow-credentials:
+ - 'true'
+ access-control-allow-origin:
+ - ! '*'
+ access-control-expose-headers:
+ - Content-Type, Cache-Control, Expires, Etag, Last-Modified
+ cache-control:
+ - no-cache
+ content-type:
+ - application/json;charset=utf-8
+ date:
+ - Sat, 15 Dec 2012 02:39:04 GMT
+ etag:
+ - ! '"aa451983b94cbec99aa94346f358b5b0"'
+ status:
+ - 200 OK
+ strict-transport-security:
+ - max-age=31536000
+ vary:
+ - Accept,Accept-Encoding
+ x-accepted-oauth-scopes:
+ - public
+ x-oauth-scopes:
+ - public
+ content-length:
+ - '217'
+ connection:
+ - keep-alive
+ body:
+ encoding: US-ASCII
+ string: ! "hhh"
+ http_version: '1.1'
+ recorded_at: Sat, 15 Dec 2012 02:39:09 GMT
+recorded_with: VCR 2.3.0
View
54 fixtures/vcr_cassettes/running.yml
@@ -0,0 +1,54 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ accept:
+ - ! '*/*'
+ user-agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ access-control-allow-credentials:
+ - 'true'
+ access-control-allow-origin:
+ - ! '*'
+ access-control-expose-headers:
+ - Content-Type, Cache-Control, Expires, Etag, Last-Modified
+ cache-control:
+ - no-cache
+ content-type:
+ - application/json;charset=utf-8
+ date:
+ - Sat, 15 Dec 2012 02:39:04 GMT
+ etag:
+ - ! '"aa451983b94cbec99aa94346f358b5b0"'
+ status:
+ - 200 OK
+ strict-transport-security:
+ - max-age=31536000
+ vary:
+ - Accept,Accept-Encoding
+ x-accepted-oauth-scopes:
+ - public
+ x-oauth-scopes:
+ - public
+ content-length:
+ - '217'
+ connection:
+ - keep-alive
+ body:
+ encoding: US-ASCII
+ string: ! "<Projects>\n <Project\n name=\"markryall/chicanery\"\n activity=\"Building\"\n
+ \ lastBuildStatus=\"Unknown\"\n lastBuildLabel=\"49\"\n lastBuildTime=\"\"\n
+ \ webUrl=\"api.travis-ci.org/markryall/chicanery\" />\n</Projects>"
+ http_version: '1.1'
+ recorded_at: Sat, 15 Dec 2012 02:39:09 GMT
+recorded_with: VCR 2.3.0
View
21 lib/chicanery.rb
@@ -18,27 +18,24 @@ module Chicanery
VERSION = "0.0.7"
- def execute args
- load args.shift
- poll_period = args.shift
- if poll_period
- run_every poll_period.to_i
- else
- run
- end
+ def poll_period seconds=nil
+ @poll_period = seconds if seconds
+ @poll_period
end
- def run_every poll_period
+ def execute args
+ load args.shift
begin
loop do
run
+ break unless poll_period
sleep poll_period
end
rescue Interrupt
end
end
- def run
+ def run
previous_state = restore
current_state = {
servers: {},
@@ -55,8 +52,8 @@ def run
current_state[:servers][server.name] = current_jobs
end
current_state.extend Chicanery::Summary
- run_handlers.each {|handler| handler.call current_state }
- persist current_state
+ run_handlers.each {|handler| handler.call current_state, previous_state }
+ persist current_state
end
end
View
79 lib/chicanery/cctray.rb
@@ -3,48 +3,61 @@
require 'date'
module Chicanery
- class Cctray
- attr_reader :name, :uri, :options
+ module Cctray
+ def self.new *args
+ Cctray::Server.new *args
+ end
- def initialize name, url, options={}
- @name, @uri, @options = name, URI(url), options
+ def cctray *args
+ server Cctray::Server.new *args
end
- def get
- req = Net::HTTP::Get.new(uri.path)
- req.basic_auth user, password if options[:user] and options[:password]
- res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https', verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
- https.request(req)
+ class Server
+ attr_reader :name, :uri, :options
+
+ def initialize name, url, options={}
+ @name, @uri, @options = name, URI(url), options
end
- res.body
- end
- def jobs
- jobs = {}
- Nokogiri::XML(get).css("Project").each do |project|
- job = {
- activity: project[:activity] == 'Sleeping' ? :sleeping : :building,
- last_build_status: parse_build_status(project[:lastBuildStatus]),
- last_build_time: project[:lastBuildTime].empty? ? nil : DateTime.parse(project[:lastBuildTime]).to_time.to_i,
- url: project[:webUrl],
- last_label: project[:lastBuildLabel]
- }
- jobs[project[:name]] = job unless filtered project[:name]
+ def get
+ req = Net::HTTP::Get.new(uri.path)
+ req.basic_auth user, password if options[:user] and options[:password]
+ res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https', verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
+ https.request(req)
+ end
+ res.value #check for success via a spectactulalry poorly named method
+ res.body
end
- jobs
- end
- def parse_build_status status
- case status
- when /^Success/ then :success
- when /^Unknown/ then :unknown
- else :failure
+ def jobs
+ jobs = {}
+ response_body = get
+ Nokogiri::XML(response_body).css("Project").each do |project|
+ job = {
+ activity: project[:activity] == 'Sleeping' ? :sleeping : :building,
+ last_build_status: parse_build_status(project[:lastBuildStatus]),
+ last_build_time: project[:lastBuildTime].empty? ? nil : DateTime.parse(project[:lastBuildTime]).to_time.to_i,
+ url: project[:webUrl],
+ last_label: project[:lastBuildLabel]
+ }
+ jobs[project[:name]] = job unless filtered project[:name]
+ end
+ raise "could not find any jobs in response: [#{response_body}]" if jobs.empty?
+ jobs
+ end
+
+ def parse_build_status status
+ case status
+ when /^Success/ then :success
+ when /^Unknown/ then :unknown
+ else :failure
+ end
end
- end
- def filtered name
- return false unless options[:include]
- !options[:include].match(name)
+ def filtered name
+ return false unless options[:include]
+ !options[:include].match(name)
+ end
end
end
end
View
2  lib/chicanery/git.rb
@@ -54,7 +54,7 @@ def git command
end
end
- def git_repo *args
+ def git *args
repo Repo.new *args
end
end
View
11 lib/chicanery/persistence.rb
@@ -3,14 +3,19 @@
module Chicanery
module Persistence
def persist state
- File.open 'state', 'w' do |file|
+ File.open persist_state_to, 'w' do |file|
file.puts state.to_yaml
end
end
def restore
- return {} unless File.exist? 'state'
- YAML.load_file 'state'
+ return {} unless File.exist? persist_state_to
+ YAML.load_file persist_state_to
+ end
+
+ def persist_state_to path=nil
+ @state = path if path
+ @state || 'state'
end
end
end
View
68 spec/chicanery/cctray_spec.rb
@@ -0,0 +1,68 @@
+require 'chicanery/cctray'
+require 'vcr'
+
+VCR.configure do |c|
+ c.cassette_library_dir = 'fixtures/vcr_cassettes'
+ c.hook_into :fakeweb
+end
+
+describe Chicanery::Cctray do
+ let(:server) do
+ Chicanery::Cctray.new 'chicanery', 'https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml'
+ end
+
+ it 'should detect idle build' do
+ VCR.use_cassette('idle') do
+ server.jobs.should == {
+ "markryall/chicanery" => {
+ activity: :sleeping,
+ last_build_status: :success,
+ last_build_time: 1355537908,
+ url: "api.travis-ci.org/markryall/chicanery",
+ last_label: "48"
+ }
+ }
+ end
+ end
+
+ it 'should detect running build' do
+ VCR.use_cassette('running') do
+ server.jobs.should == {
+ "markryall/chicanery" => {
+ activity: :building,
+ last_build_status: :unknown,
+ last_build_time: nil,
+ url: "api.travis-ci.org/markryall/chicanery",
+ last_label: "49"
+ }
+ }
+ end
+ end
+
+ it 'should detect failed build' do
+ VCR.use_cassette('broken') do
+ server.jobs.should == {
+ "markryall/chicanery" => {
+ activity: :sleeping,
+ last_build_status: :failure,
+ last_build_time: 1355539280,
+ url: "api.travis-ci.org/markryall/chicanery",
+ last_label: "50"
+ }
+ }
+ end
+ end
+
+ it 'should complain if there are no jobs in response' do
+ VCR.use_cassette('no_projects') do
+ expect{server.jobs}.to raise_error "could not find any jobs in response: [Nothing here but us chickens]"
+ end
+ end
+
+ it 'should complain if it gets a non 2xx response' do
+ VCR.use_cassette('redirect') do
+ expect{server.jobs}.to raise_error Net::HTTPRetriableError
+ end
+ end
+
+end
View
20 spec/chicanery/persistence_spec.rb
@@ -1,14 +1,22 @@
describe Chicanery::Persistence do
include Chicanery::Persistence
+ let(:file) { stub 'file' }
+ let(:state) { stub 'state', to_yaml: :yaml }
+
describe '#persist' do
it 'should write state to disk as yaml' do
- file = stub 'file'
- state = stub 'state', to_yaml: :yaml
File.should_receive(:open).with('state', 'w').and_yield file
file.should_receive(:puts).with :yaml
persist state
end
+
+ it 'should persist state to where it is told' do
+ persist_state_to 'foo'
+ File.should_receive(:open).with('foo', 'w').and_yield file
+ file.should_receive(:puts).with :yaml
+ persist state
+ end
end
describe '#restore' do
@@ -18,10 +26,16 @@
end
it 'should read yaml from disk' do
- state = stub 'state'
File.should_receive(:exist?).with('state').and_return true
YAML.should_receive(:load_file).with('state').and_return state
restore.should == state
end
+
+ it 'should read yaml from another location if it is told to do so' do
+ persist_state_to 'foo'
+ File.should_receive(:exist?).with('foo').and_return true
+ YAML.should_receive(:load_file).with('foo').and_return state
+ restore.should == state
+ end
end
end
View
15 spec/chicanery_spec.rb
@@ -4,14 +4,14 @@
describe '#execute' do
before { %w{load restore persist}.each {|m| stub! m } }
+ after { execute ['configuration'] }
+
it 'should load configuration and exit immediately when nothing is configured no poll period is provided' do
should_receive(:load).with 'configuration'
- execute %w{configuration}
end
it 'should restore previous state' do
should_receive(:restore)
- execute %w{configuration}
end
it 'should persist new state' do
@@ -19,12 +19,19 @@
servers: {},
repos: {}
})
- execute %w{configuration}
end
it 'should sleep for specified time when poll period is provided' do
should_receive(:sleep).with(10).and_raise Interrupt
- execute %w{configuration 10}
+ poll_period 10
+ end
+
+ it "polls with a specified period" do
+ should_receive(:run).exactly(3).times
+ should_receive(:sleep).with(10).ordered
+ should_receive(:sleep).with(10).ordered
+ should_receive(:sleep).with(10).ordered.and_raise Interrupt
+ poll_period 10
end
end
end
View
29 spec/embedded_chicanery_spec.rb
@@ -1,8 +1,8 @@
describe Chicanery do
include Chicanery
-
+
describe '#run' do
-
+
before do
server double("Server A", :name => "A", :jobs => "A jobs")
server double("Server B", :name => "B", :jobs => "B jobs")
@@ -13,37 +13,26 @@
end
@current_state = nil
end
-
+
before { stub!("restore").and_return({})}
before { %w{persist}.each {|m| stub! m } }
-
+
it "notifies when_run listeners of the current state of the servers jobs" do
- run
+ run
@current_state[:servers]["A"].should == "A jobs"
@current_state[:servers]["B"].should == "B jobs"
end
-
+
it "notifies when_run listeners of the current state of the repos" do
- run
+ run
@current_state[:repos]["X"].should == "X state"
@current_state[:repos]["Y"].should == "Y state"
end
-
+
#TESTS TODO
# it restores previous state and records current state
# it compares current state and previous state for each server
# it compares current state and previous state for each server
-
- end
-
- describe '#run_every' do
- it "polls with a specified period" do
- should_receive(:run).exactly(3).times
- should_receive(:sleep).with(10).ordered
- should_receive(:sleep).with(10).ordered
- should_receive(:sleep).with(10).ordered.and_raise Interrupt
- run_every 10
- end
+
end
-
end

No commit comments for this range

Something went wrong with that request. Please try again.