Skip to content

Commit

Permalink
Merge pull request #174 from Fryguy/exe_floe_params_bug
Browse files Browse the repository at this point in the history
Fix issues with exe/floe and various combinations of workflow and input
  • Loading branch information
agrare committed Apr 18, 2024
2 parents 553d46c + 7ecc3c7 commit a33074f
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 15 deletions.
34 changes: 25 additions & 9 deletions exe/floe
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,37 @@ opts = Optimist.options do
version("v#{Floe::VERSION}\n")
usage("[options] workflow input [workflow2 input2]")

opt :workflow, "Path to your workflow json (legacy)", :type => :string
opt :input, "JSON payload to input to the workflow (legacy)", :type => :string
opt :context, "JSON payload of the Context", :type => :string
opt :credentials, "JSON payload with credentials", :type => :string
opt :credentials_file, "Path to a file with credentials", :type => :string
opt :workflow, "Path to your workflow json file (alternative to passing a bare workflow)", :type => :string
opt :input, <<~EOMSG, :type => :string
JSON payload of the Input to the workflow
If --input is passed and --workflow is not passed, will be used for all bare workflows listed.
If --input is not passed and --workflow is passed, defaults to '{}'.
EOMSG
opt :context, "JSON payload of the Context", :type => :string
opt :credentials, "JSON payload with Credentials", :type => :string
opt :credentials_file, "Path to a file with Credentials", :type => :string

Floe::ContainerRunner.cli_options(self)

banner("")
banner("General options:")
end

# legacy support for --workflow
args = ARGV.empty? ? [opts[:workflow], opts[:input]] : ARGV
Optimist.die(:workflow, "must be specified") if args.empty?
# Create workflow/input pairs from the various combinations of paramaters
args =
if opts[:workflow_given]
Optimist.die("cannot specify both --workflow and bare workflows") if ARGV.any?

[opts[:workflow], opts.fetch(:input, "{}")]
elsif opts[:input_given]
Optimist.die("workflow(s) must be specified") if ARGV.empty?

ARGV.flat_map { |w| [w, opts[:input].dup] }
else
Optimist.die("workflow/input pairs must be specified") if ARGV.empty? || (ARGV.size > 1 && ARGV.size.odd?)

ARGV
end

Floe::ContainerRunner.resolve_cli_options!(opts)

Expand All @@ -41,7 +57,7 @@ credentials =

workflows =
args.each_slice(2).map do |workflow, input|
context = Floe::Workflow::Context.new(opts[:context], :input => input || opts[:input] || "{}")
context = Floe::Workflow::Context.new(opts[:context], :input => input)
Floe::Workflow.load(workflow, context, credentials)
end

Expand Down
4 changes: 3 additions & 1 deletion lib/floe/workflow/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ class Workflow
class Context
# @param context [Json|Hash] (default, create another with input and execution params)
# @param input [Hash] (default: {})
def initialize(context = nil, input: {})
def initialize(context = nil, input: nil)
context = JSON.parse(context) if context.kind_of?(String)

input ||= {}
input = JSON.parse(input) if input.kind_of?(String)

@context = context || {}
Expand Down
9 changes: 9 additions & 0 deletions spec/exe/data/workflow.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Comment": "Test workflow.",
"StartAt": "FirstState",
"States": {
"FirstState": {
"Type": "Succeed"
}
}
}
118 changes: 113 additions & 5 deletions spec/exe/floe_spec.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,122 @@
RSpec.describe "exe/floe" do
RSpec.describe "exe/floe", :slow => true do
include AwesomeSpawn::SpecHelper
before { enable_spawning }

let(:exe) { File.expand_path("../../exe/floe", __dir__) }
let(:workflow) { File.expand_path("data/workflow.asl", __dir__) }

it "displays help" do
output = AwesomeSpawn.run!("exe/floe --help").output
output = AwesomeSpawn.run!(exe, :params => [:help]).output
lines = output.lines(:chomp => true)

