From 6d027f267769398654a92e9b63adc3fd271db914 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 15 Sep 2020 15:24:27 +0200 Subject: hooks: Extract function to call hooks accepting stdin As there are multiple hooks in Git which accept both arguments and input from stdin, it makes sense to refactor calling such hooks into its own function. So this commit pulls out most of the implementation of the receive hooks and makes it generic to make it reusable for other hooks. --- ruby/lib/gitlab/git/hook.rb | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'ruby') diff --git a/ruby/lib/gitlab/git/hook.rb b/ruby/lib/gitlab/git/hook.rb index c391bbf78..dd3875d2f 100644 --- a/ruby/lib/gitlab/git/hook.rb +++ b/ruby/lib/gitlab/git/hook.rb @@ -43,30 +43,22 @@ module Gitlab private - def call_receive_hook(gl_id, gl_username, oldrev, newrev, ref, push_options, transaction) - changes = [oldrev, newrev, ref].join(" ") - + def call_stdin_hook(args, input, env) exit_status = false exit_message = nil - vars = env_base_vars(gl_id, gl_username) - vars.merge!(push_options.env_data) if push_options - vars.merge!(transaction.env_vars) if transaction - options = { chdir: repo_path } - Open3.popen3(vars, path, options) do |stdin, stdout, stderr, wait_thr| + Open3.popen3(env, path, *args, options) do |stdin, stdout, stderr, wait_thr| exit_status = true stdin.sync = true - # in git, pre- and post- receive hooks may just exit without - # reading stdin. We catch the exception to avoid a broken pipe - # warning + # in git, hooks may just exit without reading stdin. We catch the + # exception to avoid a broken pipe warning begin - # inject all the changes as stdin to the hook - changes.lines do |line| + input.lines do |line| stdin.puts line end rescue Errno::EPIPE @@ -83,6 +75,16 @@ module Gitlab [exit_status, exit_message] end + def call_receive_hook(gl_id, gl_username, oldrev, newrev, ref, push_options, transaction) + changes = [oldrev, newrev, ref].join(" ") + + vars = env_base_vars(gl_id, gl_username) + vars.merge!(push_options.env_data) if push_options + vars.merge!(transaction.env_vars) if transaction + + call_stdin_hook([], changes, vars) + end + def call_update_hook(gl_id, gl_username, oldrev, newrev, ref) options = { chdir: repo_path -- cgit v1.2.3 From b81ed87e4e8330295d0e12cd70a04e96c41e6992 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 15 Sep 2020 15:44:35 +0200 Subject: hooks: Implement calling the reference-transaction hook To enable the transition from voting on reference transaction via the pre-receive hook towards the reference-transaction hook, we'll have to start calling the latter from our Ruby sidecar. This commit thus implements the logic to invoke the reference transaction hook, but doesn't yet wire up this new hook implementation. --- ruby/lib/gitlab/git/hook.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'ruby') diff --git a/ruby/lib/gitlab/git/hook.rb b/ruby/lib/gitlab/git/hook.rb index dd3875d2f..8a514da2c 100644 --- a/ruby/lib/gitlab/git/hook.rb +++ b/ruby/lib/gitlab/git/hook.rb @@ -35,6 +35,8 @@ module Gitlab case name when "pre-receive", "post-receive" call_receive_hook(gl_id, gl_username, oldrev, newrev, ref, push_options, transaction) + when "reference-transaction" + call_reference_transaction_hook(gl_id, gl_username, oldrev, newrev, ref, transaction) when "update" call_update_hook(gl_id, gl_username, oldrev, newrev, ref) end @@ -85,6 +87,15 @@ module Gitlab call_stdin_hook([], changes, vars) end + def call_reference_transaction_hook(gl_id, gl_username, oldrev, newrev, ref, transaction) + changes = [oldrev, newrev, ref].join(" ") + + vars = env_base_vars(gl_id, gl_username) + vars.merge!(transaction.env_vars) if transaction + + call_stdin_hook(["prepared"], changes, vars) + end + def call_update_hook(gl_id, gl_username, oldrev, newrev, ref) options = { chdir: repo_path -- cgit v1.2.3 From b44de3009cd851681a21565a37d4072474aaf2cd Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Wed, 16 Sep 2020 08:20:39 +0200 Subject: hooks: Call reference-transaction hook from Ruby HooksService When modifying Git references, we want to perform voting on the change that's about to be made to enable strong consistency. While we're currently emulating this behaviour mostly via the pre-receive hook, eventually we'll want to fully migrate to the new reference-transaction hook. This buys us more granularity, allows us to capture reference updates across all commands and also allows us to abort any update. To reach this goal, there's two steps we need to do: first we need to always invoke Git with appropriate environment variables to make our reference-transaction hook implementation aware of the ongoing transaction. And second we'll need to adjust places where we manually call out to Git hooks. This commit addresses the second part for our Ruby sidecar, invoking the reference-transaction hook in the hooks service. As the hook implementation is currently hidden behind a feature flag, this commit also sets up a separate feature flag for Ruby. If set, it knows to set up the correct environment variables required by our hook implementation to execute the actual logic. --- ruby/lib/gitlab/git/hook.rb | 3 ++- ruby/lib/gitlab/git/hooks_service.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'ruby') diff --git a/ruby/lib/gitlab/git/hook.rb b/ruby/lib/gitlab/git/hook.rb index 8a514da2c..4a6ee936f 100644 --- a/ruby/lib/gitlab/git/hook.rb +++ b/ruby/lib/gitlab/git/hook.rb @@ -133,7 +133,8 @@ module Gitlab 'GIT_DIR' => repo_path, 'GITALY_REPO' => repository.gitaly_repository.to_json, 'GITALY_SOCKET' => Gitlab.config.gitaly.internal_socket, - 'GITALY_GO_POSTRECEIVE' => repository.feature_enabled?('go-postreceive-hook').to_s + 'GITALY_GO_POSTRECEIVE' => repository.feature_enabled?('go-postreceive-hook').to_s, + 'GITALY_REFERENCE_TRANSACTION_HOOK' => repository.feature_enabled?('reference-transaction-hook').to_s } end end diff --git a/ruby/lib/gitlab/git/hooks_service.rb b/ruby/lib/gitlab/git/hooks_service.rb index 5ad8e43b7..67ac4c3fb 100644 --- a/ruby/lib/gitlab/git/hooks_service.rb +++ b/ruby/lib/gitlab/git/hooks_service.rb @@ -13,7 +13,7 @@ module Gitlab @push_options = push_options @transaction = transaction - %w[pre-receive update].each do |hook_name| + %w[pre-receive update reference-transaction].each do |hook_name| status, message = run_hook(hook_name) raise PreReceiveError, message unless status -- cgit v1.2.3