hookie 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gitolite-hooks.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Marcin Szczepanski
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # Hookie
2
+
3
+ Hookie is a pluggable framework for creating git hooks using Ruby. It was originally designed for writing hooks for gitolite, but should work for any hooks, including local ones.
4
+
5
+ ## Background
6
+
7
+ After we had setup [HipChat](http://hipchat.com) at our organisation I wanted to get notifications from gitolite pushes pushed to HipChat. I found the [gitolite-hipchat-notification](https://github.com/peplin/gitolite-hipchat-notification) project, and [forked it](https://github.com/marcins/gitolite-hipchat-notification) and cleaned it up a bit for my purposes. However this script wasn't very flexible in that you needed to add it individually to each repo (or suffer with a single config). Then I wanted to add Jenkins build notifications as well, so had to enhance the script to support running multiple tasks. Eventually it was all getting too crufty and so Hookie was born!
8
+
9
+ Hookie is designed so that you can have multiple actions take place as a result of a git hook (usually post-receive), these actions are built as plugins, and configured via git - the beauty of this is that for gitolite you define the hook globally and then configure which plugins run where via git config keys, which can be defined in your gitolite-admin repository. So once Hookie is setup you don't need to make changes on the server.
10
+
11
+ Hookie includes those aforementioned plugins for HipChat and Jenkins in the base build.
12
+
13
+ ## Acknowledgements
14
+
15
+ Hookie is built on the base of @peplin's (gitolite-hipchat-notification)[https://github.com/peplin/gitolite-hipchat-notification] project, which was originally forked from (gitolite-campfire-notification)[https://github.com/LegionSB/gitolite-campfire-notification] - the magic of Open Source!
16
+
17
+ Hookie uses [grit](https://github.com/mojombo/grit) for accessing information in git repositories.
18
+
19
+ ## Installation
20
+
21
+ Install the gem on your git server
22
+
23
+ gem install hookie
24
+
25
+ You then need to create a post-receive script in your repository's hooks directory, there are a couple of ways to do this, see below for some options. The post-receive hook will look like this:
26
+
27
+ #!/usr/bin/env ruby
28
+ require 'hookie'
29
+
30
+ # Add your plugins here
31
+ # require 'my_plugin'
32
+
33
+ Hookie::Framework.hook "post_receive"
34
+
35
+ **NOTE** the above doesn't work if your gitolite user is using RVM as the gitolite shell won't have loaded RVM. The alternative hook script looks like this:
36
+
37
+ #!/bin/bash
38
+ source ~/.rvm/scripts/rvm
39
+ ruby -rhookie -e 'Hookie::Framework.hook "post_receive"'
40
+
41
+ If you need to add your own custom plugins then add them with additional -r arguments (require)
42
+
43
+ ### Installing hooks with gitolite
44
+
45
+ The idea is that you install hookie as a post_receive hook for all your repositories, but configuration determines when the hook is actually run. To install for all repositories you create the post-receive script in the .gitolite/hooks/common/ directory. Make sure the script is exectuable.
46
+
47
+ ### Installing hooks manually
48
+
49
+ You can also install Hookie hooks manually, by adding them to the hooks directory within your repository. Note that the same configuration still applies. You should also be able to install Hookie for local repository hooks, but I haven't tried this yet! Currently Hookie assumes it will be receiving changeset information on STDIN in the format gitolite provides it, I'm not sure if other git servers and/or local hooks also receive information the same way?
50
+
51
+ ## Configuration
52
+
53
+ Hookie was written such that it can be configured using Gitolite's ability to set git config keys via the gitolite-admin repository.
54
+
55
+ You can set "global" config keys using the special repository @all in gitolite, and override or set project specific keys within the repository itself. This makes it easy to, for example, set your HipChat API key for all repos, but then set the room that gets notified in each repo separately - and this can all be done via the gitolite-admin repository, without requiring access to the git server.
56
+
57
+ An example conf/gitolite.conf:
58
+
59
+ repo gitolite-admin
60
+ RW+ = marcin
61
+
62
+ repo testing
63
+ RW+ = @all
64
+ config hookie.core.allowedplugins = hipchat,jenkins
65
+ config hookie.hipchat.room = 123456
66
+ config hookie.jenkins.url = http://jenkins.example.com/job/Test%20Job/build?token=test
67
+ config hookie.jenkins.branches=develop
68
+ config hookie.jenkins.auth=jenkins:TOKEN
69
+
70
+ repo @all
71
+ config hookie.hipchat.apikey = APIKEY
72
+ config hookie.hipchat.from = "Git Test"
73
+ config hookie.core.web.commit = https://fisheye.example.com/changelog/%REPO%?cs=%COMMIT%
74
+ config hookie.core.web.browse = https://fisheye.example.com/browse/%REPO%
75
+
76
+ The following core keys are used by the framework:
77
+
78
+ * **hookie.core.allowedplugins** - comma separated list of plugins that are run for this repo - by default NO plugins get run.
79
+ * **hookie.core.repo.name** - set the name of the repository used when generating URLs or for display purposes. Normally it can be determined from the path and the key isn't required
80
+ * **hookie.core.web.browse** - URL to a web based repo browser. The special variable %REPO% will be replaced with the repo name.
81
+ * **hookie.core.web.commit** - URL to a web based view of a single commit. The special variables %REPO% and %COMMIT% will be replaced with the repo name and commit id respectively.
82
+ * **hookie.core.web.proxy** - optional proxy to use when making HTTP calls in plugins (example syntax: "proxy.example.com:8080")
83
+
84
+ ## Plugins
85
+
86
+ The following plugins are shipped with Hookie:
87
+
88
+ * HipChat - posts a notification to a HipChat room in response to a commit
89
+ * Jenkins - triggers a Jenkins build in reponse to a commit
90
+
91
+ ### HipChat
92
+
93
+ The following config keys apply to the HipChat plugin:
94
+
95
+ * **hookie.hipchat.apikey** - your HipChat API key
96
+ * **hookie.hipchat.room** - the HipChat room to post your message to - you can get a list of rooms using the following API call:
97
+ http://api.hipchat.com/v1/rooms/list?auth_token=YOUR_TOKEN
98
+ * **hookie.hipchat.from** - who the notification appears from (default: git)
99
+ * **hookie.hipchat.notify** - set to 1 to trigger a notification (default: 0)
100
+
101
+ ### Jenkins
102
+
103
+ The following config keys apply to the Jenkins plugin:
104
+
105
+ * **hookie.jenkins.url** - the trigger URL to be called for this repostiory (you should set this per-repository)
106
+ * **hookie.jenkins.branches** - only trigger a build if the change set includes commits to the branches in this list. Comma separated. Default is to build for any commit.
107
+ * **hookie.jenkins.auth** - the username:token combo to use to authenticate with Jenkins
108
+
109
+ ## Writing Plugins
110
+
111
+ Hookie was designed to be extensible by writing your own plugins.
112
+
113
+ A minimal plugin is:
114
+
115
+ require 'hookie/plugins/base_plugin'
116
+
117
+ module Hookie
118
+ module Plugin
119
+ class EmptyPlugin < BasePlugin
120
+ def post_receive
121
+ log "Empty Plugin - post_receive"
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ BasePlugin provides useful instance variables such as config and framework.config is a symbol keyed hash of your plugins config. By convention your config key is the lowercased first part of your plugin name (eg. EmptyPlugin -> empty), so config keys are, for example, hookie.empty.blah
128
+
129
+ Your plugin will be called if it has a method matching the name of the hook being run (eg. "post_receive" above). See the HipChat and Jenkins plugins for vaguely more complex examples.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new('spec')
data/bin/hookie ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ require 'hookie'
3
+ if ARGV.length < 1
4
+ puts "Usage: hookie hook_name [repo_path]"
5
+ exit 1
6
+ end
7
+ Hookie::Framework.hook ARGV[0]
data/hookie.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'hookie'
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = "hookie"
9
+ gem.version = Hookie::VERSION
10
+ gem.authors = ["Marcin Szczepanski"]
11
+ gem.email = ["marcins@webqem.com"]
12
+ gem.description = %q{Hookie provides a way to write git hooks with ruby without too much worrying about any of the plumbing required, you can easily write your own plugins and focus on the core of your functionality.
13
+
14
+ Hookie includes plugins for Jenkins and HipChat.}
15
+ gem.summary = %q{Framework for writing gitolite/git hooks with Ruby}
16
+ gem.homepage = "https://github.com/marcins/hookie"
17
+
18
+ gem.files = `git ls-files`.split($/)
19
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.require_paths = ["lib"]
22
+
23
+ gem.add_dependency 'grit', '~> 2.5.0'
24
+ gem.add_dependency 'diff-lcs', '~> 1.1.3'
25
+
26
+ gem.add_development_dependency 'rspec', '~> 2.12.0'
27
+ end
@@ -0,0 +1,100 @@
1
+ module Hookie
2
+
3
+ class Framework
4
+
5
+ require 'grit'
6
+
7
+ attr_reader :changes
8
+
9
+ def self.hook(hook)
10
+ hookie = Hookie::Framework.new hook, ARGV[1] || Dir.getwd
11
+ hookie.run_plugins(hook)
12
+ end
13
+
14
+ def initialize(hook, repo_path)
15
+ @repo = Grit::Repo.new(repo_path)
16
+ read_changes
17
+ end
18
+
19
+ def run_plugins(hook)
20
+ # we are only allowed to run if the plugin is in the list of allowed
21
+ # plugins
22
+ unless config['hookie.core.allowedplugins']
23
+ exit 255
24
+ end
25
+
26
+ Dir.glob(File.join(File.join(File.dirname(__FILE__),"plugins"), "*_plugin.rb")) do |filename|
27
+ begin
28
+ require filename
29
+ rescue LoadError => e
30
+ puts "Unable to load plugin #{filename}: #{e}"
31
+ end
32
+ end
33
+
34
+ Hookie::Plugin.constants.each do |constant|
35
+ clazz = Hookie::Plugin.const_get(constant)
36
+ if clazz < Hookie::BasePlugin
37
+ plugin = clazz.new(self)
38
+ if config['hookie.core.allowedplugins'].include?(plugin.config_key) and
39
+ plugin.respond_to?(hook) and
40
+ plugin.should_run?
41
+ begin
42
+ plugin.send(hook)
43
+ rescue Exception => e
44
+ log plugin, "ERROR: plugin threw an exception: #{e}"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ def log(plugin, message)
52
+ timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
53
+ puts "[#{timestamp}] #{plugin}: #{message}"
54
+ end
55
+
56
+ def repo_url
57
+ if config['hookie.core.web.browse']
58
+ config['hookie.core.web.browse'].gsub("%REPO%", repo_name)
59
+ end
60
+ end
61
+
62
+ def commit_url(commit)
63
+ if config['hookie.core.web.commit']
64
+ config['hookie.core.web.commit'].gsub("%REPO%", repo_name).gsub("%COMMIT%", commit.id)
65
+ end
66
+ end
67
+
68
+ def repo_name
69
+ if config['hookie.core.repo.name']
70
+ config['hookie.core.repo.name']
71
+ elsif @repo.bare
72
+ File.basename(@repo.path, ".git")
73
+ else
74
+ File.basename(File.expand_path(File.join(@repo.path, "..")))
75
+ end
76
+ end
77
+
78
+ def head_names_for_commit(commit)
79
+ @repo.heads.collect { |head| head.name if head.commit.id == commit.id }.compact
80
+ end
81
+
82
+ def config
83
+ @repo.config
84
+ end
85
+
86
+ private
87
+ def read_changes
88
+ @changes = []
89
+ STDIN.each_line do |line|
90
+ parts = line.split(" ")
91
+ @changes << {
92
+ old_hash: parts[0],
93
+ new_hash: parts[1],
94
+ ref: parts[2],
95
+ commit: @repo.commits(parts[1], 1)[0]
96
+ }
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,40 @@
1
+ module Hookie
2
+ class BasePlugin
3
+
4
+ attr_reader :config
5
+
6
+ def initialize(framework)
7
+ @framework = framework
8
+
9
+ @config = {}
10
+ @framework.config.keys.each do |k|
11
+ if k.start_with?("hookie.#{self.config_key}")
12
+ @config[k.split(".")[2..-1].join("_").to_sym] = @framework.config[k]
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ def log(message)
19
+ @framework.log(self, message)
20
+ end
21
+
22
+ def should_run?
23
+ true
24
+ end
25
+
26
+ def to_s
27
+ plugin_name
28
+ end
29
+
30
+ def config_key
31
+ plugin_name.downcase
32
+ end
33
+
34
+ protected
35
+ def plugin_name
36
+ @plugin_name ||= self.class.to_s[/(.*::)?(\w+)Plugin/, 2]
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,12 @@
1
+ require_relative "base_plugin"
2
+
3
+ module Hookie
4
+ module Plugin
5
+ class EmptyPlugin < BasePlugin
6
+ def post_receive
7
+ log "Empty Plugin - post_receive"
8
+ raise "Shite"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,88 @@
1
+ require_relative 'base_plugin'
2
+
3
+ require 'time'
4
+ require 'net/https'
5
+ require 'json'
6
+
7
+ module Hookie
8
+ module Plugin
9
+ class HipChatPlugin < BasePlugin
10
+ def to_s
11
+ "HipChat Notifier"
12
+ end
13
+
14
+ def should_run?
15
+ warnings = []
16
+ if @framework.changes.empty?
17
+ log "No changes"
18
+ return false
19
+ end
20
+ warnings << "hookie.hipchat.apikey not set!" unless @config[:apikey]
21
+ warnings << "hookie.hipchat.room not set!" unless @config[:room]
22
+
23
+ log warnings.join(", ") unless warnings.empty?
24
+
25
+ warnings.empty?
26
+ end
27
+
28
+ def post_receive
29
+ log "Sending message to HipChat ... "
30
+ response = {}
31
+ #log "Message: #{format_message}"
32
+ response = speak format_message
33
+ if response[:status]
34
+ log "Message sent to HipChat"
35
+ elsif response[:error]
36
+ log "Message end failed: #{response[:error][:message]}"
37
+ else
38
+ log "Unknown response"
39
+ end
40
+ end
41
+
42
+ private
43
+ def format_message
44
+ # Commits just pushed to <a href="repo-url">repo-name</a>:
45
+ # hash (branch) Author: message
46
+ message = ""
47
+ message << "Commits just pushed to "
48
+ message << if @framework.repo_url
49
+ "<a href='#{@framework.repo_url}'>#{@framework.repo_name}</a>"
50
+ else
51
+ @framework.repo_name
52
+ end
53
+ message << ":<br/>"
54
+ @framework.changes.each do |change|
55
+ commit = change[:commit]
56
+
57
+ message << if @framework.commit_url(commit)
58
+ "<a href='#{@framework.commit_url(commit)}'>#{commit.id_abbrev}</a>"
59
+ else
60
+ "#{commit.id_abbrev}"
61
+ end
62
+ head_names = @framework.head_names_for_commit(commit).join(", ")
63
+ message << " (#{head_names})" unless head_names.empty?
64
+ message << " #{commit.author}: #{commit.short_message}"
65
+ message << "<br/>"
66
+ end
67
+ message
68
+ end
69
+
70
+ private
71
+ def speak(message)
72
+ uri = URI.parse("https://api.hipchat.com/")
73
+ http = Net::HTTP.new(uri.host, uri.port, @config[:proxyaddress], @config[:proxyport])
74
+ http.use_ssl = true
75
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
76
+ request = Net::HTTP::Post.new("/v1/rooms/message")
77
+ request.set_form_data({"message" => message,
78
+ "auth_token" => @config[:apikey],
79
+ "room_id" => @config[:room],
80
+ "notify" => @config[:notify] || 0,
81
+ "from" => @config[:from] || "git"})
82
+
83
+ JSON.parse(http.request(request).body, {symbolize_names: true})
84
+ end
85
+
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,39 @@
1
+ require_relative "base_plugin"
2
+
3
+ module Hookie
4
+ module Plugin
5
+ class JenkinsPlugin < BasePlugin
6
+
7
+ def should_run?
8
+ #puts "Config: #{config}"
9
+ unless config[:url]
10
+ log "Jenkins URL not configured!"
11
+ return false
12
+ end
13
+
14
+ if config[:branches]
15
+ allowed_branches = config[:branches].split(",")
16
+ commits = @framework.changes.map { |change| change[:commit] }
17
+ branches = commits.collect { |commit| @framework.head_names_for_commit(commit) }
18
+ branches.flatten!
19
+ if (branches & allowed_branches).empty?
20
+ log "No commits on matching branches (#{allowed_branches.join(', ')})"
21
+ return false
22
+ end
23
+ end
24
+ return true
25
+ end
26
+
27
+ def post_receive
28
+ uri = URI.parse(config[:url])
29
+ http = Net::HTTP.new(uri.host, uri.port)
30
+ request = Net::HTTP::Get.new(uri.request_uri)
31
+ if config[:auth]
32
+ request.basic_auth(*config[:auth].split(":"))
33
+ end
34
+ response = http.request(request)
35
+ log "Response: #{response.body}"
36
+ end
37
+ end
38
+ end
39
+ end
data/lib/hookie.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative "hookie/framework"
2
+
3
+ module Hookie
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'hookie'
3
+ require 'hookie/plugins/base_plugin'
4
+
5
+ class ThisHasALongNamePlugin < Hookie::BasePlugin
6
+ end
7
+
8
+ describe Hookie::BasePlugin do
9
+ before :each do
10
+ @hookie = double(Hookie::Framework)
11
+ @config = double(Grit::Config)
12
+ @config.stub(:keys).and_return([])
13
+ @hookie.stub(:config).and_return(@config)
14
+ end
15
+ context "base plugin" do
16
+ before :each do
17
+ @plugin = Hookie::BasePlugin.new @hookie
18
+ end
19
+ it "should initialise" do
20
+
21
+ end
22
+ it "should correctly derive the plugin name" do
23
+ @plugin.to_s.should eq "Base"
24
+ @plugin.config_key.should eq "base"
25
+
26
+ plugin = ThisHasALongNamePlugin.new @hookie
27
+ plugin.to_s.should eq "ThisHasALongName"
28
+ plugin.config_key.should eq "thishasalongname"
29
+ end
30
+
31
+ it "should read the correct config" do
32
+ @config.should_receive(:keys).once.and_return(["core.key","hookie.base.mykey"])
33
+ @config.should_receive('[]').with('hookie.base.mykey').and_return("value")
34
+ @plugin = Hookie::BasePlugin.new @hookie
35
+ @plugin.config.should have(1).items
36
+ end
37
+
38
+ it "should send log messages" do
39
+ @hookie.should_receive(:log).once.with(@plugin, "message")
40
+ @plugin.log "message"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hookie do
4
+ before(:each) do
5
+ @repo = double('Grit::Repo')
6
+ @config = double('Grit::Config')
7
+ Grit::Repo.should_receive(:new).once.and_return(@repo)
8
+ @repo.stub(:commits).and_return([])
9
+ @repo.stub(:config).and_return(@config)
10
+ STDIN.should_receive(:each_line).and_yield("bf6245eb3f1fa4cadff4299cb45e3ed85bc3337e b37c9728362ec39ce57adaab6ad9f0225d3513fe refs/heads/master").and_yield("0000000000000000000000000000000000000000 09e6a76d20ae8c8e1d40ce21b6ea586ff860e5d3 refs/heads/develop")
11
+ end
12
+
13
+ context 'initialisation' do
14
+ it "intialises" do
15
+ hookie = Hookie::Framework.new "test_hook", Dir.getwd
16
+ end
17
+
18
+ it "reads changes" do
19
+ commit = double('Grit::Commit')
20
+ @repo.should_receive(:commits).with("b37c9728362ec39ce57adaab6ad9f0225d3513fe", 1).once.and_return([commit])
21
+
22
+ hookie = Hookie::Framework.new "test_hook", Dir.getwd
23
+
24
+ hookie.changes.should have(2).items
25
+ change = hookie.changes[0]
26
+
27
+ change[:old_hash].should eq "bf6245eb3f1fa4cadff4299cb45e3ed85bc3337e"
28
+ change[:new_hash].should eq "b37c9728362ec39ce57adaab6ad9f0225d3513fe"
29
+ change[:ref].should eq "refs/heads/master"
30
+
31
+ change[:commit].should be commit
32
+ end
33
+ end
34
+
35
+ context "helpers" do
36
+ before(:each) do
37
+ @hookie = Hookie::Framework.new "test_hook", Dir.getwd
38
+ end
39
+
40
+ it "should not return a repo browsing url if it's not set" do
41
+ @repo.should_receive(:config).once.and_return(@config)
42
+ @config.should_receive('[]').with('hookie.core.web.browse').and_return(nil)
43
+ @hookie.repo_url.should be_nil
44
+ end
45
+
46
+ it "should return a repo browsing url if it's set" do
47
+ @repo.config.should_receive('[]').with("hookie.core.web.browse").at_least(:once).and_return("TEST %REPO% TEST")
48
+ @repo.config.should_receive('[]').with("hookie.core.repo.name").at_least(:once).and_return("testrepo")
49
+ @hookie.repo_url.should eq "TEST testrepo TEST"
50
+ end
51
+
52
+ it "should not return a commit url if it's not set" do
53
+ @repo.config.should_receive('[]').with("hookie.core.web.commit").at_least(:once).and_return(nil)
54
+ commit = double('Grit::Commit')
55
+ @hookie.commit_url(commit).should be_nil
56
+ end
57
+
58
+ it "should return a commit url if it's set" do
59
+ @repo.config.should_receive('[]').with("hookie.core.web.commit").at_least(:once).and_return("TEST %REPO% TEST %COMMIT%")
60
+ @repo.config.should_receive('[]').with("hookie.core.repo.name").at_least(:once).and_return("testrepo")
61
+ commit = double('Grit::Commit')
62
+ commit.stub(:id).and_return("ABC")
63
+ @hookie.commit_url(commit).should eq "TEST testrepo TEST ABC"
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+ require 'hookie'
3
+ require 'hookie/plugins/hipchat_plugin'
4
+
5
+ describe Hookie::Plugin::HipChatPlugin do
6
+ before :each do
7
+ @hookie = double(Hookie::Framework)
8
+ @config = double(Grit::Config)
9
+ @config.stub(:keys).and_return([])
10
+
11
+ @hookie.stub(:config).and_return(@config)
12
+ @hookie.stub(:log)
13
+ end
14
+ context "HipChat plugin" do
15
+ before :each do
16
+ @plugin = Hookie::Plugin::HipChatPlugin.new @hookie
17
+ end
18
+
19
+ context "config" do
20
+ it "shouldn't run only when there are no changes" do
21
+ @hookie.should_receive(:changes).once.and_return([])
22
+ @plugin.should_run?.should be_false
23
+ end
24
+
25
+ it "shouldn't run when there are changes but config is missing" do
26
+ @hookie.should_receive(:changes).once.and_return(["something"])
27
+ @hookie.should_receive(:log).once
28
+ @plugin.should_run?.should be_false
29
+ end
30
+
31
+ it "should run when there are no changes and config is correct" do
32
+ @config.should_receive(:keys).and_return(['hookie.hipchat.apikey','hookie.hipchat.room'])
33
+ @config.should_receive('[]').with('hookie.hipchat.apikey').and_return("ABC123")
34
+ @config.should_receive('[]').with('hookie.hipchat.room').and_return("1234")
35
+ plugin = Hookie::Plugin::HipChatPlugin.new @hookie
36
+ @hookie.should_receive(:changes).once.and_return(["something"])
37
+ @hookie.should_not_receive(:log)
38
+ plugin.should_run?.should be_true
39
+ end
40
+ end
41
+
42
+ it "sends the correct message" do
43
+ # FIXME this neds to be better
44
+ @plugin.stub(:format_message).and_return("message")
45
+ @plugin.should_receive(:speak).with("message").and_return({"status" => "sent"})
46
+ @hookie.should_receive(:log).twice
47
+ @plugin.post_receive
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'hookie'
3
+ require 'hookie/plugins/jenkins_plugin'
4
+
5
+ describe Hookie::Plugin::JenkinsPlugin do
6
+ before :each do
7
+ @hookie = double(Hookie::Framework)
8
+ @config = double(Grit::Config)
9
+ @config.stub(:keys).and_return([])
10
+
11
+ @hookie.stub(:config).and_return(@config)
12
+ @hookie.stub(:log)
13
+
14
+ @plugin = Hookie::Plugin::JenkinsPlugin.new @hookie
15
+ end
16
+ context "Jenkins plugin" do
17
+
18
+ context "config" do
19
+ it "shouldn't run when not configured" do
20
+ @plugin.stub(:config).and_return({})
21
+ @plugin.should_run?.should be_false
22
+ end
23
+ it "should run when it is configured" do
24
+ @plugin.should_receive(:config).at_least(:once).and_return({url: "foo"})
25
+ @plugin.should_run?.should be_true
26
+ end
27
+ it "should check for branches if configured" do
28
+ commit = double("Grit::Commit")
29
+ @hookie.should_receive(:changes).at_least(:once).and_return([
30
+ {old_hash: "", new_hash: "", ref: "", commit: commit}
31
+ ])
32
+ @hookie.should_receive(:head_names_for_commit).with(commit).and_return(['develop'])
33
+ @plugin.should_receive(:config).at_least(:once).and_return({
34
+ url: "foo",
35
+ branches: "develop,master"
36
+ })
37
+ @plugin.should_run?.should be_true
38
+
39
+ @hookie.should_receive(:head_names_for_commit).with(commit).and_return(['develop','foob'])
40
+ @plugin.should_run?.should be_true
41
+
42
+ @hookie.should_receive(:head_names_for_commit).with(commit).and_return(['develop','master'])
43
+ @plugin.should_run?.should be_true
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,7 @@
1
+ require 'rspec'
2
+ require 'hookie'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ config.formatter = 'documentation'
7
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hookie
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Marcin Szczepanski
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: grit
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.5.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.5.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: diff-lcs
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.1.3
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.1.3
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 2.12.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.12.0
62
+ description: ! "Hookie provides a way to write git hooks with ruby without too much
63
+ worrying about any of the plumbing required, you can easily write your own plugins
64
+ and focus on the core of your functionality. \n\n Hookie includes plugins for
65
+ Jenkins and HipChat."
66
+ email:
67
+ - marcins@webqem.com
68
+ executables:
69
+ - hookie
70
+ extensions: []
71
+ extra_rdoc_files: []
72
+ files:
73
+ - .gitignore
74
+ - Gemfile
75
+ - LICENSE.txt
76
+ - README.md
77
+ - Rakefile
78
+ - bin/hookie
79
+ - hookie.gemspec
80
+ - lib/hookie.rb
81
+ - lib/hookie/framework.rb
82
+ - lib/hookie/plugins/base_plugin.rb
83
+ - lib/hookie/plugins/empty_plugin.rb
84
+ - lib/hookie/plugins/hipchat_plugin.rb
85
+ - lib/hookie/plugins/jenkins_plugin.rb
86
+ - spec/base_plugin_spec.rb
87
+ - spec/framework_spec.rb
88
+ - spec/hipchat_plugin_spec.rb
89
+ - spec/jenkins_plugin_spec.rb
90
+ - spec/spec_helper.rb
91
+ homepage: https://github.com/marcins/hookie
92
+ licenses: []
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 1.8.23
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: Framework for writing gitolite/git hooks with Ruby
115
+ test_files:
116
+ - spec/base_plugin_spec.rb
117
+ - spec/framework_spec.rb
118
+ - spec/hipchat_plugin_spec.rb
119
+ - spec/jenkins_plugin_spec.rb
120
+ - spec/spec_helper.rb