From 308ba550efeab34d786c43594d6cfb59744df184 Mon Sep 17 00:00:00 2001 From: Jonathan Hooper Date: Tue, 9 May 2017 19:17:36 -0500 Subject: [PATCH] Add option to fail a build with front matter syntax errors (#5832) Merge pull request 5832 --- docs/_docs/configuration.md | 25 ++++++++--- lib/jekyll/command.rb | 4 ++ lib/jekyll/configuration.rb | 79 +++++++++++++++++---------------- lib/jekyll/convertible.rb | 2 + lib/jekyll/document.rb | 18 ++++++-- test/source/_broken/bad_post.md | 4 ++ test/test_convertible.rb | 8 ++++ test/test_site.rb | 18 ++++++++ 8 files changed, 109 insertions(+), 49 deletions(-) create mode 100644 test/source/_broken/bad_post.md diff --git a/docs/_docs/configuration.md b/docs/_docs/configuration.md index 7789d52f..057e4ee2 100644 --- a/docs/_docs/configuration.md +++ b/docs/_docs/configuration.md @@ -305,6 +305,18 @@ class="flag">flags (specified on the command-line) that control them.

--profile

+ + +

Strict Front Matter

+

+ Cause a build to fail if there is a YAML syntax error in a page's front matter. +

+ + +

strict_front_matter: BOOL

+

--strict_front_matter

+ + @@ -601,12 +613,13 @@ collections: output: true # Handling Reading -safe: false -include: [".htaccess"] -exclude: ["Gemfile", "Gemfile.lock", "node_modules", "vendor/bundle/", "vendor/cache/", "vendor/gems/", "vendor/ruby/"] -keep_files: [".git", ".svn"] -encoding: "utf-8" -markdown_ext: "markdown,mkdown,mkdn,mkd,md" +safe: false +include: [".htaccess"] +exclude: ["Gemfile", "Gemfile.lock", "node_modules", "vendor/bundle/", "vendor/cache/", "vendor/gems/", "vendor/ruby/"] +keep_files: [".git", ".svn"] +encoding: "utf-8" +markdown_ext: "markdown,mkdown,mkdn,mkd,md" +strict_front_matter: false # Filtering Content show_drafts: null diff --git a/lib/jekyll/command.rb b/lib/jekyll/command.rb index 9150d24d..f9f243dd 100644 --- a/lib/jekyll/command.rb +++ b/lib/jekyll/command.rb @@ -46,6 +46,7 @@ module Jekyll # c - the Jekyll::Command to add these options to # # Returns nothing + # rubocop:disable Metrics/MethodLength def add_build_options(c) c.option "config", "--config CONFIG_FILE[,CONFIG_FILE2,...]", Array, "Custom configuration file" @@ -66,7 +67,10 @@ module Jekyll c.option "quiet", "-q", "--quiet", "Silence output." c.option "verbose", "-V", "--verbose", "Print verbose output." c.option "incremental", "-I", "--incremental", "Enable incremental rebuild." + c.option "strict_front_matter", "--strict_front_matter", + "Fail if errors are present in front matter" end + # rubocop:enable Metrics/MethodLength end end end diff --git a/lib/jekyll/configuration.rb b/lib/jekyll/configuration.rb index 86bee3c1..153d98fe 100644 --- a/lib/jekyll/configuration.rb +++ b/lib/jekyll/configuration.rb @@ -6,71 +6,72 @@ module Jekyll # Strings rather than symbols are used for compatibility with YAML. DEFAULTS = Configuration[{ # Where things are - "source" => Dir.pwd, - "destination" => File.join(Dir.pwd, "_site"), - "plugins_dir" => "_plugins", - "layouts_dir" => "_layouts", - "data_dir" => "_data", - "includes_dir" => "_includes", - "collections" => {}, + "source" => Dir.pwd, + "destination" => File.join(Dir.pwd, "_site"), + "plugins_dir" => "_plugins", + "layouts_dir" => "_layouts", + "data_dir" => "_data", + "includes_dir" => "_includes", + "collections" => {}, # Handling Reading - "safe" => false, - "include" => [".htaccess"], - "exclude" => %w( + "safe" => false, + "include" => [".htaccess"], + "exclude" => %w( Gemfile Gemfile.lock node_modules vendor/bundle/ vendor/cache/ vendor/gems/ vendor/ruby/ ), - "keep_files" => [".git", ".svn"], - "encoding" => "utf-8", - "markdown_ext" => "markdown,mkdown,mkdn,mkd,md", + "keep_files" => [".git", ".svn"], + "encoding" => "utf-8", + "markdown_ext" => "markdown,mkdown,mkdn,mkd,md", + "strict_front_matter" => false, # Filtering Content - "show_drafts" => nil, - "limit_posts" => 0, - "future" => false, - "unpublished" => false, + "show_drafts" => nil, + "limit_posts" => 0, + "future" => false, + "unpublished" => false, # Plugins - "whitelist" => [], - "plugins" => [], + "whitelist" => [], + "plugins" => [], # Conversion - "markdown" => "kramdown", - "highlighter" => "rouge", - "lsi" => false, - "excerpt_separator" => "\n\n", - "incremental" => false, + "markdown" => "kramdown", + "highlighter" => "rouge", + "lsi" => false, + "excerpt_separator" => "\n\n", + "incremental" => false, # Serving - "detach" => false, # default to not detaching the server - "port" => "4000", - "host" => "127.0.0.1", - "baseurl" => "", - "show_dir_listing" => false, + "detach" => false, # default to not detaching the server + "port" => "4000", + "host" => "127.0.0.1", + "baseurl" => "", + "show_dir_listing" => false, # Output Configuration - "permalink" => "date", - "paginate_path" => "/page:num", - "timezone" => nil, # use the local timezone + "permalink" => "date", + "paginate_path" => "/page:num", + "timezone" => nil, # use the local timezone - "quiet" => false, - "verbose" => false, - "defaults" => [], + "quiet" => false, + "verbose" => false, + "defaults" => [], - "liquid" => { + "liquid" => { "error_mode" => "warn", }, - "rdiscount" => { + "rdiscount" => { "extensions" => [], }, - "redcarpet" => { + "redcarpet" => { "extensions" => [], }, - "kramdown" => { + "kramdown" => { "auto_ids" => true, "toc_levels" => "1..6", "entity_output" => "as_char", diff --git a/lib/jekyll/convertible.rb b/lib/jekyll/convertible.rb index 34741c8f..16745dd5 100644 --- a/lib/jekyll/convertible.rb +++ b/lib/jekyll/convertible.rb @@ -48,8 +48,10 @@ module Jekyll end rescue SyntaxError => e Jekyll.logger.warn "YAML Exception reading #{filename}: #{e.message}" + raise e if self.site.config["strict_front_matter"] rescue => e Jekyll.logger.warn "Error reading file #{filename}: #{e.message}" + raise e if self.site.config["strict_front_matter"] end self.data ||= {} diff --git a/lib/jekyll/document.rb b/lib/jekyll/document.rb index a37ca1e4..90cfd1be 100644 --- a/lib/jekyll/document.rb +++ b/lib/jekyll/document.rb @@ -259,11 +259,8 @@ module Jekyll merge_defaults read_content(opts) read_post_data - rescue SyntaxError => e - Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{e.message}" rescue => e - raise e if e.is_a? Jekyll::Errors::FatalException - Jekyll.logger.error "Error:", "could not read file #{path}: #{e.message}" + handle_read_error(e) end end end @@ -457,6 +454,19 @@ module Jekyll generate_excerpt end + private + def handle_read_error(error) + if error.is_a? SyntaxError + Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{error.message}" + else + Jekyll.logger.error "Error:", "could not read file #{path}: #{error.message}" + end + + if site.config["strict_front_matter"] || error.is_a?(Jekyll::Errors::FatalException) + raise error + end + end + private def populate_title if relative_path =~ DATE_FILENAME_MATCHER diff --git a/test/source/_broken/bad_post.md b/test/source/_broken/bad_post.md new file mode 100644 index 00000000..f895dd26 --- /dev/null +++ b/test/source/_broken/bad_post.md @@ -0,0 +1,4 @@ +--- +bad yaml: [ +--- +Real content starts here diff --git a/test/test_convertible.rb b/test/test_convertible.rb index 82d64374..6e6defa6 100644 --- a/test/test_convertible.rb +++ b/test/test_convertible.rb @@ -33,6 +33,14 @@ class TestConvertible < JekyllUnitTest assert_match(%r!#{File.join(@base, name)}!, out) end + should "raise for broken front matter with `strict_front_matter` set" do + name = "broken_front_matter2.erb" + @convertible.site.config["strict_front_matter"] = true + assert_raises do + @convertible.read_yaml(@base, name) + end + end + should "not allow ruby objects in YAML" do out = capture_stderr do @convertible.read_yaml(@base, "exploit_front_matter.erb") diff --git a/test/test_site.rb b/test/test_site.rb index 65032ebd..d039cb8a 100644 --- a/test/test_site.rb +++ b/test/test_site.rb @@ -280,6 +280,24 @@ class TestSite < JekyllUnitTest Site.new(site_configuration("destination" => File.join(source_dir, ".."))) end end + + should "raise for bad frontmatter if strict_front_matter is set" do + site = Site.new(site_configuration( + "collections" => ["broken"], + "strict_front_matter" => true + )) + assert_raises do + site.process + end + end + + should "not raise for bad frontmatter if strict_front_matter is not set" do + site = Site.new(site_configuration( + "collections" => ["broken"], + "strict_front_matter" => false + )) + site.process + end end context "with orphaned files in destination" do