travis-surveillance 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.travis.yml +11 -0
- data/Gemfile +6 -0
- data/Makefile +19 -0
- data/README.md +40 -0
- data/Rakefile +11 -0
- data/bin/travis-surveillance +10 -0
- data/lib/travis/surveillance.rb +68 -0
- data/lib/travis/surveillance/build.rb +112 -0
- data/lib/travis/surveillance/cli.rb +83 -0
- data/lib/travis/surveillance/job.rb +93 -0
- data/lib/travis/surveillance/project.rb +60 -0
- data/lib/travis/surveillance/surveyor.rb +106 -0
- data/lib/travis/surveillance/version.rb +5 -0
- data/logs/.gitignore +1 -0
- data/spec/helper.rb +40 -0
- data/spec/support/builds/1.json +16 -0
- data/spec/support/jobs/1.json +10 -0
- data/spec/support/projects/dylanegan-travis-surveillance.json +14 -0
- data/spec/support/pusher/dylanegan-travis-surveillance-build-finished.json +10 -0
- data/spec/support/pusher/dylanegan-travis-surveillance-build-started.json +13 -0
- data/spec/support/pusher/dylanegan-travis-surveillance-job-finished.json +7 -0
- data/spec/support/pusher/dylanegan-travis-surveillance-job-started.json +5 -0
- data/spec/travis/surveillance/build_spec.rb +116 -0
- data/spec/travis/surveillance/job_spec.rb +89 -0
- data/spec/travis/surveillance/project_spec.rb +65 -0
- data/spec/travis/surveillance/surveyor_spec.rb +62 -0
- data/spec/travis/surveillance_spec.rb +22 -0
- data/travis-surveillance.gemspec +25 -0
- data/travis-surveillance.jpg +0 -0
- metadata +185 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
module Travis
|
2
|
+
module Surveillance
|
3
|
+
class Project
|
4
|
+
attr_accessor :description, :id, :name, :owner, :slug, :status
|
5
|
+
|
6
|
+
def initialize(name)
|
7
|
+
@owner, @name = name.split('/')
|
8
|
+
@slug = name
|
9
|
+
populate
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_build(json)
|
13
|
+
if build = build_for(json['id'])
|
14
|
+
return build
|
15
|
+
end
|
16
|
+
|
17
|
+
build = Build.new(json.merge({'project' => self}))
|
18
|
+
builds << build
|
19
|
+
build
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_for(id)
|
23
|
+
builds.find { |b| b.id == id }
|
24
|
+
end
|
25
|
+
|
26
|
+
def building?
|
27
|
+
status.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def builds
|
31
|
+
@builds ||= []
|
32
|
+
end
|
33
|
+
|
34
|
+
def failed?
|
35
|
+
!status.nil? && !passed?
|
36
|
+
end
|
37
|
+
|
38
|
+
def passed?
|
39
|
+
!status.nil? && status.zero?
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def get_details
|
45
|
+
if Travis::Surveillance.mocking?
|
46
|
+
JSON.parse(IO.read(File.dirname(__FILE__) + "/../../../spec/support/projects/#{slug.gsub('/', '-')}.json"))
|
47
|
+
else
|
48
|
+
JSON.parse(open("http://travis-ci.org/#{slug}.json").read)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def populate
|
53
|
+
details = get_details
|
54
|
+
@description = details['description']
|
55
|
+
@id = details['id']
|
56
|
+
@status = details['last_build_status']
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require "json"
|
2
|
+
require "open-uri"
|
3
|
+
|
4
|
+
gem "pusher-client-merman"
|
5
|
+
require "pusher-client"
|
6
|
+
PusherClient.logger.level = Logger::INFO
|
7
|
+
|
8
|
+
module Travis
|
9
|
+
module Surveillance
|
10
|
+
class Surveyor
|
11
|
+
attr_accessor :project, :socket
|
12
|
+
|
13
|
+
def initialize(project, pusher_token = "23ed642e81512118260e")
|
14
|
+
@project = project
|
15
|
+
@socket = PusherClient::Socket.new(pusher_token)
|
16
|
+
end
|
17
|
+
|
18
|
+
def survey(&block)
|
19
|
+
@socket.subscribe('common')
|
20
|
+
|
21
|
+
@socket['common'].bind('build:started') do |payload|
|
22
|
+
payload_to_new_build(payload)
|
23
|
+
yield if block_given?
|
24
|
+
end
|
25
|
+
@socket['common'].bind('build:finished') do |payload|
|
26
|
+
payload_to_finished_build(payload)
|
27
|
+
yield if block_given?
|
28
|
+
end
|
29
|
+
@socket['common'].bind('job:started') do |payload|
|
30
|
+
payload_to_job_started(payload)
|
31
|
+
yield if block_given?
|
32
|
+
end
|
33
|
+
@socket['common'].bind('job:finished') do |payload|
|
34
|
+
payload_to_job_finished(payload)
|
35
|
+
yield if block_given?
|
36
|
+
end
|
37
|
+
|
38
|
+
@socket.connect unless Travis::Surveillance.mocking?
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def add_missing_build(build)
|
44
|
+
Travis::Surveillance.log({ surveyor: true, build: true, missing: true, id: build['id'] })
|
45
|
+
@project.add_build(build)
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_and_check(payload)
|
49
|
+
json = JSON.parse(payload)
|
50
|
+
repository_id = json['repository'] ? json['repository']['id'] : json['repository_id']
|
51
|
+
repository_id == @project.id ? json : nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_and_check_and_build(payload)
|
55
|
+
return unless json = parse_and_check(payload)
|
56
|
+
|
57
|
+
json_build = json['build'] ? json['build'] : { 'id' => json['build_id'] }
|
58
|
+
|
59
|
+
unless build = @project.build_for(json_build['id'])
|
60
|
+
build = add_missing_build(json_build)
|
61
|
+
end
|
62
|
+
|
63
|
+
[json, build]
|
64
|
+
end
|
65
|
+
|
66
|
+
def payload_to_new_build(payload)
|
67
|
+
return unless json = parse_and_check(payload)
|
68
|
+
|
69
|
+
unless build = @project.build_for(json['build']['id'])
|
70
|
+
Travis::Surveillance.log({ surveyor: true, build: true, started: true, id: json['build']['id'] })
|
71
|
+
@project.add_build(json['build'])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def payload_to_finished_build(payload)
|
76
|
+
json, build = parse_and_check_and_build(payload)
|
77
|
+
return unless build
|
78
|
+
|
79
|
+
Travis::Surveillance.log({ surveyor: true, build: true, finished: true, id: build.id })
|
80
|
+
build.attributes = json['build']
|
81
|
+
@project.status = build.status
|
82
|
+
end
|
83
|
+
|
84
|
+
def payload_to_job_started(payload)
|
85
|
+
json, build = parse_and_check_and_build(payload)
|
86
|
+
return unless build
|
87
|
+
|
88
|
+
Travis::Surveillance.log({ surveyor: true, job: true, started: true, id: json['id'], build_id: build.id })
|
89
|
+
build.add_job(json)
|
90
|
+
end
|
91
|
+
|
92
|
+
def payload_to_job_finished(payload)
|
93
|
+
json, build = parse_and_check_and_build(payload)
|
94
|
+
return unless build
|
95
|
+
|
96
|
+
unless job = build.job_for(json['id'])
|
97
|
+
Travis::Surveillance.log({ surveyor: true, job: true, missing: true, id: json['id'], build_id: build.id })
|
98
|
+
job = build.add_job(json)
|
99
|
+
end
|
100
|
+
|
101
|
+
Travis::Surveillance.log({ surveyor: true, job: true, finished: true, id: json['id'], build_id: build.id })
|
102
|
+
job.attributes = json
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/logs/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.log
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "simplecov" unless ENV['NO_SIMPLECOV']
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
require "scrolls"
|
5
|
+
require "travis/surveillance"
|
6
|
+
|
7
|
+
Scrolls::Log.stream = File.open(File.dirname(__FILE__) + '/../logs/test.log', 'w')
|
8
|
+
|
9
|
+
module TestLogger
|
10
|
+
def self.log(data, &blk)
|
11
|
+
Scrolls.log(data, &blk)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Travis::Surveillance.instrument_with(TestLogger.method(:log))
|
16
|
+
Travis::Surveillance.mock!
|
17
|
+
|
18
|
+
# "".deindent from https://github.com/visionmedia/terminal-table/blob/master/spec/spec_helper.rb
|
19
|
+
|
20
|
+
class String
|
21
|
+
def deindent
|
22
|
+
strip.gsub(/^ */, '')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# PusherClient mock from https://github.com/pusher/pusher-ruby-client/blob/master/test/teststrap.rb
|
27
|
+
|
28
|
+
module PusherClient
|
29
|
+
class Socket
|
30
|
+
def simulate_received(event_name, event_data, channel_name)
|
31
|
+
send_local_event(event_name, event_data, channel_name)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
PusherClient.logger.level = Logger::INFO
|
37
|
+
|
38
|
+
def pusher_json_for(slug, event)
|
39
|
+
JSON.parse(IO.read(File.dirname(__FILE__) + "/support/pusher/#{slug.gsub('/', '-')}-#{event.gsub(':', '-')}.json")).to_json
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"id":1,
|
3
|
+
"number":"1",
|
4
|
+
"config":{
|
5
|
+
"language":"ruby"
|
6
|
+
},
|
7
|
+
"started_at":"2012-08-04T13:28:29Z",
|
8
|
+
"commit":"af0d1c46e019ff61f1faaba7003ebf912ab245d6",
|
9
|
+
"branch":"master",
|
10
|
+
"message":"Test",
|
11
|
+
"compare_url":"https://github.com/dylanegan/travis-surveillance/compare/74791a0faacf...af0d1c46e019",
|
12
|
+
"committed_at":"2012-08-04T13:28:22Z",
|
13
|
+
"author_name":"Dylan Egan",
|
14
|
+
"committer_name":"Dylan Egan",
|
15
|
+
"status":null
|
16
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"id":143690,
|
3
|
+
"slug":"dylanegan/travis-surveillance",
|
4
|
+
"description":"",
|
5
|
+
"public_key":"-----BEGIN RSA PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCPeL3PD+uSXgaF4bvK4BMfCB3g\nple4P8PD+klPMQi3FTjXgyzPqsbiTaeKka0WNtmd+BXKIdczxrbjqNIAPurE3NeT\nM8aPbnkW0HNZ+oL1AsZveUyxjwMqN6iwrPbuLEKnueSpTcBOPBk3TY7Lec/HmlPV\n2PZM4LHOgmFA1P29pwIDAQAB\n-----END RSA PUBLIC KEY-----\n",
|
6
|
+
"last_build_id":2026814,
|
7
|
+
"last_build_number":"1",
|
8
|
+
"last_build_status":0,
|
9
|
+
"last_build_result":0,
|
10
|
+
"last_build_duration":113,
|
11
|
+
"last_build_language":null,
|
12
|
+
"last_build_started_at":"2012-08-03T09:13:51Z",
|
13
|
+
"last_build_finished_at":"2012-08-03T09:14:31Z"
|
14
|
+
}
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
describe Travis::Surveillance::Build do
|
4
|
+
before do
|
5
|
+
@project = Travis::Surveillance::Project.new("dylanegan/travis-surveillance")
|
6
|
+
@build = @project.add_build({'id' => 1})
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "a new build" do
|
10
|
+
it "should have an author_name" do
|
11
|
+
@build.author_name.must_equal "Dylan Egan"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have a branch" do
|
15
|
+
@build.branch.must_equal "master"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should have a commit" do
|
19
|
+
@build.commit.must_equal "af0d1c46e019ff61f1faaba7003ebf912ab245d6"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have a committed_at" do
|
23
|
+
@build.committed_at.must_equal Time.parse("2012-08-04T13:28:22Z")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have a committer_name" do
|
27
|
+
@build.committer_name.must_equal "Dylan Egan"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should have a compare_url" do
|
31
|
+
@build.compare_url.must_equal "https://github.com/dylanegan/travis-surveillance/compare/74791a0faacf...af0d1c46e019"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should have a configuration" do
|
35
|
+
@build.config.language.must_equal "ruby"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should have an id" do
|
39
|
+
@build.id.must_equal 1
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should have a message" do
|
43
|
+
@build.message.must_equal "Test"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have a number" do
|
47
|
+
@build.number.must_equal "1"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should have a project" do
|
51
|
+
@build.project.must_equal @project
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should have a started_at" do
|
55
|
+
@build.started_at.must_equal Time.parse("2012-08-04T13:28:29Z")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "a finished build" do
|
60
|
+
before do
|
61
|
+
@surveyor = Travis::Surveillance::Surveyor.new(@project)
|
62
|
+
@surveyor.survey
|
63
|
+
@surveyor.socket.simulate_received('build:finished', pusher_json_for(@project.slug, 'build:finished'), 'common')
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should have a duration" do
|
67
|
+
@build.duration.must_equal 30
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should have a finished_at" do
|
71
|
+
@build.finished_at.must_equal Time.parse("2012-08-04T13:28:59Z")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should have a status" do
|
75
|
+
@build.status.must_equal 1
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "status" do
|
80
|
+
describe "when nil" do
|
81
|
+
before do
|
82
|
+
@build.status = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should be building" do
|
86
|
+
@build.building?.must_equal true
|
87
|
+
@build.failed?.must_equal false
|
88
|
+
@build.passed?.must_equal false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "when zero" do
|
93
|
+
before do
|
94
|
+
@build.status = 0
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should have passed" do
|
98
|
+
@build.building?.must_equal false
|
99
|
+
@build.failed?.must_equal false
|
100
|
+
@build.passed?.must_equal true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "when one" do
|
105
|
+
before do
|
106
|
+
@build.status = 1
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should have failed" do
|
110
|
+
@build.building?.must_equal false
|
111
|
+
@build.failed?.must_equal true
|
112
|
+
@build.passed?.must_equal false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
describe Travis::Surveillance::Job do
|
4
|
+
before do
|
5
|
+
@project = Travis::Surveillance::Project.new("dylanegan/travis-surveillance")
|
6
|
+
@build = @project.add_build({'id' => 1})
|
7
|
+
@job = @build.add_job({'id' => 1})
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "a new job" do
|
11
|
+
it "should have a build" do
|
12
|
+
@job.build.must_equal @build
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have a config" do
|
16
|
+
@job.config.env.must_equal "NO_SIMPLECOV=true"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have an id" do
|
20
|
+
@job.id.must_equal 1
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should have a number" do
|
24
|
+
@job.number.must_equal "1.1"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should have a started_at" do
|
28
|
+
@job.started_at.must_equal Time.parse("2012-08-04T13:28:29Z")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "a finished job" do
|
33
|
+
before do
|
34
|
+
@surveyor = Travis::Surveillance::Surveyor.new(@project)
|
35
|
+
@surveyor.survey
|
36
|
+
@surveyor.socket.simulate_received('job:finished', pusher_json_for(@project.slug, 'job:finished'), 'common')
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have a duration" do
|
40
|
+
@job.duration.must_equal 30
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should have a finished_at" do
|
44
|
+
@job.finished_at.must_equal Time.parse("2012-08-04T13:28:59Z")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have a status" do
|
48
|
+
@job.status.must_equal 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "status" do
|
53
|
+
describe "when nil" do
|
54
|
+
before do
|
55
|
+
@job.status = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should be running" do
|
59
|
+
@job.running?.must_equal true
|
60
|
+
@job.failed?.must_equal false
|
61
|
+
@job.passed?.must_equal false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "when zero" do
|
66
|
+
before do
|
67
|
+
@job.status = 0
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should have passed" do
|
71
|
+
@job.running?.must_equal false
|
72
|
+
@job.failed?.must_equal false
|
73
|
+
@job.passed?.must_equal true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "when one" do
|
78
|
+
before do
|
79
|
+
@job.status = 1
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should have failed" do
|
83
|
+
@job.running?.must_equal false
|
84
|
+
@job.failed?.must_equal true
|
85
|
+
@job.passed?.must_equal false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|