From bd5c749f2911e9d843a5bfe7487fdc1566c5dfa6 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 13 Jun 2016 18:24:21 +0200 Subject: fix file.write --- lib/gitlab/import_export/version_saver.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/gitlab/import_export/version_saver.rb b/lib/gitlab/import_export/version_saver.rb index 4706f929476..fe28b618c76 100644 --- a/lib/gitlab/import_export/version_saver.rb +++ b/lib/gitlab/import_export/version_saver.rb @@ -9,9 +9,7 @@ module Gitlab def save FileUtils.mkdir_p(@shared.export_path) - File.open(version_file, 'w') do |file| - file.write(Gitlab::ImportExport.version) - end + File.write(version_file, Gitlab::ImportExport.version, mode: 'w') rescue => e @shared.error(e.message) false -- cgit v1.2.1 From 4020b0f55fa7df3a410a11debfd155527b1a79ee Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 13 Jun 2016 21:18:26 +0200 Subject: few changes based on MR feedback --- lib/gitlab/import_export/import_export_reader.rb | 115 --------------------- lib/gitlab/import_export/project_tree_saver.rb | 2 +- lib/gitlab/import_export/reader.rb | 115 +++++++++++++++++++++ .../import_export/import_export_reader_spec.rb | 26 ----- spec/lib/gitlab/import_export/reader_spec.rb | 26 +++++ 5 files changed, 142 insertions(+), 142 deletions(-) delete mode 100644 lib/gitlab/import_export/import_export_reader.rb create mode 100644 lib/gitlab/import_export/reader.rb delete mode 100644 spec/lib/gitlab/import_export/import_export_reader_spec.rb create mode 100644 spec/lib/gitlab/import_export/reader_spec.rb diff --git a/lib/gitlab/import_export/import_export_reader.rb b/lib/gitlab/import_export/import_export_reader.rb deleted file mode 100644 index 5ed4885a066..00000000000 --- a/lib/gitlab/import_export/import_export_reader.rb +++ /dev/null @@ -1,115 +0,0 @@ -module Gitlab - module ImportExport - class ImportExportReader - - def initialize(shared:) - @shared = shared - config_hash = YAML.load_file(Gitlab::ImportExport.config_file).deep_symbolize_keys - @tree = config_hash[:project_tree] - @attributes_finder = Gitlab::ImportExport::AttributesFinder.new(included_attributes: config_hash[:included_attributes], - excluded_attributes: config_hash[:excluded_attributes], - methods: config_hash[:methods]) - end - - # Outputs a hash in the format described here: http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html - # for outputting a project in JSON format, including its relations and sub relations. - def project_tree - @attributes_finder.find_included(:project).merge(include: build_hash(@tree)) - rescue => e - @shared.error(e.message) - false - end - - private - - # Builds a hash in the format described here: http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html - # - # +model_list+ - List of models as a relation tree to be included in the generated JSON, from the _import_export.yml_ file - def build_hash(model_list) - model_list.map do |model_objects| - if model_objects.is_a?(Hash) - build_json_config_hash(model_objects) - else - @attributes_finder.find(model_objects) - end - end - end - - # Called when the model is actually a hash containing other relations (more models) - # Returns the config in the right format for calling +to_json+ - # +model_object_hash+ - A model relationship such as: - # {:merge_requests=>[:merge_request_diff, :notes]} - def build_json_config_hash(model_object_hash) - @json_config_hash = {} - - model_object_hash.values.flatten.each do |model_object| - current_key = model_object_hash.keys.first - - @attributes_finder.parse(current_key) { |hash| @json_config_hash[current_key] ||= hash } - - handle_model_object(current_key, model_object) - process_sub_model(current_key, model_object) if model_object.is_a?(Hash) - end - @json_config_hash - end - - - # If the model is a hash, process the sub_models, which could also be hashes - # If there is a list, add to an existing array, otherwise use hash syntax - # +current_key+ main model that will be a key in the hash - # +model_object+ model or list of models to include in the hash - def process_sub_model(current_key, model_object) - sub_model_json = build_json_config_hash(model_object).dup - @json_config_hash.slice!(current_key) - - if @json_config_hash[current_key] && @json_config_hash[current_key][:include] - @json_config_hash[current_key][:include] << sub_model_json - else - @json_config_hash[current_key] = { include: sub_model_json } - end - end - - # Creates or adds to an existing hash an individual model or list - # +current_key+ main model that will be a key in the hash - # +model_object+ model or list of models to include in the hash - def handle_model_object(current_key, model_object) - if @json_config_hash[current_key] - add_model_value(current_key, model_object) - else - create_model_value(current_key, model_object) - end - end - - # Constructs a new hash that will hold the configuration for that particular object - # It may include exceptions or other attribute detail configuration, parsed by +@attributes_finder+ - # +current_key+ main model that will be a key in the hash - # +value+ existing model to be included in the hash - def create_model_value(current_key, value) - parsed_hash = { include: value } - - @attributes_finder.parse(value) do |hash| - parsed_hash = { include: hash_or_merge(value, hash) } - end - @json_config_hash[current_key] = parsed_hash - end - - # Adds new model configuration to an existing hash with key +current_key+ - # It may include exceptions or other attribute detail configuration, parsed by +@attributes_finder+ - # +current_key+ main model that will be a key in the hash - # +value+ existing model to be included in the hash - def add_model_value(current_key, value) - @attributes_finder.parse(value) { |hash| value = { value => hash } } - old_values = @json_config_hash[current_key][:include] - @json_config_hash[current_key][:include] = ([old_values] + [value]).compact.flatten - end - - # Construct a new hash or merge with an existing one a model configuration - # This is to fulfil +to_json+ requirements. - # +value+ existing model to be included in the hash - # +hash+ hash containing configuration generated mainly from +@attributes_finder+ - def hash_or_merge(value, hash) - value.is_a?(Hash) ? value.merge(hash) : { value => hash } - end - end - end -end diff --git a/lib/gitlab/import_export/project_tree_saver.rb b/lib/gitlab/import_export/project_tree_saver.rb index a2c5df8af25..de1da2158ab 100644 --- a/lib/gitlab/import_export/project_tree_saver.rb +++ b/lib/gitlab/import_export/project_tree_saver.rb @@ -22,7 +22,7 @@ module Gitlab private def project_json_tree - @project.to_json(Gitlab::ImportExport::ImportExportReader.new(shared: @shared).project_tree) + @project.to_json(Gitlab::ImportExport::Reader.new(shared: @shared).project_tree) end end end diff --git a/lib/gitlab/import_export/reader.rb b/lib/gitlab/import_export/reader.rb new file mode 100644 index 00000000000..3a329e255c3 --- /dev/null +++ b/lib/gitlab/import_export/reader.rb @@ -0,0 +1,115 @@ +module Gitlab + module ImportExport + class Reader + + def initialize(shared:) + @shared = shared + config_hash = YAML.load_file(Gitlab::ImportExport.config_file).deep_symbolize_keys + @tree = config_hash[:project_tree] + @attributes_finder = Gitlab::ImportExport::AttributesFinder.new(included_attributes: config_hash[:included_attributes], + excluded_attributes: config_hash[:excluded_attributes], + methods: config_hash[:methods]) + end + + # Outputs a hash in the format described here: http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html + # for outputting a project in JSON format, including its relations and sub relations. + def project_tree + @attributes_finder.find_included(:project).merge(include: build_hash(@tree)) + rescue => e + @shared.error(e.message) + false + end + + private + + # Builds a hash in the format described here: http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html + # + # +model_list+ - List of models as a relation tree to be included in the generated JSON, from the _import_export.yml_ file + def build_hash(model_list) + model_list.map do |model_objects| + if model_objects.is_a?(Hash) + build_json_config_hash(model_objects) + else + @attributes_finder.find(model_objects) + end + end + end + + # Called when the model is actually a hash containing other relations (more models) + # Returns the config in the right format for calling +to_json+ + # +model_object_hash+ - A model relationship such as: + # {:merge_requests=>[:merge_request_diff, :notes]} + def build_json_config_hash(model_object_hash) + @json_config_hash = {} + + model_object_hash.values.flatten.each do |model_object| + current_key = model_object_hash.keys.first + + @attributes_finder.parse(current_key) { |hash| @json_config_hash[current_key] ||= hash } + + handle_model_object(current_key, model_object) + process_sub_model(current_key, model_object) if model_object.is_a?(Hash) + end + @json_config_hash + end + + + # If the model is a hash, process the sub_models, which could also be hashes + # If there is a list, add to an existing array, otherwise use hash syntax + # +current_key+ main model that will be a key in the hash + # +model_object+ model or list of models to include in the hash + def process_sub_model(current_key, model_object) + sub_model_json = build_json_config_hash(model_object).dup + @json_config_hash.slice!(current_key) + + if @json_config_hash[current_key] && @json_config_hash[current_key][:include] + @json_config_hash[current_key][:include] << sub_model_json + else + @json_config_hash[current_key] = { include: sub_model_json } + end + end + + # Creates or adds to an existing hash an individual model or list + # +current_key+ main model that will be a key in the hash + # +model_object+ model or list of models to include in the hash + def handle_model_object(current_key, model_object) + if @json_config_hash[current_key] + add_model_value(current_key, model_object) + else + create_model_value(current_key, model_object) + end + end + + # Constructs a new hash that will hold the configuration for that particular object + # It may include exceptions or other attribute detail configuration, parsed by +@attributes_finder+ + # +current_key+ main model that will be a key in the hash + # +value+ existing model to be included in the hash + def create_model_value(current_key, value) + parsed_hash = { include: value } + + @attributes_finder.parse(value) do |hash| + parsed_hash = { include: hash_or_merge(value, hash) } + end + @json_config_hash[current_key] = parsed_hash + end + + # Adds new model configuration to an existing hash with key +current_key+ + # It may include exceptions or other attribute detail configuration, parsed by +@attributes_finder+ + # +current_key+ main model that will be a key in the hash + # +value+ existing model to be included in the hash + def add_model_value(current_key, value) + @attributes_finder.parse(value) { |hash| value = { value => hash } } + old_values = @json_config_hash[current_key][:include] + @json_config_hash[current_key][:include] = ([old_values] + [value]).compact.flatten + end + + # Construct a new hash or merge with an existing one a model configuration + # This is to fulfil +to_json+ requirements. + # +value+ existing model to be included in the hash + # +hash+ hash containing configuration generated mainly from +@attributes_finder+ + def hash_or_merge(value, hash) + value.is_a?(Hash) ? value.merge(hash) : { value => hash } + end + end + end +end diff --git a/spec/lib/gitlab/import_export/import_export_reader_spec.rb b/spec/lib/gitlab/import_export/import_export_reader_spec.rb deleted file mode 100644 index 19f9bdc8d3f..00000000000 --- a/spec/lib/gitlab/import_export/import_export_reader_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'spec_helper' - -describe Gitlab::ImportExport::ImportExportReader, lib: true do - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path:'') } - let(:test_config) { 'spec/support/import_export/import_export.yml' } - let(:project_tree_hash) do - { - only: [:name, :path], - include: [:issues, :labels, - { merge_requests: { - only: [:id], - except: [:iid], - include: [:merge_request_diff, :merge_request_test] - } }, - { commit_statuses: { include: :commit } }] - } - end - - before do - allow_any_instance_of(Gitlab::ImportExport).to receive(:config_file).and_return(test_config) - end - - it 'generates hash from project tree config' do - expect(described_class.new(shared: shared).project_tree).to match(project_tree_hash) - end -end diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb new file mode 100644 index 00000000000..f16b4f8e2bd --- /dev/null +++ b/spec/lib/gitlab/import_export/reader_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe Gitlab::ImportExport::Reader, lib: true do + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path:'') } + let(:test_config) { 'spec/support/import_export/import_export.yml' } + let(:project_tree_hash) do + { + only: [:name, :path], + include: [:issues, :labels, + { merge_requests: { + only: [:id], + except: [:iid], + include: [:merge_request_diff, :merge_request_test] + } }, + { commit_statuses: { include: :commit } }] + } + end + + before do + allow_any_instance_of(Gitlab::ImportExport).to receive(:config_file).and_return(test_config) + end + + it 'generates hash from project tree config' do + expect(described_class.new(shared: shared).project_tree).to match(project_tree_hash) + end +end -- cgit v1.2.1 From fde90c3e7fe97420e029c1e7c02227d3e8773c7f Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 14 Jun 2016 10:12:41 +0200 Subject: better coverage for Reader --- spec/lib/gitlab/import_export/reader_spec.rb | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb index f16b4f8e2bd..d7029c2efe6 100644 --- a/spec/lib/gitlab/import_export/reader_spec.rb +++ b/spec/lib/gitlab/import_export/reader_spec.rb @@ -23,4 +23,65 @@ describe Gitlab::ImportExport::Reader, lib: true do it 'generates hash from project tree config' do expect(described_class.new(shared: shared).project_tree).to match(project_tree_hash) end + + context 'individual scenarios' do + + it 'generates the correct hash for a single project relation' do + setup_yaml(project_tree: [:issues]) + + expect(described_class.new(shared: shared).project_tree).to match(include: [:issues]) + end + + it 'generates the correct hash for a multiple project relation' do + setup_yaml(project_tree: [:issues, :snippets]) + + expect(described_class.new(shared: shared).project_tree).to match(include: [:issues, :snippets]) + end + + it 'generates the correct hash for a single sub-relation' do + setup_yaml(project_tree: [issues: [:notes]]) + + expect(described_class.new(shared: shared).project_tree).to match(include: [{ issues: { include: :notes } }]) + end + + it 'generates the correct hash for a multiple sub-relation' do + setup_yaml(project_tree: [merge_requests: [:notes, :merge_request_diff]]) + + expect(described_class.new(shared: shared).project_tree).to match(include: [{ merge_requests: { include: [:notes, :merge_request_diff] } }]) + end + + it 'generates the correct hash for a sub-relation with another sub-relation' do + setup_yaml(project_tree: [merge_requests: [notes: :author]]) + + expect(described_class.new(shared: shared).project_tree).to match(include: [{ merge_requests: { include: { notes: { include: :author } } } }]) + end + + it 'generates the correct hash for a relation with included attributes' do + setup_yaml(project_tree: [:issues], included_attributes: {issues: [:name, :description]}) + + expect(described_class.new(shared: shared).project_tree).to match(include: [{ issues: { only: [:name, :description] } }]) + end + + it 'generates the correct hash for a relation with excluded attributes' do + setup_yaml(project_tree: [:issues], excluded_attributes: {issues: [:name]}) + + expect(described_class.new(shared: shared).project_tree).to match(include: [{ issues: { except: [:name] } }]) + end + + it 'generates the correct hash for a relation with both excluded and included attributes' do + setup_yaml(project_tree: [:issues], excluded_attributes: {issues: [:name]}, included_attributes: {issues: [:description]}) + + expect(described_class.new(shared: shared).project_tree).to match(include: [{ issues: { except: [:name], only: [:description]} }]) + end + + it 'generates the correct hash for a relation with custom methods' do + setup_yaml(project_tree: [:issues], methods: {issues: [:name]}) + + expect(described_class.new(shared: shared).project_tree).to match(include: [{ issues: { methods: [:name] } }]) + end + + def setup_yaml(hash) + allow(YAML).to receive(:load_file).with(test_config).and_return(hash) + end + end end -- cgit v1.2.1 From f6ed7c8ff8313826a08aace346f30facc55a202f Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 14 Jun 2016 10:15:20 +0200 Subject: missed line break --- lib/gitlab/import_export/repo_saver.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gitlab/import_export/repo_saver.rb b/lib/gitlab/import_export/repo_saver.rb index 14174873625..ab480e4413b 100644 --- a/lib/gitlab/import_export/repo_saver.rb +++ b/lib/gitlab/import_export/repo_saver.rb @@ -12,6 +12,7 @@ module Gitlab def save return false if @project.empty_repo? + @full_path = File.join(@shared.export_path, ImportExport.project_bundle_filename) bundle_to_disk end -- cgit v1.2.1