meathook 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +24 -0
- data/README.md +49 -0
- data/bin/meathook +31 -0
- data/lib/meathook.rb +47 -0
- data/lib/meathook/captain.rb +31 -0
- data/lib/meathook/command.rb +49 -0
- data/lib/meathook/hook.rb +19 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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.
|
data/bin/meathook
ADDED
@@ -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
|
data/lib/meathook.rb
ADDED
@@ -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: []
|