mirror of
https://github.com/jekyll/jekyll.git
synced 2026-04-28 03:01:03 -04:00
Compare commits
5 Commits
master
...
make-it-an
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29d1f21df7 | ||
|
|
07c8e3e333 | ||
|
|
b0c42090ea | ||
|
|
de8547b208 | ||
|
|
4db922d95e |
@@ -1,6 +1,8 @@
|
||||
module Jekyll
|
||||
class Command
|
||||
class << self
|
||||
attr_accessor :trace
|
||||
|
||||
# A list of subclasses of Jekyll::Command
|
||||
def subclasses
|
||||
@subclasses ||= []
|
||||
@@ -26,8 +28,15 @@ module Jekyll
|
||||
site.process
|
||||
rescue Jekyll::Errors::FatalException => e
|
||||
Jekyll.logger.error "ERROR:", "YOUR SITE COULD NOT BE BUILT:"
|
||||
Jekyll.logger.error "", "------------------------------------"
|
||||
Jekyll.logger.error "", "------------------------------------------"
|
||||
Jekyll.logger.error "", e.message
|
||||
if self.class.trace
|
||||
Jekyll.logger.error "", "------------------------------------------"
|
||||
Jekyll.logger.error "Stacktrace:", e.backtrace.join("\n")
|
||||
else
|
||||
Jekyll.logger.error "", ""
|
||||
Jekyll.logger.error "", "Run jekyll with --trace for more information."
|
||||
end
|
||||
exit(1)
|
||||
end
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ module Jekyll
|
||||
|
||||
c.action do |_, options|
|
||||
options["serving"] = false
|
||||
self.class.trace = c.trace
|
||||
Jekyll::Commands::Build.process(options)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,7 +23,7 @@ module Jekyll
|
||||
if healthy?(site)
|
||||
Jekyll.logger.info "Your test results", "are in. Everything looks fine."
|
||||
else
|
||||
abort
|
||||
raise Jekyll::Errors::UnhealthySiteError
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ module Jekyll
|
||||
cmd.action do |_, opts|
|
||||
opts["serving"] = true
|
||||
opts["watch" ] = true unless opts.key?("watch")
|
||||
self.class.trace = cmd.trace
|
||||
Build.process(opts)
|
||||
Serve.process(opts)
|
||||
end
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
module Jekyll
|
||||
class Configuration < Hash
|
||||
attr_accessor :default_config_file
|
||||
|
||||
# Default options. Overridden by values in _config.yml.
|
||||
# Strings rather than symbols are used for compatibility with YAML.
|
||||
DEFAULTS = Configuration[{
|
||||
@@ -74,6 +76,10 @@ module Jekyll
|
||||
}
|
||||
}]
|
||||
|
||||
def self.from(other_hash = {})
|
||||
Jekyll::Utils.deep_merge_hashes DEFAULTS, other_hash
|
||||
end
|
||||
|
||||
# Public: Turn all keys into string
|
||||
#
|
||||
# Return a copy of the hash where all its keys are strings
|
||||
@@ -112,7 +118,8 @@ module Jekyll
|
||||
when /\.ya?ml/i
|
||||
SafeYAML.load_file(filename) || {}
|
||||
else
|
||||
raise ArgumentError, "No parser for '#{filename}' is available. Use a .toml or .y(a)ml file instead."
|
||||
raise Jekyll::Errors::InvalidFileFormatError,
|
||||
"No parser for '#{filename}' is available. Use a .toml or .y(a)ml file instead."
|
||||
end
|
||||
end
|
||||
|
||||
@@ -132,7 +139,7 @@ module Jekyll
|
||||
File.exist?(Jekyll.sanitized_path(source(override), "_config.#{ext}"))
|
||||
end
|
||||
config_files = Jekyll.sanitized_path(source(override), "_config.#{default}")
|
||||
@default_config_file = true
|
||||
self.default_config_file = true
|
||||
end
|
||||
config_files = [config_files] unless config_files.is_a? Array
|
||||
config_files
|
||||
@@ -148,13 +155,13 @@ module Jekyll
|
||||
check_config_is_hash!(next_config, file)
|
||||
Jekyll.logger.info "Configuration file:", file
|
||||
next_config
|
||||
rescue SystemCallError
|
||||
if @default_config_file
|
||||
rescue SystemCallError, Errno::ENOENT
|
||||
if default_config_file
|
||||
Jekyll.logger.warn "Configuration file:", "none"
|
||||
{}
|
||||
else
|
||||
Jekyll.logger.error "Fatal:", "The configuration file '#{file}' could not be found."
|
||||
raise LoadError, "The Configuration file '#{file}' could not be found."
|
||||
raise Jekyll::Errors::FileNotFoundError,
|
||||
"The configuration file '#{file}' could not be found."
|
||||
end
|
||||
end
|
||||
|
||||
@@ -246,7 +253,7 @@ module Jekyll
|
||||
end
|
||||
|
||||
if config.fetch('markdown', 'kramdown').to_s.downcase.eql?("maruku")
|
||||
Jekyll.logger.abort_with "Error:", "You're using the 'maruku' " \
|
||||
raise Jekyll::Errors::InvalidConfigurationError, "You're using the 'maruku' " \
|
||||
"Markdown processor, which has been removed as of 3.0.0. " \
|
||||
"We recommend you switch to Kramdown. To do this, replace " \
|
||||
"`markdown: maruku` with `markdown: kramdown` in your " \
|
||||
@@ -317,7 +324,8 @@ module Jekyll
|
||||
# Raises an ArgumentError if given config is not a hash
|
||||
def check_config_is_hash!(extracted_config, file)
|
||||
unless extracted_config.is_a?(Hash)
|
||||
raise ArgumentError.new("Configuration file: (INVALID) #{file}".yellow)
|
||||
raise Jekyll::Errors::InvalidConfigurationError,
|
||||
"The configuration file '#{file}' is invalid: it is not a Hash."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -76,7 +76,8 @@ module Jekyll
|
||||
))
|
||||
|
||||
unless Gem::Version.new(Rouge.version) > Gem::Version.new("1.3.0")
|
||||
abort "Please install Rouge 1.3.0 or greater and try running Jekyll again."
|
||||
raise Jekyll::Errors::IncorrectDependencyError,
|
||||
"Please install Rouge 1.3.0 or greater and try running Jekyll again."
|
||||
end
|
||||
|
||||
include Rouge::Plugins::Redcarpet
|
||||
|
||||
@@ -79,9 +79,9 @@ module Jekyll
|
||||
begin
|
||||
converter.convert output
|
||||
rescue => e
|
||||
Jekyll.logger.error "Conversion error:", "#{converter.class} encountered an error while converting '#{path}':"
|
||||
Jekyll.logger.error("", e.to_s)
|
||||
raise e
|
||||
raise Jekyll::Errors::ConversionError, "" \
|
||||
"#{converter.class} encountered an error while converting '#{path}':" \
|
||||
"\n#{e.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -112,11 +112,17 @@ module Jekyll
|
||||
def render_liquid(content, payload, info, path)
|
||||
site.liquid_renderer.file(path).parse(content).render!(payload, info)
|
||||
rescue Tags::IncludeTagError => e
|
||||
Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{e.path}, included in #{path || self.path}"
|
||||
raise e
|
||||
rescue Exception => e
|
||||
Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{path || self.path}"
|
||||
raise e
|
||||
raise Jekyll::Errors::LiquidRenderError,
|
||||
"Liquid exception in #{e.path} included in #{path || self.path}:" \
|
||||
"\n#{e.message}"
|
||||
rescue Liquid::Error => e
|
||||
raise Jekyll::Errors::LiquidRenderError,
|
||||
"Liquid exception on line #{e.line_number} in #{path || self.path}:" \
|
||||
"\n#{e.message}"
|
||||
rescue => e
|
||||
raise Jekyll::Errors::LiquidRenderError,
|
||||
"Liquid exception in #{path || self.path}:" \
|
||||
"\n#{e.message}"
|
||||
end
|
||||
|
||||
# Convert this Convertible's data to a Hash suitable for use by Liquid.
|
||||
|
||||
@@ -2,11 +2,26 @@ module Jekyll
|
||||
module Errors
|
||||
FatalException = Class.new(::RuntimeError)
|
||||
|
||||
# Errors for commands
|
||||
UnhealthySiteError = Class.new(FatalException)
|
||||
|
||||
# Configuration errors
|
||||
InvalidConfigurationError = Class.new(FatalException)
|
||||
InvalidFileFormatError = Class.new(FatalException)
|
||||
|
||||
# IO Errors
|
||||
FileNotFoundError = Class.new(FatalException)
|
||||
|
||||
# Render errors
|
||||
DropMutationException = Class.new(FatalException)
|
||||
InvalidPermalinkError = Class.new(FatalException)
|
||||
InvalidYAMLFrontMatterError = Class.new(FatalException)
|
||||
MissingDependencyException = Class.new(FatalException)
|
||||
MissingDependencyError = Class.new(FatalException)
|
||||
IncorrectDependencyError = Class.new(FatalException)
|
||||
ConversionError = Class.new(FatalException)
|
||||
LiquidRenderError = Class.new(FatalException)
|
||||
|
||||
# post_url tag errors
|
||||
InvalidDateError = Class.new(FatalException)
|
||||
InvalidPostNameError = Class.new(FatalException)
|
||||
PostURLError = Class.new(FatalException)
|
||||
|
||||
@@ -98,7 +98,11 @@ module Jekyll
|
||||
#
|
||||
# Returns the formatted message
|
||||
def message(topic, message)
|
||||
msg = formatted_topic(topic) + message.to_s.gsub(/\s+/, ' ')
|
||||
lines = message.to_s.split("\n")
|
||||
first_line = formatted_topic(topic) + lines.shift.to_s
|
||||
msg = ([first_line] + lines.map {|line|
|
||||
formatted_topic("") + line.gsub(/[ ]+/, ' ')
|
||||
}).join("\n")
|
||||
messages << msg
|
||||
msg
|
||||
end
|
||||
|
||||
@@ -107,11 +107,17 @@ module Jekyll
|
||||
def render_liquid(content, payload, info, path = nil)
|
||||
site.liquid_renderer.file(path).parse(content).render!(payload, info)
|
||||
rescue Tags::IncludeTagError => e
|
||||
Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{e.path}, included in #{path || document.relative_path}"
|
||||
raise e
|
||||
rescue Exception => e
|
||||
Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{path || document.relative_path}"
|
||||
raise e
|
||||
raise Jekyll::Errors::LiquidRenderError,
|
||||
"Liquid exception in #{e.path} included in #{path || self.path}:" \
|
||||
"\n#{e.message}"
|
||||
rescue Liquid::Error => e
|
||||
raise Jekyll::Errors::LiquidRenderError,
|
||||
"Liquid exception on line #{e.line_number} in #{path || self.path}:" \
|
||||
"\n#{e.message}"
|
||||
rescue => e
|
||||
raise Jekyll::Errors::LiquidRenderError,
|
||||
"Liquid exception in #{path || self.path}:" \
|
||||
"\n#{e.message}"
|
||||
end
|
||||
|
||||
# Checks if the layout specified in the document actually exists
|
||||
|
||||
@@ -300,11 +300,12 @@ module Jekyll
|
||||
# Returns
|
||||
def relative_permalinks_are_deprecated
|
||||
if config['relative_permalinks']
|
||||
Jekyll.logger.abort_with "Since v3.0, permalinks for pages" \
|
||||
" in subfolders must be relative to the" \
|
||||
" site source directory, not the parent" \
|
||||
" directory. Check http://jekyllrb.com/docs/upgrading/"\
|
||||
" for more info."
|
||||
raise Jekyll::Errors::InvalidConfigurationError,
|
||||
"Since v3.0, permalinks for pages" \
|
||||
" in subfolders must be relative to the" \
|
||||
" site source directory, not the parent" \
|
||||
" directory. Check http://jekyllrb.com/docs/upgrading/"\
|
||||
" for more info."
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
2
script/spec
Executable file
2
script/spec
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
bundle exec rspec --color --require spec_helper $@
|
||||
@@ -48,9 +48,13 @@ for ruby in $rubies; do
|
||||
set -x
|
||||
time $ruby -S bundle exec \
|
||||
rake TESTOPTS='--profile' test
|
||||
time $ruby -S bundle exec rspec --color \
|
||||
--require spec_helper
|
||||
else
|
||||
set -x
|
||||
time $ruby -S bundle exec ruby -Itest \
|
||||
"$@" --profile
|
||||
time $ruby -S bundle exec rspec --color \
|
||||
--require spec_helper --profile
|
||||
fi
|
||||
done
|
||||
|
||||
37
spec/jekyll/configuration_spec.rb
Normal file
37
spec/jekyll/configuration_spec.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
RSpec.describe(Jekyll::Configuration) do
|
||||
subject { described_class.from({}) }
|
||||
|
||||
describe "#safe_load_file" do
|
||||
it "throws an InvalidFileFormat on a bad extension" do
|
||||
filename = "my_config.json"
|
||||
expect(-> { subject.safe_load_file(filename) }).to raise_error(
|
||||
Jekyll::Errors::InvalidFileFormatError,
|
||||
"No parser for '#{filename}' is available. Use a .toml or .y(a)ml file instead."
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#read_config_file" do
|
||||
it "throws a FileNotFoundError if the file doesn't exist" do
|
||||
filename = "_config.yml"
|
||||
expect(-> { subject.read_config_file(filename) }).to raise_error(
|
||||
Jekyll::Errors::FileNotFoundError,
|
||||
"The configuration file '#{filename}' could not be found."
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#check_config_is_hash!" do
|
||||
it "does not throw if the input is a hash" do
|
||||
expect(subject.send(:check_config_is_hash!, {}, "_config.yml")).to eq(nil)
|
||||
end
|
||||
|
||||
it "throws an InvalidConfigurationError if the input is not a hash" do
|
||||
filename = "_config.yml"
|
||||
expect(-> { subject.send(:check_config_is_hash!, false, filename) }).to raise_error(
|
||||
Jekyll::Errors::InvalidConfigurationError,
|
||||
"The configuration file '#{filename}' is invalid: it is not a Hash."
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
7
spec/jekyll/errors_spec.rb
Normal file
7
spec/jekyll/errors_spec.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe(Jekyll::Errors) do
|
||||
it "defines the base exception, FatalException" do
|
||||
expect(described_class).to be_const_defined(:FatalException)
|
||||
end
|
||||
end
|
||||
66
spec/spec_helper.rb
Normal file
66
spec/spec_helper.rb
Normal file
@@ -0,0 +1,66 @@
|
||||
ROOT = Pathname.new(File.expand_path("../", __dir__))
|
||||
|
||||
require ROOT.join("lib", "jekyll.rb")
|
||||
|
||||
RSpec.configure do |config|
|
||||
# rspec-expectations config goes here. You can use an alternate
|
||||
# assertion/expectation library such as wrong or the stdlib/minitest
|
||||
# assertions if you prefer.
|
||||
config.expect_with :rspec do |expectations|
|
||||
# This option will default to `true` in RSpec 4. It makes the `description`
|
||||
# and `failure_message` of custom matchers include text for helper methods
|
||||
# defined using `chain`, e.g.:
|
||||
# be_bigger_than(2).and_smaller_than(4).description
|
||||
# # => "be bigger than 2 and smaller than 4"
|
||||
# ...rather than:
|
||||
# # => "be bigger than 2"
|
||||
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
||||
end
|
||||
|
||||
# rspec-mocks config goes here. You can use an alternate test double
|
||||
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
||||
config.mock_with :rspec do |mocks|
|
||||
# Prevents you from mocking or stubbing a method that does not exist on
|
||||
# a real object. This is generally recommended, and will default to
|
||||
# `true` in RSpec 4.
|
||||
mocks.verify_partial_doubles = true
|
||||
end
|
||||
|
||||
# Allows RSpec to persist some state between runs in order to support
|
||||
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
||||
# you configure your source control system to ignore this file.
|
||||
# config.example_status_persistence_file_path = "spec/examples.txt"
|
||||
|
||||
# Limits the available syntax to the non-monkey patched syntax that is
|
||||
# recommended. For more details, see:
|
||||
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
||||
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
||||
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
||||
config.disable_monkey_patching!
|
||||
|
||||
# This setting enables warnings. It's recommended, but in some cases may
|
||||
# be too noisy due to issues in dependencies.
|
||||
config.warnings = true
|
||||
|
||||
# Many RSpec users commonly either run the entire suite or an individual
|
||||
# file, and it's useful to allow more verbose output when running an
|
||||
# individual spec file.
|
||||
if config.files_to_run.one?
|
||||
# Use the documentation formatter for detailed output,
|
||||
# unless a formatter has already been configured
|
||||
# (e.g. via a command-line flag).
|
||||
config.default_formatter = 'doc'
|
||||
end
|
||||
|
||||
# Run specs in random order to surface order dependencies. If you find an
|
||||
# order dependency and want to debug it, you can fix the order by providing
|
||||
# the seed, which is printed after each run.
|
||||
# --seed 1234
|
||||
config.order = :random
|
||||
|
||||
# Seed global randomization in this process using the `--seed` CLI option.
|
||||
# Setting this allows you to use `--seed` to deterministically reproduce
|
||||
# test failures related to randomization by passing the same `--seed` value
|
||||
# as the one that triggered the failure.
|
||||
Kernel.srand config.seed
|
||||
end
|
||||
@@ -174,13 +174,15 @@ class TestConfiguration < JekyllUnitTest
|
||||
allow(SafeYAML).to receive(:load_file).with(@path).and_return(Array.new)
|
||||
allow($stderr).to receive(:puts).and_return(("WARNING: ".rjust(20) + "Error reading configuration. Using defaults (and options).").yellow)
|
||||
allow($stderr).to receive(:puts).and_return("Configuration file: (INVALID) #{@path}".yellow)
|
||||
assert_equal @@defaults, Jekyll.configuration({})
|
||||
assert_raises Jekyll::Errors::InvalidConfigurationError do
|
||||
Jekyll.configuration({})
|
||||
end
|
||||
end
|
||||
|
||||
should "fire warning when user-specified config file isn't there" do
|
||||
allow(SafeYAML).to receive(:load_file).with(@user_config) { raise SystemCallError, "No such file or directory - #{@user_config}" }
|
||||
allow($stderr).to receive(:puts).with(("Fatal: ".rjust(20) + "The configuration file '#{@user_config}' could not be found.").red)
|
||||
assert_raises LoadError do
|
||||
assert_raises Jekyll::Errors::FileNotFoundError do
|
||||
Jekyll.configuration({'config' => [@user_config]})
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user