From 8c61bf35408c0b47eb79d2d9d135b5b479abfecb Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 23 Oct 2015 15:18:58 -0400 Subject: a callback to push config changes to a remote repository --- lib/oxidized/hook/githubrepo.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 lib/oxidized/hook/githubrepo.rb (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb new file mode 100644 index 0000000..f2ffa2a --- /dev/null +++ b/lib/oxidized/hook/githubrepo.rb @@ -0,0 +1,16 @@ +class GithubRepo < Oxidized::Hook + def validate_cfg! + cfg.has_key?('remote_repo') or raise 'remote_repo is required' + end + + def run_hook(ctx) + credentials = Rugged::Credentials::SshKeyFromAgent.new(username: 'git') + repo = Rugged::Repository.new(Oxidized::CFG.output.git.repo) + log "Pushing local repository(#{repo.path})..." + remote = repo.remotes['origin'] || repo.remotes.create('origin', cfg.remote_repo) + log "to remote: #{remote.url}" + remote.push(['refs/heads/master'], credentials: credentials) + rescue Exception => e + log e.backtrace.join('\n') + end +end -- cgit v1.2.3 From c96c52ab7153ffd85906550544df627c6c80aac8 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Mon, 26 Oct 2015 12:48:48 -0400 Subject: raise more specific exception when required key is not present --- lib/oxidized/hook/githubrepo.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index f2ffa2a..efa536b 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -1,6 +1,6 @@ class GithubRepo < Oxidized::Hook def validate_cfg! - cfg.has_key?('remote_repo') or raise 'remote_repo is required' + cfg.has_key?('remote_repo') or raise KeyError, 'remote_repo is required' end def run_hook(ctx) -- cgit v1.2.3 From bd7d0b1660be8bd4a32828ea5ca83c16c1797045 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Mon, 26 Oct 2015 13:33:53 -0400 Subject: do not rescue general exception --- lib/oxidized/hook/githubrepo.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index efa536b..a17d6b9 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -10,7 +10,5 @@ class GithubRepo < Oxidized::Hook remote = repo.remotes['origin'] || repo.remotes.create('origin', cfg.remote_repo) log "to remote: #{remote.url}" remote.push(['refs/heads/master'], credentials: credentials) - rescue Exception => e - log e.backtrace.join('\n') end end -- cgit v1.2.3 From 817f33a2a1e8f78720f5e73a10ee45384e886ae9 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 13 Nov 2015 16:31:02 -0500 Subject: githubrepo hook spec --- lib/oxidized/hook/githubrepo.rb | 2 +- spec/githubrepo_spec.rb | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 spec/githubrepo_spec.rb (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index a17d6b9..85adaab 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -5,7 +5,7 @@ class GithubRepo < Oxidized::Hook def run_hook(ctx) credentials = Rugged::Credentials::SshKeyFromAgent.new(username: 'git') - repo = Rugged::Repository.new(Oxidized::CFG.output.git.repo) + repo = Rugged::Repository.new(Oxidized.config.output.git.repo) log "Pushing local repository(#{repo.path})..." remote = repo.remotes['origin'] || repo.remotes.create('origin', cfg.remote_repo) log "to remote: #{remote.url}" diff --git a/spec/githubrepo_spec.rb b/spec/githubrepo_spec.rb new file mode 100644 index 0000000..c98244d --- /dev/null +++ b/spec/githubrepo_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' +require 'rugged' +require 'oxidized/hook/githubrepo' + +describe Oxidized::Node do + before(:each) do + asetus = Asetus.new + asetus.cfg.output.git.repo = 'foo.git' + Oxidized.stubs(:asetus).returns(asetus) + repo = mock() + remote = mock() + remote.expects(:url).returns('github.com/foo.git') + remote.expects(:push).returns(true) + repo.expects(:remotes).returns({'origin' => remote}) + repo.expects(:path).returns('foo.git') + Rugged::Repository.expects(:new).with('foo.git').returns(repo) + end + + describe "#run_hook" do + it "will push to the remote repository" do + gr = GithubRepo.new + gr.run_hook(nil).must_equal true + end + end +end -- cgit v1.2.3 From bb1d59b78fd197c992e2a59dd3b56b0ffe0d3320 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 4 Dec 2015 00:13:35 -0500 Subject: user password username for github api --- lib/oxidized/hook/githubrepo.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index 85adaab..fe73015 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -4,7 +4,7 @@ class GithubRepo < Oxidized::Hook end def run_hook(ctx) - credentials = Rugged::Credentials::SshKeyFromAgent.new(username: 'git') + credentials = Rugged::Credentials::UserPassword.new(username: cfg.username, password: cfg.password) repo = Rugged::Repository.new(Oxidized.config.output.git.repo) log "Pushing local repository(#{repo.path})..." remote = repo.remotes['origin'] || repo.remotes.create('origin', cfg.remote_repo) -- cgit v1.2.3 From eead03c1557117882b42759de2de4114e3a4b5cd Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Fri, 4 Dec 2015 03:51:12 -0500 Subject: consider local repo main --- lib/oxidized/hook/githubrepo.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index fe73015..bf33b89 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -9,6 +9,6 @@ class GithubRepo < Oxidized::Hook log "Pushing local repository(#{repo.path})..." remote = repo.remotes['origin'] || repo.remotes.create('origin', cfg.remote_repo) log "to remote: #{remote.url}" - remote.push(['refs/heads/master'], credentials: credentials) + remote.push(['+refs/heads/master'], credentials: credentials) end end -- cgit v1.2.3 From d2e8c0e96460b34371bbb72f0ecf878321fbf8e3 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Mon, 7 Dec 2015 14:46:40 -0500 Subject: pull origin/master before pushing --- lib/oxidized/hook/githubrepo.rb | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index bf33b89..83e1078 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -9,6 +9,24 @@ class GithubRepo < Oxidized::Hook log "Pushing local repository(#{repo.path})..." remote = repo.remotes['origin'] || repo.remotes.create('origin', cfg.remote_repo) log "to remote: #{remote.url}" - remote.push(['+refs/heads/master'], credentials: credentials) + + fetch_and_merge_remote(repo, credentials) + + remote.push([repo.head.name], credentials: credentials) + end + + def fetch_and_merge_remote(repo, credentials) + their_branch = repo.branches["origin/master"] or return + + repo.fetch('origin', [repo.head.name], credentials: credentials) + + merge_index = repo.merge_commits(repo.head.target_id, their_branch.target_id) + + Rugged::Commit.create(repo, { + parents: [repo.head.target, their_branch.target], + tree: merge_index.write_tree(repo), + message: "Merge remote-tracking branch '#{their_branch.name}'", + update_ref: "HEAD" + }) end end -- cgit v1.2.3 From 2eef353c6ef98662c3092a5a28ee6f167b1d1774 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Tue, 8 Dec 2015 18:34:16 -0500 Subject: warn when there is a conflict --- lib/oxidized/hook/githubrepo.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index 83e1078..25b2cd0 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -16,12 +16,14 @@ class GithubRepo < Oxidized::Hook end def fetch_and_merge_remote(repo, credentials) - their_branch = repo.branches["origin/master"] or return - repo.fetch('origin', [repo.head.name], credentials: credentials) + their_branch = repo.branches["origin/master"] or return + merge_index = repo.merge_commits(repo.head.target_id, their_branch.target_id) + log("Conflicts detected", :warn) if merge_index.conflicts? + Rugged::Commit.create(repo, { parents: [repo.head.target, their_branch.target], tree: merge_index.write_tree(repo), -- cgit v1.2.3 From fa3b93c5046f23ebbb2e82ac4944357683f8c5d8 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Wed, 9 Dec 2015 22:53:16 -0500 Subject: let user configure which auth method to use --- lib/oxidized/hook/githubrepo.rb | 18 ++++++++++++--- spec/githubrepo_spec.rb | 50 ++++++++++++++++++++++++++++------------- 2 files changed, 50 insertions(+), 18 deletions(-) (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index 25b2cd0..22ee8ea 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -4,18 +4,17 @@ class GithubRepo < Oxidized::Hook end def run_hook(ctx) - credentials = Rugged::Credentials::UserPassword.new(username: cfg.username, password: cfg.password) repo = Rugged::Repository.new(Oxidized.config.output.git.repo) log "Pushing local repository(#{repo.path})..." remote = repo.remotes['origin'] || repo.remotes.create('origin', cfg.remote_repo) log "to remote: #{remote.url}" - fetch_and_merge_remote(repo, credentials) + fetch_and_merge_remote(repo) remote.push([repo.head.name], credentials: credentials) end - def fetch_and_merge_remote(repo, credentials) + def fetch_and_merge_remote(repo) repo.fetch('origin', [repo.head.name], credentials: credentials) their_branch = repo.branches["origin/master"] or return @@ -31,4 +30,17 @@ class GithubRepo < Oxidized::Hook update_ref: "HEAD" }) end + + private + + def credentials + @credentials ||= if cfg.has_key?('username') && cfg.has_key?('password') + log "Using https auth", :debug + Rugged::Credentials::UserPassword.new(username: cfg.username, password: cfg.password) + else + log "Using ssh auth", :debug + Rugged::Credentials::SshKeyFromAgent.new(username: 'git') + end + end + end diff --git a/spec/githubrepo_spec.rb b/spec/githubrepo_spec.rb index 07296f3..a3b4953 100644 --- a/spec/githubrepo_spec.rb +++ b/spec/githubrepo_spec.rb @@ -4,30 +4,50 @@ require 'oxidized/hook/githubrepo' describe Oxidized::Node do before(:each) do - asetus = Asetus.new - asetus.cfg.output.git.repo = 'foo.git' - asetus.cfg.hooks.github_repo_hook.remote_repo = 'https://github.com/blah/blah.git' - asetus.cfg.hooks.github_repo_hook.username = 'username' - asetus.cfg.hooks.github_repo_hook.password = 'password' - GithubRepo.any_instance.stubs(:cfg).returns(asetus.cfg.hooks.github_repo_hook) - Oxidized.stubs(:asetus).returns(asetus) - repo = mock() + Oxidized.asetus = Asetus.new + Oxidized.config.output.git.repo = 'foo.git' + + @credentials = mock() + remote = mock() - remote.expects(:url).returns('github.com/foo.git') - remote.expects(:push).returns(true) - repo.expects(:remotes).returns({'origin' => remote}) - repo.expects(:path).returns('foo.git') + remote.expects(:url).returns('https://github.com/username/foo.git') + remote.expects(:push).with(['refs/heads/master'], credentials: @credentials).returns(true) + repo_head = mock() - repo_head.expects(:name).twice.returns('origin/master') + repo_head.expects(:name).twice.returns('refs/heads/master') + + repo = mock() + repo.expects(:path).returns('foo.git') + repo.expects(:remotes).returns({'origin' => remote}) repo.expects(:head).twice.returns(repo_head) - repo.expects(:fetch).returns(true) + repo.expects(:fetch).with('origin', ['refs/heads/master'], credentials: @credentials).returns(true) repo.expects(:branches).returns({}) + Rugged::Repository.expects(:new).with('foo.git').returns(repo) end describe "#run_hook" do - it "will push to the remote repository" do + it "will push to the remote repository using https" do + Oxidized.config.hooks.github_repo_hook.remote_repo = 'https://github.com/username/foo.git' + Oxidized.config.hooks.github_repo_hook.username = 'username' + Oxidized.config.hooks.github_repo_hook.password = 'password' + + Rugged::Credentials::UserPassword.expects(:new).with(username: 'username', password: 'password').returns(@credentials) + + gr = GithubRepo.new + gr.cfg = Oxidized.config.hooks.github_repo_hook + + gr.run_hook(nil).must_equal true + end + + it "will push to the remote repository using ssh" do + Oxidized.config.hooks.github_repo_hook.remote_repo = 'git@github.com:username/foo.git' + + Rugged::Credentials::SshKeyFromAgent.expects(:new).with(username: 'git').returns(@credentials) + gr = GithubRepo.new + gr.cfg = Oxidized.config.hooks.github_repo_hook + gr.run_hook(nil).must_equal true end end -- cgit v1.2.3 From c2a52593a70a89582202d629842189b4a1448a15 Mon Sep 17 00:00:00 2001 From: Elvin Efendi Date: Sun, 13 Dec 2015 22:12:24 -0500 Subject: do not commit when there is no diff --- lib/oxidized/hook/githubrepo.rb | 17 ++++++-- spec/githubrepo_spec.rb | 89 ++++++++++++++++++++++++++++++----------- 2 files changed, 80 insertions(+), 26 deletions(-) (limited to 'lib/oxidized/hook') diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb index 22ee8ea..d10b51e 100644 --- a/lib/oxidized/hook/githubrepo.rb +++ b/lib/oxidized/hook/githubrepo.rb @@ -15,13 +15,24 @@ class GithubRepo < Oxidized::Hook end def fetch_and_merge_remote(repo) - repo.fetch('origin', [repo.head.name], credentials: credentials) + result = repo.fetch('origin', [repo.head.name], credentials: credentials) + log result.inspect, :debug - their_branch = repo.branches["origin/master"] or return + unless result[:total_deltas] > 0 + log "nothing recieved after fetch", :debug + return + end + + their_branch = repo.branches["origin/master"] + + log "merging fetched branch #{their_branch.name}", :debug merge_index = repo.merge_commits(repo.head.target_id, their_branch.target_id) - log("Conflicts detected", :warn) if merge_index.conflicts? + if merge_index.conflicts? + log("Conflicts detected, skipping Rugged::Commit.create", :warn) + return + end Rugged::Commit.create(repo, { parents: [repo.head.target, their_branch.target], diff --git a/spec/githubrepo_spec.rb b/spec/githubrepo_spec.rb index 5786d73..9ad43e9 100644 --- a/spec/githubrepo_spec.rb +++ b/spec/githubrepo_spec.rb @@ -3,52 +3,95 @@ require 'rugged' require 'oxidized/hook/githubrepo' describe Oxidized::Node do + let(:credentials) { mock() } + let(:remote) { mock() } + let(:repo_head) { mock() } + let(:repo) { mock() } + let(:gr) { GithubRepo.new } + before(:each) do Oxidized.asetus = Asetus.new Oxidized.config.output.git.repo = 'foo.git' Oxidized.setup_logger + end - @credentials = mock() + describe "#fetch_and_merge_remote" do + before(:each) do + Oxidized.config.hooks.github_repo_hook.remote_repo = 'git@github.com:username/foo.git' + Rugged::Credentials::SshKeyFromAgent.expects(:new).with(username: 'git').returns(credentials) + repo_head.expects(:name).returns('refs/heads/master') + gr.cfg = Oxidized.config.hooks.github_repo_hook + end - remote = mock() - remote.expects(:url).returns('https://github.com/username/foo.git') - remote.expects(:push).with(['refs/heads/master'], credentials: @credentials).returns(true) + it "should not try to merge when there is no update in remote branch" do + repo.expects(:fetch).with('origin', ['refs/heads/master'], credentials: credentials).returns(Hash.new(0)) + repo.expects(:branches).never + repo.expects(:head).returns(repo_head) + gr.fetch_and_merge_remote(repo).must_equal nil + end + describe "when there is update considering conflicts" do + let(:merge_index) { mock() } + let(:their_branch) { mock() } - repo_head = mock() - repo_head.expects(:name).twice.returns('refs/heads/master') + before(:each) do + repo.expects(:fetch).with('origin', ['refs/heads/master'], credentials: credentials).returns({total_deltas: 1}) + their_branch.expects(:target_id).returns(1) + repo_head.expects(:target_id).returns(2) + repo.expects(:merge_commits).with(2, 1).returns(merge_index) + repo.expects(:branches).returns({"origin/master" => their_branch}) + end - repo = mock() - repo.expects(:path).returns('foo.git') - repo.expects(:remotes).returns({'origin' => remote}) - repo.expects(:head).twice.returns(repo_head) - repo.expects(:fetch).with('origin', ['refs/heads/master'], credentials: @credentials).returns(true) - repo.expects(:branches).returns({}) + it "should not try merging when there's conflict" do + repo.expects(:head).twice.returns(repo_head) + their_branch.expects(:name).returns("origin/master") + merge_index.expects(:conflicts?).returns(true) + Rugged::Commit.expects(:create).never + gr.fetch_and_merge_remote(repo).must_equal nil + end - Rugged::Repository.expects(:new).with('foo.git').returns(repo) + it "should merge when there is no conflict" do + repo.expects(:head).times(3).returns(repo_head) + their_branch.expects(:target).returns("their_target") + their_branch.expects(:name).twice.returns("origin/master") + repo_head.expects(:target).returns("our_target") + merge_index.expects(:write_tree).with(repo).returns("tree") + merge_index.expects(:conflicts?).returns(false) + Rugged::Commit.expects(:create).with(repo, { + parents: ["our_target", "their_target"], + tree: "tree", + message: "Merge remote-tracking branch 'origin/master'", + update_ref: "HEAD" + }).returns(1) + gr.fetch_and_merge_remote(repo).must_equal 1 + end + end end describe "#run_hook" do + before(:each) do + remote.expects(:url).returns('https://github.com/username/foo.git') + remote.expects(:push).with(['refs/heads/master'], credentials: credentials).returns(true) + repo_head.expects(:name).twice.returns('refs/heads/master') + repo.expects(:head).twice.returns(repo_head) + repo.expects(:path).returns('foo.git') + repo.expects(:remotes).returns({'origin' => remote}) + repo.expects(:fetch).with('origin', ['refs/heads/master'], credentials: credentials).returns(Hash.new(0)) + Rugged::Repository.expects(:new).with('foo.git').returns(repo) + end + it "will push to the remote repository using https" do Oxidized.config.hooks.github_repo_hook.remote_repo = 'https://github.com/username/foo.git' Oxidized.config.hooks.github_repo_hook.username = 'username' Oxidized.config.hooks.github_repo_hook.password = 'password' - - Rugged::Credentials::UserPassword.expects(:new).with(username: 'username', password: 'password').returns(@credentials) - - gr = GithubRepo.new + Rugged::Credentials::UserPassword.expects(:new).with(username: 'username', password: 'password').returns(credentials) gr.cfg = Oxidized.config.hooks.github_repo_hook - gr.run_hook(nil).must_equal true end it "will push to the remote repository using ssh" do Oxidized.config.hooks.github_repo_hook.remote_repo = 'git@github.com:username/foo.git' - - Rugged::Credentials::SshKeyFromAgent.expects(:new).with(username: 'git').returns(@credentials) - - gr = GithubRepo.new + Rugged::Credentials::SshKeyFromAgent.expects(:new).with(username: 'git').returns(credentials) gr.cfg = Oxidized.config.hooks.github_repo_hook - gr.run_hook(nil).must_equal true end end -- cgit v1.2.3