flowable 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +83 -0
- data/LICENSE +21 -0
- data/README.md +872 -0
- data/bin/flowable +510 -0
- data/lib/flowable/flowable.rb +273 -0
- data/lib/flowable/resources/base.rb +44 -0
- data/lib/flowable/resources/bpmn_deployments.rb +90 -0
- data/lib/flowable/resources/bpmn_history.rb +228 -0
- data/lib/flowable/resources/case_definitions.rb +115 -0
- data/lib/flowable/resources/case_instances.rb +188 -0
- data/lib/flowable/resources/deployments.rb +87 -0
- data/lib/flowable/resources/executions.rb +134 -0
- data/lib/flowable/resources/history.rb +264 -0
- data/lib/flowable/resources/plan_item_instances.rb +131 -0
- data/lib/flowable/resources/process_definitions.rb +142 -0
- data/lib/flowable/resources/process_instances.rb +200 -0
- data/lib/flowable/resources/tasks.rb +281 -0
- data/lib/flowable/version.rb +37 -0
- data/lib/flowable/workflow.rb +444 -0
- data/lib/flowable.rb +9 -0
- data/lib/flowable_client/resources/bpmn_history.rb +228 -0
- data/lib/flowable_client/resources/process_definitions.rb +142 -0
- data/lib/flowable_client/resources/process_instances.rb +200 -0
- metadata +104 -0
data/bin/flowable
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'optparse'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'yaml'
|
|
7
|
+
require_relative '../lib/flowable'
|
|
8
|
+
|
|
9
|
+
module FlowableCLI
|
|
10
|
+
class CLI
|
|
11
|
+
CONFIG_FILE = File.expand_path('~/.flowable.yml')
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
@options = load_config
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run(args)
|
|
18
|
+
return show_help if args.empty?
|
|
19
|
+
|
|
20
|
+
command = args.shift
|
|
21
|
+
case command
|
|
22
|
+
when 'config'
|
|
23
|
+
configure(args)
|
|
24
|
+
when 'deploy'
|
|
25
|
+
deploy(args)
|
|
26
|
+
when 'definitions', 'defs'
|
|
27
|
+
definitions(args)
|
|
28
|
+
when 'start'
|
|
29
|
+
start_case(args)
|
|
30
|
+
when 'cases'
|
|
31
|
+
list_cases(args)
|
|
32
|
+
when 'case'
|
|
33
|
+
show_case(args)
|
|
34
|
+
when 'tasks'
|
|
35
|
+
list_tasks(args)
|
|
36
|
+
when 'task'
|
|
37
|
+
show_task(args)
|
|
38
|
+
when 'claim'
|
|
39
|
+
claim_task(args)
|
|
40
|
+
when 'complete'
|
|
41
|
+
complete_task(args)
|
|
42
|
+
when 'vars'
|
|
43
|
+
show_variables(args)
|
|
44
|
+
when 'set'
|
|
45
|
+
set_variable(args)
|
|
46
|
+
when 'history'
|
|
47
|
+
show_history(args)
|
|
48
|
+
when 'process-start'
|
|
49
|
+
start_process(args)
|
|
50
|
+
when 'processes'
|
|
51
|
+
list_processes(args)
|
|
52
|
+
when 'help', '-h', '--help'
|
|
53
|
+
show_help
|
|
54
|
+
else
|
|
55
|
+
puts "Unknown command: #{command}"
|
|
56
|
+
show_help
|
|
57
|
+
exit 1
|
|
58
|
+
end
|
|
59
|
+
rescue Flowable::Error => e
|
|
60
|
+
puts "Error: #{e.message}"
|
|
61
|
+
exit 1
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def client
|
|
67
|
+
@client ||= Flowable::Client.new(
|
|
68
|
+
host: @options[:host] || 'localhost',
|
|
69
|
+
port: @options[:port] || 8080,
|
|
70
|
+
username: @options[:username] || 'rest-admin',
|
|
71
|
+
password: @options[:password] || 'test',
|
|
72
|
+
use_ssl: @options[:use_ssl] || false
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def load_config
|
|
77
|
+
return {} unless File.exist?(CONFIG_FILE)
|
|
78
|
+
|
|
79
|
+
YAML.load_file(CONFIG_FILE, symbolize_names: true) || {}
|
|
80
|
+
rescue StandardError
|
|
81
|
+
{}
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def save_config
|
|
85
|
+
File.write(CONFIG_FILE, @options.to_yaml)
|
|
86
|
+
puts "Config saved to #{CONFIG_FILE}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# === Commands ===
|
|
90
|
+
|
|
91
|
+
def configure(args)
|
|
92
|
+
opts = OptionParser.new do |o|
|
|
93
|
+
o.banner = 'Usage: flowable config [options]'
|
|
94
|
+
o.on('--host HOST', 'Flowable host') { |v| @options[:host] = v }
|
|
95
|
+
o.on('--port PORT', Integer, 'Flowable port') { |v| @options[:port] = v }
|
|
96
|
+
o.on('--username USER', 'Username') { |v| @options[:username] = v }
|
|
97
|
+
o.on('--password PASS', 'Password') { |v| @options[:password] = v }
|
|
98
|
+
o.on('--ssl', 'Use HTTPS') { @options[:use_ssl] = true }
|
|
99
|
+
o.on('--show', 'Show current config') do
|
|
100
|
+
puts 'Current configuration:'
|
|
101
|
+
puts " Host: #{@options[:host] || 'localhost'}"
|
|
102
|
+
puts " Port: #{@options[:port] || 8080}"
|
|
103
|
+
puts " Username: #{@options[:username] || 'rest-admin'}"
|
|
104
|
+
puts " SSL: #{@options[:use_ssl] || false}"
|
|
105
|
+
exit 0
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
opts.parse!(args)
|
|
109
|
+
save_config
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def deploy(args)
|
|
113
|
+
if args.empty?
|
|
114
|
+
puts 'Usage: flowable deploy <file.cmmn.xml|file.bpmn.xml> [--tenant TENANT]'
|
|
115
|
+
exit 1
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
file_path = args.shift
|
|
119
|
+
tenant_id = nil
|
|
120
|
+
|
|
121
|
+
opts = OptionParser.new do |o|
|
|
122
|
+
o.on('--tenant TENANT', 'Tenant ID') { |v| tenant_id = v }
|
|
123
|
+
end
|
|
124
|
+
opts.parse!(args)
|
|
125
|
+
|
|
126
|
+
unless File.exist?(file_path)
|
|
127
|
+
puts "File not found: #{file_path}"
|
|
128
|
+
exit 1
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Determine if CMMN or BPMN based on extension
|
|
132
|
+
if file_path.include?('.cmmn')
|
|
133
|
+
result = client.deployments.create(file_path, tenant_id: tenant_id)
|
|
134
|
+
puts 'CMMN Deployment created:'
|
|
135
|
+
else
|
|
136
|
+
result = client.bpmn_deployments.create(file_path, tenant_id: tenant_id)
|
|
137
|
+
puts 'BPMN Deployment created:'
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
puts " ID: #{result['id']}"
|
|
141
|
+
puts " Name: #{result['name']}"
|
|
142
|
+
puts " Time: #{result['deploymentTime']}"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def definitions(args)
|
|
146
|
+
type = 'cmmn'
|
|
147
|
+
opts = OptionParser.new do |o|
|
|
148
|
+
o.banner = 'Usage: flowable definitions [options]'
|
|
149
|
+
o.on('--bpmn', 'Show BPMN process definitions') { type = 'bpmn' }
|
|
150
|
+
o.on('--cmmn', 'Show CMMN case definitions (default)') { type = 'cmmn' }
|
|
151
|
+
end
|
|
152
|
+
opts.parse!(args)
|
|
153
|
+
|
|
154
|
+
if type == 'bpmn'
|
|
155
|
+
result = client.process_definitions.list
|
|
156
|
+
puts "Process Definitions (#{result['total']}):"
|
|
157
|
+
else
|
|
158
|
+
result = client.case_definitions.list
|
|
159
|
+
puts "Case Definitions (#{result['total']}):"
|
|
160
|
+
end
|
|
161
|
+
result['data'].each do |d|
|
|
162
|
+
puts " #{d['key']} v#{d['version']} - #{d['name']} [#{d['id']}]"
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def start_case(args)
|
|
167
|
+
if args.empty?
|
|
168
|
+
puts 'Usage: flowable start <caseKey> [--var key=value ...] [--business-key KEY]'
|
|
169
|
+
exit 1
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
case_key = args.shift
|
|
173
|
+
variables = {}
|
|
174
|
+
business_key = nil
|
|
175
|
+
|
|
176
|
+
opts = OptionParser.new do |o|
|
|
177
|
+
o.on('--var VAR', 'Variable (key=value)') do |v|
|
|
178
|
+
key, value = v.split('=', 2)
|
|
179
|
+
variables[key.to_sym] = parse_value(value)
|
|
180
|
+
end
|
|
181
|
+
o.on('--business-key KEY', 'Business key') { |v| business_key = v }
|
|
182
|
+
end
|
|
183
|
+
opts.parse!(args)
|
|
184
|
+
|
|
185
|
+
result = client.case_instances.start_by_key(
|
|
186
|
+
case_key,
|
|
187
|
+
variables: variables,
|
|
188
|
+
business_key: business_key
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
puts 'Case started:'
|
|
192
|
+
puts " ID: #{result['id']}"
|
|
193
|
+
puts " State: #{result['state']}"
|
|
194
|
+
puts " Definition: #{result['caseDefinitionName']}"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def start_process(args)
|
|
198
|
+
if args.empty?
|
|
199
|
+
puts 'Usage: flowable process-start <processKey> [--var key=value ...] [--business-key KEY]'
|
|
200
|
+
exit 1
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
process_key = args.shift
|
|
204
|
+
variables = {}
|
|
205
|
+
business_key = nil
|
|
206
|
+
|
|
207
|
+
opts = OptionParser.new do |o|
|
|
208
|
+
o.on('--var VAR', 'Variable (key=value)') do |v|
|
|
209
|
+
key, value = v.split('=', 2)
|
|
210
|
+
variables[key.to_sym] = parse_value(value)
|
|
211
|
+
end
|
|
212
|
+
o.on('--business-key KEY', 'Business key') { |v| business_key = v }
|
|
213
|
+
end
|
|
214
|
+
opts.parse!(args)
|
|
215
|
+
|
|
216
|
+
result = client.process_instances.start_by_key(
|
|
217
|
+
process_key,
|
|
218
|
+
variables: variables,
|
|
219
|
+
business_key: business_key
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
puts 'Process started:'
|
|
223
|
+
puts " ID: #{result['id']}"
|
|
224
|
+
puts " Ended: #{result['ended']}"
|
|
225
|
+
puts " Definition: #{result['processDefinitionId']}"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def list_cases(args)
|
|
229
|
+
filters = {}
|
|
230
|
+
opts = OptionParser.new do |o|
|
|
231
|
+
o.banner = 'Usage: flowable cases [options]'
|
|
232
|
+
o.on('--key KEY', 'Filter by case definition key') { |v| filters[:caseDefinitionKey] = v }
|
|
233
|
+
o.on('--business-key KEY', 'Filter by business key') { |v| filters[:businessKey] = v }
|
|
234
|
+
end
|
|
235
|
+
opts.parse!(args)
|
|
236
|
+
|
|
237
|
+
result = client.case_instances.list(**filters)
|
|
238
|
+
puts "Case Instances (#{result['total']}):"
|
|
239
|
+
result['data'].each do |c|
|
|
240
|
+
puts " [#{c['state']}] #{c['id']} - #{c['caseDefinitionName']} (#{c['businessKey'] || 'no business key'})"
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def list_processes(args)
|
|
245
|
+
filters = {}
|
|
246
|
+
opts = OptionParser.new do |o|
|
|
247
|
+
o.banner = 'Usage: flowable processes [options]'
|
|
248
|
+
o.on('--key KEY', 'Filter by process definition key') { |v| filters[:processDefinitionKey] = v }
|
|
249
|
+
o.on('--business-key KEY', 'Filter by business key') { |v| filters[:businessKey] = v }
|
|
250
|
+
end
|
|
251
|
+
opts.parse!(args)
|
|
252
|
+
|
|
253
|
+
result = client.process_instances.list(**filters)
|
|
254
|
+
puts "Process Instances (#{result['total']}):"
|
|
255
|
+
result['data'].each do |p|
|
|
256
|
+
status = if p['suspended']
|
|
257
|
+
'SUSPENDED'
|
|
258
|
+
else
|
|
259
|
+
(p['ended'] ? 'ENDED' : 'ACTIVE')
|
|
260
|
+
end
|
|
261
|
+
puts " [#{status}] #{p['id']} - #{p['processDefinitionId']} (#{p['businessKey'] || 'no business key'})"
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def show_case(args)
|
|
266
|
+
if args.empty?
|
|
267
|
+
puts 'Usage: flowable case <caseInstanceId>'
|
|
268
|
+
exit 1
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
case_id = args.shift
|
|
272
|
+
result = client.case_instances.get(case_id)
|
|
273
|
+
|
|
274
|
+
puts "Case Instance: #{result['id']}"
|
|
275
|
+
puts " Name: #{result['name']}"
|
|
276
|
+
puts " State: #{result['state']}"
|
|
277
|
+
puts " Definition: #{result['caseDefinitionName']}"
|
|
278
|
+
puts " Business Key: #{result['businessKey']}"
|
|
279
|
+
puts " Start Time: #{result['startTime']}"
|
|
280
|
+
puts " Start User: #{result['startUserId']}"
|
|
281
|
+
|
|
282
|
+
# Show stages
|
|
283
|
+
stages = client.case_instances.stage_overview(case_id) rescue []
|
|
284
|
+
unless stages.empty?
|
|
285
|
+
puts "\n Stages:"
|
|
286
|
+
stages.each do |stage|
|
|
287
|
+
status = if stage['current']
|
|
288
|
+
'▶'
|
|
289
|
+
else
|
|
290
|
+
(stage['ended'] ? '✓' : '○')
|
|
291
|
+
end
|
|
292
|
+
puts " #{status} #{stage['name']}"
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def list_tasks(args)
|
|
298
|
+
filters = {}
|
|
299
|
+
opts = OptionParser.new do |o|
|
|
300
|
+
o.banner = 'Usage: flowable tasks [options]'
|
|
301
|
+
o.on('--assignee USER', 'Filter by assignee') { |v| filters[:assignee] = v }
|
|
302
|
+
o.on('--candidate USER', 'Filter by candidate user') { |v| filters[:candidateUser] = v }
|
|
303
|
+
o.on('--case ID', 'Filter by case instance ID') { |v| filters[:caseInstanceId] = v }
|
|
304
|
+
o.on('--unassigned', 'Only unassigned tasks') { filters[:unassigned] = true }
|
|
305
|
+
end
|
|
306
|
+
opts.parse!(args)
|
|
307
|
+
|
|
308
|
+
result = client.tasks.list(**filters)
|
|
309
|
+
puts "Tasks (#{result['total']}):"
|
|
310
|
+
result['data'].each do |t|
|
|
311
|
+
assignee = t['assignee'] || 'unassigned'
|
|
312
|
+
puts " #{t['id']} - #{t['name']} [#{assignee}]"
|
|
313
|
+
puts " Case: #{t['caseInstanceId']}" if t['caseInstanceId']
|
|
314
|
+
puts " Due: #{t['dueDate']}" if t['dueDate']
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def show_task(args)
|
|
319
|
+
if args.empty?
|
|
320
|
+
puts 'Usage: flowable task <taskId>'
|
|
321
|
+
exit 1
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
task_id = args.shift
|
|
325
|
+
result = client.tasks.get(task_id)
|
|
326
|
+
|
|
327
|
+
puts "Task: #{result['id']}"
|
|
328
|
+
puts " Name: #{result['name']}"
|
|
329
|
+
puts " Description: #{result['description']}"
|
|
330
|
+
puts " Assignee: #{result['assignee'] || 'unassigned'}"
|
|
331
|
+
puts " Owner: #{result['owner']}"
|
|
332
|
+
puts " Priority: #{result['priority']}"
|
|
333
|
+
puts " Due Date: #{result['dueDate']}"
|
|
334
|
+
puts " Created: #{result['createTime']}"
|
|
335
|
+
puts " Case Instance: #{result['caseInstanceId']}"
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def claim_task(args)
|
|
339
|
+
if args.length < 2
|
|
340
|
+
puts 'Usage: flowable claim <taskId> <assignee>'
|
|
341
|
+
exit 1
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
task_id = args.shift
|
|
345
|
+
assignee = args.shift
|
|
346
|
+
|
|
347
|
+
client.tasks.claim(task_id, assignee)
|
|
348
|
+
puts "Task #{task_id} claimed by #{assignee}"
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def complete_task(args)
|
|
352
|
+
if args.empty?
|
|
353
|
+
puts 'Usage: flowable complete <taskId> [--var key=value ...] [--outcome OUTCOME]'
|
|
354
|
+
exit 1
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
task_id = args.shift
|
|
358
|
+
variables = {}
|
|
359
|
+
outcome = nil
|
|
360
|
+
|
|
361
|
+
opts = OptionParser.new do |o|
|
|
362
|
+
o.on('--var VAR', 'Variable (key=value)') do |v|
|
|
363
|
+
key, value = v.split('=', 2)
|
|
364
|
+
variables[key.to_sym] = parse_value(value)
|
|
365
|
+
end
|
|
366
|
+
o.on('--outcome OUTCOME', 'Task outcome') { |v| outcome = v }
|
|
367
|
+
end
|
|
368
|
+
opts.parse!(args)
|
|
369
|
+
|
|
370
|
+
client.tasks.complete(task_id, variables: variables, outcome: outcome)
|
|
371
|
+
puts "Task #{task_id} completed"
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def show_variables(args)
|
|
375
|
+
if args.empty?
|
|
376
|
+
puts 'Usage: flowable vars <caseInstanceId|taskId> [--task]'
|
|
377
|
+
exit 1
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
id = args.shift
|
|
381
|
+
is_task = args.include?('--task')
|
|
382
|
+
|
|
383
|
+
result = if is_task
|
|
384
|
+
client.tasks.variables(id)
|
|
385
|
+
else
|
|
386
|
+
client.case_instances.variables(id)
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
puts 'Variables:'
|
|
390
|
+
result.each do |v|
|
|
391
|
+
puts " #{v['name']} = #{v['value']} (#{v['type']})"
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
def set_variable(args)
|
|
396
|
+
if args.length < 2
|
|
397
|
+
puts 'Usage: flowable set <caseInstanceId> <key=value> [key=value ...]'
|
|
398
|
+
exit 1
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
case_id = args.shift
|
|
402
|
+
variables = {}
|
|
403
|
+
|
|
404
|
+
args.each do |arg|
|
|
405
|
+
key, value = arg.split('=', 2)
|
|
406
|
+
variables[key.to_sym] = parse_value(value)
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
client.case_instances.set_variables(case_id, variables)
|
|
410
|
+
puts "Variables updated on case #{case_id}"
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def show_history(args)
|
|
414
|
+
type = 'cases'
|
|
415
|
+
limit = 10
|
|
416
|
+
|
|
417
|
+
opts = OptionParser.new do |o|
|
|
418
|
+
o.banner = 'Usage: flowable history [options]'
|
|
419
|
+
o.on('--cases', 'Show case history (default)') { type = 'cases' }
|
|
420
|
+
o.on('--tasks', 'Show task history') { type = 'tasks' }
|
|
421
|
+
o.on('--processes', 'Show process history') { type = 'processes' }
|
|
422
|
+
o.on('--limit N', Integer, 'Limit results') { |v| limit = v }
|
|
423
|
+
end
|
|
424
|
+
opts.parse!(args)
|
|
425
|
+
|
|
426
|
+
case type
|
|
427
|
+
when 'cases'
|
|
428
|
+
result = client.history.case_instances(size: limit)
|
|
429
|
+
puts "Historic Case Instances (showing #{[limit, result['total']].min} of #{result['total']}):"
|
|
430
|
+
result['data'].each do |c|
|
|
431
|
+
status = c['endTime'] ? 'ENDED' : 'ACTIVE'
|
|
432
|
+
puts " [#{status}] #{c['id']} - #{c['caseDefinitionName']}"
|
|
433
|
+
puts " Started: #{c['startTime']} by #{c['startUserId']}"
|
|
434
|
+
puts " Ended: #{c['endTime']}" if c['endTime']
|
|
435
|
+
end
|
|
436
|
+
when 'tasks'
|
|
437
|
+
result = client.history.task_instances(size: limit)
|
|
438
|
+
puts "Historic Task Instances (showing #{[limit, result['total']].min} of #{result['total']}):"
|
|
439
|
+
result['data'].each do |t|
|
|
440
|
+
status = t['endTime'] ? 'COMPLETED' : 'ACTIVE'
|
|
441
|
+
puts " [#{status}] #{t['id']} - #{t['name']}"
|
|
442
|
+
puts " Assignee: #{t['assignee']}, Duration: #{t['durationInMillis']}ms"
|
|
443
|
+
end
|
|
444
|
+
when 'processes'
|
|
445
|
+
result = client.bpmn_history.process_instances(size: limit)
|
|
446
|
+
puts "Historic Process Instances (showing #{[limit, result['total']].min} of #{result['total']}):"
|
|
447
|
+
result['data'].each do |p|
|
|
448
|
+
status = p['endTime'] ? 'ENDED' : 'ACTIVE'
|
|
449
|
+
puts " [#{status}] #{p['id']} - #{p['processDefinitionId']}"
|
|
450
|
+
puts " Started: #{p['startTime']} by #{p['startUserId']}"
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def show_help
|
|
456
|
+
puts <<~HELP
|
|
457
|
+
Flowable CLI - Command line interface for Flowable REST API
|
|
458
|
+
|
|
459
|
+
Configuration:
|
|
460
|
+
flowable config --host HOST --port PORT --username USER --password PASS
|
|
461
|
+
flowable config --show
|
|
462
|
+
|
|
463
|
+
Deployments:
|
|
464
|
+
flowable deploy <file.cmmn.xml|file.bpmn.xml> [--tenant TENANT]
|
|
465
|
+
|
|
466
|
+
Definitions:
|
|
467
|
+
flowable definitions [--cmmn|--bpmn]
|
|
468
|
+
flowable defs
|
|
469
|
+
|
|
470
|
+
CMMN Cases:
|
|
471
|
+
flowable start <caseKey> [--var key=value] [--business-key KEY]
|
|
472
|
+
flowable cases [--key KEY] [--business-key KEY]
|
|
473
|
+
flowable case <caseInstanceId>
|
|
474
|
+
|
|
475
|
+
BPMN Processes:
|
|
476
|
+
flowable process-start <processKey> [--var key=value] [--business-key KEY]
|
|
477
|
+
flowable processes [--key KEY] [--business-key KEY]
|
|
478
|
+
|
|
479
|
+
Tasks:
|
|
480
|
+
flowable tasks [--assignee USER] [--candidate USER] [--case ID] [--unassigned]
|
|
481
|
+
flowable task <taskId>
|
|
482
|
+
flowable claim <taskId> <assignee>
|
|
483
|
+
flowable complete <taskId> [--var key=value] [--outcome OUTCOME]
|
|
484
|
+
|
|
485
|
+
Variables:
|
|
486
|
+
flowable vars <caseInstanceId>
|
|
487
|
+
flowable vars <taskId> --task
|
|
488
|
+
flowable set <caseInstanceId> key=value [key=value ...]
|
|
489
|
+
|
|
490
|
+
History:
|
|
491
|
+
flowable history [--cases|--tasks|--processes] [--limit N]
|
|
492
|
+
|
|
493
|
+
Help:
|
|
494
|
+
flowable help
|
|
495
|
+
HELP
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
def parse_value(value)
|
|
499
|
+
return true if value == 'true'
|
|
500
|
+
return false if value == 'false'
|
|
501
|
+
return value.to_i if value =~ /^\d+$/
|
|
502
|
+
return value.to_f if value =~ /^\d+\.\d+$/
|
|
503
|
+
|
|
504
|
+
value
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
# Run CLI
|
|
510
|
+
FlowableCLI::CLI.new.run(ARGV)
|