janky 0.9.0 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,6 +8,10 @@ module Janky
8
8
 
9
9
  def run(params, create_url)
10
10
  http = Net::HTTP.new(create_url.host, create_url.port)
11
+ if create_url.scheme == "https"
12
+ http.use_ssl = true
13
+ end
14
+
11
15
  request = Net::HTTP::Post.new(create_url.path)
12
16
  if @username && @password
13
17
  request.basic_auth(@username, @password)
@@ -24,6 +28,10 @@ module Janky
24
28
 
25
29
  def output(url)
26
30
  http = Net::HTTP.new(url.host, url.port)
31
+ if url.scheme == "https"
32
+ http.use_ssl = true
33
+ end
34
+
27
35
  request = Net::HTTP::Get.new(url.path)
28
36
  if @username && @password
29
37
  request.basic_auth(@username, @password)
@@ -10,7 +10,7 @@ module Janky
10
10
  elsif payload.completed?
11
11
  Build.complete(payload.id, payload.green?)
12
12
  else
13
- return Rack::Response.new("Invalid", 402).finish
13
+ return Rack::Response.new("Bad Request", 400).finish
14
14
  end
15
15
 
16
16
  Rack::Response.new("OK", 201).finish
@@ -1,39 +1,48 @@
1
1
  module Janky
2
- # Sends messages to Campfire and accesses available rooms.
3
- module Campfire
4
- # Setup the Campfire client with the given credentials.
2
+ module ChatService
3
+ Room = Struct.new(:id, :name)
4
+
5
+ # Setup the adapter used to notify chat rooms of build status.
5
6
  #
6
- # account - the Campfire account name as a String.
7
- # token - the Campfire API token as a String.
8
- # default - the name of the default Campfire room as a String.
7
+ # name - Service name as a string.
8
+ # settings - Service-specific setting hash.
9
+ # default - Name of the default chat room as a String.
9
10
  #
10
11
  # Returns nothing.
11
- def self.setup(account, token, default)
12
- ::Broach.settings = {
13
- "account" => account,
14
- "token" => token,
15
- "use_ssl" => true
16
- }
12
+ def self.setup(name, settings, default)
13
+ klass = adapters[name]
14
+
15
+ if !klass
16
+ raise Error, "Unknown chat service: #{name.inspect}. Available " \
17
+ "services are #{adapters.keys.join(", ")}"
18
+ end
17
19
 
18
- self.default_room_name = default
20
+ @adapter = klass.new(settings)
21
+ @default_room_name = default
19
22
  end
20
23
 
21
24
  class << self
22
- attr_accessor :default_room_name
25
+ attr_accessor :adapter, :default_room_name
26
+ end
27
+
28
+ # Registry of available chat implementations.
29
+ def self.adapters
30
+ @adapters ||= {}
23
31
  end
24
32
 
25
33
  def self.default_room_id
26
34
  room_id(default_room_name)
27
35
  end
28
36
 
29
- # Send a message to a Campfire room.
37
+ # Send a message to a Chat room.
30
38
  #
31
39
  # message - The String message.
32
40
  # room_id - The Integer room ID.
41
+ # options - Optional hash passed to the chat adapter.
33
42
  #
34
43
  # Returns nothing.
35
- def self.speak(message, room_id)
36
- adapter.speak(room_name(room_id), message)
44
+ def self.speak(message, room_id, options = {})
45
+ adapter.speak(message, room_id, options)
37
46
  end
38
47
 
39
48
  # Get the ID of a room.
@@ -67,9 +76,9 @@ module Janky
67
76
 
68
77
  # Memoized list of available rooms.
69
78
  #
70
- # Returns an Array of Broach::Room objects.
79
+ # Returns an Array of Room objects.
71
80
  def self.rooms
72
- @rooms ||= adapter.rooms
81
+ adapter.rooms
73
82
  end
74
83
 
75
84
  # Enable mocking. Once enabled, messages are discarded.
@@ -87,41 +96,5 @@ module Janky
87
96
  def self.rooms=(value)
88
97
  adapter.rooms = value
89
98
  end
