From d1ea62d1cba8abc18e0f797c5607590de737ea31 Mon Sep 17 00:00:00 2001 From: James Mead Date: Fri, 17 Jul 2015 15:09:35 +0100 Subject: [PATCH] WIP: First stab at git post-commit hook The post-commit hook parses the state of the code after each commit to the `master` branch, builds a tree of method definition "files" using ri-style naming, and adds a corresponding commit to the orphan `method-log` branch. * This code assumes the `method-log` branch already exists. * I've not thought about what happens if the history on `master` is re-written. * There is no explicit reference between the commits on `master` and those on the `method-log` branch. * I'm not sure how tenable it is to use a `Gemfile` and bundler for this hook. Maybe an in-line `Gemfile` [1] might be better. * I've duplicated some code from elsewhere in the repo, e.g. `#unindent`. * I've used `instance_variable_get` on the instance of `MethodFinder`, but it would be easy to surface this as a public attribute reader method. [1]: http://bundler.io/whats_new.html#inline --- hooks/Gemfile | 4 ++++ hooks/post-commit | 4 ++++ hooks/post_commit.rb | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 hooks/Gemfile create mode 100755 hooks/post-commit create mode 100644 hooks/post_commit.rb diff --git a/hooks/Gemfile b/hooks/Gemfile new file mode 100644 index 0000000..27e6ce1 --- /dev/null +++ b/hooks/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +gem 'parser' +gem 'method_log' diff --git a/hooks/post-commit b/hooks/post-commit new file mode 100755 index 0000000..ad14cd4 --- /dev/null +++ b/hooks/post-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +cd .git/hooks +bundle exec ruby post_commit.rb diff --git a/hooks/post_commit.rb b/hooks/post_commit.rb new file mode 100644 index 0000000..3f5cee2 --- /dev/null +++ b/hooks/post_commit.rb @@ -0,0 +1,41 @@ +require 'bundler/setup' + +require 'method_log/repository' +require 'method_log/method_finder' +require 'method_log/source_file' + +def unindent(code) + lines = code.split($/) + indent = lines.reject { |l| l.strip.length == 0 }.map { |l| l[/^ */].length }.min + lines.map { |l| l.sub(Regexp.new(' ' * indent), '') }.join($/) +end + +repository_path = File.expand_path('../..') +rugged_repository = Rugged::Repository.new(repository_path) +exit unless rugged_repository.head.name == 'refs/heads/master' +last_commit_sha = rugged_repository.last_commit.oid + +repository = MethodLog::Repository.new(repository_path) +last_commit = repository.build_commit(last_commit_sha) + +rugged_repository.checkout('method-log') +begin + new_commit = repository.build_commit + last_commit.source_files.each do |source_file| + next if source_file.path[%r{^(vendor|test)}] + begin + method_finder = MethodLog::MethodFinder.new(source_file) + method_finder.instance_variable_get('@methods').each do |method_signature, method_definition| + _, namespace, name = method_signature.match(/^(.*)([#.].*)$/).to_a + path = namespace.split('::').push(name).join(File::SEPARATOR) + '.rb' + new_commit.add(MethodLog::SourceFile.new(path: path, source: unindent(method_definition.source) + $/)) + end + rescue Parser::SyntaxError => e + p e + end + end + new_commit.apply(user: last_commit.author, message: last_commit.message) + rugged_repository.reset('HEAD', :hard) +ensure + rugged_repository.checkout('master') +end