travis-surveillance 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|