90
-
91
- def self.adapter
92
- @adapter ||= Broach.new
93
- end
94
-
95
- class Broach
96
- def speak(room_name, message)
97
- ::Broach.speak(room_name, message)
98
- end
99
-
100
- def rooms
101
- ::Broach.rooms
102
- end
103
- end
104
-
105
- class Mock
106
- def initialize
107
- @rooms = {}
108
- end
109
-
110
- attr_writer :rooms
111
-
112
- def speak(room_name, message)
113
- if !@rooms.values.include?(room_name)
114
- raise Error, "Unknown room #{room_name.inspect}"
115
- end
116
- end
117
-
118
- def rooms
119
- acc = []
120
- @rooms.each do |id, name|
121
- acc << ::Broach::Room.new("id" => id, "name" => name)
122
- end
123
- acc
124
- end
125
- end
126
99
  end
127
100
  end
@@ -0,0 +1,33 @@
1
+ module Janky
2
+ module ChatService
3
+ class Campfire
4
+ def initialize(settings)
5
+ account = settings["JANKY_CHAT_CAMPFIRE_ACCOUNT"]
6
+ if account.nil? || account.empty?
7
+ raise Error, "JANKY_CHAT_CAMPFIRE_ACCOUNT setting is required"
8
+ end
9
+
10
+ token = settings["JANKY_CHAT_CAMPFIRE_TOKEN"]
11
+ if token.nil? || token.empty?
12
+ raise Error, "JANKY_CHAT_CAMPFIRE_TOKEN setting is required"
13
+ end
14
+
15
+ Broach.settings = {
16
+ "account" => account,
17
+ "token" => token,
18
+ "use_ssl" => true,
19
+ }
20
+ end
21
+
22
+ def speak(message, room_id, opts={})
23
+ Broach.speak(ChatService.room_name(room_id), message)
24
+ end
25
+
26
+ def rooms
27
+ @rooms ||= Broach.rooms.map do |room|
28
+ Room.new(room.id, room.name)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ require "hipchat"
2
+
3
+ module Janky
4
+ module ChatService
5
+ class HipChat
6
+ def initialize(settings)
7
+ token = settings["JANKY_CHAT_HIPCHAT_TOKEN"]
8
+ if token.nil? || token.empty?
9
+ raise Error, "JANKY_CHAT_HIPCHAT_TOKEN setting is required"
10
+ end
11
+
12
+ @client = ::HipChat::Client.new(token)
13
+ @from = settings["JANKY_CHAT_HIPCHAT_FROM"] || "CI"
14
+ end
15
+
16
+ def speak(message, room_id, options = {:color => "yellow"})
17
+ @client[room_id].send(@from, message, options)
18
+ end
19
+
20
+ def rooms
21
+ @rooms ||= @client.rooms.map do |room|
22
+ Room.new(room.room_id, room.name)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ register_chat_service "hipchat", ChatService::HipChat
29
+ end
@@ -0,0 +1,26 @@
1
+ module Janky
2
+ module ChatService
3
+ # Mock chat implementation used in testing environments.
4
+ class Mock
5
+ def initialize
6
+ @rooms = {}
7
+ end
8
+
9
+ attr_writer :rooms
10
+
11
+ def speak(room_name, message)
12
+ if !@rooms.values.include?(room_name)
13
+ raise Error, "Unknown room #{room_name.inspect}"
14
+ end
15
+ end
16
+
17
+ def rooms
18
+ acc = []
19
+ @rooms.each do |id, name|
20
+ acc << Room.new(id, name)
21
+ end
22
+ acc
23
+ end
24
+ end
25
+ end
26
+ end
@@ -3,7 +3,7 @@ class Init < ActiveRecord::Migration
3
3
  create_table :repositories, :force => true do |t|
4
4
  t.string :name, :null => false
5
5
  t.string :uri, :null => false
6
- t.integer :room_id, :default => 376289, :null => false # Builds room
6
+ t.integer :room_id, :null => false
7
7
  t.timestamps
8
8
  end
9
9
  add_index :repositories, :name, :unique => true
