From 3c9948a80d45540603ef3cd6a6ca831019ea8102 Mon Sep 17 00:00:00 2001 From: Gil Desmarais Date: Tue, 10 Mar 2026 18:21:06 +0100 Subject: [PATCH 1/6] feat(devx): add config validation workflow --- bin/setup | 2 +- bin/validate_configs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/setup b/bin/setup index 935796b..243eb57 100755 --- a/bin/setup +++ b/bin/setup @@ -7,7 +7,7 @@ bundle install echo echo "==> Installing Node dependencies (required for make lint)..." -npm install --ignore-scripts --no-fund --no-audit +npm ci --ignore-scripts --no-fund --no-audit echo echo "==> Checking system tools..." diff --git a/bin/validate_configs b/bin/validate_configs index 4fef430..1839cba 100755 --- a/bin/validate_configs +++ b/bin/validate_configs @@ -5,6 +5,12 @@ require 'bundler/setup' require 'html2rss' require 'yaml' +unless Html2rss::Config.respond_to?(:validate) + warn 'Error: installed html2rss gem does not support Config.validate.' + warn 'Run: bundle update html2rss' + exit 1 +end + files = Dir['lib/html2rss/configs/**/*.yml'] failed = [] From f84c6eba1c43590bb5d345371123bc5b9fc2e4d4 Mon Sep 17 00:00:00 2001 From: Gil Desmarais Date: Tue, 10 Mar 2026 18:32:40 +0100 Subject: [PATCH 2/6] fix(devx): pin prettier and harden config validation --- bin/validate_configs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/bin/validate_configs b/bin/validate_configs index 1839cba..0465fe0 100755 --- a/bin/validate_configs +++ b/bin/validate_configs @@ -15,26 +15,28 @@ files = Dir['lib/html2rss/configs/**/*.yml'] failed = [] files.each do |file| - config = YAML.safe_load_file(file, symbolize_names: true) - result = Html2rss::Config.validate(config) + begin + config = YAML.safe_load_file(file, symbolize_names: true) + result = Html2rss::Config.validate(config) - if result.success? - puts "ok #{file}" - else - puts "FAIL #{file}" - result.errors.to_h.each do |key, messages| - Array(messages).each { |msg| warn " #{key}: #{msg}" } + if result.success? + puts "ok #{file}" + else + puts "FAIL #{file}" + result.errors.to_h.each do |key, messages| + Array(messages).each { |msg| warn " #{key}: #{msg}" } + end + failed << file end + rescue Psych::Exception => e + puts "FAIL #{file}" + warn " parse: #{e.message}" + failed << file + rescue StandardError => e + puts "FAIL #{file}" + warn " validation: #{e.class}: #{e.message}" failed << file end -rescue Psych::Exception => error - puts "FAIL #{file}" - warn " parse: #{error.message}" - failed << file -rescue StandardError => error - puts "FAIL #{file}" - warn " validation: #{error.class}: #{error.message}" - failed << file end puts From 8cd8210914b7fa88542e750e3bf2f8cd2c79bf11 Mon Sep 17 00:00:00 2001 From: Gil Desmarais Date: Tue, 10 Mar 2026 18:41:59 +0100 Subject: [PATCH 3/6] fix(ci): skip schema-only changed config fetch tests --- bin/rspec_changed_configs | 4 ++-- bin/validate_configs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/rspec_changed_configs b/bin/rspec_changed_configs index 4bed75e..db46eb1 100755 --- a/bin/rspec_changed_configs +++ b/bin/rspec_changed_configs @@ -13,8 +13,8 @@ def comment_only_change?(file) end changed_files = `git diff --name-only origin/master` - .split("\n") - .grep(CONFIG_PATH) + .split("\n") + .grep(CONFIG_PATH) test_files = changed_files.reject { |file| comment_only_change?(file) } diff --git a/bin/validate_configs b/bin/validate_configs index 0465fe0..eb0a2d0 100755 --- a/bin/validate_configs +++ b/bin/validate_configs @@ -28,13 +28,13 @@ files.each do |file| end failed << file end - rescue Psych::Exception => e + rescue Psych::Exception => error puts "FAIL #{file}" - warn " parse: #{e.message}" + warn " parse: #{error.message}" failed << file - rescue StandardError => e + rescue StandardError => error puts "FAIL #{file}" - warn " validation: #{e.class}: #{e.message}" + warn " validation: #{error.class}: #{error.message}" failed << file end end From 14dc7fbc7d6bd1909fe5fa6a9c6a862901da4ea9 Mon Sep 17 00:00:00 2001 From: Gil Desmarais Date: Tue, 10 Mar 2026 22:05:03 +0100 Subject: [PATCH 4/6] Fix RuboCop CI warnings --- bin/rspec_changed_configs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/rspec_changed_configs b/bin/rspec_changed_configs index db46eb1..4bed75e 100755 --- a/bin/rspec_changed_configs +++ b/bin/rspec_changed_configs @@ -13,8 +13,8 @@ def comment_only_change?(file) end changed_files = `git diff --name-only origin/master` - .split("\n") - .grep(CONFIG_PATH) + .split("\n") + .grep(CONFIG_PATH) test_files = changed_files.reject { |file| comment_only_change?(file) } From 8eace2505fe27eb384f6022df0af717cc6b37973 Mon Sep 17 00:00:00 2001 From: Gil Desmarais Date: Tue, 10 Mar 2026 23:13:19 +0100 Subject: [PATCH 5/6] fix(validation): use runtime config validation entrypoint --- bin/validate_configs | 8 ++---- spec/bin/validate_configs_spec.rb | 48 +++++++++++++++++++++++++++++++ spec/spec_helper.rb | 4 +++ 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 spec/bin/validate_configs_spec.rb diff --git a/bin/validate_configs b/bin/validate_configs index eb0a2d0..be5e4dc 100755 --- a/bin/validate_configs +++ b/bin/validate_configs @@ -3,10 +3,9 @@ require 'bundler/setup' require 'html2rss' -require 'yaml' -unless Html2rss::Config.respond_to?(:validate) - warn 'Error: installed html2rss gem does not support Config.validate.' +unless Html2rss::Config.respond_to?(:validate_yaml) + warn 'Error: installed html2rss gem does not support Config.validate_yaml.' warn 'Run: bundle update html2rss' exit 1 end @@ -16,8 +15,7 @@ failed = [] files.each do |file| begin - config = YAML.safe_load_file(file, symbolize_names: true) - result = Html2rss::Config.validate(config) + result = Html2rss::Config.validate_yaml(file) if result.success? puts "ok #{file}" diff --git a/spec/bin/validate_configs_spec.rb b/spec/bin/validate_configs_spec.rb new file mode 100644 index 0000000..57a7ae7 --- /dev/null +++ b/spec/bin/validate_configs_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'fileutils' +require 'stringio' +require 'tmpdir' + +RSpec.describe 'bin/validate_configs' do + let(:script_path) { File.expand_path('../../bin/validate_configs', __dir__) } + + it 'passes validation for parameterized configs when defaults are present' do + config = <<~YAML + parameters: + query: + type: string + default: ruby + headers: + X-Query: "%s" + channel: + url: "https://example.com/search?q=%s" + selectors: + items: + selector: ".item" + title: + selector: "h2" + YAML + + Dir.mktmpdir do |dir| + FileUtils.mkdir_p(File.join(dir, 'lib', 'html2rss', 'configs', 'example.com')) + File.write(File.join(dir, 'lib', 'html2rss', 'configs', 'example.com', 'search.yml'), config) + + stdout = StringIO.new + stderr = StringIO.new + original_stdout = $stdout + original_stderr = $stderr + $stdout = stdout + $stderr = stderr + + Dir.chdir(dir) { load script_path } + + expect(stdout.string).to include('ok lib/html2rss/configs/example.com/search.yml') + expect(stdout.string).to include('1 configs validated successfully.') + expect(stderr.string).to be_empty + ensure + $stdout = original_stdout + $stderr = original_stderr + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0c977d5..a647565 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,6 +2,10 @@ require 'bundler/setup' require 'tzinfo' + +local_html2rss_lib = File.expand_path('../../html2rss/lib', __dir__) +$LOAD_PATH.unshift(local_html2rss_lib) if File.directory?(local_html2rss_lib) + require 'html2rss' require 'html2rss/configs' From 3fc0e81e7e602c0fe7ebc5ae108198d7850e6b22 Mon Sep 17 00:00:00 2001 From: Gil Desmarais Date: Sat, 14 Mar 2026 13:35:16 +0100 Subject: [PATCH 6/6] style: fixes --- Gemfile | 1 - Gemfile.lock | 4 +-- bin/validate_configs | 32 +++++++++--------- spec/bin/validate_configs_spec.rb | 56 ++++++++++++++++++------------- spec/spec_helper.rb | 3 -- 5 files changed, 49 insertions(+), 47 deletions(-) diff --git a/Gemfile b/Gemfile index be260aa..104f863 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,6 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } gem 'html2rss', github: 'html2rss/html2rss', branch: :master group :development do - # gem 'html2rss-generator', path: '../generator' gem 'html2rss-generator', github: 'html2rss/generator', branch: :main gem 'nokogiri' diff --git a/Gemfile.lock b/Gemfile.lock index 7c32dfc..babf2a0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -12,7 +12,7 @@ GIT GIT remote: https://github.com/html2rss/html2rss - revision: 762a09c15e5def5897b2d08f0e3c11c023cc9b35 + revision: e0dca5bf74b17c1e2a0618fc0a4af27c16da1883 branch: master specs: html2rss (0.17.0) @@ -224,7 +224,7 @@ GEM rubocop-ast (>= 1.49.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.49.0) + rubocop-ast (1.49.1) parser (>= 3.3.7.2) prism (~> 1.7) rubocop-performance (1.26.1) diff --git a/bin/validate_configs b/bin/validate_configs index be5e4dc..13442e9 100755 --- a/bin/validate_configs +++ b/bin/validate_configs @@ -14,27 +14,25 @@ files = Dir['lib/html2rss/configs/**/*.yml'] failed = [] files.each do |file| - begin - result = Html2rss::Config.validate_yaml(file) + result = Html2rss::Config.validate_yaml(file) - if result.success? - puts "ok #{file}" - else - puts "FAIL #{file}" - result.errors.to_h.each do |key, messages| - Array(messages).each { |msg| warn " #{key}: #{msg}" } - end - failed << file - end - rescue Psych::Exception => error - puts "FAIL #{file}" - warn " parse: #{error.message}" - failed << file - rescue StandardError => error + if result.success? + puts "ok #{file}" + else puts "FAIL #{file}" - warn " validation: #{error.class}: #{error.message}" + result.errors.to_h.each do |key, messages| + Array(messages).each { |msg| warn " #{key}: #{msg}" } + end failed << file end +rescue Psych::Exception => error + puts "FAIL #{file}" + warn " parse: #{error.message}" + failed << file +rescue StandardError => error + puts "FAIL #{file}" + warn " validation: #{error.class}: #{error.message}" + failed << file end puts diff --git a/spec/bin/validate_configs_spec.rb b/spec/bin/validate_configs_spec.rb index 57a7ae7..cb8aa07 100644 --- a/spec/bin/validate_configs_spec.rb +++ b/spec/bin/validate_configs_spec.rb @@ -1,14 +1,43 @@ # frozen_string_literal: true require 'fileutils' -require 'stringio' require 'tmpdir' -RSpec.describe 'bin/validate_configs' do +RSpec.describe 'bin/validate_configs' do # rubocop:disable RSpec/DescribeClass let(:script_path) { File.expand_path('../../bin/validate_configs', __dir__) } + let(:config_path) { File.join('lib', 'html2rss', 'configs', 'example.com', 'search.yml') } + let(:success_output) do + a_string_including( + "ok #{config_path}", + '1 configs validated successfully.' + ) + end it 'passes validation for parameterized configs when defaults are present' do - config = <<~YAML + with_temp_config do |dir| + expect { run_script(dir) }.to output(success_output).to_stdout + .and output('').to_stderr + end + end + + def with_temp_config + Dir.mktmpdir do |dir| + write_config(dir) + yield dir + end + end + + def write_config(dir) + FileUtils.mkdir_p(File.join(dir, File.dirname(config_path))) + File.write(File.join(dir, config_path), valid_config) + end + + def run_script(dir) + Dir.chdir(dir) { load script_path } + end + + def valid_config + <<~YAML parameters: query: type: string @@ -23,26 +52,5 @@ title: selector: "h2" YAML - - Dir.mktmpdir do |dir| - FileUtils.mkdir_p(File.join(dir, 'lib', 'html2rss', 'configs', 'example.com')) - File.write(File.join(dir, 'lib', 'html2rss', 'configs', 'example.com', 'search.yml'), config) - - stdout = StringIO.new - stderr = StringIO.new - original_stdout = $stdout - original_stderr = $stderr - $stdout = stdout - $stderr = stderr - - Dir.chdir(dir) { load script_path } - - expect(stdout.string).to include('ok lib/html2rss/configs/example.com/search.yml') - expect(stdout.string).to include('1 configs validated successfully.') - expect(stderr.string).to be_empty - ensure - $stdout = original_stdout - $stderr = original_stderr - end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a647565..98fb42e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,9 +3,6 @@ require 'bundler/setup' require 'tzinfo' -local_html2rss_lib = File.expand_path('../../html2rss/lib', __dir__) -$LOAD_PATH.unshift(local_html2rss_lib) if File.directory?(local_html2rss_lib) - require 'html2rss' require 'html2rss/configs'