Module: Janky

Defined in:
lib/janky.rb,
lib/janky/app.rb,
lib/janky/build.rb,
lib/janky/hubot.rb,
lib/janky/tasks.rb,
lib/janky/branch.rb,
lib/janky/commit.rb,
lib/janky/github.rb,
lib/janky/builder.rb,
lib/janky/helpers.rb,
lib/janky/version.rb,
lib/janky/notifier.rb,
lib/janky/exception.rb,
lib/janky/github/api.rb,
lib/janky/repository.rb,
lib/janky/github/mock.rb,
lib/janky/job_creator.rb,
lib/janky/views/index.rb,
lib/janky/builder/http.rb,
lib/janky/builder/mock.rb,
lib/janky/chat_service.rb,
lib/janky/views/layout.rb,
lib/janky/build_request.rb,
lib/janky/github/commit.rb,
lib/janky/notifier/mock.rb,
lib/janky/views/console.rb,
lib/janky/builder/client.rb,
lib/janky/builder/runner.rb,
lib/janky/github/payload.rb,
lib/janky/notifier/multi.rb,
lib/janky/builder/payload.rb,
lib/janky/github/receiver.rb,
lib/janky/builder/receiver.rb,
lib/janky/chat_service/mock.rb,
lib/janky/chat_service/hubot.rb,
lib/janky/chat_service/slack.rb,
lib/janky/chat_service/hipchat.rb,
lib/janky/chat_service/campfire.rb,
lib/janky/github/payload_parser.rb,
lib/janky/notifier/chat_service.rb,
lib/janky/notifier/github_status.rb,
lib/janky/notifier/failure_service.rb

Overview

This is Janky, a continuous integration server. Checkout the ‘app’ method on this module for an overview of the different components involved.

Defined Under Namespace

Modules: Builder, ChatService, Exception, GitHub, Helpers, Notifier, Tasks, Views Classes: App, Branch, Build, BuildRequest, Commit, Error, Hubot, JobCreator, Repository

Constant Summary collapse

VERSION =
"0.12.0"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.jobs_config_dirObject

Directory where Jenkins job configuration templates are located.

Returns the directory as a Pathname.



237
238
239
# File 'lib/janky.rb', line 237

def jobs_config_dir
  @jobs_config_dir
end

Class Method Details

.appObject

The Janky Rack application, assembled from four apps. Exceptions raised during the request cycle are caught by the Exception middleware which typically reports them to an external service before re-raising the exception.

Returns a memoized Rack application.



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/janky.rb', line 266

def self.app
  @app ||= Rack::Builder.app {
    # GitHub Post-Receive requests.
    map "/_github" do
      run Janky::GitHub.receiver
    end

    # Jenkins callback requests.
    map "/_builder" do
      run Janky::Builder.receiver
    end

    # Hubot API, protected by Basic Auth.
    map "/_hubot" do
      use Rack::Auth::Basic do |username, password|
        username == Janky::Hubot.username &&
          password == Janky::Hubot.password
      end

      run Janky::Hubot
    end

    # Web dashboard
    map "/" do
      run Janky::App
    end
  }
end

.enable_mock!Object

Mock out all network-dependant components. Must be called after setup. Typically used in test environments.

Returns nothing.



244
245
246
247
248
249
250
# File 'lib/janky.rb', line 244

def self.enable_mock!
  Janky::Builder.enable_mock!
  Janky::GitHub.enable_mock!
  Janky::Notifier.enable_mock!
  Janky::ChatService.enable_mock!
  Janky::App.disable :github_team_id
end

.register_chat_service(name, service) ⇒ Object

Register a Chat service implementation.

name - Service name as a String, e.g. “irc”. service - Constant for the implementation.

Returns nothing.



301
302
303
# File 'lib/janky.rb', line 301

def self.register_chat_service(name, service)
  Janky::ChatService.adapters[name] = service
end

.required_settingsObject

List of settings required in production.

Returns an Array of Strings.



224
225
226
227
228
229
230
231
# File 'lib/janky.rb', line 224

def self.required_settings
  %w[RACK_ENV DATABASE_URL
    JANKY_BASE_URL
    JANKY_BUILDER_DEFAULT
    JANKY_CONFIG_DIR
    JANKY_GITHUB_USER JANKY_GITHUB_PASSWORD JANKY_GITHUB_HOOK_SECRET
    JANKY_HUBOT_USER JANKY_HUBOT_PASSWORD]
end

.reset!Object

Reset the state of the mocks.

Returns nothing.



255
256
257
258
# File 'lib/janky.rb', line 255

def self.reset!
  Janky::Notifier.reset!
  Janky::Builder.reset!
end

.setup(settings) ⇒ Object

Setup the application, including the database and Jenkins connections.

settings - Hash of app settings. Typically ENV but any object that responds

to #[], #[]= and #each is valid. See required_settings for
required keys. The RACK_ENV key is always required.

Raises an Error when required settings are missing. Returns nothing.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/janky.rb', line 77

