diff --git a/.circleci/config.yml b/.circleci/config.yml index 903f5a39d6..a59ac5bdb5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,7 +14,7 @@ executors: docker: # Remember to update to the latest image tag. # Run `source scripts/functions.sh && docker_image Dockerfile` to print it. - - image: cucumber/cucumber-build:9ce5f6a542de12ceecdd84caaad47365 + - image: cucumber/cucumber-build:7e07f786ac72e3597a8e5bbe435b4c90 working_directory: ~/cucumber # Go docker-circleci-golang: @@ -397,7 +397,7 @@ jobs: - persist_to_workspace: root: ~/cucumber paths: - - cucumber-messages/ruby/lib/cucumber/messages_pb.rb + - cucumber-messages/ruby gherkin-ruby-23: executor: docker-circleci-ruby-23 diff --git a/.templates/ruby/Rakefile b/.templates/ruby/Rakefile index e14df3b2fd..1a3a0f07e6 100644 --- a/.templates/ruby/Rakefile +++ b/.templates/ruby/Rakefile @@ -5,6 +5,10 @@ Bundler::GemHelper.install_tasks $:.unshift File.expand_path("../lib", __FILE__) +Dir['./rake/*.rb'].each do |f| + require f +end + require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-r./spec/coverage -w] diff --git a/Dockerfile b/Dockerfile index f3c04e29f0..6dfe931f86 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,7 @@ RUN apk add --no-cache \ py2-pip \ rsync \ ruby \ + ruby-bigdecimal \ ruby-dev \ sed \ su-exec \ diff --git a/c21e/ruby/Rakefile b/c21e/ruby/Rakefile index e14df3b2fd..1a3a0f07e6 100644 --- a/c21e/ruby/Rakefile +++ b/c21e/ruby/Rakefile @@ -5,6 +5,10 @@ Bundler::GemHelper.install_tasks $:.unshift File.expand_path("../lib", __FILE__) +Dir['./rake/*.rb'].each do |f| + require f +end + require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-r./spec/coverage -w] diff --git a/cucumber-demo-formatter/ruby/Rakefile b/cucumber-demo-formatter/ruby/Rakefile index e14df3b2fd..1a3a0f07e6 100644 --- a/cucumber-demo-formatter/ruby/Rakefile +++ b/cucumber-demo-formatter/ruby/Rakefile @@ -5,6 +5,10 @@ Bundler::GemHelper.install_tasks $:.unshift File.expand_path("../lib", __FILE__) +Dir['./rake/*.rb'].each do |f| + require f +end + require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-r./spec/coverage -w] diff --git a/cucumber-demo-formatter/ruby/bin/cucumber-demo-formatter b/cucumber-demo-formatter/ruby/bin/cucumber-demo-formatter index ed5f334615..ae730fd217 100755 --- a/cucumber-demo-formatter/ruby/bin/cucumber-demo-formatter +++ b/cucumber-demo-formatter/ruby/bin/cucumber-demo-formatter @@ -8,7 +8,7 @@ require 'cucumber_demo_formatter' ARGV << '-h' if ARGV.empty? option_parser = OptionParser.new do |opts| - opts.on '-f', '--format=ndjson|protobuf', 'Output format' + opts.on '-f', '--format=ndjson|protobuf', 'Input format' opts.on_tail("-h", "--help", "Show this message") do puts opts @@ -29,4 +29,4 @@ else raise "Unsupported format: '#{format}'" end -formatter.process_messages(message_enumerator, STDOUT) \ No newline at end of file +formatter.process_messages(message_enumerator, STDOUT) diff --git a/cucumber-demo-formatter/ruby/lib/cucumber_demo_formatter.rb b/cucumber-demo-formatter/ruby/lib/cucumber_demo_formatter.rb index a6897d8296..3780bdd837 100644 --- a/cucumber-demo-formatter/ruby/lib/cucumber_demo_formatter.rb +++ b/cucumber-demo-formatter/ruby/lib/cucumber_demo_formatter.rb @@ -3,21 +3,24 @@ class CucumberDemoFormatter def process_messages(message_enumerator, output) emoji = { - UNKNOWN: '👽', - PASSED: '😃', - SKIPPED: '🥶', - PENDING: '⏰', - UNDEFINED: '🤷', - AMBIGUOUS: '🦄', - FAILED: '💣', + ::Cucumber::Messages::TestResult::Status::UNKNOWN => '👽', + ::Cucumber::Messages::TestResult::Status::PASSED => '😃', + ::Cucumber::Messages::TestResult::Status::SKIPPED => '🥶', + ::Cucumber::Messages::TestResult::Status::PENDING => '⏰', + ::Cucumber::Messages::TestResult::Status::UNDEFINED => '🤷', + ::Cucumber::Messages::TestResult::Status::AMBIGUOUS => '🦄', + ::Cucumber::Messages::TestResult::Status::FAILED => '💣', } message_enumerator.each do |message| if message.test_step_finished - output.write(emoji[message.test_step_finished.test_result.status]) + status = message.test_step_finished.test_result.status + em = emoji[status] + raise "No emoji found for status #{status}" if em.nil? + output.write(em) end if message.test_run_finished output.write("\n") end end end -end \ No newline at end of file +end diff --git a/cucumber-expressions/ruby/Rakefile b/cucumber-expressions/ruby/Rakefile index e14df3b2fd..1a3a0f07e6 100644 --- a/cucumber-expressions/ruby/Rakefile +++ b/cucumber-expressions/ruby/Rakefile @@ -5,6 +5,10 @@ Bundler::GemHelper.install_tasks $:.unshift File.expand_path("../lib", __FILE__) +Dir['./rake/*.rb'].each do |f| + require f +end + require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-r./spec/coverage -w] diff --git a/cucumber-json-formatter/ruby/Rakefile b/cucumber-json-formatter/ruby/Rakefile index e14df3b2fd..1a3a0f07e6 100644 --- a/cucumber-json-formatter/ruby/Rakefile +++ b/cucumber-json-formatter/ruby/Rakefile @@ -5,6 +5,10 @@ Bundler::GemHelper.install_tasks $:.unshift File.expand_path("../lib", __FILE__) +Dir['./rake/*.rb'].each do |f| + require f +end + require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-r./spec/coverage -w] diff --git a/cucumber-messages/dotnet/messages.proto b/cucumber-messages/dotnet/messages.proto index c3e5e60c55..ecf3447290 100644 --- a/cucumber-messages/dotnet/messages.proto +++ b/cucumber-messages/dotnet/messages.proto @@ -1,6 +1,5 @@ syntax = "proto3"; package io.cucumber.messages; -option ruby_package = "Cucumber::Messages"; option go_package = "messages"; // When removing a field, replace it with reserved, rather than deleting the line. @@ -426,13 +425,13 @@ message TestCase { string pickle_step_id = 2; // Pointer to all the matching `StepDefinition`s (if derived from a PickleStep) repeated string step_definition_ids = 3; - // A list of list of StepMatchArgument (if derived from a `StepDefinition`). + // A list of list of StepMatchArgument (if derived from a `StepDefinition`). // Each element represents a matching step definition. A size of 0 means `UNDEFINED`, // and a size of 2+ means `AMBIGUOUS` repeated StepMatchArgumentsList step_match_arguments_lists = 4; // Pointer to the `Hook` (if derived from a Hook) string hook_id = 5; - + message StepMatchArgumentsList { repeated StepMatchArgument step_match_arguments = 1; } diff --git a/cucumber-messages/go/messages.proto b/cucumber-messages/go/messages.proto index c3e5e60c55..ecf3447290 100644 --- a/cucumber-messages/go/messages.proto +++ b/cucumber-messages/go/messages.proto @@ -1,6 +1,5 @@ syntax = "proto3"; package io.cucumber.messages; -option ruby_package = "Cucumber::Messages"; option go_package = "messages"; // When removing a field, replace it with reserved, rather than deleting the line. @@ -426,13 +425,13 @@ message TestCase { string pickle_step_id = 2; // Pointer to all the matching `StepDefinition`s (if derived from a PickleStep) repeated string step_definition_ids = 3; - // A list of list of StepMatchArgument (if derived from a `StepDefinition`). + // A list of list of StepMatchArgument (if derived from a `StepDefinition`). // Each element represents a matching step definition. A size of 0 means `UNDEFINED`, // and a size of 2+ means `AMBIGUOUS` repeated StepMatchArgumentsList step_match_arguments_lists = 4; // Pointer to the `Hook` (if derived from a Hook) string hook_id = 5; - + message StepMatchArgumentsList { repeated StepMatchArgument step_match_arguments = 1; } diff --git a/cucumber-messages/java/messages.proto b/cucumber-messages/java/messages.proto index c3e5e60c55..ecf3447290 100644 --- a/cucumber-messages/java/messages.proto +++ b/cucumber-messages/java/messages.proto @@ -1,6 +1,5 @@ syntax = "proto3"; package io.cucumber.messages; -option ruby_package = "Cucumber::Messages"; option go_package = "messages"; // When removing a field, replace it with reserved, rather than deleting the line. @@ -426,13 +425,13 @@ message TestCase { string pickle_step_id = 2; // Pointer to all the matching `StepDefinition`s (if derived from a PickleStep) repeated string step_definition_ids = 3; - // A list of list of StepMatchArgument (if derived from a `StepDefinition`). + // A list of list of StepMatchArgument (if derived from a `StepDefinition`). // Each element represents a matching step definition. A size of 0 means `UNDEFINED`, // and a size of 2+ means `AMBIGUOUS` repeated StepMatchArgumentsList step_match_arguments_lists = 4; // Pointer to the `Hook` (if derived from a Hook) string hook_id = 5; - + message StepMatchArgumentsList { repeated StepMatchArgument step_match_arguments = 1; } diff --git a/cucumber-messages/javascript/messages.proto b/cucumber-messages/javascript/messages.proto index c3e5e60c55..ecf3447290 100644 --- a/cucumber-messages/javascript/messages.proto +++ b/cucumber-messages/javascript/messages.proto @@ -1,6 +1,5 @@ syntax = "proto3"; package io.cucumber.messages; -option ruby_package = "Cucumber::Messages"; option go_package = "messages"; // When removing a field, replace it with reserved, rather than deleting the line. @@ -426,13 +425,13 @@ message TestCase { string pickle_step_id = 2; // Pointer to all the matching `StepDefinition`s (if derived from a PickleStep) repeated string step_definition_ids = 3; - // A list of list of StepMatchArgument (if derived from a `StepDefinition`). + // A list of list of StepMatchArgument (if derived from a `StepDefinition`). // Each element represents a matching step definition. A size of 0 means `UNDEFINED`, // and a size of 2+ means `AMBIGUOUS` repeated StepMatchArgumentsList step_match_arguments_lists = 4; // Pointer to the `Hook` (if derived from a Hook) string hook_id = 5; - + message StepMatchArgumentsList { repeated StepMatchArgument step_match_arguments = 1; } diff --git a/cucumber-messages/messages.proto b/cucumber-messages/messages.proto index c3e5e60c55..ecf3447290 100644 --- a/cucumber-messages/messages.proto +++ b/cucumber-messages/messages.proto @@ -1,6 +1,5 @@ syntax = "proto3"; package io.cucumber.messages; -option ruby_package = "Cucumber::Messages"; option go_package = "messages"; // When removing a field, replace it with reserved, rather than deleting the line. @@ -426,13 +425,13 @@ message TestCase { string pickle_step_id = 2; // Pointer to all the matching `StepDefinition`s (if derived from a PickleStep) repeated string step_definition_ids = 3; - // A list of list of StepMatchArgument (if derived from a `StepDefinition`). + // A list of list of StepMatchArgument (if derived from a `StepDefinition`). // Each element represents a matching step definition. A size of 0 means `UNDEFINED`, // and a size of 2+ means `AMBIGUOUS` repeated StepMatchArgumentsList step_match_arguments_lists = 4; // Pointer to the `Hook` (if derived from a Hook) string hook_id = 5; - + message StepMatchArgumentsList { repeated StepMatchArgument step_match_arguments = 1; } diff --git a/cucumber-messages/ruby/Gemfile b/cucumber-messages/ruby/Gemfile index f019a4b208..e5ad85c8dd 100644 --- a/cucumber-messages/ruby/Gemfile +++ b/cucumber-messages/ruby/Gemfile @@ -1,7 +1,4 @@ # frozen_string_literal: true source 'https://rubygems.org' -# Use an older protobuf on JRuby -gem 'google-protobuf', '~> 3.2.0.2' if RUBY_PLATFORM == 'java' - gemspec diff --git a/cucumber-messages/ruby/Makefile b/cucumber-messages/ruby/Makefile index 16dbce2f94..e79107a5c9 100644 --- a/cucumber-messages/ruby/Makefile +++ b/cucumber-messages/ruby/Makefile @@ -1,9 +1,12 @@ include default.mk -.deps: lib/cucumber/messages_pb.rb +.deps: lib/cucumber/messages.pb.rb -lib/cucumber/messages_pb.rb: messages.proto - protoc -I. --ruby_out lib/cucumber $< +lib/cucumber/messages.pb.rb: messages.proto + mv $< $<.bak + cat $<.bak | sed "s/package io.cucumber.messages/package cucumber.messages/" > $< + bundle exec rake protobuf:compile[.,.,lib/cucumber] + mv $<.bak $< clean: - rm -f lib/cucumber/messages_pb.rb + rm -f lib/cucumber/messages.pb.rb diff --git a/cucumber-messages/ruby/Rakefile b/cucumber-messages/ruby/Rakefile index e14df3b2fd..1a3a0f07e6 100644 --- a/cucumber-messages/ruby/Rakefile +++ b/cucumber-messages/ruby/Rakefile @@ -5,6 +5,10 @@ Bundler::GemHelper.install_tasks $:.unshift File.expand_path("../lib", __FILE__) +Dir['./rake/*.rb'].each do |f| + require f +end + require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-r./spec/coverage -w] diff --git a/cucumber-messages/ruby/cucumber-messages.gemspec b/cucumber-messages/ruby/cucumber-messages.gemspec index 6f153d5d5a..9c135fe7f3 100644 --- a/cucumber-messages/ruby/cucumber-messages.gemspec +++ b/cucumber-messages/ruby/cucumber-messages.gemspec @@ -19,9 +19,11 @@ Gem::Specification.new do |s| 'source_code_uri' => 'https://github.com/cucumber/cucumber/blob/master/cucumber-messages/ruby', } - # Users of JRuby should use google-protobuf 3.2.0.2 (later versions don't work) - s.add_dependency('google-protobuf', ['>= 3.2', '<= 3.8']) + # TODO: Switch back to 'protobuf' when this PR is merged and released: + # https://github.com/ruby-protobuf/protobuf/pull/411 + s.add_dependency 'protobuf-cucumber', '~> 3.10', '>= 3.10.4' s.add_dependency 'json', '~> 2.3', '>= 2.3.0' + s.add_development_dependency 'rake', '~> 13.0', '>= 13.0.1' s.add_development_dependency 'rspec', '~> 3.9', '>= 3.9.0' diff --git a/cucumber-messages/ruby/lib/cucumber/.gitignore b/cucumber-messages/ruby/lib/cucumber/.gitignore index d9b94b0736..4bf8cc2610 100644 --- a/cucumber-messages/ruby/lib/cucumber/.gitignore +++ b/cucumber-messages/ruby/lib/cucumber/.gitignore @@ -1,2 +1,2 @@ # protoc-generated file -messages_pb.rb +messages.pb.rb diff --git a/cucumber-messages/ruby/lib/cucumber/messages.rb b/cucumber-messages/ruby/lib/cucumber/messages.rb index 1264fb0849..6fec49174d 100644 --- a/cucumber-messages/ruby/lib/cucumber/messages.rb +++ b/cucumber-messages/ruby/lib/cucumber/messages.rb @@ -1,8 +1,4 @@ -module Cucumber - module Messages - end -end -require 'cucumber/messages_pb' +require 'cucumber/messages.pb' require 'cucumber/messages/binary_to_message_enumerator' require 'cucumber/messages/ndjson_to_message_enumerator' require 'cucumber/messages/protobuf_delimited' diff --git a/cucumber-messages/ruby/lib/cucumber/messages/ndjson_to_message_enumerator.rb b/cucumber-messages/ruby/lib/cucumber/messages/ndjson_to_message_enumerator.rb index ea9699f00e..88487ccc7d 100644 --- a/cucumber-messages/ruby/lib/cucumber/messages/ndjson_to_message_enumerator.rb +++ b/cucumber-messages/ruby/lib/cucumber/messages/ndjson_to_message_enumerator.rb @@ -6,7 +6,8 @@ class NdjsonToMessageEnumerator < Enumerator def initialize(io) super() do |yielder| io.each_line do |json| - yielder.yield(Cucumber::Messages::Envelope.decode_json(json)) + m = Cucumber::Messages::Envelope.from_json(json) + yielder.yield(m) end end end diff --git a/cucumber-messages/ruby/lib/cucumber/messages/protobuf_ndjson.rb b/cucumber-messages/ruby/lib/cucumber/messages/protobuf_ndjson.rb index 0e443e870e..19ad3f783b 100644 --- a/cucumber-messages/ruby/lib/cucumber/messages/protobuf_ndjson.rb +++ b/cucumber-messages/ruby/lib/cucumber/messages/protobuf_ndjson.rb @@ -4,7 +4,8 @@ module Cucumber module Messages module WriteNdjson def write_ndjson_to(io) - json = self.class.encode_json(self) + # https://github.com/ruby-protobuf/protobuf/pull/410 + json = self.to_json(lower_camel_case: true) ob = JSON.parse(json) remove_empties(ob) io.puts(JSON.generate(ob)) @@ -13,7 +14,7 @@ def write_ndjson_to(io) def remove_empties(ob) if Hash === ob ob.each do |key, value| - if value == [] + if value == [] || value == '' || value == 0 ob.delete(key) else remove_empties(value) @@ -27,4 +28,4 @@ def remove_empties(ob) end end end -end \ No newline at end of file +end diff --git a/cucumber-messages/ruby/messages.proto b/cucumber-messages/ruby/messages.proto index c3e5e60c55..ecf3447290 100644 --- a/cucumber-messages/ruby/messages.proto +++ b/cucumber-messages/ruby/messages.proto @@ -1,6 +1,5 @@ syntax = "proto3"; package io.cucumber.messages; -option ruby_package = "Cucumber::Messages"; option go_package = "messages"; // When removing a field, replace it with reserved, rather than deleting the line. @@ -426,13 +425,13 @@ message TestCase { string pickle_step_id = 2; // Pointer to all the matching `StepDefinition`s (if derived from a PickleStep) repeated string step_definition_ids = 3; - // A list of list of StepMatchArgument (if derived from a `StepDefinition`). + // A list of list of StepMatchArgument (if derived from a `StepDefinition`). // Each element represents a matching step definition. A size of 0 means `UNDEFINED`, // and a size of 2+ means `AMBIGUOUS` repeated StepMatchArgumentsList step_match_arguments_lists = 4; // Pointer to the `Hook` (if derived from a Hook) string hook_id = 5; - + message StepMatchArgumentsList { repeated StepMatchArgument step_match_arguments = 1; } diff --git a/cucumber-messages/ruby/rake/protobuf.rb b/cucumber-messages/ruby/rake/protobuf.rb new file mode 100644 index 0000000000..2a5b805296 --- /dev/null +++ b/cucumber-messages/ruby/rake/protobuf.rb @@ -0,0 +1 @@ +load 'protobuf/tasks/compile.rake' diff --git a/cucumber-messages/ruby/spec/cucumber/messages/ndjson_serialization_spec.rb b/cucumber-messages/ruby/spec/cucumber/messages/ndjson_serialization_spec.rb index 0c4945f600..a0cedc6698 100644 --- a/cucumber-messages/ruby/spec/cucumber/messages/ndjson_serialization_spec.rb +++ b/cucumber-messages/ruby/spec/cucumber/messages/ndjson_serialization_spec.rb @@ -4,6 +4,24 @@ module Cucumber module Messages describe Messages do + it "json-roundtrips messages with bytes fields" do + a1 = Attachment.new(binary: [1,2,3,4].pack('C*')) + expect(a1.binary.length).to eq(4) + a2 = Attachment.new(JSON.parse(a1.to_json)) + expect(a2).to(eq(a1)) + end + + it "omits empty string fields in output" do + io = StringIO.new + message = Envelope.new(source: Source.new(data: '')) + message.write_ndjson_to(io) + + io.rewind + json = io.read + + expect(json).to eq("{\"source\":{}}\n") + end + it "can be serialised over an ndjson stream" do outgoing_messages = [ Envelope.new(source: Source.new(data: 'Feature: Hello')), diff --git a/cucumber-tag-expressions/ruby/Rakefile b/cucumber-tag-expressions/ruby/Rakefile index e14df3b2fd..1a3a0f07e6 100644 --- a/cucumber-tag-expressions/ruby/Rakefile +++ b/cucumber-tag-expressions/ruby/Rakefile @@ -5,6 +5,10 @@ Bundler::GemHelper.install_tasks $:.unshift File.expand_path("../lib", __FILE__) +Dir['./rake/*.rb'].each do |f| + require f +end + require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-r./spec/coverage -w] diff --git a/gherkin/ruby/Gemfile b/gherkin/ruby/Gemfile index 8c7ccc99dc..6f66fdca50 100644 --- a/gherkin/ruby/Gemfile +++ b/gherkin/ruby/Gemfile @@ -3,7 +3,4 @@ source "https://rubygems.org" gem 'cucumber-messages', :path => File.dirname(__FILE__) + '/../../cucumber-messages/ruby' -# Use an older protobuf on JRuby -gem 'google-protobuf', '~> 3.2.0.2' if RUBY_PLATFORM == 'java' - gemspec diff --git a/gherkin/ruby/Rakefile b/gherkin/ruby/Rakefile index e14df3b2fd..1a3a0f07e6 100644 --- a/gherkin/ruby/Rakefile +++ b/gherkin/ruby/Rakefile @@ -5,6 +5,10 @@ Bundler::GemHelper.install_tasks $:.unshift File.expand_path("../lib", __FILE__) +Dir['./rake/*.rb'].each do |f| + require f +end + require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-r./spec/coverage -w]