meathook 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|