meathook 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: df74157c4d8c0038c54fdf7faef66aef8ab3bb15
4
+ data.tar.gz: d20dec733dcd1fdc9bc3dbba6a7438c0f8503499
5
+ SHA512:
6
+ metadata.gz: 607bdabedd4d9f27dadca0228907be4e2d94833d601f9a4fde692e8b345fe88dc69eccf3a4e18e824d1866f2f0e668ae4f2eb7a66ffc858ff84b60cab42f346f
7
+ data.tar.gz: 914a6635284d2c20349af4ba533f52d2361faefcea3259c09a772b7bed1eac795e527df362beee0dc1a96ab3579c976ef410a7918a77d4adcd9408939d8509da
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ copyright (c) 2015, Emcien Corporation
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+ * Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ * Neither the name of the <organization> nor the
12
+ names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,49 @@
1
+ # Meathook
2
+
3
+ Meathook is a gem to help manage a living set of githooks.
4
+ Inspired by Babar (http://github.com/jdabbs/babar), but intended to be
5
+ more general in purpose.
6
+
7
+ ## .hooks
8
+
9
+ The `.hooks.yaml` file should be committed in the root of your repository -
10
+ it's a yaml file like so:
11
+
12
+ ```yaml
13
+ ---
14
+ path: "bin/meathook"
15
+ pre-commit:
16
+ no_focus:
17
+ command: "git diff --cached spec/ | grep '^+' | grep ':focus'"
18
+ condition: "nonempty"
19
+ halt: true
20
+ message: "You are trying to commit a focused spec!"
21
+ post-merge:
22
+ remember_to_bundle:
23
+ command: "git diff --name-only HEAD^..HEAD | grep Gemfile
24
+ condition: "nonempty"
25
+ halt: false
26
+ message: "Gemfile was just updated - remember to run 'bundle install'"
27
+ ```
28
+
29
+ Each hook type can be a toplevel key in that file, and the keys in each are arbitrary
30
+ names of tasks. Each task then has the keys:
31
+
32
+ - command: command to run - output and exit code can both be relevant
33
+ - condition: one of [nonempty, empty, failed, successful]
34
+ - halt: under those conditions, should we halt the procedure? (commit, merge, etc)
35
+ - message: message to show the user if the condition is true
36
+
37
+ The 'path' key is special, and is used to supply a literal path to the meathook script,
38
+ so that your githooks don't have to use bundler (which can add a half-second onto each
39
+ operation). if `which meathook` doesn't give you a path, then you need to specify a path
40
+ with this key.
41
+
42
+ ## `meathook install`
43
+
44
+ In order to run the githooks, meathook needs to install a self-call into each of the
45
+ .git/hooks scripts of the form `meathook execute <hookname>`.
46
+
47
+ ## `meathook uninstall`
48
+
49
+ Removes the meathook call from all of the githooks.
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/meathook'
4
+
5
+ command = ARGV.shift
6
+
7
+ xname = "meathook"
8
+ if File.exist?(".hook")
9
+ text = File.read(".hook")
10
+ data = YAML.load(text)
11
+ if data["path"]
12
+ xname = data["path"]
13
+ end
14
+ end
15
+
16
+ if command == "install"
17
+ Meathook.install(xname)
18
+ elsif command == "uninstall"
19
+ Meathook.uninstall(xname)
20
+ elsif command == "execute"
21
+ capn = Meathook::Captain.new
22
+ hookname = ARGV.shift || raise("usage: meathook execute HOOKNAME")
23
+ capn.each_hook(hookname) do |h|
24
+ h.each_command do |cmd|
25
+ cmd.execute
26
+ end
27
+ end
28
+ else
29
+ warn "The command '#{command}' is not recognized."
30
+ exit(1)
31
+ end
@@ -0,0 +1,47 @@
1
+ module Meathook
2
+ RECOGNIZED_HOOKS = [
3
+ "applypatch-msg",
4
+ "pre-applypatch",
5
+ "post-applypatch",
6
+ "pre-commit",
7
+ "prepare-commit-msg",
8
+ "commit-msg",
9
+ "post-commit",
10
+ "pre-rebase",
11
+ "post-checkout",
12
+ "post-merge",
13
+ "pre-receive",
14
+ "update",
15
+ "post-receive",
16
+ "post-update",
17
+ "pre-auto-gc",
18
+ "post-rewrite",
19
+ ]
20
+
21
+
22
+ def self.install(xname)
23
+ RECOGNIZED_HOOKS.each do |name|
24
+ path = ".git/hooks/#{name}"
25
+ hook_contents = File.exist?(path) ? File.read(path) : ""
26
+ unless hook_contents =~ /#{xname} execute/
27
+ system("echo '#{xname} execute #{name} #MEATHOOK' >> '#{path}'")
28
+ system("chmod +x '#{path}'")
29
+ end
30
+ end
31
+ end
32
+
33
+ def self.uninstall(xname)
34
+ RECOGNIZED_HOOKS.each do |name|
35
+ path = ".git/hooks/#{name}"
36
+ hook_contents = File.exist?(path) ? File.read(path) : ""
37
+ if hook_contents =~ /#{xname} execute/
38
+ system("sed -i '.bak' '/MEATHOOK/d' '#{path}'")
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ dirpath = File.expand_path("../meathook", __FILE__)
45
+ Dir.glob("#{dirpath}/*.rb").each do |p|
46
+ require p
47
+ end
@@ -0,0 +1,31 @@
1
+ require 'yaml'
2
+
3
+ module Meathook
4
+ class Captain
5
+ attr_accessor :path, :text, :data, :hooks
6
+
7
+ def initialize
8
+ self.path = '.hook'
9
+ self.text = ""
10
+ self.data = {}
11
+ self.hooks = []
12
+
13
+ if File.exist?(path)
14
+ self.text = File.read(self.path)
15
+ self.data = YAML.load(self.text)
16
+ self.data.each_pair do |hname, hdata|
17
+ next if hname == "path"
18
+ self.hooks << Meathook::Hook.new(hname, hdata)
19
+ end
20
+ end
21
+ end
22
+
23
+ def each_hook(name=nil, &block)
24
+ self.hooks.each do |h|
25
+ if h.name == name
26
+ yield h
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ module Meathook
2
+ class Command
3
+ attr_accessor :name, :hookname
4
+ attr_accessor :command, :condition, :halt, :message
5
+ attr_accessor :match
6
+
7
+ def initialize(n, hn, opts)
8
+ self.name = n
9
+ self.hookname = hn
10
+
11
+ self.command = opts.fetch('command')
12
+ self.condition = opts.fetch('condition')
13
+ self.halt = opts['halt'] || false
14
+ self.message = opts["message"]
15
+
16
+ self.match = false
17
+ end
18
+
19
+ def execute
20
+ output = `#{command}`
21
+ exit_code = ($?)
22
+
23
+ case condition
24
+ when "empty" then self.match = (output =~ /\S/ ? false : true)
25
+ when "nonempty" then self.match = (output =~ /\S/ ? true : false)
26
+ when "failed" then self.match = (exit_code != 0)
27
+ when "successful" then self.match = (exit_code == 0)
28
+ else raise("The condition '#{condition}' was not recognized")
29
+ end
30
+
31
+ if self.match
32
+ if self.message and self.message =~ /\S/
33
+ warn ""
34
+ warn "============================================================"
35
+ warn " Git Hook '#{hookname}' :: '#{name}' triggered"
36
+ warn ""
37
+ warn " #{message}"
38
+ warn ""
39
+ end
40
+
41
+ if self.halt
42
+ exit(1)
43
+ else
44
+ exit(0)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ module Meathook
2
+ class Hook
3
+ attr_accessor :name, :commands, :data
4
+
5
+ def initialize(hn, d)
6
+ self.name = hn
7
+ self.data = d
8
+ self.commands = []
9
+
10
+ self.data.each_pair do |cname, cdata|
11
+ self.commands << Meathook::Command.new(self.name, cname, cdata)
12
+ end
13
+ end
14
+
15
+ def each_command(&block)
16
+ self.commands.each{|c| yield c}
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: meathook
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Emcien
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-19 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Allows a project to specify git hooks for its devs to install
14
+ email:
15
+ - engineering@emcien.com
16
+ executables:
17
+ - meathook
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE
22
+ - README.md
23
+ - bin/meathook
24
+ - lib/meathook.rb
25
+ - lib/meathook/captain.rb
26
+ - lib/meathook/command.rb
27
+ - lib/meathook/hook.rb
28
+ homepage: https://github.com/emcien/meathook
29
+ licenses:
30
+ - ''
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 2.4.3
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: Git hook manager
52
+ test_files: []