Add bin and edit workflow
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 9s

This commit is contained in:
2026-09-16 13:11:16 -06:00
parent c8ac4fcae5
commit 4cee170d66
17576 changed files with 895740 additions and 2 deletions
@@ -0,0 +1,85 @@
require:
# - rubocop-jekyll
- rubocop-md
- rubocop-performance
- rubocop-rake
- rubocop-rspec
# inherit_gem:
# rubocop-jekyll: .rubocop.yml
AllCops:
Exclude:
- demo/_site/**/*
- binstub/**/*
- vendor/**/*
- jekyll_plugin_logger.gemspec
NewCops: enable
Gemspec/DeprecatedAttributeAssignment:
Enabled: false
Gemspec/RequiredRubyVersion:
Enabled: false
Gemspec/RequireMFA:
Enabled: false
# Jekyll/NoPutsAllowed:
# Exclude:
# - spec/**/*
Layout/InitialIndentation:
Exclude:
- README.md
Layout/HashAlignment:
EnforcedColonStyle: table
EnforcedHashRocketStyle: table
Layout/LineLength:
Max: 150
Lint/RedundantCopDisableDirective:
Exclude:
- jekyll_plugin_logger.gemspec
Metrics/AbcSize:
Max: 25
Metrics/BlockLength:
Exclude:
- jekyll_plugin_logger.gemspec
- spec/**/*
Metrics/ClassLength:
Exclude:
- spec/**/*
Metrics/CyclomaticComplexity:
Max: 25
Metrics/MethodLength:
Max: 25
Metrics/PerceivedComplexity:
Max: 20
Naming/FileName:
Exclude:
- Rakefile
RSpec/ExampleLength:
Max: 20
RSpec/MultipleExpectations:
Max: 15
Style/Documentation:
Enabled: false
Style/FrozenStringLiteralComment:
Enabled: false
Style/TrailingCommaInHashLiteral:
EnforcedStyleForMultiline: comma
@@ -0,0 +1,47 @@
# Change Log
## 2.1.2 / 2023-11-21
* Added `demo`.
* Added `fatal` and `unknown` log levels.
## 2.1.1 / 2022-04-15
* Fixed `progname` reference for the `PluginMetaLogger` debug startup statement.
## 2.1.0 / 2022-04-05
* Changed how config info is made available.
* `PluginLogger` is a class once again.
## 2.0.1 / 2022-04-05
* Changed to registration hook to `:site`, `:after_reset` because that is the first hook that gets called.
* Improved the detection of various types of `progname`.
## 2.0.0 / 2022-03-16
* Completely rewrote this plugin, now not a class,
but a module that monkey patches the existing Jekyll logger for compatibility.
* Renamed the gem from `jekyll_logger_factory` to `jekyll_plugin_logger`.
* Automatically obtains plugin class name and uses that as `progname`.
* `:into` level output is colored cyan.
## 1.0.0 / 2022-03-16
* Published as a gem.
* New instances are now created with `new` instead of `create_logger`.
* Now subclasses Jekyll's Stevenson logger.
* Documentation improved, clarifies that the only supported levels are those provided by the
Stevenson logger: `:debug`, `:info`, and `:error`.
* No longer supports control over where log output goes; STDERR and STDOUT are automatically selected according to log level.
## 2020-12-28
* Initial version published at https://www.mslinn.com/blog/2020/12/28/custom-logging-in-jekyll-plugins.html
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2020 Mike Slinn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@@ -0,0 +1,160 @@
# `jekyll_plugin_logger` [![Gem Version](https://badge.fury.io/rb/jekyll_plugin_logger.svg)](https://badge.fury.io/rb/jekyll_plugin_logger)
`jekyll_plugin_logger` is a Jekyll plugin, packaged as a Ruby gem, that provides colored console logs for Jekyll plugins.
It is based on the standard Ruby [`Logger`](https://ruby-doc.org/stdlib-3.1.0/libdoc/logger/rdoc/Logger.html) class.
Log levels are normally set from `_config.yml`:
* 0: `debug`
* 1: `info`
* 2: `warn`
* 3: `error`
* 4: `fatal`
* 5: `unknown` (displays as `ANY`)
## Usage
The [`demo/_plugins/`](demo/_plugins/) directory demonstrates two ways of working with `jekyll_plugin_logger`:
* `liquid_tag.rb`, a Jekyll plugin subclassed from
[`Liquid::Tag`](https://jekyllrb.com/docs/plugins/tags/).
* `support_tag.rb`, a Jekyll plugin subclassed from
[`JekyllSupport::JekyllTag`](https://www.mslinn.com/jekyll_plugins/jekyll_plugin_support.html).
## Installation
### To A Jekyll Website
Add the following to your Jekyll website's `Gemfile`:
```ruby
group :jekyll_plugins do
gem 'jekyll_plugin_logger'
end
```
Install all of the dependent gems of your Jekyll website by typing:
```shell
$ bundle
```
### To A Jekyll Plugin Packaged As A Gem
Add the following to your Gem’s `.gemspec`:
```ruby
Gem::Specification.new do |spec|
spec.add_dependency 'jekyll_plugin_logger'
end
```
Install all of the dependent gems of your Gem by typing:
```shell
$ bundle
```
## Configuration
The default log level is `info`.
You can change the log level by editing `_config.yml` and adding a `plugin_loggers` section.
Within that section, add an entry for the fully qualified name of your plugin class.
For example, the fully qualified class names of the Jekyll plugins provided in `demo/_plugins/`
are `Raw::InlineTag` and `Support::InlineTag`, respectively.
Their log levels can be set to `debug` with the following entries in [`_config.yml`](demo/_config.yml):
```yaml
plugin_loggers:
Raw::InlineTag: debug # Notice the module name is specified as well as the class name
Support::InlineTag: debug # Notice the module name is specified as well as the class name
```
## Run the Demo
Run the demo by typing:
```shell
$ demo/_bin/debug -r
```
See what happens to the output when you edit the logging levels in the `plugin_loggers` section of `_config.yml`.
You will have to restart the demo after each modification to `_config.yml`
in order to see the output change.
## Additional Information
More information is available on Mike Slinn's web site about
[Jekyll plugins](https://www.mslinn.com/jekyll/10100-custom-logging-in-jekyll-plugins.html).
## Development
After checking out the `jekyll_plugin_logger` repository,
run `bin/setup` to install dependencies,
which includes development dependencies.
You can then run `bin/console` for an interactive prompt that will allow you to experiment.
### Build and Install Locally
To build and install this gem onto your local machine, run:
```shell
$ bundle exec rake install
jekyll_plugin_logger 1.0.0 built to pkg/jekyll_plugin_logger-0.1.0.gem.
jekyll_plugin_logger (1.0.0) installed.
```
Examine the newly built gem:
```shell
$ gem info jekyll_plugin_logger
*** LOCAL GEMS ***
jekyll_plugin_logger (1.0.0)
Author: Mike Slinn
Homepage:
https://github.com/mslinn/jekyll_plugin_logger
License: MIT
Installed at: /home/mslinn/.gems
Generates a Jekyll logger with colored output.
```
### Build and Push to RubyGems
To release a new version,
1. Update the version number in `version.rb`.
2. Commit all changes to git; if you don't the next step might fail with an unexplainable error message.
3. Run the following:
```shell
$ bundle exec rake release
```
The above creates a git tag for the version, commits the created tag,
and pushes the new `.gem` file to [RubyGems.org](https://rubygems.org).
## Contributing
1. Fork the project
2. Create a descriptively named feature branch
3. Add your feature
4. Submit a pull request
## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,21 @@
require 'bump/tasks'
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
# do not always tag the version
# Bump.tag_by_default = false
# bump the version in additional files
# Bump.replace_in_default = ['Readme.md']
# Maintain changelog:
Bump.changelog = true
# Open the changelog in an editor when bumping
Bump.changelog = :editor
# Configure bump to not use a prefix:
ENV['TAG_PREFIX'] = ''
RSpec::Core::RakeTask.new(:spec)
task default: :spec
@@ -0,0 +1,36 @@
require_relative 'lib/jekyll_plugin_logger/version'
Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
github = 'https://github.com/mslinn/jekyll_plugin_logger'
spec.authors = ['Mike Slinn']
spec.bindir = 'exe'
spec.description = <<~END_OF_DESC
Generates Jekyll logger with colored output.
END_OF_DESC
spec.email = ['mslinn@mslinn.com']
spec.files = Dir['.rubocop.yml', 'LICENSE.*', 'Rakefile', '{lib,spec}/**/*', '*.gemspec', '*.md']
spec.homepage = 'https://www.mslinn.com/jekyll_plugins/jekyll_plugin_logger.html'
spec.license = 'MIT'
spec.metadata = {
'allowed_push_host' => 'https://rubygems.org',
'bug_tracker_uri' => "#{github}/issues",
'changelog_uri' => "#{github}/CHANGELOG.md",
'homepage_uri' => spec.homepage,
'source_code_uri' => github,
}
spec.name = 'jekyll_plugin_logger'
spec.post_install_message = <<~END_MESSAGE
Thanks for installing #{spec.name}!
END_MESSAGE
spec.require_paths = ['lib']
spec.required_ruby_version = '>= 2.6.0'
spec.summary = 'Generates a Jekyll logger with colored output.'
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.version = JekyllPluginLoggerVersion::VERSION
spec.add_dependency 'bump'
spec.add_dependency 'jekyll', '>= 3.5.0'
end
@@ -0,0 +1,152 @@
require 'colorator'
require 'logger'
require 'yaml'
require_relative 'jekyll_plugin_logger/version'
require_relative 'jekyll_plugin_meta_logger'
module JekyllPluginLoggerName
PLUGIN_NAME = 'jekyll_plugin_logger'.freeze
end
# Once the meta-logger is made (see `PluginMetaLogger`, below) new instances of `PluginLogger` can be created with log levels set
# by `config` entries.
# @example Create new `PluginLogger`s like this:
# @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
#
# self can be a module, a class, a string, or a symbol.
#
# Best practice is to invoke `info`, `warn, `debug` and `error` methods by passing blocks that contain the message.
# The blocks will only be evaluated if output for that level is enabled.
# @example Use `PluginLogger`s like this:
# @logger.info { "This is only evaluated if info level debugging is enabled" }
#
# For more information about the logging feature in the Ruby standard library,
# @see https://ruby-doc.org/stdlib-2.7.1/libdoc/logger/rdoc/Logger.html
class PluginLogger
# This method should only be called by PluginMetaLogger
# @param log_level [String, Symbol, Integer] can be specified as $stderr or $stdout,
# or an integer from 0..3 (inclusive),
# or as a case-insensitive string
# (`debug`, `info`, `warn`, `error`, or `DEBUG`, `INFO`, `WARN`, `ERROR`),
# or as a symbol (`:debug`, `:info`, `:warn`, `:error` ).
#
# 0: debug
# 1: info
# 2: warn
# 3: error
# 4: fatal
# 5: unknown (displays as ANY)
#
# @param config [YAML] is normally created by reading a YAML file such as Jekyll's `_config.yml`.
# When invoking from a Jekyll plugin, provide `site.config`,
# which is available from all types of Jekyll plugins as `Jekyll.configuration({})`.
#
# @example If `progname` has value `abc`, then the YAML to override the programmatically set log_level to `debug` is:
# logger_factory:
# abc: debug
def initialize(klass, config = nil, stream_name = $stdout)
@config = config
plugin_loggers = config&.[] 'plugin_loggers'
@logger = Logger.new stream_name
@logger.progname = derive_progname klass
@logger.level = :info
@logger.level = plugin_loggers[@logger.progname] if plugin_loggers&.[] @logger.progname
# puts "PluginLogger.initialize: @logger.progname=#{@logger.progname} set to #{@logger.level}".red
@logger.formatter = proc { |severity, _datetime, progname, msg|
"#{severity} #{progname}: #{msg}\n"
}
end
def debug(progname = nil, &block)
if block
@logger.debug(@logger.progname) { (yield block).to_s.magenta }
else
@logger.debug(@logger.progname) { progname.to_s.magenta }
end
end
def info(progname = nil, &block)
if block
@logger.info(@logger.progname) { (yield block).to_s.cyan }
else
@logger.info(@logger.progname) { progname.to_s.cyan }
end
end
def level=(value)
@logger.level = value
end
# @return the log level specified in _config.yml, or :info (1) if not specified
def level
@logger.level
end
def progname=(value)
@logger.progname = value
end
def progname
@logger.progname
end
def warn(progname = nil, &block)
if block
@logger.warn(@logger.progname) { (yield block).to_s.yellow }
else
@logger.warn(@logger.progname) { progname.to_s.yellow }
end
end
def error(progname = nil, &block)
if block
@logger.error(@logger.progname) { (yield block).to_s.red }
else
@logger.error(@logger.progname) { progname.to_s.red }
end
end
def fatal(progname = nil, &block)
if block
@logger.fatal(@logger.progname) { (yield block).to_s.red.bold }
else
@logger.fatal(@logger.progname) { progname.to_s.red.bold }
end
end
# @return the log level specified in _config.yml, or :info (1) if not specified
# Available colors are: :black, :red, :green, :yellow, :blue, :magenta, :cyan, :white, and the modifier :bold
def level_as_sym
return :unknown if @logger.level.negative? || level > 4
%i[debug info warn error fatal unknown][@logger.level]
end
def unknown(progname = nil, &block)
if block
@logger.unknown(@logger.progname) { (yield block).to_s.green }
else
@logger.unknown(@logger.progname) { progname.to_s.green }
end
end
private
def derive_progname(klass)
class_name = klass.class.to_s
case class_name
when 'Class', 'Module', 'Symbol', 'String'
klass.to_s.split('::').last
else
class_name
end
end
end
Jekyll::Hooks.register(:site, :after_reset, priority: :high) do |site|
instance = PluginMetaLogger.instance
logger = instance.new_logger(PluginMetaLogger, site.config)
logger.info { "Loaded #{JekyllPluginLoggerName::PLUGIN_NAME} v#{JekyllPluginLoggerVersion::VERSION} plugin." }
logger.debug { "Logger for #{instance.logger.progname} created at level #{instance.level_as_sym}" }
end
@@ -0,0 +1,3 @@
module JekyllPluginLoggerVersion
VERSION = '2.1.2'.freeze
end
@@ -0,0 +1,70 @@
require 'colorator'
require 'logger'
require 'singleton'
# Makes a meta-logger instance (a singleton) with level set by `site.config`.
# Saves `site.config` for later use when creating plugin loggers; these loggers each have their own log levels.
#
# For example, if the plugin's progname has value `MyPlugin` then an entry called `plugin_loggers.MyPlugin`
# will be read from `config`, if present.
# If no such entry is found then the meta-logger log_level is set to `:info`.
# If you want to see messages that indicate the loggers and log levels as they are created,
# set the log level for `PluginMetaLogger` to `debug` in `_config.yml`
#
# @example
# # Create and initialize the meta-logger singleton in a high priority Jekyll `site` `:after_init` hook:
# @meta_logger = PluginMetaLogger.instance.new_logger(site.config, self)
# @meta_logger.info { "Meta-logger has been created" }
#
# # In `config.yml`:
# plugin_loggers:
# PluginMetaLogger: info
# MyPlugin: warn
# MakeArchive: error
# ArchiveDisplayTag: debug
#
# # In a Jekyll plugin:
# @logger = PluginMetaLogger.instance.setup(self)
# @logger.info { "This is a log message from a Jekyll plugin" }
# #
# PluginMetaLogger.instance.info { "MyPlugin vX.Y.Z has been loaded" }
class PluginMetaLogger
include Singleton
attr_reader :config, :logger
def initialize
super
@config = nil
@logger = new_logger(self)
end
def info(&block)
@logger.info(self) { yield block }
end
def debug(&block)
@logger.debug(self) { yield block }
end
def level_as_sym
@logger.level_as_sym
end
def warn(&block)
@logger.warn(self) { yield block }
end
def error(&block)
@logger.error(self) { yield block }
end
def new_logger(klass, config = nil, stream_name = $stdout)
@config ||= config
if @config.nil?
puts { 'Error: PluginMetaLogger has not been initialized with site.config.'.red }
PluginLogger.new(klass, {}, stream_name)
else
PluginLogger.new(klass, @config, stream_name)
end
end
end
@@ -0,0 +1,85 @@
require 'colorator'
require 'jekyll'
require_relative '../lib/jekyll_plugin_logger'
# Output should be:
# Info message 1 (cyan)
# MyPlugin Info message 2 (cyan)
# MyPlugin: Info message 3 (cyan)
# MyTestPlugin: Info message 4 (cyan)
# .
# MyPlugin: Warn message 1 (yellow)
# MyTestPlugin: Warn message 2 (yellow)
# MyPlugin: Error message 1 (red)
# MyTestPlugin: Error message 2 (red)
class MyTestPlugin
instance = PluginMetaLogger.instance
logger = instance.new_logger(self) # Should generate a warning
PluginMetaLogger.instance.info { 'How now, brown cow' }
PluginMetaLogger.instance.debug { 'How now, brown cow' }
PluginMetaLogger.instance.warn { 'How now, brown cow' }
PluginMetaLogger.instance.error { 'How now, brown cow' }
logger = PluginMetaLogger.instance.new_logger(self, RSpec.configuration.site_config)
logger.debug { '3 fleas fleeing freedom' }
logger.info { '3 fleas fleeing freedom' }
logger.warn { '3 fleas fleeing freedom' }
logger.error { '3 fleas fleeing freedom' }
def self.exercise(logger)
puts
# puts '\ncalling_class_name=#{logger.send(:calling_class_name)}'
logger.debug('Debug message 1')
# logger.debug('MyPlugin', 'Debug message 2')
# logger.debug('MyPlugin') { 'Debug message 3' }
logger.debug { 'Debug message 4' }
logger.info('Info message 1')
# logger.info('MyPlugin', 'Info message 2')
# logger.info('MyPlugin') { 'Info message 3' }
logger.info { 'Info message 4' }
logger.warn('Warn message 1')
# logger.warn('MyPlugin', 'Warn message 2')
# logger.warn('MyPlugin') { 'Warn message 3' }
logger.warn { 'Warn message 4' }
logger.error('Error message 1')
# logger.error('MyPlugin', 'Error message 2')
# logger.error('MyPlugin') { 'Error message 3' }
logger.error { 'Error message 4' }
end
RSpec.describe PluginLogger do
it 'outputs at info level' do
MyTestPlugin.exercise(PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config, $stdout))
expect(PluginMetaLogger.instance.level_as_sym).to eq(:info)
end
it 'uses config debug' do
logger = PluginMetaLogger.instance.new_logger(:MyBlock, PluginMetaLogger.instance.config)
expect(logger.level_as_sym).to eq(:debug)
MyTestPlugin.exercise(logger)
end
it 'uses config info' do
logger = PluginMetaLogger.instance.new_logger(:ArchiveDisplayTag, PluginMetaLogger.instance.config)
expect(logger.level_as_sym).to eq(:info)
MyTestPlugin.exercise(logger)
end
it 'uses config warn' do
logger = PluginMetaLogger.instance.new_logger('SiteInspector', PluginMetaLogger.instance.config, $stdout)
expect(logger.level_as_sym).to eq(:warn)
MyTestPlugin.exercise(logger)
end
it 'uses config error' do
logger = PluginMetaLogger.instance.new_logger(:PreTagBlock, PluginMetaLogger.instance.config)
expect(logger.level_as_sym).to eq(:error)
MyTestPlugin.exercise(logger)
end
end
end
@@ -0,0 +1,27 @@
require 'jekyll'
require_relative '../lib/jekyll_plugin_logger'
Jekyll.logger.log_level = :info
RSpec.configure do |config|
config.filter_run_when_matching focus: true
plugin_config = <<~END_CONFIG
plugin_loggers:
ArchiveDisplayTag: info
FlexibleInclude: info
MakeArchive: info
MyBlock: debug
PluginMetaLogger: info
PreTagBlock: error
SiteInspector: warn
UnselectableTag: info
END_CONFIG
config.add_setting :site_config
config.site_config = YAML.safe_load(plugin_config)
config.order = 'random'
# See https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures
config.example_status_persistence_file_path = 'spec/status_persistence.txt'
end
@@ -0,0 +1,7 @@
example_id | status | run_time |
---------------------------------------- | ------ | --------------- |
./spec/jekyll_plugin_logger_spec.rb[1:1] | passed | 0.00004 seconds |
./spec/jekyll_plugin_logger_spec.rb[1:2] | passed | 0.00005 seconds |
./spec/jekyll_plugin_logger_spec.rb[1:3] | passed | 0.00009 seconds |
./spec/jekyll_plugin_logger_spec.rb[1:4] | passed | 0.00005 seconds |
./spec/jekyll_plugin_logger_spec.rb[1:5] | passed | 0.00117 seconds |