From 11b0b34eb7626c3486df45ed3dccbdb0a2c34771 Mon Sep 17 00:00:00 2001 From: David Litvak Bruno Date: Fri, 14 Apr 2017 13:14:17 -0300 Subject: [PATCH] Add Individual Files per Entries Option --- README.md | 44 +++++++--- ...data_exporter.rb => base_data_exporter.rb} | 45 +++++----- lib/jekyll-contentful-data-import/importer.rb | 33 ++++++- .../multi_file_data_exporter.rb | 35 ++++++++ .../single_file_data_exporter.rb | 27 ++++++ spec/jekyll-contentful/importer_spec.rb | 24 +++++- .../multi_file_data_exporter_spec.rb | 85 +++++++++++++++++++ ...c.rb => single_file_data_exporter_spec.rb} | 6 +- 8 files changed, 256 insertions(+), 43 deletions(-) rename lib/jekyll-contentful-data-import/{data_exporter.rb => base_data_exporter.rb} (51%) create mode 100644 lib/jekyll-contentful-data-import/multi_file_data_exporter.rb create mode 100644 lib/jekyll-contentful-data-import/single_file_data_exporter.rb create mode 100644 spec/jekyll-contentful/multi_file_data_exporter_spec.rb rename spec/jekyll-contentful/{data_exporter_spec.rb => single_file_data_exporter_spec.rb} (95%) diff --git a/README.md b/README.md index ce0afa3..43db641 100644 --- a/README.md +++ b/README.md @@ -55,19 +55,21 @@ contentful: api_url: 'preview.contentful.com' # Defaults to 'api.contentful.com' which is Production base_path: app_path # Optional - Defaults to Current directory destination: destination_in_data # Optional - Defaults to _data/contentful/spaces + individual_entry_files: true # Optional - Defaults to false ``` -Parameter | Description ----------- | ------------ -space | Contentful Space ID -access_token | Contentful Delivery API access token -cda_query | Hash describing query configuration. See [contentful.rb](https://github.com/contentful/contentful.rb) for more info (look for filter options there). Note that by default only 100 entries will be fetched, this can be configured to up to 1000 entries using the `limit` option. -all_entries | Boolean, if true will run multiple queries to the API until it fetches all entries for the space -all_entries_page_size | Integer, the amount of maximum entries per CDA Request when fetching :all_entries -content_types | Hash describing the mapping applied to entries of the imported content types -client_options | Hash describing Contentful::Client configuration. See [contentful.rb](https://github.com/contentful/contentful.rb) for more info. -base_path | String with path to your Jekyll Application, defaults to current directory. Path is relative to your current location. -destination | String with path within `_data` under which to store the output yaml file. Defaults to contentful/spaces +Parameter | Description +---------- | ------------ +space | Contentful Space ID +access_token | Contentful Delivery API access token +cda_query | Hash describing query configuration. See [contentful.rb](https://github.com/contentful/contentful.rb) for more info (look for filter options there). Note that by default only 100 entries will be fetched, this can be configured to up to 1000 entries using the `limit` option. +all_entries | Boolean, if true will run multiple queries to the API until it fetches all entries for the space +all_entries_page_size | Integer, the amount of maximum entries per CDA Request when fetching :all_entries +content_types | Hash describing the mapping applied to entries of the imported content types +client_options | Hash describing Contentful::Client configuration. See [contentful.rb](https://github.com/contentful/contentful.rb) for more info. +base_path | String with path to your Jekyll Application, defaults to current directory. Path is relative to your current location. +destination | String with path within `_data` under which to store the output yaml file. Defaults to contentful/spaces +individual_entry_files | Boolean, if true will create an individual file per entry separated in folders by content type, file path will be `{space_alias}/{content_type_id}/{entry_id}.yaml`. Default behavior is to create a file per space. Usage is affected when this is set to true, please look in the section below. You can add multiple spaces to your configuration @@ -157,6 +159,26 @@ therefore you can do the following: This way, it is safe to share your code without having to worry about your credentials. +### Using Multiple Entry Files + +When setting the `individual_entry_files` flag to true, the usage pattern changes a little, +as Jekyll does not allow for variable unpacking when iterating. + +A usage example is as follows: + +```html + +``` + ## Examples You can find working examples of multiple uses [here](https://github.com/contentful/contentful_jekyll_examples). diff --git a/lib/jekyll-contentful-data-import/data_exporter.rb b/lib/jekyll-contentful-data-import/base_data_exporter.rb similarity index 51% rename from lib/jekyll-contentful-data-import/data_exporter.rb rename to lib/jekyll-contentful-data-import/base_data_exporter.rb index a48d239..080f99c 100644 --- a/lib/jekyll-contentful-data-import/data_exporter.rb +++ b/lib/jekyll-contentful-data-import/base_data_exporter.rb @@ -2,14 +2,10 @@ module Jekyll module Contentful - # Data Exporter Class + # Base Data Exporter Class # - # Serializes Contentful data into YAML files - class DataExporter - DATA_FOLDER = '_data'.freeze - CONTENTFUL_FOLDER = 'contentful'.freeze - SPACES_FOLDER = 'spaces'.freeze - + # Generic Data Exporter Implementation + class BaseDataExporter attr_reader :name, :entries, :config def initialize(name, entries, config = {}) @@ -19,16 +15,7 @@ def initialize(name, entries, config = {}) end def run - setup_directory - - File.open(destination_file, 'w') do |file| - file.write( - ::Jekyll::Contentful::Serializer.new( - entries, - config - ).to_yaml - ) - end + raise 'must implement' end def base_directory @@ -45,24 +32,34 @@ def base_directory def destination_directory destination_dir = File.join( - base_directory, DATA_FOLDER, - CONTENTFUL_FOLDER, SPACES_FOLDER + base_directory, data_folder, + contentful_folder, spaces_folder ) if config.key?('destination') destination_dir = File.join( - base_directory, DATA_FOLDER, config['destination'] + base_directory, data_folder, config['destination'] ) end destination_dir end - def destination_file - File.join(destination_directory, "#{name}.yaml") + def setup_directory(directory) + FileUtils.mkdir_p(directory) + end + + protected + + def data_folder + '_data' + end + + def contentful_folder + 'contentful' end - def setup_directory - FileUtils.mkdir_p destination_directory + def spaces_folder + 'spaces' end end end diff --git a/lib/jekyll-contentful-data-import/importer.rb b/lib/jekyll-contentful-data-import/importer.rb index df24920..3f66388 100644 --- a/lib/jekyll-contentful-data-import/importer.rb +++ b/lib/jekyll-contentful-data-import/importer.rb @@ -1,5 +1,6 @@ require 'contentful' -require 'jekyll-contentful-data-import/data_exporter' +require 'jekyll-contentful-data-import/single_file_data_exporter' +require 'jekyll-contentful-data-import/multi_file_data_exporter' module Jekyll module Contentful @@ -26,9 +27,35 @@ def run end def export_data(name, space_client, options) - Jekyll::Contentful::DataExporter.new( + entries = get_entries(space_client, options) + + if options.fetch('individual_entry_files', false) + export_data_multiple_files( + name, + entries, + options + ) + else + export_data_single_file( + name, + entries, + options + ) + end + end + + def export_data_single_file(name, entries, options) + Jekyll::Contentful::SingleFileDataExporter.new( + name, + entries, + options + ).run + end + + def export_data_multiple_files(name, entries, options) + Jekyll::Contentful::MultiFileDataExporter.new( name, - get_entries(space_client, options), + entries, options ).run end diff --git a/lib/jekyll-contentful-data-import/multi_file_data_exporter.rb b/lib/jekyll-contentful-data-import/multi_file_data_exporter.rb new file mode 100644 index 0000000..1734706 --- /dev/null +++ b/lib/jekyll-contentful-data-import/multi_file_data_exporter.rb @@ -0,0 +1,35 @@ +require 'jekyll-contentful-data-import/base_data_exporter' +require 'yaml' + +module Jekyll + module Contentful + # Single File Data Exporter Class + # + # Serializes Contentful data into a multiple YAML files + class MultiFileDataExporter < BaseDataExporter + def run + data = ::Jekyll::Contentful::Serializer.new( + entries, + config + ).serialize + + data.each do |content_type, entries| + content_type_directory = File.join(destination_directory, name, content_type.to_s) + setup_directory(content_type_directory) + + entries.each do |entry| + yaml_entry = YAML.dump(entry) + + File.open(destination_file(content_type_directory, entry), 'w') do |file| + file.write(yaml_entry) + end + end + end + end + + def destination_file(content_type_directory, entry) + File.join(content_type_directory, "#{entry['sys']['id']}.yaml") + end + end + end +end diff --git a/lib/jekyll-contentful-data-import/single_file_data_exporter.rb b/lib/jekyll-contentful-data-import/single_file_data_exporter.rb new file mode 100644 index 0000000..78a28b3 --- /dev/null +++ b/lib/jekyll-contentful-data-import/single_file_data_exporter.rb @@ -0,0 +1,27 @@ +require 'jekyll-contentful-data-import/base_data_exporter' + +module Jekyll + module Contentful + # Single File Data Exporter Class + # + # Serializes Contentful data into a single YAML file + class SingleFileDataExporter < BaseDataExporter + def run + setup_directory(destination_directory) + + File.open(destination_file, 'w') do |file| + file.write( + ::Jekyll::Contentful::Serializer.new( + entries, + config + ).to_yaml + ) + end + end + + def destination_file + File.join(destination_directory, "#{name}.yaml") + end + end + end +end diff --git a/spec/jekyll-contentful/importer_spec.rb b/spec/jekyll-contentful/importer_spec.rb index 7842041..b0dd61c 100644 --- a/spec/jekyll-contentful/importer_spec.rb +++ b/spec/jekyll-contentful/importer_spec.rb @@ -70,7 +70,7 @@ def run; end allow(subject).to receive(:spaces).and_return([['foo', {'space' => 'foo', 'access_token' => 'bar'}], ['bar', {'space' => 'bar', 'access_token' => 'foo'}]]) allow(subject).to receive(:client).and_return(ClientDouble.new) - expect(Jekyll::Contentful::DataExporter).to receive(:new).and_return(ExporterDouble.new).twice + expect(Jekyll::Contentful::SingleFileDataExporter).to receive(:new).and_return(ExporterDouble.new).twice subject.run end @@ -78,7 +78,27 @@ def run; end it 'runs exporter with correct arguments' do allow(subject).to receive(:client).and_return(ClientDouble.new) - expect(Jekyll::Contentful::DataExporter).to receive(:new).with('example', [], config['spaces'].first['example']).and_return(ExporterDouble.new) + expect(Jekyll::Contentful::SingleFileDataExporter).to receive(:new).with('example', [], config['spaces'].first['example']).and_return(ExporterDouble.new) + + subject.run + end + + it 'runs multifile exporter when passed :individual_entry_files flag' do + config = { + 'spaces' => [ + { + 'example' => { + 'space' => 'cfexampleapi', + 'access_token' => 'b4c0n73n7fu1', + 'individual_entry_files' => true + } + } + ] + } + subject = described_class.new(config) + allow(subject).to receive(:client).and_return(ClientDouble.new) + + expect(Jekyll::Contentful::MultiFileDataExporter).to receive(:new).with('example', [], config['spaces'].first['example']).and_return(ExporterDouble.new) subject.run end diff --git a/spec/jekyll-contentful/multi_file_data_exporter_spec.rb b/spec/jekyll-contentful/multi_file_data_exporter_spec.rb new file mode 100644 index 0000000..e299854 --- /dev/null +++ b/spec/jekyll-contentful/multi_file_data_exporter_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' +require 'stringio' + +describe Jekyll::Contentful::MultiFileDataExporter do + subject { described_class.new('foo', []) } + + describe 'instance methods' do + describe '#base_directory' do + it 'default directory' do + expect(subject.base_directory).to eq(Dir.pwd) + end + + it 'overriden directory' do + subject = described_class.new('foo', [], {'base_path' => 'foo_dir'}) + + expect(subject.base_directory).to eq(File.join(Dir.pwd, 'foo_dir')) + end + end + + describe '#destination_directory' do + it 'default directory' do + expected = File.join(Dir.pwd, '_data', 'contentful', 'spaces') + expect(subject.destination_directory).to eq(expected) + end + + it 'overridden directory' do + subject = described_class.new('foo', [], {'base_path' => 'foo_dir'}) + + expected = File.join(Dir.pwd, 'foo_dir', '_data', 'contentful', 'spaces') + expect(subject.destination_directory).to eq(expected) + end + end + + it '#destination_file' do + entry_double = { 'sys' => { 'id' => 'bar' } } + expected = File.join('foo', 'bar.yaml') + expect(subject.destination_file('foo', entry_double)).to eq(expected) + end + + describe '#setup_directory' do + it 'default directory' do + expected = File.join(Dir.pwd, '_data', 'contentful', 'spaces') + expect(FileUtils).to receive(:mkdir_p).with(expected) + + subject.setup_directory(expected) + end + + it 'overridden directory' do + subject = described_class.new('foo', [], {'base_path' => 'foo_dir'}) + + expected = File.join(Dir.pwd, 'foo_dir', '_data', 'contentful', 'spaces') + expect(FileUtils).to receive(:mkdir_p).with(expected) + + subject.setup_directory(expected) + end + end + + describe '#run' do + before do + allow(subject).to receive(:setup_directory) + end + + it 'does nothing with no entries' do + subject.run + end + + it 'serializes entries' do + expect_any_instance_of(::Jekyll::Contentful::Serializer).to receive(:serialize) { {} } + + subject.run + end + + it 'creates a file per entry' do + subject = described_class.new('foo', [EntryDouble.new('bar', ContentTypeDouble.new('bar_ct'))]) + + expected_directory_path = File.join(Dir.pwd, '_data', 'contentful', 'spaces', 'foo', 'bar_ct') + expect(FileUtils).to receive(:mkdir_p).with(expected_directory_path) + expect(File).to receive(:open).with(File.join(expected_directory_path, 'bar.yaml'), 'w') + + subject.run + end + end + end +end + diff --git a/spec/jekyll-contentful/data_exporter_spec.rb b/spec/jekyll-contentful/single_file_data_exporter_spec.rb similarity index 95% rename from spec/jekyll-contentful/data_exporter_spec.rb rename to spec/jekyll-contentful/single_file_data_exporter_spec.rb index 0d57261..2c2c9d2 100644 --- a/spec/jekyll-contentful/data_exporter_spec.rb +++ b/spec/jekyll-contentful/single_file_data_exporter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'stringio' -describe Jekyll::Contentful::DataExporter do +describe Jekyll::Contentful::SingleFileDataExporter do subject { described_class.new('foo', []) } describe 'instance methods' do @@ -57,7 +57,7 @@ expected = File.join(Dir.pwd, '_data', 'contentful', 'spaces') expect(FileUtils).to receive(:mkdir_p).with(expected) - subject.setup_directory + subject.setup_directory(expected) end it 'overridden directory' do @@ -66,7 +66,7 @@ expected = File.join(Dir.pwd, 'foo_dir', '_data', 'contentful', 'spaces') expect(FileUtils).to receive(:mkdir_p).with(expected) - subject.setup_directory + subject.setup_directory(expected) end end