@@ -48,6 +48,29 @@ module Janky
48
48
  end
49
49
  end
50
50
 
51
+ class Logger
52
+ def initialize(stream)
53
+ @stream = stream
54
+ @context = {}
55
+ end
56
+
57
+ def reset!
58
+ @context = {}
59
+ end
60
+
61
+ def report(e, context={})
62
+ @stream.puts "ERROR: #{e.class} - #{e.message}\n"
63
+ @context.each do |k, v|
64
+ @stream.puts "%12s %4s\n" % [k, v]
65
+ end
66
+ @stream.puts "\n#{e.backtrace.join("\n")}"
67
+ end
68
+
69
+ def push(context)
70
+ @context.update(context)
71
+ end
72
+ end
73
+
51
74
  class Mock
52
75
  def self.push(context)
53
76
  end
@@ -1,36 +1,43 @@
1
1
  module Janky
2
2
  module GitHub
3
- def self.setup(user, password, secret, url)
4
- @user = user
3
+ # Setup the GitHub API client and Post-Receive hook endpoint.
4
+ #
5
+ # user - API user as a String.
6
+ # password - API password as a String.
7
+ # secret - Secret used to sign hook requests from GitHub.
8
+ # hook_url - String URL that handles Post-Receive requests.
9
+ # api_url - GitHub API URL as a String. Requires a trailing slash.
10
+ # git_host - Hostname where git repos are hosted. e.g. "github.com"
11
+ #
12
+ # Returns nothing.
13
+ def self.setup(user, password, secret, hook_url, api_url, git_host)
14
+ @user = user
5
15
  @password = password
6
- @secret = secret
7
- @url = url
16
+ @secret = secret
17
+ @hook_url = hook_url
18
+ @api_url = api_url
19
+ @git_host = git_host
8
20
  end
9
21
 
10
22
  class << self
11
- attr_reader :secret
12
- end
13
-
14
- def self.enable_mock!
15
- @api = Mock.new(@user, @password)
16
- end
17
-
18
- def self.repo_make_private(nwo)
19
- api.make_private(nwo)
20
- end
21
-
22
- def self.repo_make_public(nwo)
23
- api.make_public(nwo)
24
- end
25
-
26
- def self.repo_make_unauthorized(nwo)
27
- api.make_unauthorized(nwo)
23
+ attr_reader :secret, :git_host
28
24
  end
29
25
 
26
+ # Rack app that handles Post-Receive hook requests from GitHub.
27
+ #
28
+ # Returns a GitHub::Receiver.
30
29
  def self.receiver
31
30
  @receiver ||= Receiver.new(@secret)
32
31
  end
33
32
 
33
+ # Fetch repository details.
34
+ # http://developer.github.com/v3/repos/#get
35
+ #
36
+ # nwo - qualified "owner/repo" name.
37
+ #
38
+ # Returns the Hash representation of the repo, nil when it doesn't exists
39
+ # or access was denied.
40
+ # Raises an Error for any unexpected response.
34
41
  def self.repo_get(nwo)
35
42
  response = api.repo_get(nwo)
36
43
 
@@ -45,8 +52,15 @@ module Janky
45
52
  end
46
53
  end
47
54
 
55
+ # Create a Post-Receive hook for the given repository.
56
+ # http://developer.github.com/v3/repos/hooks/#create-a-hook
57
+ #
58
+ # nwo - qualified "owner/repo" name.
59
+ #
60
+ # Returns the newly created hook URL as String when successful.
61
+ # Raises an Error for any other response.
48
62
  def self.hook_create(nwo)
49
- response = api.create(nwo, @secret, @url)
63
+ response = api.create(nwo, @secret, @hook_url)
50
64
 
51
65
  if response.code == "201"
52
66
  Yajl.load(response.body)["url"]
@@ -56,12 +70,57 @@ module Janky
56
70
  end
57
71
  end
58
72
 
73
+ # Check existance of a hook.
74
+ # http://developer.github.com/v3/repos/hooks/#get-single-hook
75
+ #
76
+ # url - Hook URL as a String.
59
77
  def self.hook_exists?(url)
