From bf602b1b39c5f433ef71aec599f995be4f55704c Mon Sep 17 00:00:00 2001 From: Patrick Cherry Date: Thu, 12 Feb 2026 16:56:17 +0000 Subject: [PATCH 1/6] Move CI to github --- .circleci/config.yml | 24 ------------ .github/workflows/ci.yml | 81 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 24 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/workflows/ci.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 5db364e..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: cimg/ruby:2.7.2 - environment: - RAILS_ENV: test - steps: - - checkout - - # Which version of bundler? - - run: - name: Which bundler? - command: bundle -v - - - run: - name: Bundle Install - command: bundle check || bundle install - - # Run rspec - - run: - name: Run rspec - command: | - bundle exec rspec diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9642844 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,81 @@ +name: CI + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + + - name: Run RuboCop + run: bundle exec rubocop + + test: + runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: ['2.7', '3.0', '3.1', '3.2'] + + 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: + ruby-version: '3.2' + 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 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 5bd666f50bed179bc4b003ccc2770c96a2d79975 Mon Sep 17 00:00:00 2001 From: Patrick Cherry Date: Thu, 12 Feb 2026 17:00:23 +0000 Subject: [PATCH 2/6] Move to Ruby 3.2 --- .github/workflows/ci.yml | 4 +--- .tool-versions | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9642844..5014946 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,6 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.2' bundler-cache: true - name: Run RuboCop @@ -26,7 +25,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['2.7', '3.0', '3.1', '3.2'] + ruby-version: ['3.2', '3.3'] steps: - uses: actions/checkout@v4 @@ -54,7 +53,6 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.2' bundler-cache: true - name: Build gem diff --git a/.tool-versions b/.tool-versions index 9eb38ed..9c68d12 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -ruby 2.7.2 +ruby 3.2.7 From 20003a606bbcb6c4aa1b59adfc2a9f8aa93f59b6 Mon Sep 17 00:00:00 2001 From: Patrick Cherry Date: Thu, 12 Feb 2026 17:03:40 +0000 Subject: [PATCH 3/6] Added Rubocop --- .rubocop.yml | 8 ++-- .rubocop_todo.yml | 82 ++++++++++++++++++++++++++++++++++++ Gemfile | 2 + kramdown_rpf.gemspec | 3 +- lib/kramdown_rpf/kramdown.rb | 26 ++++++------ lib/kramdown_rpf/rpf.rb | 20 ++++----- lib/kramdown_rpf/version.rb | 4 +- 7 files changed, 117 insertions(+), 28 deletions(-) create mode 100644 .rubocop_todo.yml diff --git a/.rubocop.yml b/.rubocop.yml index 148986c..88f4e2e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,7 @@ -AllCops: - TargetRubyVersion: 2.5 +inherit_from: .rubocop_todo.yml -Metrics/LineLength: +Layout/LineLength: Max: 120 + +AllCops: + NewCops: enable diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 0000000..4eb1fed --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,82 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2026-02-12 17:03:03 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: 2 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings. +# URISchemes: http, https +Layout/LineLength: + Max: 136 + +# 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 diff --git a/Gemfile b/Gemfile index adc17f5..f9fae16 100644 --- a/Gemfile +++ b/Gemfile @@ -4,3 +4,5 @@ source 'https://rubygems.org' # Specify your gem's dependencies in kramdown_rpf.gemspec gemspec + +gem 'rubocop', '~> 1.84' diff --git a/kramdown_rpf.gemspec b/kramdown_rpf.gemspec index 98ecc8d..d7f558c 100644 --- a/kramdown_rpf.gemspec +++ b/kramdown_rpf.gemspec @@ -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| diff --git a/lib/kramdown_rpf/kramdown.rb b/lib/kramdown_rpf/kramdown.rb index 1fdb293..91039b0 100644 --- a/lib/kramdown_rpf/kramdown.rb +++ b/lib/kramdown_rpf/kramdown.rb @@ -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 @@ -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 diff --git a/lib/kramdown_rpf/rpf.rb b/lib/kramdown_rpf/rpf.rb index 794eca4..ad0a4a3 100644 --- a/lib/kramdown_rpf/rpf.rb +++ b/lib/kramdown_rpf/rpf.rb @@ -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?|(?[#{VALID_CHECK_MARKS.join}]?))\)\s*(?.*)/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?|(?[#{VALID_CHECK_MARKS.join}]?))\)\s*(?.*)/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', @@ -38,11 +38,11 @@ def self.convert_code_to_html(code_block) if filename filename_html = <<~HEREDOC -
+
#{filename}
HEREDOC - .strip + .strip end if line_numbers @@ -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} @@ -234,7 +234,7 @@ def self.convert_label_to_html(label, index, checked) number = index + 1 <<~HEREDOC
- +
HEREDOC diff --git a/lib/kramdown_rpf/version.rb b/lib/kramdown_rpf/version.rb index 48cdd67..9ce8605 100644 --- a/lib/kramdown_rpf/version.rb +++ b/lib/kramdown_rpf/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module KramdownRPF - VERSION = '0.11.8'.freeze + VERSION = '0.11.8' end From 99bb47851c0174f0ddcd2dded04b5ffcf1680c20 Mon Sep 17 00:00:00 2001 From: Patrick Cherry Date: Thu, 12 Feb 2026 17:05:24 +0000 Subject: [PATCH 4/6] Add Rexml as a specific dependency --- kramdown_rpf.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/kramdown_rpf.gemspec b/kramdown_rpf.gemspec index d7f558c..bd20704 100644 --- a/kramdown_rpf.gemspec +++ b/kramdown_rpf.gemspec @@ -32,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' spec.add_development_dependency 'bundler' spec.add_development_dependency 'byebug' From b1bda5258352993f270dc191de2096abe0b74052 Mon Sep 17 00:00:00 2001 From: Patrick Cherry Date: Thu, 12 Feb 2026 17:07:50 +0000 Subject: [PATCH 5/6] Update Rubocop config + todo --- .rubocop.yml | 3 --- .rubocop_todo.yml | 9 +-------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 88f4e2e..2cac09a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,4 @@ inherit_from: .rubocop_todo.yml -Layout/LineLength: - Max: 120 - AllCops: NewCops: enable diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 4eb1fed..90db122 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2026-02-12 17:03:03 UTC using RuboCop version 1.84.2. +# 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 @@ -18,13 +18,6 @@ Gemspec/RequiredRubyVersion: Exclude: - 'kramdown_rpf.gemspec' -# 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 - # Offense count: 7 # Configuration parameters: AllowedMethods. # AllowedMethods: enums From 2fd888afd785ce81a00f09af5fe9c7d77c27abaa Mon Sep 17 00:00:00 2001 From: Patrick Cherry Date: Thu, 12 Feb 2026 17:13:25 +0000 Subject: [PATCH 6/6] Tweak CI --- .github/workflows/ci.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5014946..b11a6e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ main, master ] + branches: [ main ] pull_request: - branches: [ main, master ] + branches: [ main ] jobs: lint: @@ -70,10 +70,8 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Create GitHub Release - uses: softprops/action-gh-release@v1 - with: - files: pkg/*.gem - generate_release_notes: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + files: pkg/*.gem + generate_release_notes: true