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.
@@ -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: []