From 645dceb0a233fc523ac16611fa3fec317d29a7e1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 23 Feb 2018 15:58:57 +0200 Subject: Run plugins as separate process and pass data via STDIN Signed-off-by: Dmitriy Zaporozhets --- .gitignore | 2 +- config/application.rb | 1 - generator_templates/plugins/template.rb | 16 ---------------- lib/gitlab/plugin.rb | 28 ++++++++++++++++++++-------- lib/tasks/plugins.rake | 24 ------------------------ plugins/.gitkeep | 0 plugins/available/save_to_file.clj | 3 +++ plugins/available/save_to_file.rb | 3 +++ plugins/enabled/.gitkeep | 0 9 files changed, 27 insertions(+), 50 deletions(-) delete mode 100644 generator_templates/plugins/template.rb delete mode 100644 plugins/.gitkeep create mode 100755 plugins/available/save_to_file.clj create mode 100755 plugins/available/save_to_file.rb create mode 100644 plugins/enabled/.gitkeep diff --git a/.gitignore b/.gitignore index fa39ae01ff0..35ca92b1a93 100644 --- a/.gitignore +++ b/.gitignore @@ -66,4 +66,4 @@ eslint-report.html /locale/**/LC_MESSAGES /locale/**/*.time_stamp /.rspec -/plugins/* +/plugins/enabled/* diff --git a/config/application.rb b/config/application.rb index f2fc6270748..918bd4d57cf 100644 --- a/config/application.rb +++ b/config/application.rb @@ -28,7 +28,6 @@ module Gitlab config.eager_load_paths.push(*%W[#{config.root}/lib #{config.root}/app/models/hooks #{config.root}/app/models/members - #{config.root}/plugins #{config.root}/app/models/project_services #{config.root}/app/workers/concerns #{config.root}/app/services/concerns diff --git a/generator_templates/plugins/template.rb b/generator_templates/plugins/template.rb deleted file mode 100644 index 16c87f2c2b2..00000000000 --- a/generator_templates/plugins/template.rb +++ /dev/null @@ -1,16 +0,0 @@ -# Requirements -# * File name must end with _s.rb. For example, jenkins_plugin.rb. -# * All code should be inside class. No code should be executed on file load. -# * Class name must be same as file name. -# If file name is jenkins_plugin.rb then class name must be JenkinsPlugin. -# -# Reccomendations -# * Code should not depend on or use GitLab classes and other code. -# * Consider contributing your plugin to GitLab source code so we can test it -# and make sure it will work in further version. -# -class $NAMEPlugin - def execute(data) - # TODO: Implement me - end -end diff --git a/lib/gitlab/plugin.rb b/lib/gitlab/plugin.rb index 9604cac4b20..1035d258907 100644 --- a/lib/gitlab/plugin.rb +++ b/lib/gitlab/plugin.rb @@ -1,23 +1,35 @@ module Gitlab module Plugin def self.files - Dir.glob(Rails.root.join('plugins', '*_plugin.rb')) + Dir.glob(Rails.root.join('plugins/enabled/*')) end def self.execute_all_async(data) files.each do |file| + puts file PluginWorker.perform_async(file, data) end end def self.execute(file, data) - # TODO: Implement - # - # Reuse some code from gitlab-shell https://gitlab.com/gitlab-org/gitlab-shell/blob/master/lib/gitlab_custom_hook.rb#L40 - # Pass data as STDIN (or JSON encode?) - # - # 1. Return true if 0 exit code - # 2. Return false if non-zero exit code + # Prepare the hook subprocess. Attach a pipe to its stdin, and merge + # both its stdout and stderr into our own stdout. + stdin_reader, stdin_writer = IO.pipe + hook_pid = spawn({}, file, in: stdin_reader, err: :out) + stdin_reader.close + + # Submit changes to the hook via its stdin. + begin + IO.copy_stream(StringIO.new(data.to_json), stdin_writer) + rescue Errno::EPIPE + # It is not an error if the hook does not consume all of its input. + end + + # Close the pipe to let the hook know there is no further input. + stdin_writer.close + + Process.wait(hook_pid) + $?.success? end end end diff --git a/lib/tasks/plugins.rake b/lib/tasks/plugins.rake index 9c9f1fece85..f4d7edb2eb2 100644 --- a/lib/tasks/plugins.rake +++ b/lib/tasks/plugins.rake @@ -1,28 +1,4 @@ namespace :plugins do - desc 'Generate skeleton for new plugin' - task generate: :environment do - ARGV.each { |a| task a.to_sym { } } - name = ARGV[1] - - unless name.present? - puts 'Error. You need to specify a name for the plugin' - exit 1 - end - - class_name = name.classify - param = name.underscore - file_path = Rails.root.join('plugins', param + '_plugin.rb') - template = File.read(Rails.root.join('generator_templates', 'plugins', 'template.rb')) - template.gsub!('$NAME', class_name) - - if File.write(file_path, template) - puts "Done. Your plugin saved under #{file_path}." - puts 'Feel free to edit it.' - else - puts "Failed to save #{file_path}." - end - end - desc 'Validate existing plugins' task validate: :environment do puts 'Validating plugins from /plugins directory' diff --git a/plugins/.gitkeep b/plugins/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/plugins/available/save_to_file.clj b/plugins/available/save_to_file.clj new file mode 100755 index 00000000000..a59d83749d3 --- /dev/null +++ b/plugins/available/save_to_file.clj @@ -0,0 +1,3 @@ +#!/usr/bin/env clojure +(let [in (slurp *in*)] + (spit "/tmp/clj-data.txt" in)) diff --git a/plugins/available/save_to_file.rb b/plugins/available/save_to_file.rb new file mode 100755 index 00000000000..61b0df9bfd6 --- /dev/null +++ b/plugins/available/save_to_file.rb @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +x = STDIN.read +File.write('/tmp/rb-data.txt', x) diff --git a/plugins/enabled/.gitkeep b/plugins/enabled/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d -- cgit v1.2.1