expect(output).to start_with("Usage: floe [options] workflow input [workflow2 input2]")
expect(output).to include(Floe::VERSION)
expect(lines).to start_with("Usage: floe [options] workflow input [workflow2 input2]")
expect(lines).to include("v#{Floe::VERSION}")

# it should also include options from runners
expect(output).to include("Container runner options:")
expect(lines).to include("Container runner options:")
end

it "with no parameters" do
result = AwesomeSpawn.run(exe)
expect(result).to be_failure

lines = result.error.lines(:chomp => true)
expect(lines.first).to eq("Error: workflow/input pairs must be specified.")
end

it "with a bare workflow and no input" do
output = AwesomeSpawn.run!(exe, :params => [workflow]).output
lines = output.lines(:chomp => true)

expect(lines.first).to include("checking 1 workflows...")
expect(lines.last).to eq("{}")
end

it "with a bare workflow and input" do
output = AwesomeSpawn.run!(exe, :params => [workflow, '{"foo":1}']).output
lines = output.lines(:chomp => true)

expect(lines.first).to include("checking 1 workflows...")
expect(lines.last).to eq('{"foo"=>1}')
end

it "with a bare workflow and --input" do
output = AwesomeSpawn.run!(exe, :params => [workflow, {:input => '{"foo":1}'}]).output
lines = output.lines(:chomp => true)

expect(lines.first).to include("checking 1 workflows...")
expect(lines.last).to eq('{"foo"=>1}')
end

it "with --workflow and no input" do
output = AwesomeSpawn.run!(exe, :params => {:workflow => workflow}).output
lines = output.lines(:chomp => true)

expect(lines.first).to include("checking 1 workflows...")
expect(lines.last).to eq("{}")
end

it "with --workflow and --input" do
output = AwesomeSpawn.run!(exe, :params => {:workflow => workflow, :input => '{"foo":1}'}).output
lines = output.lines(:chomp => true)

expect(lines.first).to include("checking 1 workflows...")
expect(lines.last).to eq('{"foo"=>1}')
end

it "with a bare workflow and --workflow" do
result = AwesomeSpawn.run(exe, :params => [workflow, {:workflow => workflow}])
expect(result).to be_failure

lines = result.error.lines(:chomp => true)
expect(lines.first).to eq("Error: cannot specify both --workflow and bare workflows.")
end

it "with --input but no workflows" do
result = AwesomeSpawn.run(exe, :params => {:input => '{"foo":1}'})
expect(result).to be_failure

lines = result.error.lines(:chomp => true)
expect(lines.first).to eq("Error: workflow(s) must be specified.")
end

it "with multiple bare workflow/input pairs" do
output = AwesomeSpawn.run!(exe, :params => [workflow, '{"foo":1}', workflow, '{"foo":2}']).output
lines = output.lines(:chomp => true)

expect(lines.first).to include("checking 2 workflows...")
expect(lines.last(7).join("\n")).to eq(<<~OUTPUT.chomp)
workflow
===
{"foo"=>1}
workflow
===
{"foo"=>2}
OUTPUT
end

it "with multiple bare workflows and --input" do
output = AwesomeSpawn.run!(exe, :params => [workflow, workflow, {:input => '{"foo":1}'}]).output
lines = output.lines(:chomp => true)

expect(lines.first).to include("checking 2 workflows...")
expect(lines.last(7).join("\n")).to eq(<<~OUTPUT.chomp)
workflow
===
{"foo"=>1}
workflow
===
{"foo"=>1}
OUTPUT
end

it "with mismatched workflow/input pairs" do
result = AwesomeSpawn.run(exe, :params => [workflow, workflow, '{"foo":2}'])
expect(result).to be_failure

lines = result.error.lines(:chomp => true)
expect(lines.first).to eq("Error: workflow/input pairs must be specified.")
end
end

0 comments on commit a33074f

Please sign in to comment.