From 415bb0e4eb2a3e828543a643af8224957cdf11f3 Mon Sep 17 00:00:00 2001 From: Paulo Barros <450960+promulo@users.noreply.github.com> Date: Wed, 25 May 2022 16:06:15 +0200 Subject: [PATCH] Add support for CSV content from stdin in CLI (#637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Étienne Barrié --- README.md | 10 ++++-- lib/maintenance_tasks/cli.rb | 12 +++++-- test/lib/maintenance_tasks/cli_test.rb | 44 ++++++++++++++++++++------ 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0c62c002..d7459682 100644 --- a/README.md +++ b/README.md @@ -508,13 +508,19 @@ Alternatively, you can run your Task in the command line: bundle exec maintenance_tasks perform Maintenance::UpdatePostsTask ``` -To run a Task that processes CSVs from the command line, use the --csv option: +To run a Task that processes CSVs from the command line, use the `--csv` option: ```sh-session bundle exec maintenance_tasks perform Maintenance::ImportPostsTask --csv "path/to/my_csv.csv" ``` -To run a Task that takes arguments from the command line, use the --arguments +The `--csv` option also works with CSV content coming from the standard input: + +```sh-session +curl "some/remote/csv" | bundle exec maintenance_tasks perform Maintenance::ImportPostsTask --csv +``` + +To run a Task that takes arguments from the command line, use the `--arguments` option, passing arguments as a set of \:\ pairs: ```sh-session diff --git a/lib/maintenance_tasks/cli.rb b/lib/maintenance_tasks/cli.rb index b8920e4a..b6bdb621 100644 --- a/lib/maintenance_tasks/cli.rb +++ b/lib/maintenance_tasks/cli.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require "stringio" require "thor" module MaintenanceTasks @@ -27,7 +28,7 @@ def exit_on_failure? # Specify the CSV file to process for CSV Tasks desc = "Supply a CSV file to be processed by a CSV Task, "\ "--csv path/to/csv/file.csv" - option :csv, desc: desc + option :csv, lazy_default: :stdin, desc: desc # Specify arguments to supply to a Task supporting parameters desc = "Supply arguments for a Task that accepts parameters as a set of "\ ": pairs." @@ -52,10 +53,17 @@ def perform(name) private def csv_file + return unless options.key?(:csv) + csv_option = options[:csv] - if csv_option + + if csv_option == :stdin + { io: StringIO.new($stdin.read), filename: "stdin.csv" } + else { io: File.open(csv_option), filename: File.basename(csv_option) } end + rescue Errno::ENOENT + raise ArgumentError, "CSV file not found: #{csv_option}" end end end diff --git a/test/lib/maintenance_tasks/cli_test.rb b/test/lib/maintenance_tasks/cli_test.rb index b7aebdd3..93a4cd6a 100644 --- a/test/lib/maintenance_tasks/cli_test.rb +++ b/test/lib/maintenance_tasks/cli_test.rb @@ -31,21 +31,47 @@ class CLITest < ActiveSupport::TestCase @cli.perform("Wrong") end - test "#perform runs a CSV Task with the supplied CSV when --csv option used" do + test "#perform runs CSV task with supplied CSV when --csv option used" do task = mock(name: "MyCsvTask") csv_file_path = file_fixture("sample.csv") - opened_csv_file = File.open(csv_file_path) - expected_attachable = { io: opened_csv_file, filename: "sample.csv" } - @cli.expects(:options).at_least_once.returns(csv: csv_file_path) - File.expects(:open).with(csv_file_path).returns(opened_csv_file) Runner.expects(:run) - .with(name: "MyCsvTask", csv_file: expected_attachable, arguments: {}) + .with do |kwargs| + assert_equal("MyCsvTask", kwargs[:name]) + assert_equal(csv_file_path.to_s, kwargs[:csv_file][:io].path) + assert_equal({}, kwargs[:arguments]) + end .returns(task) - @cli.expects(:say_status) - .with(:success, "MyCsvTask was enqueued.", :green) - @cli.perform("MyCsvTask") + assert_output(/success\s+MyCsvTask was enqueued\./) do + CLI.start(["perform", "MyCsvTask", "--csv", csv_file_path]) + end + end + + test "#perform runs CSV task with content from stdin" do + task = mock(name: "MyCsvTask") + csv_string = "foo,bar\n1,2\n" + $stdin = StringIO.new(csv_string) + + Runner.expects(:run) + .with do |kwargs| + assert_equal("MyCsvTask", kwargs[:name]) + assert_equal(csv_string, kwargs[:csv_file][:io].read) + assert_equal({}, kwargs[:arguments]) + end + .returns(task) + + assert_output(/success\s+MyCsvTask was enqueued\./) do + CLI.start(["perform", "MyCsvTask", "--csv"]) + end + + $stdin = STDIN + end + + test "#perform prints error message when CSV file does not exist" do + assert_output(/error\s+CSV file not found: foo\.csv/) do + CLI.start(["perform", "MyCsvTask", "--csv", "foo.csv"]) + end end test "#perform runs a Task with the supplied arguments when --arguments option used" do