60
78
  api.get(url).code == "200"
61
79
  end
62
80
 
81
+ # Default API implementation that goes over the wire (HTTP).
82
+ #
83
+ # Returns nothing.
63
84
  def self.api
64
- @api ||= API.new(@user, @password)
85
+ @api ||= API.new(@api_url, @user, @password)
86
+ end
87
+
88
+ # Turn on mock mode, meaning no request goes over the wire. Useful in
89
+ # testing environments.
90
+ #
91
+ # Returns nothing.
92
+ def self.enable_mock!
93
+ @api = Mock.new(@user, @password)
94
+ end
95
+
96
+ # Make any subsequent response for the given repository look like as if
97
+ # it was a private repo.
98
+ #
99
+ # nwo - qualified "owner/repo" name.
100
+ #
101
+ # Returns nothing.
102
+ def self.repo_make_private(nwo)
103
+ api.make_private(nwo)
104
+ end
105
+
106
+ # Make any subsequent request to the given repository succeed. Only
107
+ # available in mock mode.
108
+ #
109
+ # nwo - qualified "owner/repo" name.
110
+ #
111
+ # Returns nothing.
112
+ def self.repo_make_public(nwo)
113
+ api.make_public(nwo)
114
+ end
115
+
116
+ # Make any subsequent request for the given repository fail with an
117
+ # unauthorized response. Only available when mocked.
118
+ #
119
+ # nwo - qualified "owner/repo" name.
120
+ #
121
+ # Returns nothing.
122
+ def self.repo_make_unauthorized(nwo)
123
+ api.make_unauthorized(nwo)
65
124
  end
66
125
  end
67
126
  end
@@ -1,13 +1,14 @@
1
1
  module Janky
2
2
  module GitHub
3
3
  class API
4
- def initialize(user, password)
5
- @user = user
4
+ def initialize(url, user, password)
5
+ @url = url
6
+ @user = user
6
7
  @password = password
7
8
  end
8
9
 
9
10
  def create(nwo, secret, url)
10
- request = Net::HTTP::Post.new("/repos/#{nwo}/hooks")
11
+ request = Net::HTTP::Post.new(build_path("repos/#{nwo}/hooks"))
11
12
  payload = build_payload(url, secret)
12
13
  request.body = Yajl.dump(payload)
13
14
  request.basic_auth(@user, @password)
@@ -16,15 +17,15 @@ module Janky
16
17
  end
17
18
 
18
19
  def trigger(hook_url)
19
- path = URI(hook_url).path
20
- request = Net::HTTP::Post.new("#{path}/test")
20
+ path = build_path(URI(hook_url).path + "/test")
21
+ request = Net::HTTP::Post.new(path)
21
22
  request.basic_auth(@user, @password)
22
23
 
23
24
  http.request(request)
24
25
  end
25
26
 
26
27
  def get(hook_url)
27
- path = URI(hook_url).path
28
+ path = build_path(URI(hook_url).path)
28
29
  request = Net::HTTP::Get.new(path)
29
30
  request.basic_auth(@user, @password)
30
31
 
@@ -32,13 +33,21 @@ module Janky
32
33
  end
33
34
 
34
35
  def repo_get(nwo)
35
- path = "/repos/#{nwo}"
36
+ path = build_path("repos/#{nwo}")
36
37
  request = Net::HTTP::Get.new(path)
37
38
  request.basic_auth(@user, @password)
38
39
 
39
40
  http.request(request)
40
41
  end
41
42
 
43
+ def build_path(path)
44
+ if path[0] == ?/
45
+ URI.join(@url, path[1..-1]).path
46
+ else
47
+ URI.join(@url, path).path
48
+ end
49
+ end
50
+
42
51
  def build_payload(url, secret)
43
52
  { "name" => "web",
44
53
  "active" => true,
@@ -55,7 +64,7 @@ module Janky
55
64
  end
56
65
 
57
66
  def http!
58
- uri = URI("https://api.github.com")
67
+ uri = URI(@url)
59
68
  http = Net::HTTP.new(uri.host, uri.port)
60
69
 
61
70
  http.use_ssl = true