trailblazer-pro 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +2 -0
- data/CHANGELOG.md +3 -1
- data/Gemfile +8 -2
- data/README.md +15 -14
- data/Rakefile +13 -1
- data/lib/trailblazer/pro/call/activity.rb +20 -0
- data/lib/trailblazer/pro/debugger.rb +124 -0
- data/lib/trailblazer/pro/operation/WTF.rb +17 -0
- data/lib/trailblazer/pro/operation/call.rb +24 -0
- data/lib/trailblazer/pro/session.rb +82 -0
- data/lib/trailblazer/pro/trace/decision.rb +15 -0
- data/lib/trailblazer/pro/trace/refresh.rb +33 -0
- data/lib/trailblazer/pro/trace/signin.rb +97 -0
- data/lib/trailblazer/pro/trace/store.rb +38 -0
- data/lib/trailblazer/pro/trace/wtf.rb +38 -0
- data/lib/trailblazer/pro/version.rb +1 -1
- data/lib/trailblazer/pro.rb +13 -3
- data/lib/trailblazer-pro.rb +1 -0
- data/trailblazer-pro.gemspec +9 -7
- metadata +125 -6
- data/lib/trailblazer/pro/client.rb +0 -95
- data/lib/trailblazer/pro/generate.rb +0 -99
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6abc91ad413fd17c14fb3a1c665b9c1cc73701fd7ad41f82ef973dd726102349
|
4
|
+
data.tar.gz: c5407c726b22a5f74462c7847c4e454176f0a3e1596215e5555c17415051261b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b2837a745201f9cd075a38fd0dcbb3601301f98ff5b37a60827981d0ea88bdcc4894399c9a30210bb9b857fe6e422d1ae209323faf4a5300e1a27917712ebdb
|
7
|
+
data.tar.gz: dce8f6060c62fcc657440d334397e1406c8ac9116a5bc9f78ff5b344423bf023adda62e28b8191a68b20cd5a0b867d86f7257a395d41807e351e9047e4060552
|
data/.github/workflows/main.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -8,6 +8,12 @@ gemspec
|
|
8
8
|
gem "rake", "~> 13.0"
|
9
9
|
|
10
10
|
gem "minitest", "~> 5.0"
|
11
|
-
|
12
|
-
|
11
|
+
# gem "trailblazer-developer", path: "../trailblazer-developer"
|
12
|
+
gem "faraday"
|
13
13
|
# gem "multi_json"
|
14
|
+
# gem "trailblazer-macro", path: "../trailblazer-macro"
|
15
|
+
# gem "trailblazer-activity", path: "../trailblazer-activity"
|
16
|
+
# gem "trailblazer-activity", github: "trailblazer/trailblazer-activity"
|
17
|
+
# gem "trailblazer-developer", path: "../trailblazer-developer"
|
18
|
+
# gem "trailblazer-operation", path: "../trailblazer-operation"
|
19
|
+
# gem "trailblazer-operation"
|
data/README.md
CHANGED
@@ -1,35 +1,36 @@
|
|
1
1
|
# Trailblazer::Pro
|
2
2
|
|
3
|
-
|
3
|
+
A library to communicate with the TRAILBLAZER PRO platform.
|
4
4
|
|
5
|
-
|
5
|
+
* Push local traces to us, and analyze using the online debugger.
|
6
|
+
* Export diagrams from the PRO editor to use with the `trailblazer-workflow` gem.
|
6
7
|
|
7
8
|
## Installation
|
8
9
|
|
9
10
|
Add this line to your application's Gemfile:
|
10
11
|
|
11
12
|
```ruby
|
12
|
-
gem
|
13
|
+
gem "trailblazer-pro"
|
13
14
|
```
|
14
15
|
|
15
|
-
|
16
|
+
## Rails support
|
16
17
|
|
17
|
-
|
18
|
+
Check out the [Rails support docs](https://trailblazer.to/2.1/docs/pro) of `trailblazer-pro-rails` if you want to start web-debugging right away.
|
18
19
|
|
19
|
-
|
20
|
+
## Trace
|
20
21
|
|
21
|
-
|
22
|
+
Retrieve you API key from https://pro.trailblazer.to/settings.
|
23
|
+
It will be something like `tpka_f5c698e2_d1ac_48fa_b59f_70e9ab100604`.
|
22
24
|
|
23
|
-
##
|
25
|
+
## Internals
|
24
26
|
|
25
|
-
|
27
|
+
### Testing
|
26
28
|
|
27
|
-
|
29
|
+
Either run against our hosted https://test-pro-rails-jwt.onrender.com TRB PRO host, or locally. This is currently set in `test/test_helper.rb`.
|
28
30
|
|
29
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
31
|
|
31
|
-
|
32
|
+
* `test/no_extend` Tests an environment where no monkey-patches happened, and if, only on anonymous classes.
|
32
33
|
|
33
|
-
|
34
|
+
### Notes
|
34
35
|
|
35
|
-
|
36
|
+
* With `endpoint`, monkey-patching might become obsolete, since we can inject {:present_options} transparently.
|
data/Rakefile
CHANGED
@@ -6,7 +6,19 @@ require "rake/testtask"
|
|
6
6
|
Rake::TestTask.new(:test) do |t|
|
7
7
|
t.libs << "test"
|
8
8
|
t.libs << "lib"
|
9
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"] - FileList["test/global_extend/*"]
|
10
10
|
end
|
11
11
|
|
12
12
|
task default: :test
|
13
|
+
|
14
|
+
Rake::TestTask.new(:test_1) do |t|
|
15
|
+
t.libs << "test"
|
16
|
+
t.libs << "lib"
|
17
|
+
t.test_files = FileList["test/global_extend/activity_call_test.rb"]
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake::TestTask.new(:test_2) do |t|
|
21
|
+
t.libs << "test"
|
22
|
+
t.libs << "lib"
|
23
|
+
t.test_files = FileList["test/global_extend/integration_test.rb"]
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Pro
|
3
|
+
module Call
|
4
|
+
module Activity
|
5
|
+
# This is the monkey-patch for {Activity.call}.
|
6
|
+
# Here we decide whether to use tracing, and what to render,
|
7
|
+
# or if we should bypass tracing.
|
8
|
+
def call(activity, ctx)
|
9
|
+
trace_strategy, present_options_merge = Pro::Session.trace_guards.(activity, ctx)
|
10
|
+
|
11
|
+
if trace_strategy
|
12
|
+
return trace_strategy.invoke(activity, [ctx, {}], present_options: present_options_merge)
|
13
|
+
else
|
14
|
+
return super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end # Activity
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Pro
|
3
|
+
module Debugger
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Called in {Trace::Present.call} as {:render_method}.
|
7
|
+
def call(debugger_trace:, activity:, render_wtf: false, renderer:, **options)
|
8
|
+
trace_data = render_trace_data(debugger_trace, activity: activity, **options)
|
9
|
+
|
10
|
+
trace_envelope = {
|
11
|
+
fields: {
|
12
|
+
activity_name: {stringValue: activity},
|
13
|
+
trace: {stringValue: trace_data},
|
14
|
+
created_at: {timestampValue: DateTime.now}, # we're using local client time currently.
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
session, stored_trace_id, session_updated = push(trace_envelope, activity: activity, **options)
|
19
|
+
|
20
|
+
debugger_url = "https://ide.trailblazer.to/#{stored_trace_id}"
|
21
|
+
# output = "[TRB PRO] view trace (#{activity}) at #{debugger_url}"
|
22
|
+
# output = Developer::Wtf::Renderer::String.bold(output)
|
23
|
+
output = Developer::Wtf::Renderer::String.bold("[TRB PRO] view trace (#{activity}) at ")
|
24
|
+
output += debugger_url # DISCUSS: what do we want bold here?
|
25
|
+
|
26
|
+
if render_wtf
|
27
|
+
# TODO: take the color_map from outside caller.
|
28
|
+
wtf_output = Developer::Trace::Present.render(debugger_trace: debugger_trace, renderer: renderer, color_map: Developer::Wtf::Renderer::DEFAULT_COLOR_MAP) # , activity: activity
|
29
|
+
|
30
|
+
output = [wtf_output, output].join("\n")
|
31
|
+
end
|
32
|
+
|
33
|
+
returned_values = [session, stored_trace_id, debugger_url, trace_envelope, session_updated]
|
34
|
+
|
35
|
+
return output, returned_values
|
36
|
+
end
|
37
|
+
|
38
|
+
def render_trace_data(debugger_trace, activity:, **)
|
39
|
+
flat_tree_json = debugger_trace.to_a.collect do |debugger_node|
|
40
|
+
|
41
|
+
# TODO: do we even need to grab tw by path here?
|
42
|
+
introspect_nodes_node = OpenStruct.new(task: debugger_node.task)
|
43
|
+
tw_render = Developer::Render::TaskWrap.render_for(debugger_node.activity, introspect_nodes_node)
|
44
|
+
|
45
|
+
# This rendering code has deep knowledge of Trace/pro/v1 tracing interface.
|
46
|
+
{
|
47
|
+
id: debugger_node.id.to_s,
|
48
|
+
runtime_id: debugger_node.runtime_id,
|
49
|
+
level: debugger_node.level,
|
50
|
+
label: debugger_node.label,
|
51
|
+
ctx_snapshots: {
|
52
|
+
before: debugger_node.snapshot_before.data[:ctx_variable_changeset].collect { |name, hash, has_changed| [name, {version: hash.to_s, has_changed: !!has_changed}] },
|
53
|
+
after: debugger_node.snapshot_after ?
|
54
|
+
|
55
|
+
debugger_node.snapshot_after.data[:ctx_variable_changeset].collect { |name, hash, has_changed| [name, {version: hash.to_s, has_changed: !!has_changed}] } # FIXME: of course, this is horrible.
|
56
|
+
: [],
|
57
|
+
},
|
58
|
+
|
59
|
+
rendered_task_wrap: tw_render,
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
JSON.dump(
|
64
|
+
nodes: flat_tree_json,
|
65
|
+
variable_versions: debugger_trace.to_h[:variable_versions].to_h,
|
66
|
+
pro_version: Pro::VERSION.to_s,
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
class Push < Trailblazer::Activity::Railway
|
71
|
+
step :session_initialized?,
|
72
|
+
Output(:failure) => Path(track_color: :signin, connect_to: Track(:rebuild)) do # FIXME: move to after {valid?}
|
73
|
+
# Signin only consumes {:api_key} and friends and doesn't know about {:session}.
|
74
|
+
step Subprocess(Trailblazer::Pro::Trace::Signin),
|
75
|
+
In() => :session_to_args#,
|
76
|
+
# Out() => Trace::Signin::SESSION_VARIABLE_NAMES
|
77
|
+
end
|
78
|
+
|
79
|
+
step Trace.method(:valid?), In() => :session_to_args, Inject() => [:now],
|
80
|
+
Output(:failure) => Path(track_color: :refresh, connect_to: Track(:rebuild)) do
|
81
|
+
step Subprocess(Trailblazer::Pro::Trace::Refresh), In() => :session_to_args
|
82
|
+
end
|
83
|
+
|
84
|
+
step :rebuild_session, magnetic_to: :rebuild # TODO: assert that success/failure go to right Track.
|
85
|
+
|
86
|
+
step Subprocess(Trailblazer::Pro::Trace::Store),
|
87
|
+
In() => :session_to_args,
|
88
|
+
In() => [:data_to_store]
|
89
|
+
|
90
|
+
def session_initialized?(ctx, session:, **)
|
91
|
+
session.is_a?(Session)
|
92
|
+
end
|
93
|
+
|
94
|
+
def rebuild_session(ctx, session:, **)
|
95
|
+
session_params = ctx.to_h.slice(*Trace::Signin::SESSION_VARIABLE_NAMES)
|
96
|
+
|
97
|
+
session = Session.new(
|
98
|
+
**session.to_h, # old data
|
99
|
+
**session_params, # new input
|
100
|
+
)
|
101
|
+
|
102
|
+
ctx[:session] = session
|
103
|
+
ctx[:session_updated] = true
|
104
|
+
end
|
105
|
+
|
106
|
+
def session_to_args(ctx, session:, **)
|
107
|
+
session.to_h
|
108
|
+
end
|
109
|
+
end # Push
|
110
|
+
|
111
|
+
def push(trace_data, activity:, now: DateTime.now, **options)
|
112
|
+
# signal, (ctx, _) = Trailblazer::Developer.wtf?(Push, [{now: now, data_to_store: trace_data, **options}, {}])
|
113
|
+
_signal, (ctx, _) = Trailblazer::Activity.(Push, {now: now, data_to_store: trace_data, **options})
|
114
|
+
# signal, (ctx, _) = Push.invoke([{now: now, data_to_store: trace_data, **options}, {}])
|
115
|
+
|
116
|
+
session = ctx[:session]
|
117
|
+
stored_trace_id = ctx[:id]
|
118
|
+
session_updated = ctx[:session_updated]
|
119
|
+
|
120
|
+
return session, stored_trace_id, session_updated
|
121
|
+
end
|
122
|
+
end # Debugger
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Pro
|
3
|
+
module Operation
|
4
|
+
module WTF
|
5
|
+
# {Operation.WTF?} will always use web tracing and CLI.
|
6
|
+
def WTF?(options)
|
7
|
+
call_with_public_interface(
|
8
|
+
options,
|
9
|
+
{},
|
10
|
+
invoke_class: Trailblazer::Pro::Trace::Wtf,
|
11
|
+
present_options: {render_wtf: true}
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end # Operation
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Pro
|
3
|
+
module Operation
|
4
|
+
# @private This is experimental.
|
5
|
+
module Call
|
6
|
+
# This is the monkey-patch for {Operation.call}.
|
7
|
+
# Here we decide whether to use tracing, and what to render,
|
8
|
+
# or if we should bypass tracing.
|
9
|
+
def call_with_public_interface(options, flow_options, **circuit_options)
|
10
|
+
trace_strategy, present_options_merge = Pro::Session.trace_guards.(self, options)
|
11
|
+
|
12
|
+
if trace_strategy
|
13
|
+
# trace_strategy.invoke(activity, [ctx, {}], present_options: present_options_merge)
|
14
|
+
|
15
|
+
# local invoke_class is overridden by circuit_options
|
16
|
+
super(options, flow_options, invoke_class: trace_strategy, **circuit_options, present_options: present_options_merge)
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end # Operation
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Pro
|
3
|
+
# DISCUSS: do we want {id_token} here explicitely?
|
4
|
+
# Data structure to hold all data values necessary to keep an authenticated
|
5
|
+
# session with Firebase.
|
6
|
+
class Session < Struct.new(:expires_at, :jwt_token_exp, :id_token, :firebase_upload_url, :firestore_fields_template, :firebase_refresh_url, :firebase_signin_url, :refresh_token, :api_key, :trailblazer_pro_host, keyword_init: true)
|
7
|
+
singleton_class.attr_accessor :wtf_present_options
|
8
|
+
singleton_class.attr_accessor :session
|
9
|
+
singleton_class.attr_accessor :trace_guards
|
10
|
+
|
11
|
+
self.trace_guards = Trailblazer::Pro::Trace::Decision.new([]) # here we say "don't trace anything!"
|
12
|
+
# .trace_guards = Pro::Trace::Decision.new([->(*) { [Trace::Wtf, {}] }]) # always use Pro web/CLI tracing per default.
|
13
|
+
|
14
|
+
class Uninitialized < Struct.new(:api_key, :trailblazer_pro_host, keyword_init: true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.serialize(session)
|
18
|
+
attributes = session.to_h
|
19
|
+
attributes = attributes.slice(*(attributes.keys - [:expires_at]))
|
20
|
+
|
21
|
+
JSON.dump(attributes)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.deserialize(json)
|
25
|
+
data = JSON.parse(json)
|
26
|
+
|
27
|
+
options = data.key?("jwt_token_exp") ? {expires_at: Trace.parse_exp(data["jwt_token_exp"])} : {}
|
28
|
+
|
29
|
+
data
|
30
|
+
.merge(options) # TODO: use representer
|
31
|
+
.collect { |k, v| [k.to_sym, v] }
|
32
|
+
.to_h
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# TODO:
|
37
|
+
# pass session, e.g. from RAils/tmp
|
38
|
+
def self.initialize!(api_key:, id_token: nil, render_wtf: true, **options)
|
39
|
+
Session.wtf_present_options = {
|
40
|
+
render_method: Trailblazer::Pro::Debugger,
|
41
|
+
render_wtf: render_wtf,
|
42
|
+
# api_key: api_key,
|
43
|
+
# **options
|
44
|
+
}
|
45
|
+
|
46
|
+
if id_token
|
47
|
+
Session.session = Trailblazer::Pro::Session.new(api_key: api_key, id_token: id_token, **options)
|
48
|
+
else
|
49
|
+
Session.session = Trailblazer::Pro::Session::Uninitialized.new(api_key: api_key, **options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.trace_operations!(operation_hash)
|
54
|
+
Trailblazer::Pro::Session.trace_guards = DSL.trace_operations(operation_hash)
|
55
|
+
end
|
56
|
+
|
57
|
+
module DSL
|
58
|
+
module_function
|
59
|
+
|
60
|
+
def trace_operations(operation_hash)
|
61
|
+
decisions =
|
62
|
+
if operation_hash == :all
|
63
|
+
Trailblazer::Operation.extend(Trailblazer::Pro::Operation::Call)
|
64
|
+
|
65
|
+
raise "implement me"
|
66
|
+
elsif operation_hash.is_a?(Hash)
|
67
|
+
operation_hash.collect do |operation, strategy| # DISCUSS: this can be easily made faster for runtime.
|
68
|
+
operation.extend(Trailblazer::Pro::Operation::Call) # only extend selected OPs.
|
69
|
+
|
70
|
+
strategy = Trailblazer::Pro::Trace::Wtf if strategy === true # defaulting.
|
71
|
+
|
72
|
+
->(activity, *) { activity == operation ? [strategy, {}] : false }
|
73
|
+
end
|
74
|
+
else
|
75
|
+
[]
|
76
|
+
end
|
77
|
+
|
78
|
+
Trace::Decision.new(decisions)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Trailblazer::Pro
|
2
|
+
module Trace
|
3
|
+
# Used in Activity.call monkey-patch.
|
4
|
+
class Decision < Struct.new(:guards)
|
5
|
+
def call(activity, ctx) # DISCUSS: signature not stable, yet.
|
6
|
+
guards.each do |guard|
|
7
|
+
result = guard.(activity, ctx) and return result # DISCUSS: {ctx.to_hash}?
|
8
|
+
end
|
9
|
+
|
10
|
+
false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Trailblazer::Pro
|
2
|
+
module Trace
|
3
|
+
class Refresh < Trailblazer::Activity::Railway
|
4
|
+
step :refresh_id_token
|
5
|
+
step Trace.method(:parse_response)
|
6
|
+
step :extract_id_token
|
7
|
+
step :extract_refresh_token
|
8
|
+
step Trace.method(:parse_jwt_token)
|
9
|
+
step Trace.method(:parse_expires_at)
|
10
|
+
|
11
|
+
def refresh_id_token(ctx, http: Faraday, refresh_token:, firebase_refresh_url:, **)
|
12
|
+
ctx[:response] = http.post(
|
13
|
+
firebase_refresh_url,
|
14
|
+
{
|
15
|
+
refresh_token: refresh_token,
|
16
|
+
grant_type: "refresh_token"
|
17
|
+
}.to_json,
|
18
|
+
{'Content-Type'=>'application/json', "Accept": "application/json"}
|
19
|
+
)
|
20
|
+
|
21
|
+
ctx[:response].status == 200
|
22
|
+
end
|
23
|
+
|
24
|
+
def extract_id_token(ctx, parsed_response:, **)
|
25
|
+
ctx[:id_token] = parsed_response["id_token"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def extract_refresh_token(ctx, parsed_response:, **)
|
29
|
+
ctx[:refresh_token] = parsed_response["refresh_token"]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Trailblazer::Pro
|
2
|
+
module Trace
|
3
|
+
def self.parse_response(ctx, response:, **)
|
4
|
+
ctx[:parsed_response] = JSON.parse(response.body)
|
5
|
+
end
|
6
|
+
|
7
|
+
require "jwt"
|
8
|
+
require "date"
|
9
|
+
def self.parse_jwt_token(ctx, id_token:, **)
|
10
|
+
token, _ = JWT.decode(id_token, nil, false, algorithm: "RS256")
|
11
|
+
|
12
|
+
ctx[:jwt_token_exp] = token["exp"]
|
13
|
+
# ctx[:jwt_token] = token
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.parse_expires_at(ctx, jwt_token_exp:, **)
|
17
|
+
ctx[:expires_at] = parse_exp(jwt_token_exp)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.parse_exp(exp)
|
21
|
+
DateTime.strptime(exp.to_s, "%s")
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.valid?(ctx, now:, expires_at:, **)
|
25
|
+
# FIXME
|
26
|
+
puts "id_token expires at #{expires_at}, that is in #{((expires_at - now) * 24 * 60 * 60).to_i} seconds"
|
27
|
+
|
28
|
+
now < expires_at
|
29
|
+
end
|
30
|
+
|
31
|
+
class Signin < Trailblazer::Activity::Railway
|
32
|
+
step :request_custom_token
|
33
|
+
step Trace.method(:parse_response)
|
34
|
+
step :extract_custom_token
|
35
|
+
step :extract_data_for_firebase
|
36
|
+
step :request_id_token
|
37
|
+
step Trace.method(:parse_response), id: :parse_firebase_response
|
38
|
+
step :extract_id_token
|
39
|
+
step :extract_refresh_token
|
40
|
+
step Trace.method(:parse_jwt_token)
|
41
|
+
step Trace.method(:parse_expires_at)
|
42
|
+
# left ->(ctx, response:, **) { puts response.status } # FIXME: better error handling!
|
43
|
+
|
44
|
+
PRO_SIGNIN_PATH = "/api/v1/signin_with_api_key"
|
45
|
+
|
46
|
+
# DISCUSS: this is the "outgoing" contract, the variables we should store in {session_params}.
|
47
|
+
SESSION_VARIABLE_NAMES = [
|
48
|
+
#:custom_token,
|
49
|
+
:id_token, :refresh_token, :expires_at, :jwt_token_exp, :firebase_signin_url, :firebase_refresh_url, :firebase_upload_url, :firestore_fields_template
|
50
|
+
]
|
51
|
+
|
52
|
+
def request_custom_token(ctx, http: Faraday, api_key:, trailblazer_pro_host: "https://pro.trailblazer.to", **) # DISCUSS: do we like the defaulting?
|
53
|
+
ctx[:response] = http.post(
|
54
|
+
"#{trailblazer_pro_host}#{PRO_SIGNIN_PATH}",
|
55
|
+
{
|
56
|
+
api_key: api_key,
|
57
|
+
}.to_json,
|
58
|
+
{'Content-Type'=>'application/json', "Accept": "application/json"}
|
59
|
+
)
|
60
|
+
|
61
|
+
ctx[:response].status == 200
|
62
|
+
end
|
63
|
+
|
64
|
+
def extract_custom_token(ctx, parsed_response:, **)
|
65
|
+
ctx[:custom_token] = parsed_response["custom_token"]
|
66
|
+
end
|
67
|
+
|
68
|
+
def extract_data_for_firebase(ctx, parsed_response:, **)
|
69
|
+
ctx[:firebase_signin_url] = parsed_response["firebase_signin_url"] or return
|
70
|
+
ctx[:firebase_refresh_url] = parsed_response["firebase_refresh_url"] or return
|
71
|
+
ctx[:firebase_upload_url] = parsed_response["firebase_upload_url"] or return # needed in {Trace::Store}.
|
72
|
+
ctx[:firestore_fields_template] = parsed_response["firebase_upload_data"] or return
|
73
|
+
end
|
74
|
+
|
75
|
+
def request_id_token(ctx, http: Faraday, firebase_signin_url:, custom_token:, **)
|
76
|
+
ctx[:response] = http.post(
|
77
|
+
firebase_signin_url,
|
78
|
+
{
|
79
|
+
token: custom_token,
|
80
|
+
returnSecureToken: true
|
81
|
+
}.to_json,
|
82
|
+
{'Content-Type'=>'application/json', "Accept": "application/json"}
|
83
|
+
)
|
84
|
+
|
85
|
+
ctx[:response].status == 200
|
86
|
+
end
|
87
|
+
|
88
|
+
def extract_id_token(ctx, parsed_response:, **)
|
89
|
+
ctx[:id_token] = parsed_response["idToken"]
|
90
|
+
end
|
91
|
+
|
92
|
+
def extract_refresh_token(ctx, parsed_response:, **)
|
93
|
+
ctx[:refresh_token] = parsed_response["refreshToken"]
|
94
|
+
end
|
95
|
+
end # Signin
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Trailblazer::Pro
|
2
|
+
module Trace
|
3
|
+
class Store < Trailblazer::Activity::Railway
|
4
|
+
step :upload
|
5
|
+
step :extract_id
|
6
|
+
fail :error
|
7
|
+
|
8
|
+
def upload(ctx, firebase_upload_url:, data_to_store:, id_token:, firestore_fields_template:, **)
|
9
|
+
fields = data_to_store[:fields].merge(firestore_fields_template)
|
10
|
+
|
11
|
+
json_to_store = JSON.dump(data_to_store.merge(fields: fields))#.to_json
|
12
|
+
|
13
|
+
# puts "@@@@@ DATA SIZE: #{json_to_store.size / 1024} kb"
|
14
|
+
|
15
|
+
ctx[:response] = Faraday.post(
|
16
|
+
firebase_upload_url,
|
17
|
+
json_to_store,
|
18
|
+
{'Content-Type'=>'application/json', "Accept": "application/json",
|
19
|
+
"Authorization": "Bearer #{id_token}"
|
20
|
+
}
|
21
|
+
)
|
22
|
+
|
23
|
+
ctx[:response].status == 200
|
24
|
+
end
|
25
|
+
|
26
|
+
def extract_id(ctx, response:, **)
|
27
|
+
parsed_response = JSON.parse(response.body)
|
28
|
+
|
29
|
+
ctx[:firestore_name] = parsed_response["name"]
|
30
|
+
ctx[:id] = ctx[:firestore_name].split("/").last
|
31
|
+
end
|
32
|
+
|
33
|
+
def error(ctx, response:, **)
|
34
|
+
puts response.inspect
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Trailblazer::Pro
|
2
|
+
module Trace
|
3
|
+
module Wtf
|
4
|
+
module_function
|
5
|
+
# DISCUSS: this is called inside the monkey-patch for Activity/Operation.()
|
6
|
+
# in {Pro::Call.call}.
|
7
|
+
def call(*args, present_options: {}, **options)
|
8
|
+
global_present_options = Session.wtf_present_options
|
9
|
+
raise "[Trailblazer] Please configure your PRO API key." if global_present_options.nil?
|
10
|
+
|
11
|
+
present_options =
|
12
|
+
global_present_options
|
13
|
+
.merge(present_options)
|
14
|
+
.merge(session: Session.session)
|
15
|
+
|
16
|
+
returned = Trailblazer::Developer::Wtf.invoke( # identical to {Developer.wtf?}.
|
17
|
+
*args,
|
18
|
+
present_options: present_options,
|
19
|
+
**options
|
20
|
+
)
|
21
|
+
|
22
|
+
(session, _trace_id, _debugger_url, _trace_envelope, session_updated) = returned[-1]
|
23
|
+
|
24
|
+
update_session!(session) if session_updated # DISCUSS: this is a hook for pro-rails, not a massive fan.
|
25
|
+
|
26
|
+
returned
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
alias invoke call
|
31
|
+
end
|
32
|
+
|
33
|
+
def update_session!(session)
|
34
|
+
Session.session = session
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/trailblazer/pro.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require_relative "pro/version"
|
2
|
+
require "trailblazer/activity/dsl/linear"
|
3
|
+
require "faraday"
|
4
4
|
|
5
5
|
module Trailblazer
|
6
6
|
module Pro
|
7
|
-
class Error < StandardError; end
|
8
7
|
# Your code goes here...
|
9
8
|
end
|
10
9
|
end
|
10
|
+
|
11
|
+
require_relative "pro/trace/decision"
|
12
|
+
require_relative "pro/session"
|
13
|
+
require_relative "pro/trace/signin"
|
14
|
+
require_relative "pro/trace/refresh"
|
15
|
+
require_relative "pro/trace/store"
|
16
|
+
require_relative "pro/trace/wtf"
|
17
|
+
require_relative "pro/debugger"
|
18
|
+
require_relative "pro/call/activity"
|
19
|
+
require_relative "pro/operation/call"
|
20
|
+
require_relative "pro/operation/WTF"
|
@@ -0,0 +1 @@
|
|
1
|
+
require "trailblazer/pro"
|
data/trailblazer-pro.gemspec
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require_relative "lib/trailblazer/pro/version"
|
4
2
|
|
5
3
|
Gem::Specification.new do |spec|
|
@@ -8,8 +6,7 @@ Gem::Specification.new do |spec|
|
|
8
6
|
spec.authors = ["Nick Sutterer"]
|
9
7
|
spec.email = ["apotonick@gmail.com"]
|
10
8
|
|
11
|
-
spec.summary = "
|
12
|
-
# spec.description = "TODO: Write a longer description or delete this line."
|
9
|
+
spec.summary = "Integration code for TRB PRO."
|
13
10
|
spec.homepage = "https://trailblazer.to/2.1/docs/pro.html"
|
14
11
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
|
15
12
|
|
@@ -27,8 +24,13 @@ Gem::Specification.new do |spec|
|
|
27
24
|
spec.require_paths = ["lib"]
|
28
25
|
|
29
26
|
# Uncomment to register a new dependency of your gem
|
30
|
-
|
27
|
+
spec.add_dependency "trailblazer-activity", ">= 0.16.1", "< 0.17.0"
|
28
|
+
# spec.add_dependency "trailblazer-activity-dsl-linear", "~> 1.2"
|
29
|
+
spec.add_dependency "trailblazer-developer", ">= 0.1.0", "< 0.2.0"
|
30
|
+
spec.add_dependency "jwt"
|
31
|
+
spec.add_dependency "faraday"
|
32
|
+
spec.add_development_dependency "trailblazer-operation"
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
+
spec.add_development_dependency "minitest-line"
|
35
|
+
spec.add_development_dependency "rake"
|
34
36
|
end
|
metadata
CHANGED
@@ -1,15 +1,125 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trailblazer-pro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2023-08-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: trailblazer-activity
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.16.1
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.17.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.16.1
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.17.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: trailblazer-developer
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.1.0
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 0.2.0
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 0.1.0
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 0.2.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: jwt
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: faraday
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: trailblazer-operation
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: minitest-line
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: rake
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
13
123
|
description:
|
14
124
|
email:
|
15
125
|
- apotonick@gmail.com
|
@@ -25,9 +135,18 @@ files:
|
|
25
135
|
- Rakefile
|
26
136
|
- bin/console
|
27
137
|
- bin/setup
|
138
|
+
- lib/trailblazer-pro.rb
|
28
139
|
- lib/trailblazer/pro.rb
|
29
|
-
- lib/trailblazer/pro/
|
30
|
-
- lib/trailblazer/pro/
|
140
|
+
- lib/trailblazer/pro/call/activity.rb
|
141
|
+
- lib/trailblazer/pro/debugger.rb
|
142
|
+
- lib/trailblazer/pro/operation/WTF.rb
|
143
|
+
- lib/trailblazer/pro/operation/call.rb
|
144
|
+
- lib/trailblazer/pro/session.rb
|
145
|
+
- lib/trailblazer/pro/trace/decision.rb
|
146
|
+
- lib/trailblazer/pro/trace/refresh.rb
|
147
|
+
- lib/trailblazer/pro/trace/signin.rb
|
148
|
+
- lib/trailblazer/pro/trace/store.rb
|
149
|
+
- lib/trailblazer/pro/trace/wtf.rb
|
31
150
|
- lib/trailblazer/pro/version.rb
|
32
151
|
- trailblazer-pro.gemspec
|
33
152
|
homepage: https://trailblazer.to/2.1/docs/pro.html
|
@@ -54,5 +173,5 @@ requirements: []
|
|
54
173
|
rubygems_version: 3.2.3
|
55
174
|
signing_key:
|
56
175
|
specification_version: 4
|
57
|
-
summary:
|
176
|
+
summary: Integration code for TRB PRO.
|
58
177
|
test_files: []
|
@@ -1,95 +0,0 @@
|
|
1
|
-
require "faraday"
|
2
|
-
require "base64"
|
3
|
-
require "json"
|
4
|
-
require "representable/json"
|
5
|
-
|
6
|
-
module Trailblazer::Developer
|
7
|
-
module Client
|
8
|
-
Diagram = Struct.new(:id, :body)
|
9
|
-
|
10
|
-
class Diagram::Representer < Representable::Decorator
|
11
|
-
include Representable::JSON
|
12
|
-
property :id
|
13
|
-
property :body, as: :diagram
|
14
|
-
end
|
15
|
-
|
16
|
-
module_function
|
17
|
-
|
18
|
-
def Diagram(id, body)
|
19
|
-
Diagram.new(id, body).freeze
|
20
|
-
end
|
21
|
-
|
22
|
-
def import(id:, query:"", **options)
|
23
|
-
token = retrieve_token(**options)
|
24
|
-
export_diagram(id: id, token: token, query: query, **options)
|
25
|
-
end
|
26
|
-
|
27
|
-
def retrieve_token(email:, api_key:, url: "/signin", **options)
|
28
|
-
body = JSON.generate({email: email, api_key: api_key})
|
29
|
-
|
30
|
-
response = request(token: nil, method: :get, url: url, body: body, **options)
|
31
|
-
return false unless response.status == 200
|
32
|
-
|
33
|
-
# token = CGI::Cookie.parse(response.headers["set-cookie"])["token"][0]
|
34
|
-
JSON.parse(response.body)["token"]
|
35
|
-
end
|
36
|
-
|
37
|
-
def export_diagram(id:, query:, **options)
|
38
|
-
response = request(body: nil, url: "/api/v1/diagrams/#{id}/export#{query}", method: :get, **options)
|
39
|
-
|
40
|
-
# parse_response(response)
|
41
|
-
response.body
|
42
|
-
end
|
43
|
-
|
44
|
-
def duplicate(id:, **options)
|
45
|
-
token = retrieve_token(**options)
|
46
|
-
|
47
|
-
response = request(body: nil, token: token, url: "/api/v1/diagrams/#{id}/duplicate", method: :get, **options)
|
48
|
-
parse_response(response)
|
49
|
-
end
|
50
|
-
|
51
|
-
# DISCUSS: do we need that?
|
52
|
-
def new_diagram(token:, **options)
|
53
|
-
response = request(body: nil, url: "/api/v1/diagrams/new", method: :get, token: token, **options)
|
54
|
-
|
55
|
-
# TODO: use Dry::Struct
|
56
|
-
# TODO: handle unauthorized/errors
|
57
|
-
parse_response(response)
|
58
|
-
end
|
59
|
-
|
60
|
-
def request(host:, url:, method:, token:, body:, **)
|
61
|
-
conn = Faraday.new(url: host)
|
62
|
-
|
63
|
-
conn.send(method) do |req|
|
64
|
-
req.url url
|
65
|
-
req.headers["Content-Type"] = "application/json"
|
66
|
-
req.body = body
|
67
|
-
req.headers["Authorization"] = token
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def parse_response(response)
|
72
|
-
diagram = Diagram.new
|
73
|
-
Diagram::Representer.new(diagram).from_json(response.body) # a parsed hash would be cooler?
|
74
|
-
|
75
|
-
diagram
|
76
|
-
end
|
77
|
-
|
78
|
-
# TODO: remove me!
|
79
|
-
def self.push(operation:, name:)
|
80
|
-
xml = Trailblazer::Diagram::BPMN.to_xml(operation["__activity__"], operation["__sequence__"].map(&:id))
|
81
|
-
token = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpZCI6MywidXNlcm5hbWUiOiJhcG90b25pY2siLCJlbWFpbCI6Im5pY2tAdHJhaWxibGF6ZXIudG8ifQ." # rubocop:disable Metrics/LineLength
|
82
|
-
conn = Faraday.new(url: "https://api.trb.to")
|
83
|
-
response = conn.post do |req|
|
84
|
-
req.url "/dev/v1/import"
|
85
|
-
req.headers["Content-Type"] = "application/json"
|
86
|
-
req.headers["Authorization"] = token
|
87
|
-
require "base64"
|
88
|
-
|
89
|
-
req.body = %({ "name": "#{name}", "xml":"#{Base64.strict_encode64(xml)}" })
|
90
|
-
end
|
91
|
-
|
92
|
-
puts response.status.inspect
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
gem "representable"
|
2
|
-
require "representable/hash"
|
3
|
-
require "trailblazer/activity/dsl/linear" # Railway.
|
4
|
-
|
5
|
-
module Trailblazer
|
6
|
-
module Developer
|
7
|
-
# Computes an {Intermediate} data structure from a TRB-editor.js file.
|
8
|
-
module Generate
|
9
|
-
module_function
|
10
|
-
|
11
|
-
Element = Struct.new(:id, :type, :linksTo, :data, :label, :parent)
|
12
|
-
Arrow = Struct.new(:target, :label, :message, :target_lane)
|
13
|
-
|
14
|
-
module Representer
|
15
|
-
class Activity < Representable::Decorator
|
16
|
-
include Representable::Hash
|
17
|
-
|
18
|
-
collection :elements, class: Element do
|
19
|
-
property :id
|
20
|
-
property :type
|
21
|
-
collection :linksTo, class: Arrow, default: ::Declarative::Variables::Append([]) do
|
22
|
-
property :target
|
23
|
-
property :label
|
24
|
-
property :message
|
25
|
-
property :target_lane
|
26
|
-
end
|
27
|
-
property :data, default: {}
|
28
|
-
|
29
|
-
property :label
|
30
|
-
property :parent # TODO: remove?
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def call(hash)
|
36
|
-
_, (ctx, _) = Activity::TaskWrap.invoke(Pipeline, [{hash: hash}, {}])
|
37
|
-
ctx[:intermediate]
|
38
|
-
end
|
39
|
-
|
40
|
-
def transform_from_hash(ctx, hash:, parser: Representer::Activity, **)
|
41
|
-
ctx[:elements] = parser.new(OpenStruct.new).from_hash(hash).elements
|
42
|
-
end
|
43
|
-
|
44
|
-
def find_start_events(ctx, elements:, **)
|
45
|
-
ctx[:start_events] = elements.find_all { |el| el.type == "Event" }
|
46
|
-
end
|
47
|
-
|
48
|
-
def compute_intermediate(ctx, elements:, start_events:, **)
|
49
|
-
end_events = elements.find_all { |el| el.type == "EndEventTerminate" } # DISCUSS: is it really called TERMINATE?
|
50
|
-
|
51
|
-
inter = Activity::Schema::Intermediate
|
52
|
-
|
53
|
-
wiring = elements.collect { |el|
|
54
|
-
data = data_for(el)
|
55
|
-
|
56
|
-
[inter.TaskRef(el.id, data), el.linksTo.collect { |arrow| inter.Out(semantic_for(**arrow.to_h), arrow.target) } ] }
|
57
|
-
wiring = Hash[wiring]
|
58
|
-
|
59
|
-
# end events need this stupid special handling
|
60
|
-
# DISCUSS: currently, the END-SEMANTIC is read from the event's label.
|
61
|
-
wiring = wiring.merge(Hash[
|
62
|
-
end_events.collect do |_end|
|
63
|
-
ref, = wiring.find { |ref, _| ref.id == _end.id }
|
64
|
-
|
65
|
-
[ref, [inter.Out(semantic_for(**_end.to_h)|| raise, nil)]] # TODO: test the raise, happens when the semantic of an End can't be distinguished. # TODO: don't extract semantic from :label but from :data.
|
66
|
-
end
|
67
|
-
])
|
68
|
-
# pp wiring
|
69
|
-
|
70
|
-
ctx[:intermediate] = inter.new(wiring, end_events.collect(&:id), start_events.collect(&:id))
|
71
|
-
end
|
72
|
-
|
73
|
-
# private
|
74
|
-
|
75
|
-
def data_for(element)
|
76
|
-
{type: element.type}.merge(element.data)
|
77
|
-
end
|
78
|
-
|
79
|
-
# We currently use the {:label} field of an arrow to encode an output semantic.
|
80
|
-
# The {:symbol_style} part will be filtered out as semantic. Defaults to {:success}.
|
81
|
-
def semantic_for(label:nil, **)
|
82
|
-
return :success unless label
|
83
|
-
|
84
|
-
extract_semantic(label)
|
85
|
-
end
|
86
|
-
|
87
|
-
def extract_semantic(label)
|
88
|
-
label.to_sym
|
89
|
-
end
|
90
|
-
|
91
|
-
class Pipeline < Trailblazer::Activity::Railway
|
92
|
-
step Generate.method(:transform_from_hash), id: :transform_from_hash
|
93
|
-
step Generate.method(:find_start_events), id: :find_start_events
|
94
|
-
step Generate.method(:compute_intermediate), id: :compute_intermediate
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
# [Inter::Out(:success, nil)]
|