Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 0 additions & 24 deletions .circleci/config.yml

This file was deleted.

77 changes: 77 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: CI

on:
push:
branches: [ main ]
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow is configured to run on pushes to the main branch only, so it will not run on tag pushes. As a result, the publish job guarded by startsWith(github.ref, 'refs/tags/v') will never execute. Add a push.tags trigger (e.g., v*) or remove the branch-only restriction if you want tag builds to publish.

Suggested change
branches: [ main ]
branches: [ main ]
tags:
- 'v*'

Copilot uses AI. Check for mistakes.
pull_request:
branches: [ main ]

jobs:
lint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
Comment on lines +16 to +19
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lint job doesn't pin a Ruby version (unlike the test matrix), so it will run on whatever default Ruby happens to be on the runner. To keep lint results consistent (and compatible with the Ruby syntax used in this repo), set ruby-version explicitly here (and similarly in the publish job).

Copilot uses AI. Check for mistakes.

- name: Run RuboCop
run: bundle exec rubocop
Comment on lines +13 to +22
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The steps: blocks are not indented correctly: the list items (- uses, - name, etc.) are aligned with steps: instead of being nested under it. This makes the workflow YAML invalid and will prevent the jobs from running; indent each step list item under steps: (and apply consistently across lint, test, and publish).

Copilot uses AI. Check for mistakes.

test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['3.2', '3.3']

steps:
- uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true

- name: Run tests
run: bundle exec rake spec

publish:
needs: [lint, test]
runs-on: ubuntu-latest
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
packages: write

steps:
- uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true

- name: Build gem
run: bundle exec rake build

- name: Publish to GitHub Packages
run: |
mkdir -p ~/.gem
cat << EOF > ~/.gem/credentials
---
:github: Bearer ${GITHUB_TOKEN}
EOF
chmod 0600 ~/.gem/credentials
gem push --key github --host https://rubygems.pkg.github.com/RaspberryPiFoundation pkg/*.gem
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: pkg/*.gem
generate_release_notes: true
Comment on lines +73 to +77
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Create GitHub Release step is mis-indented relative to the publish job's steps: list (it appears outside the steps sequence). As written, the workflow will fail to parse or the step will be ignored; align it with the other - name: entries in the publish job.

Suggested change
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: pkg/*.gem
generate_release_notes: true
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: pkg/*.gem
generate_release_notes: true

Copilot uses AI. Check for mistakes.
7 changes: 3 additions & 4 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
AllCops:
TargetRubyVersion: 2.5
inherit_from: .rubocop_todo.yml

Metrics/LineLength:
Max: 120
AllCops:
NewCops: enable
75 changes: 75 additions & 0 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2026-02-12 17:07:44 UTC using RuboCop version 1.84.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 4
# Configuration parameters: EnforcedStyle, AllowedGems.
# SupportedStyles: Gemfile, gems.rb, gemspec
Gemspec/DevelopmentDependencies:
Exclude:
- 'kramdown_rpf.gemspec'

# Offense count: 1
Gemspec/RequiredRubyVersion:
Exclude:
- 'kramdown_rpf.gemspec'

# Offense count: 7
# Configuration parameters: AllowedMethods.
# AllowedMethods: enums
Lint/ConstantDefinitionInBlock:
Exclude:
- 'spec/errors_spec.rb'
- 'spec/i18n_spec.rb'
- 'spec/kramdown_rpf_spec.rb'

# Offense count: 3
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 33

# Offense count: 2
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
# AllowedMethods: refine
Metrics/BlockLength:
Max: 55

# Offense count: 1
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/CyclomaticComplexity:
Max: 13

# Offense count: 8
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
Metrics/MethodLength:
Max: 29

# Offense count: 1
# Configuration parameters: CountComments, CountAsOne.
Metrics/ModuleLength:
Max: 163

# Offense count: 1
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/PerceivedComplexity:
Max: 14

# Offense count: 6
# Configuration parameters: AllowedConstants.
Style/Documentation:
Exclude:
- 'spec/**/*'
- 'test/**/*'
- 'lib/kramdown_rpf/kramdown.rb'
- 'lib/kramdown_rpf/rpf.rb'

# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
# URISchemes: http, https
Layout/LineLength:
Max: 136
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ruby 2.7.2
ruby 3.2.7
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ source 'https://rubygems.org'

# Specify your gem's dependencies in kramdown_rpf.gemspec
gemspec

gem 'rubocop', '~> 1.84'
Comment on lines 6 to +8
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RuboCop is added directly to the Gemfile, while the rest of the development tooling dependencies are declared in the gemspec. For consistency (and so bundle exec rubocop works anywhere gemspec is used), consider moving this to spec.add_development_dependency 'rubocop' and keeping the Gemfile as just gemspec.

Copilot uses AI. Check for mistakes.
4 changes: 3 additions & 1 deletion kramdown_rpf.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ Gem::Specification.new do |spec|
# to allow pushing to a single host or delete this section to allow pushing to any host.
if spec.respond_to?(:metadata)
spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
spec.metadata['rubygems_mfa_required'] = 'true'
else
raise 'RubyGems 2.0 or newer is required to protect against ' \
'public gem pushes.'
'public gem pushes.'
end

spec.files = `git ls-files -z`.split("\x0").reject do |f|
Expand All @@ -31,6 +32,7 @@ Gem::Specification.new do |spec|

spec.add_dependency 'i18n', '0.8.6'
spec.add_dependency 'kramdown', '~> 1.2', '>= 1.2.0'
spec.add_dependency 'rexml', '~> 3.4'

Comment on lines +35 to 36
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rexml is added as a runtime dependency, but there are no references to it in the library code. If this is only needed for development tooling/transitive security pinning, prefer a development dependency (or document why consumers need it), otherwise this unnecessarily expands the gem’s runtime dependency surface.

Suggested change
spec.add_dependency 'rexml', '~> 3.4'
spec.add_development_dependency 'rexml', '~> 3.4'

Copilot uses AI. Check for mistakes.
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'byebug'
Expand Down
26 changes: 13 additions & 13 deletions lib/kramdown_rpf/kramdown.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def convert_task(element, _indent)
end

module RaiseNotImplementedForUndefinedConvertMethods
def method_missing(method_name, *args, &block)
def method_missing(method_name, *args, &)
raise NotImplementedError if method_name.to_s.start_with?('convert_')

super
Expand Down Expand Up @@ -116,18 +116,18 @@ class KramdownRPF < ::Kramdown::Parser::GFM
task
].freeze