def self.setup(settings)
  env = settings["RACK_ENV"]
  if env.nil? || env.empty?
    raise Error, "RACK_ENV is required"
  end

  required_settings.each do |setting|
    next if !settings[setting].nil? && !settings[setting].empty?

    if env == "production"
      raise Error, "#{setting} setting is required"
    end
  end

  if env != "production"
    settings["DATABASE_URL"] ||= "mysql2://root@localhost/janky_#{env}"
    settings["JANKY_BASE_URL"] ||= "http://localhost:9393/"
    settings["JANKY_BUILDER_DEFAULT"] ||= "http://localhost:8080/"
    settings["JANKY_CONFIG_DIR"] ||= File.dirname(__FILE__)
    settings["JANKY_CHAT"] ||= "campfire"
    settings["JANKY_CHAT_CAMPFIRE_ACCOUNT"] ||= "account"
    settings["JANKY_CHAT_CAMPFIRE_TOKEN"] ||= "token"
  end

  database = URI(settings["DATABASE_URL"])
  adapter  = database.scheme == "postgres" ? "postgresql" : database.scheme
  encoding = database.scheme == "postgres" ? "unicode" : "utf8"
  base_url = URI(settings["JANKY_BASE_URL"]).to_s
  Build.base_url = base_url

  connection = {
    :adapter   => adapter,
    :encoding  => encoding,
    :pool      => 5,
    :database  => database.path[1..-1],
    :username  => database.user,
    :password  => database.password,
    :host      => database.host,
    :port      => database.port,
    :reconnect => true,
  }
  if socket = settings["JANKY_DATABASE_SOCKET"]
    connection[:socket] = socket
  end
  ActiveRecord::Base.establish_connection(connection)

  self.jobs_config_dir = config_dir = Pathname(settings["JANKY_CONFIG_DIR"])
  if !config_dir.directory?
    raise Error, "#{config_dir} is not a directory"
  end

  # Setup the callback URL of this Janky host.
  Janky::Builder.setup(base_url + "_builder")

  # Setup the default Jenkins build host
  if settings["JANKY_BUILDER_DEFAULT"][-1] != ?/
    raise Error, "JANKY_BUILDER_DEFAULT must have a trailing slash"
  end
  Janky::Builder[:default] = settings["JANKY_BUILDER_DEFAULT"]

  if settings.key?("JANKY_GITHUB_API_URL")
    api_url  = settings["JANKY_GITHUB_API_URL"]
    git_host = URI(api_url).host
  else
    api_url = "https://api.github.com/"
    git_host = "github.com"
  end
  if api_url[-1] != ?/
    raise Error, "JANKY_GITHUB_API_URL must have a trailing slash"
  end
  hook_url = base_url + "_github"
  Janky::GitHub.setup(
    settings["JANKY_GITHUB_USER"],
    settings["JANKY_GITHUB_PASSWORD"],
    settings["JANKY_GITHUB_HOOK_SECRET"],
    hook_url,
    api_url,
    git_host
  )

  if settings.key?("JANKY_SESSION_SECRET")
    Janky::App.register Sinatra::Auth::Github
    Janky::App.set({
      :sessions => true,
      :session_secret => settings["JANKY_SESSION_SECRET"],
      :github_team_id => settings["JANKY_AUTH_TEAM_ID"],
      :github_organization => settings["JANKY_AUTH_ORGANIZATION"],
      :github_options => {
        :secret => settings["JANKY_AUTH_CLIENT_SECRET"],
        :client_id => settings["JANKY_AUTH_CLIENT_ID"],
        :scopes => "repo",
      },
    })
  end

  Janky::Hubot.set(
    :base_url => settings["JANKY_BASE_URL"],
    :username => settings["JANKY_HUBOT_USER"],
    :password => settings["JANKY_HUBOT_PASSWORD"]
  )

  Janky::Exception.setup(Janky::Exception::Logger.new($stderr))

  if  = settings["JANKY_CAMPFIRE_ACCOUNT"]
    warn "JANKY_CAMPFIRE_ACCOUNT is deprecated. Please use " \
      "JANKY_CHAT_CAMPFIRE_ACCOUNT instead."
    settings["JANKY_CHAT_CAMPFIRE_ACCOUNT"] ||=
      settings["JANKY_CAMPFIRE_ACCOUNT"]
  end

  if campfire_token = settings["JANKY_CAMPFIRE_TOKEN"]
    warn "JANKY_CAMPFIRE_TOKEN is deprecated. Please use " \
      "JANKY_CHAT_CAMPFIRE_TOKEN instead."
    settings["JANKY_CHAT_CAMPFIRE_TOKEN"] ||=
      settings["JANKY_CAMPFIRE_TOKEN"]
  end

  chat_name = settings["JANKY_CHAT"] || "campfire"
  chat_settings = {}
  settings.each do |key, value|
    if key =~ /^JANKY_CHAT_#{chat_name.upcase}_/
      chat_settings[key] = value
    end
  end
  chat_room = settings["JANKY_CHAT_DEFAULT_ROOM"] ||
    settings["JANKY_CAMPFIRE_DEFAULT_ROOM"]
  if settings["JANKY_CAMPFIRE_DEFAULT_ROOM"]
    warn "JANKY_CAMPFIRE_DEFAULT_ROOM is deprecated. Please use " \
      "JANKY_CHAT_DEFAULT_ROOM instead."
  end
  ChatService.setup(chat_name, chat_settings, chat_room)

  if token = settings["JANKY_GITHUB_STATUS_TOKEN"]
    context = settings["JANKY_GITHUB_STATUS_CONTEXT"]
    Notifier.setup([
      Notifier::GithubStatus.new(token, api_url, context),
      Notifier::ChatService,
      Notifier::FailureService
    ])
  else
    Notifier.setup(Notifier::ChatService)
  end
end