diff --git a/Rakefile b/Rakefile index c2e4f58..e233999 100644 --- a/Rakefile +++ b/Rakefile @@ -17,7 +17,12 @@ begin s.add_dependency(%q, [">= 2"]) end rescue LoadError - puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" + puts "Jeweler, or one of its dependencies, is not available." +end + +desc 'Start the commit monitor' +task 'start' do |t, args| + ruby "-Ilib commit_monitor.rb" end begin @@ -25,6 +30,7 @@ begin RSpec::Core::RakeTask.new('spec') do |t| t.rspec_opts = ["-fd", "-c"] + t.ruby_opts = ["-Ispec,lib"] t.pattern = 'spec/**/*_spec.rb' end diff --git a/commit_monitor.rb b/commit_monitor.rb index 9470ab4..b9208c9 100644 --- a/commit_monitor.rb +++ b/commit_monitor.rb @@ -11,13 +11,13 @@ configure do repos = File.join(`pwd`.chomp, 'data/repos') config = 'config/repos.yml' - repo_manager = GITRepoManager.new(config, repos) + repo_manager = ForkGITRepoManager.new(config, repos) end configure :test do local_repos = File.join(`pwd`.chomp, 'spec/files/test_repos') test_config = 'spec/files/config/repos.yml' - repo_manager = GITRepoManager.new(test_config, local_repos) + repo_manager = ForkGITRepoManager.new(test_config, local_repos) end # Repositories are single-threaded diff --git a/lib/git_repo_manager.rb b/lib/git_repo_manager.rb index c57d9b4..0471fcf 100644 --- a/lib/git_repo_manager.rb +++ b/lib/git_repo_manager.rb @@ -1,8 +1,7 @@ -require 'rubygems' require 'yaml' -require 'lib/global_logger' require 'git' require 'fileutils' +require 'global_logger' class GITRepoManager attr_reader :config_file, :clone_path, :submodules, :config_hash @@ -30,29 +29,30 @@ def update_submodule(uri, branch, commit) $logger.info("Received commit #{commit[0..8]} from `#{uri}`, branch `#{branch}`") - @repos_using_submodules.each do |repo_name| - $logger.debug("Checking `#{repo_name}` for submodules") + if sync_branch?(branch) + @repos_using_submodules.each do |repo_name| + $logger.debug("Checking `#{repo_name}` for submodules") - repo = @repos[repo_name] + repo = @repos[repo_name] - repo.submodules.each do |submodule| - submodule_path = submodule.path - submodule_uri = submodule.uri - $logger.debug("Repo `#{repo_name}` has submodule `#{submodule_path}`, #{submodule_uri}") + repo.submodules.each do |submodule| + submodule_path = submodule.path + submodule_uri = submodule.uri + $logger.debug("Repo `#{repo_name}` has submodule `#{submodule_path}`, #{submodule_uri}") - normalized_local = GITRepoManager.normalize_git_uri(submodule_uri) - normalized_receiving = GITRepoManager.normalize_git_uri(uri) + normalized_local = self.class.normalize_git_uri(submodule_uri) + normalized_receiving = self.class.normalize_git_uri(uri) + $logger.debug("Comparing: #{normalized_local} == #{normalized_receiving}") - $logger.debug("Comparing: #{normalized_local} == #{normalized_receiving}") - if normalized_local == normalized_receiving - $logger.debug("Found submodule `#{uri}` as `#{submodule_path}` in `#{repo_name}`") - # repo has a submodule corresponding to uri + if normalized_local == normalized_receiving + $logger.debug("Found submodule `#{uri}` as `#{submodule_path}` in `#{repo_name}`") - submodule.init unless submodule.initialized? - submodule.update unless submodule.updated? + # repo has a submodule corresponding to uri - if repo.is_branch?(branch) - if @ignore_sync_only_branch_list || @sync_branch[branch.to_sym] + submodule.init unless submodule.initialized? + submodule.update unless submodule.updated? + + if repo.is_branch?(branch) $logger.info("Updating `#{repo_name}` with submodule branch `#{branch}`.") repo.branch(branch).checkout repo.reset_hard("origin/#{branch}") @@ -62,9 +62,18 @@ def update_submodule(uri, branch, commit) sub_repo.fetch sub_repo.checkout(commit) + # Let's try to get the name of the actual commiter from the submodule in as the commiter + # to the pointer update + if author = self.class.git_commit_author_name(sub_repo.log.first) + $logger.debug("Submodule author: #{author}") + opts = {:author => author} + else + opts = {} + end + repo.add(submodule_path) message = "Auto-updating submodule to commit #{self.class.github_user_project_name(submodule_uri)}@#{commit}." - repo.commit(message) + repo.commit(message, opts) begin repo.push('origin', branch) $logger.debug("Committed with message: #{message}") @@ -73,14 +82,15 @@ def update_submodule(uri, branch, commit) end updated << message else - $logger.debug("Branch `#{branch}` is not on the sync list. Ignoring commit.") + $logger.info("Repository `#{repo_name}` does not have a branch called `#{branch}`") end - else - $logger.info("Repository `#{repo_name}` does not have a branch called `#{branch}`") end end end + else + $logger.debug("Branch `#{branch}` is not on the sync list. Ignoring commit.") end + updated end @@ -103,7 +113,6 @@ def clone_or_pull_repositories end end - def process_config_hash @submodules = [] @repos_using_submodules = [] @@ -138,6 +147,10 @@ def repo_path(name) File.join(@clone_path, name.to_s) end + def sync_branch?(name) + @ignore_sync_only_branch_list || @sync_branch[name.to_sym] + end + def self.symbolize_keys(hash) new_hash = Hash.new hash.each do |key, value| @@ -189,4 +202,54 @@ def self.github_user_project_name(uri) end end + def self.git_commit_author_name(commit) + author = commit.author + "#{author.name} <#{author.email}>" + end + +end + +class BGGitRepoManager + + def initialize(config = 'config/repos.yml', clone_path = 'data/repos') + @repomanager = GITRepoManager.new(config, clone_path) + setup_worker_thread + end + + def update_submodule(uri, branch, commit) + $logger.debug("Pushing request to bg queue uri #{uri} branch #{branch} commit #{commit}") + @bgqueue.push([uri, branch, commit]) + [] + end + + private + + def setup_worker_thread + require 'thread' + @bgqueue = Queue.new + @bgthread = Thread.start do + while true + #pop will make the thread sleep until there is data + uri, branch, commit = *(@bgqueue.pop) + $logger.debug("BG thread popped data uri #{uri} branch #{branch} commit #{commit}") + @repomanager.update_submodule(uri, branch, commit) + end + end + end +end + +class ForkGitRepoManager + + def initialize(config = 'config/repos.yml', clone_path = 'data/repos') + @repomanager = GITRepoManager.new(config, clone_path) + end + + def update_submodule(uri, branch, commit) + $logger.debug("Pushing request to bg queue uri #{uri} branch #{branch} commit #{commit}") + Process.fork do + @repomanager.update_submodule(uri, branch, commit) + end + [] + end + end diff --git a/spec/git_manager_spec.rb b/spec/git_manager_spec.rb index acf526b..d96c2c3 100644 --- a/spec/git_manager_spec.rb +++ b/spec/git_manager_spec.rb @@ -1,11 +1,9 @@ -require 'lib/git_repo_manager' -require 'lib/global_logger' -require 'spec/spec_helper.rb' +require 'spec_helper.rb' require 'git' describe GITRepoManager do - LOCAL_REPOS = File.join(`pwd`.chomp, 'spec/files/test_repos') + LOCAL_REPOS = File.join(Dir.pwd, 'spec/files/test_repos') TEST_CONFIG = 'spec/files/config/repos.yml' # TODO move @@ -80,8 +78,10 @@ it 'should auto commit an update to repositories using submodules' do commit = change_submodule_via_third_party_checkout + local_using_submodule_checkout.log.first.message.should_not == "Auto-updating submodule to commit spec_testing/submodule@#{commit.sha}." manager.update_submodule(TEST_REPO_SUBMODULE, 'master', commit.sha) local_using_submodule_checkout.log.first.message.should == "Auto-updating submodule to commit spec_testing/submodule@#{commit.sha}." + GITRepoManager.git_commit_author_name(local_using_submodule_checkout.log.first).should == "Third party " end it 'should push auto commits to the remote repository' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 501b174..68a1675 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,6 @@ +require 'git_repo_manager' +require 'global_logger' + TEMP_DIRECTORY = '/tmp/spec_testing' def initalize_repos @@ -49,7 +52,7 @@ def change_submodule_via_third_party_checkout(branch = 'master', line = 'Updatin @third_party_submodule_clone.branch(branch).checkout `echo "#{line}" >> #{@third_party_submodule_path}/README` @third_party_submodule_clone.add('.') - @third_party_submodule_clone.commit('New line in readme') + @third_party_submodule_clone.commit('New line in readme', :author => 'Third party ') @third_party_submodule_clone.push('origin', branch) @third_party_submodule_clone.log.first end