CHALLENGE_PATTERN = %r{^#{OPT_SPACE}---[ \t]*challenge[ \t]*---(.*?)---[ \t]*\/challenge[ \t]*---}m.freeze
CODE_PATTERN = %r{^#{OPT_SPACE}---[ \t]*code[ \t]*---(.*?)---[ \t]*\/code[ \t]*---}m.freeze
COLLAPSE_PATTERN = %r{^#{OPT_SPACE}---[ \t]*collapse[ \t]*---(.*?)---[ \t]*\/collapse[ \t]*---}m.freeze
HINT_PATTERN = %r{^#{OPT_SPACE}---[ \t]*hint[ \t]*---(.*?)---[ \t]*\/hint[ \t]*---}m.freeze
HINTS_PATTERN = %r{^#{OPT_SPACE}---[ \t]*hints[ \t]*---(.*?)---[ \t]*\/hints[ \t]*---}m.freeze
NEW_PAGE_PATTERN = /^#{OPT_SPACE}---[ \t]*new-page[ \t]*---/m.freeze
NO_PRINT_PATTERN = %r{^#{OPT_SPACE}---[ \t]*no-print[ \t]*---(.*?)---[ \t]*\/no-print[ \t]*---}m.freeze
PRINT_ONLY_PATTERN = %r{^#{OPT_SPACE}---[ \t]*print-only[ \t]*---(.*?)---[ \t]*\/print-only[ \t]*---}m.freeze
KNOWLEDGE_QUIZ_QUESTION_PATTERN = %r{^#{OPT_SPACE}---[ \t]*question[ \t]*---(.*?)---[ \t]*\/question[ \t]*---}m.freeze
QUIZ_PATTERN = %r{^#{OPT_SPACE}---[ \t]*quiz[ \t]*---(.*?)---[ \t]*\/quiz[ \t]*---}m.freeze
SAVE_PATTERN = /^#{OPT_SPACE}---[ \t]*save[ \t]*---/m.freeze
TASK_PATTERN = %r{^#{OPT_SPACE}---[ \t]*task[ \t]*---(.*?)---[ \t]*\/task[ \t]*---}m.freeze
CHALLENGE_PATTERN = %r{^#{OPT_SPACE}---[ \t]*challenge[ \t]*---(.*?)---[ \t]*/challenge[ \t]*---}m
CODE_PATTERN = %r{^#{OPT_SPACE}---[ \t]*code[ \t]*---(.*?)---[ \t]*/code[ \t]*---}m
COLLAPSE_PATTERN = %r{^#{OPT_SPACE}---[ \t]*collapse[ \t]*---(.*?)---[ \t]*/collapse[ \t]*---}m
HINT_PATTERN = %r{^#{OPT_SPACE}---[ \t]*hint[ \t]*---(.*?)---[ \t]*/hint[ \t]*---}m
HINTS_PATTERN = %r{^#{OPT_SPACE}---[ \t]*hints[ \t]*---(.*?)---[ \t]*/hints[ \t]*---}m
NEW_PAGE_PATTERN = /^#{OPT_SPACE}---[ \t]*new-page[ \t]*---/m
NO_PRINT_PATTERN = %r{^#{OPT_SPACE}---[ \t]*no-print[ \t]*---(.*?)---[ \t]*/no-print[ \t]*---}m
PRINT_ONLY_PATTERN = %r{^#{OPT_SPACE}---[ \t]*print-only[ \t]*---(.*?)---[ \t]*/print-only[ \t]*---}m
KNOWLEDGE_QUIZ_QUESTION_PATTERN = %r{^#{OPT_SPACE}---[ \t]*question[ \t]*---(.*?)---[ \t]*/question[ \t]*---}m
QUIZ_PATTERN = %r{^#{OPT_SPACE}---[ \t]*quiz[ \t]*---(.*?)---[ \t]*/quiz[ \t]*---}m
SAVE_PATTERN = /^#{OPT_SPACE}---[ \t]*save[ \t]*---/m
TASK_PATTERN = %r{^#{OPT_SPACE}---[ \t]*task[ \t]*---(.*?)---[ \t]*/task[ \t]*---}m

def initialize(source, options)
super
Expand Down
20 changes: 10 additions & 10 deletions lib/kramdown_rpf/rpf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
module RPF
module Plugin
module Kramdown
YAML_FRONT_MATTER_REGEXP = /\n\s*---\s*\n(.*?)---(.*)/m.freeze
YAML_FRONT_MATTER_REGEXP = /\n\s*---\s*\n(.*?)---(.*)/m
VALID_CHECK_MARKS = %w[* x].freeze
QUESTION_REGEXP = %r{(.*?)^#{::Kramdown::Parser::Kramdown::OPT_SPACE}---[ \t]*choices[ \t]*---(.*?)---[ \t]*\/choices[ \t]*---}m.freeze
RADIO_REGEXP = /\((?:\s?|(?<check>[#{VALID_CHECK_MARKS.join}]?))\)\s*(?<text>.*)/m.freeze
CHOICE_BLOCK_REGEXP = /^(?=#{::Kramdown::Parser::Kramdown::OPT_SPACE}- \([\s#{VALID_CHECK_MARKS.join}]?\)\s*.*)/m.freeze
CHOICE_FEEDBACK_REGEXP = %r{#{::Kramdown::Parser::Kramdown::OPT_SPACE}---[ \t]*feedback[ \t]*---(.*?)---[ \t]*\/feedback[ \t]*---}m.freeze
SINGLE_FEEDBACK_REGEXP = /\A#{CHOICE_FEEDBACK_REGEXP}/m.freeze
QUESTION_REGEXP = %r{(.*?)^#{::Kramdown::Parser::Kramdown::OPT_SPACE}---[ \t]*choices[ \t]*---(.*?)---[ \t]*/choices[ \t]*---}m
RADIO_REGEXP = /\((?:\s?|(?<check>[#{VALID_CHECK_MARKS.join}]?))\)\s*(?<text>.*)/m
CHOICE_BLOCK_REGEXP = /^(?=#{::Kramdown::Parser::Kramdown::OPT_SPACE}- \([\s#{VALID_CHECK_MARKS.join}]?\)\s*.*)/m
CHOICE_FEEDBACK_REGEXP = %r{#{::Kramdown::Parser::Kramdown::OPT_SPACE}---[ \t]*feedback[ \t]*---(.*?)---[ \t]*/feedback[ \t]*---}m
SINGLE_FEEDBACK_REGEXP = /\A#{CHOICE_FEEDBACK_REGEXP}/m

KRAMDOWN_OPTIONS = {
input: 'KramdownRPF',
Expand All @@ -38,11 +38,11 @@ def self.convert_code_to_html(code_block)

if filename
filename_html = <<~HEREDOC
<div class=\"c-code-filename\">
<div class="c-code-filename">
#{filename}
</div>
HEREDOC
.strip
.strip
end

if line_numbers
Expand All @@ -54,7 +54,7 @@ def self.convert_code_to_html(code_block)
pre_attrs << "data-line-offset=\"#{line_number_start}\"" if line_highlights && line_number_start
pre_attrs << "data-line=\"#{line_highlights}\"" if line_highlights

pre_attrs_html = ' ' + pre_attrs.join(' ') if pre_attrs.size.positive?
pre_attrs_html = " #{pre_attrs.join(' ')}" if pre_attrs.size.positive?

<<~HEREDOC
#{filename_html}
Expand Down Expand Up @@ -234,7 +234,7 @@ def self.convert_label_to_html(label, index, checked)
number = index + 1
<<~HEREDOC
<div class="knowledge-quiz-question__answer">
<input type="radio" name="answer" value="#{number}" id="choice-#{number}" #{checked ? 'checked' : ''}/>
<input type="radio" name="answer" value="#{number}" id="choice-#{number}" #{'checked' if checked}/>
<label for="choice-#{number}">#{::Kramdown::Document.new(label, KRAMDOWN_OPTIONS).to_html.strip}</label>
</div>
HEREDOC
Expand Down
4 changes: 3 additions & 1 deletion lib/kramdown_rpf/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

module KramdownRPF
VERSION = '0.11.8'.freeze
VERSION = '0.11.8'
end
Loading