Last active
August 29, 2015 14:12
-
-
Save jfryman/4af1142157477d2831c4 to your computer and use it in GitHub Desktop.
Graph Generators for ActionChain/Mistral
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# damn ugly spike to generate dot files from an actionchain workflow | |
require 'yaml' | |
require 'erb' | |
module ActionChain | |
class Graph | |
include ERB::Util | |
attr_reader :title, :workflow | |
def initialize(title, workflow) | |
@title = title | |
@workflow = workflow | |
end # ActionChain::Graph#initialize | |
def render | |
ERB.new(dot_template).result(binding) | |
end # ActionChain::Graph#render | |
def dot_template | |
%{ | |
graph <%= @title %> { | |
<% # Render all nodes %> | |
<% @workflow.nodes.each do |node| %> | |
<%= node %>; | |
<% end %> | |
<% # Render all relationships %> | |
<% @workflow.relationships.each do |relationship| %> | |
<% relationship.each do |action, attributes| %> | |
<%= action %> -> <%= attributes['destination'] %> <% if attributes.has_key?('condition') %>[label="<%= attributes['condition'] %>"]<% end %>; | |
<% end %> | |
<% end %> | |
} | |
} | |
end # ActionChain::Graph#dot_template | |
def save | |
File.open("#{workflow.name}.dot", 'w') { |f| f.write(render) } | |
end # ActionChain::Graph#save | |
end # ActionChain::Graph | |
class Parser | |
attr_accessor :name | |
def initialize(name, workflow) | |
@workflow = workflow | |
@name = name | |
end | |
def nodes | |
@nodes = Array.new | |
workflow['chain'].each { |task| @nodes << task['name'] } | |
@nodes.uniq | |
end | |
def workflow | |
@workflow | |
end | |
# Super ugly | |
def relationships | |
@relationships = Array.new | |
# Calculate workflow relationships | |
# For each task | |
workflow['chain'].each do |task| | |
['on-success', 'on-failure'].each do |condition| | |
@relationships << { | |
task['name'] => { | |
'destination' => task[condition], | |
'condition' => condition, | |
} | |
} if task.has_key?(condition) | |
end | |
end | |
@relationships | |
end # ActionChain::Parser#relationships | |
end # ActionChain::Parser | |
class Loader | |
attr_reader :file | |
def initialize(file) | |
begin | |
@file = YAML::load_file(file) | |
rescue => e | |
puts "Unable to load YAML file..." | |
puts e | |
exit 1 | |
end | |
end | |
def self.generate_graphs(title, file) | |
workflow = ActionChain::Loader.new(file).file | |
parsed_workflow = ActionChain::Parser.new(title, workflow) | |
graph = ActionChain::Graph.new(title, parsed_workflow) | |
graph.save | |
end | |
end # ActionChain::Loader | |
end # ActionChain | |
# Command line business | |
file = ARGV.shift | |
title = file.split('.')[0] | |
ActionChain::Loader.generate_graphs(title, file) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# damn ugly spike to generate dot files from a mistral workflow | |
require 'yaml' | |
require 'erb' | |
module Mistral | |
class Graph | |
include ERB::Util | |
attr_reader :workflow | |
def initialize(workflow) | |
@workflow = workflow | |
end # Mistral::Graph#initialize | |
def render | |
ERB.new(dot_template).result(binding) | |
end # Mistral::Graph#render | |
def dot_template | |
%{ | |
graph <%= @workflow.name %> { | |
<% # Render all nodes %> | |
<% @workflow.nodes.each do |node| %> | |
<%= node %>; | |
<% end %> | |
<% if @workflow.global_nodes %> | |
{ rank=same; <%= @workflow.global_nodes.join(' ') %> } | |
<% end %> | |
<% # Render all relationships %> | |
<% @workflow.relationships.each do |relationship| %> | |
<% relationship.each do |action, attributes| %> | |
<%= action %> -> <%= attributes['destination'] %> <% if attributes.has_key?('condition') %>[label="<%= attributes['condition'] %>"]<% end %>; | |
<% end %> | |
<% end %> | |
} | |
} | |
end # Mistral::Graph#dot_template | |
def save | |
File.open("#{workflow.name}.dot", 'w') { |f| f.write(render) } | |
end # Mistral::Graph#save | |
end # Mistral::Graph | |
class Parser | |
attr_accessor :name | |
def initialize(name, workflow) | |
@workflow = workflow | |
@name = name | |
end | |
def nodes | |
@nodes = Array.new | |
@relationships.each do |relationship| | |
@nodes << relationship.first[0] | |
end | |
@nodes.uniq | |
end | |
def workflow | |
@workflow | |
end | |
# Super ugly | |
def relationships | |
@relationships = Array.new | |
# Calculate workflow relationships | |
# For each task | |
workflow['tasks'].each do |task, attributes| | |
# Check to see if either an action or workflow has been assigned | |
['workflow', 'action'].each do |next_action| | |
next unless attributes.has_key?(next_action) | |
# And add a new relationship from the current task to the next step in the graph | |
@relationships << { | |
task => { | |
'destination' => attributes[next_action], | |
} | |
} | |
# Now, let's see what steps each next_action | |
# take if it has been defined | |
['on-success', 'on-error'].each do |condition| | |
# Let's first get all the globally defined defaults | |
if workflow.has_key?('task-defaults') | |
# Loop through all of the global defaults if they exist and add | |
# individual relationships | |
Array(workflow['task-defaults'][condition]).each do |global_action| | |
next unless workflow['task-defaults'].has_key? condition | |
@relationships << { | |
attributes[next_action] => { | |
'destination' => global_action, | |
'condition' => condition | |
} | |
} | |
end | |
end | |
# And now let's loop through the individual task conditions | |
Array(attributes[condition]).each do |local_action| | |
@relationships << { | |
attributes[next_action] => { | |
'destination' => local_action, | |
'condition' => condition | |
} | |
} | |
end if attributes.has_key?(condition) | |
end | |
end | |
end | |
@relationships | |
end # Mistral::Parser#relationships | |
def global_nodes | |
return nil unless workflow.has_key?('task-defaults') | |
@nodes = Array.new | |
['on-error', 'on-success'].each do |condition| | |
next unless workflow['task-defaults'].has_key?(condition) | |
@nodes << workflow['task-defaults'][condition] | |
end | |
@nodes.flatten.uniq | |
end | |
end # Mistral::Parser | |
class Loader | |
attr_reader :file | |
def initialize(file) | |
begin | |
@file = YAML::load_file(file) | |
rescue => e | |
puts "Unable to load YAML file..." | |
puts e | |
exit 1 | |
end | |
end | |
def self.generate_graphs(file) | |
master_document = Mistral::Loader.new(file).file | |
master_document['workflows'].each do |workflow, attributes| | |
parsed_workflow = Mistral::Parser.new(workflow, attributes) | |
parsed_workflow.relationships | |
graph = Mistral::Graph.new(parsed_workflow) | |
graph.save | |
end | |
end | |
end # Mistral::Loader | |
end # Mistral | |
# Command line business | |
file = ARGV.shift | |
Mistral::Loader.generate_graphs(file) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment