camunda-workflow 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -3
- data/lib/camunda.rb +25 -7
- data/lib/camunda/bpmn_xml.rb +22 -1
- data/lib/camunda/deployment.rb +22 -1
- data/lib/camunda/external_task.rb +64 -2
- data/lib/camunda/external_task_job.rb +23 -0
- data/lib/camunda/incident.rb +3 -0
- data/lib/camunda/matchers.rb +2 -1
- data/lib/camunda/model.rb +19 -0
- data/lib/camunda/poller.rb +8 -0
- data/lib/camunda/process_definition.rb +26 -1
- data/lib/camunda/process_instance.rb +8 -1
- data/lib/camunda/signal.rb +8 -1
- data/lib/camunda/task.rb +25 -9
- data/lib/camunda/variable_serialization.rb +11 -1
- data/lib/camunda/workflow.rb +44 -1
- data/lib/camunda/workflow/version.rb +1 -1
- data/lib/generators/camunda/bpmn_classes/bpmn_classes_generator.rb +9 -0
- data/lib/generators/camunda/install/install_generator.rb +5 -1
- data/lib/generators/camunda/install/templates/camunda_job.rb +1 -0
- data/lib/generators/camunda/spring_boot/spring_boot_generator.rb +7 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba961748beb590604ec47e0044a1ce7fa50f97d45bec52652a0e528011e4b2f3
|
4
|
+
data.tar.gz: 3886388d63f770a0fa49686489cbb5a82e3884df697d52cbb9c28582ac5dd867
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc768ad2478ce728101e69d6c891e53e0045a0ea266a0c2d87d87109f0692cc9d7b3c554f4048c261d96d06e23c3c4f2b66a1054ceeb8f8804bcf3de1748bc05
|
7
|
+
data.tar.gz: de9541842d8c4158a7bf7553a527ffd25a67fdd7dfb6d1b1da8fa5fe713cb58f01c41f0f2dc1d91984b903aae95d77c91b98ea1120661fcb2dd1d37109ec2420
|
data/CHANGELOG.md
CHANGED
@@ -1,15 +1,44 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [
|
3
|
+
## [v0.1.4](https://github.com/amalagaura/camunda-workflow/tree/v0.1.4) (2019-12-11)
|
4
4
|
|
5
|
-
[Full Changelog](https://github.com/amalagaura/camunda-workflow/compare/
|
5
|
+
[Full Changelog](https://github.com/amalagaura/camunda-workflow/compare/v0.1.3...v0.1.4)
|
6
|
+
|
7
|
+
**Closed issues:**
|
8
|
+
|
9
|
+
- add find\_by! [\#13](https://github.com/amalagaura/camunda-workflow/issues/13)
|
6
10
|
|
7
11
|
**Merged pull requests:**
|
8
12
|
|
13
|
+
- Add find\_by! to all Camunda Her models [\#14](https://github.com/amalagaura/camunda-workflow/pull/14) ([amalagaura](https://github.com/amalagaura))
|
14
|
+
- Yarddoc documentation [\#12](https://github.com/amalagaura/camunda-workflow/pull/12) ([curatingbits](https://github.com/curatingbits))
|
15
|
+
|
16
|
+
## [v0.1.3](https://github.com/amalagaura/camunda-workflow/tree/v0.1.3) (2019-12-06)
|
17
|
+
|
18
|
+
[Full Changelog](https://github.com/amalagaura/camunda-workflow/compare/v0.1.2...v0.1.3)
|
19
|
+
|
20
|
+
**Closed issues:**
|
21
|
+
|
22
|
+
- When there is a logic error in submitting a user task we are getting a MissingTask error instead [\#9](https://github.com/amalagaura/camunda-workflow/issues/9)
|
23
|
+
- If a class does not exist, the Poller loop crashes [\#7](https://github.com/amalagaura/camunda-workflow/issues/7)
|
24
|
+
|
25
|
+
**Merged pull requests:**
|
26
|
+
|
27
|
+
- Raise Submission errors if Camunda does not accept completion [\#11](https://github.com/amalagaura/camunda-workflow/pull/11) ([amalagaura](https://github.com/amalagaura))
|
28
|
+
- Allow Poller to not exit its loop when there is a missing class and report error [\#8](https://github.com/amalagaura/camunda-workflow/pull/8) ([amalagaura](https://github.com/amalagaura))
|
29
|
+
|
30
|
+
## [v0.1.2](https://github.com/amalagaura/camunda-workflow/tree/v0.1.2) (2019-11-27)
|
31
|
+
|
32
|
+
[Full Changelog](https://github.com/amalagaura/camunda-workflow/compare/fc9ab266909628118a892082abdff953f3bc7eca...v0.1.2)
|
33
|
+
|
34
|
+
**Merged pull requests:**
|
35
|
+
|
36
|
+
- Add rubocop rspec [\#6](https://github.com/amalagaura/camunda-workflow/pull/6) ([amalagaura](https://github.com/amalagaura))
|
9
37
|
- Correct find\_by\_business\_key\_and\_task\_definition\_key! [\#5](https://github.com/amalagaura/camunda-workflow/pull/5) ([amalagaura](https://github.com/amalagaura))
|
10
|
-
- added authentication via templates for spring
|
38
|
+
- added authentication via templates for spring\\_boot generator and Her [\#4](https://github.com/amalagaura/camunda-workflow/pull/4) ([curatingbits](https://github.com/curatingbits))
|
11
39
|
- Refactor to return proper Her models after responses [\#3](https://github.com/amalagaura/camunda-workflow/pull/3) ([amalagaura](https://github.com/amalagaura))
|
12
40
|
- Added tests for Camunda workflow [\#2](https://github.com/amalagaura/camunda-workflow/pull/2) ([curatingbits](https://github.com/curatingbits))
|
13
41
|
|
14
42
|
|
43
|
+
|
15
44
|
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
data/lib/camunda.rb
CHANGED
@@ -3,19 +3,25 @@ require 'active_support/core_ext/object/blank.rb'
|
|
3
3
|
require 'her'
|
4
4
|
require 'faraday'
|
5
5
|
require 'faraday_middleware'
|
6
|
-
|
6
|
+
# Top level module for camunda-workflow.
|
7
7
|
module Camunda
|
8
|
+
# Camunda class
|
8
9
|
class << self
|
10
|
+
# Allows setting the logger to a custom logger
|
9
11
|
attr_writer :logger
|
10
|
-
|
12
|
+
# Default is output to the standard output stream.
|
13
|
+
# @return [Object] instance which is used for logging
|
11
14
|
def logger
|
12
15
|
@logger ||= Logger.new($stdout).tap do |log|
|
13
16
|
log.progname = name
|
14
17
|
end
|
15
18
|
end
|
16
19
|
end
|
17
|
-
|
20
|
+
##
|
21
|
+
# Responsible for handling deserialization of variables.
|
18
22
|
class Her::Middleware::SnakeCase < Faraday::Response::Middleware
|
23
|
+
# Check if variables are an Array or JSON and ensure variable names are transformed back from camelCase to snake_case.
|
24
|
+
# @param env [Array,Hash]
|
19
25
|
def on_complete(env)
|
20
26
|
return if env[:body].blank?
|
21
27
|
|
@@ -28,23 +34,35 @@ module Camunda
|
|
28
34
|
env[:body] = JSON.generate(json)
|
29
35
|
end
|
30
36
|
|
37
|
+
private
|
38
|
+
|
39
|
+
# Return a new hash with all keys converted by the block operation.
|
31
40
|
def transform_hash!(hash)
|
32
41
|
hash.deep_transform_keys!(&:underscore)
|
33
42
|
end
|
34
43
|
end
|
35
|
-
|
44
|
+
# Error when class corresponding to Camunda bpmn task does not exist.
|
36
45
|
class MissingImplementationClass < StandardError
|
46
|
+
# Initializes message for MissingImplementationClass
|
37
47
|
def initialize(class_name)
|
38
48
|
super "Class to run a Camunda activity does not exist. Ensure there is a class with name: #{class_name} available."
|
39
49
|
end
|
40
50
|
end
|
41
|
-
|
51
|
+
# Error when deployment of process definition fails.
|
42
52
|
class ProcessEngineException < StandardError
|
43
53
|
end
|
44
|
-
|
54
|
+
# Error when BPMN process cannot be deployed.
|
45
55
|
class BpmnError < StandardError
|
46
|
-
|
56
|
+
# Camunda BPMN error code
|
57
|
+
# @return [String]
|
58
|
+
attr_reader :error_code
|
59
|
+
# variables to send to Camunda along with the error
|
60
|
+
# @return [Hash]
|
61
|
+
attr_reader :variables
|
47
62
|
|
63
|
+
# @param message [String]
|
64
|
+
# @param error_code [String]
|
65
|
+
# @param variables [Hash]
|
48
66
|
def initialize(message:, error_code:, variables: {})
|
49
67
|
super(message)
|
50
68
|
@error_code = error_code
|
data/lib/camunda/bpmn_xml.rb
CHANGED
@@ -1,50 +1,71 @@
|
|
1
|
+
# Used to parse bpmn file during bpmn_classes generator to create Camunda job class based on process id
|
1
2
|
class Camunda::BpmnXML
|
2
|
-
|
3
|
+
# @param io_or_string [IO,String] valid xml string for bpmn file
|
3
4
|
def initialize(io_or_string)
|
4
5
|
@doc = Nokogiri::XML(io_or_string)
|
5
6
|
end
|
6
7
|
|
8
|
+
# Friendly name of this BPMN file is the module name
|
9
|
+
# @return [String] module name
|
7
10
|
def to_s
|
8
11
|
module_name
|
9
12
|
end
|
10
13
|
|
14
|
+
# @return [String] Id (process definition key) of the BPMN process
|
15
|
+
# @example
|
16
|
+
# "CamundaWorkflow"
|
11
17
|
def module_name
|
12
18
|
@doc.xpath('/bpmn:definitions/bpmn:process').first['id']
|
13
19
|
end
|
14
20
|
|
21
|
+
# creates a new instance of Camunda::BpmnXML::Task
|
15
22
|
def external_tasks
|
16
23
|
@doc.xpath('//*[@camunda:type="external"]').map do |task|
|
17
24
|
Task.new(task)
|
18
25
|
end
|
19
26
|
end
|
20
27
|
|
28
|
+
# We may have tasks with different topics. Returns classes with topics which are the same as the BPMN process id
|
29
|
+
# @return [Array<String>] class names which should be implemented
|
30
|
+
# @example
|
31
|
+
# ["DoSomething"]
|
21
32
|
def class_names_with_same_bpmn_id_as_topic
|
22
33
|
tasks_with_same_bpmn_id_as_topic.map(&:class_name)
|
23
34
|
end
|
24
35
|
|
36
|
+
# @return [Array<String>] array of modularized class names
|
37
|
+
# @example
|
38
|
+
# ["CamundaWorkflow::DoSomething"]
|
25
39
|
def modularized_class_names
|
26
40
|
class_names_with_same_bpmn_id_as_topic.map { |name| "#{module_name}::#{name}" }
|
27
41
|
end
|
28
42
|
|
43
|
+
# @return [Array<String>] topics in this BPMN file
|
29
44
|
def topics
|
30
45
|
@doc.xpath('//*[@camunda:topic]').map { |node| node.attribute('topic').value }.uniq
|
31
46
|
end
|
32
47
|
|
33
48
|
private
|
34
49
|
|
50
|
+
# We may have tasks with different topics.
|
51
|
+
# @return [Array<Camunda::BpmnXML::Task>] tasks with topics which are the same as the BPMN process id
|
35
52
|
def tasks_with_same_bpmn_id_as_topic
|
36
53
|
external_tasks.select { |task| task.topic == module_name }
|
37
54
|
end
|
38
55
|
|
56
|
+
# Wrapper for BPMN task XML node
|
39
57
|
class Task
|
58
|
+
# Stores XML node about a task
|
40
59
|
def initialize(task)
|
41
60
|
@task = task
|
42
61
|
end
|
43
62
|
|
63
|
+
# Extracts class name from Task XML node
|
44
64
|
def class_name
|
45
65
|
@task.attribute('id').value
|
46
66
|
end
|
47
67
|
|
68
|
+
# Extracts topic name from Task XML node
|
48
69
|
def topic
|
49
70
|
@task.attribute('topic').value
|
50
71
|
end
|
data/lib/camunda/deployment.rb
CHANGED
@@ -1,6 +1,21 @@
|
|
1
|
+
# Deployment is responsible for creating BPMN, DMN, and CMMN processes within Camunda. Before a process (or case, or decision)
|
2
|
+
# can be executed by the process engine, it has to be deployed. A deployment is a logical entity that groups multiple resources
|
3
|
+
# that are deployed together. Camunda offers an application called Modeler(https://camunda.com/download/modeler/) that allows you
|
4
|
+
# to create and edit BPMN diagrams and BPMN decision tables.
|
5
|
+
# @see https://docs.camunda.org/manual/7.4/user-guide/process-engine/deployments/
|
6
|
+
# @note You must supply the paths of the BPMN files as a param titled file_names to deploy the BPMN file
|
7
|
+
# and deploy BPMN, DMN, CMMN definitions in the Camunda engine.
|
1
8
|
class Camunda::Deployment < Camunda::Model
|
2
9
|
collection_path 'deployment'
|
3
|
-
#
|
10
|
+
# Deploys a new process definition to Camunda and returns an instance of Camunda::ProcessDefinition.
|
11
|
+
# @note Only supporting .create which uses a POST on deployment/create.
|
12
|
+
# @example
|
13
|
+
# pd = Camunda::Deployment.create(file_names: ['bpmn/diagrams/sample.bpmn']).first
|
14
|
+
# @param files_names [Array<String>] file paths of the bpmn file for deployment
|
15
|
+
# @param tenant_id [String] supplied when a single Camunda installation should serve more than one tenant
|
16
|
+
# @param deployment_source [String] the source of where the deployment occurred.
|
17
|
+
# @param deployment_name [String] provide the name of the deployment, otherwise the deployment name will be the bpmn file names.
|
18
|
+
# @return [Camunda::ProcessDefinition]
|
4
19
|
def self.create(file_names:, tenant_id: nil, deployment_source: 'Camunda Workflow Gem', deployment_name: nil)
|
5
20
|
deployment_name ||= file_names.map { |file_name| File.basename(file_name) }.join(", ")
|
6
21
|
tenant_id ||= Camunda::Workflow.configuration.tenant_id
|
@@ -11,12 +26,18 @@ class Camunda::Deployment < Camunda::Model
|
|
11
26
|
deployed_process_definitions(response[:parsed_data][:data][:deployed_process_definitions])
|
12
27
|
end
|
13
28
|
|
29
|
+
# Convenience method for dealing with files and IO that are to be uploaded
|
30
|
+
# @param file_names [Array<String>] local files paths to be uploaded
|
14
31
|
def self.file_data(file_names)
|
15
32
|
file_names.map do |file_name|
|
16
33
|
[file_name, UploadIO.new(file_name, 'text/plain')]
|
17
34
|
end.to_h
|
18
35
|
end
|
19
36
|
|
37
|
+
# Returns a new instance of Camunda::ProcessDefinition according to definitions hash returned by Camunda
|
38
|
+
# @raise [ProcessEngineException] if process definition is nil
|
39
|
+
# @param definitions_hash [Hash]
|
40
|
+
# @return [Array<Camunda::ProcessDefinition>]
|
20
41
|
def self.deployed_process_definitions(definitions_hash)
|
21
42
|
# Currently only returning the process definitions. But this Deployment.create can create a DMN, CMMN also
|
22
43
|
# It returns :deployed_process_definitions, :deployed_case_definitions, :deployed_decision_definitions,
|
@@ -1,22 +1,42 @@
|
|
1
1
|
require 'active_support/core_ext/string/inflections.rb'
|
2
|
-
|
2
|
+
# External Tasks are the task entity for camunda. We can query the topic and lock the task. After the task
|
3
|
+
# is locked, the external task of the process instance can be worked and completed. Below is an excerpt from the Camunda
|
4
|
+
# documentation regarding the ExternalTask process.
|
5
|
+
# @see https://docs.camunda.org/manual/7.7/user-guide/process-engine/external-tasks/
|
6
|
+
# "When the process engine encounters a service task that is configured to be externally handled, it creates an external task
|
7
|
+
# instance and adds it to a list of external tasks(step 1). The task instance receives a topic that identifies the nature of
|
8
|
+
# the work to be performed. At a time in the future, an external worker may fetch and lock tasks for a specific set of
|
9
|
+
# topics (step 2). To prevent one task being fetched by multiple workers at the same time, a task has a timestamp-based lock
|
10
|
+
# that is set when the task is acquired. Only when the lock expires, another worker can fetch the task again. When an external
|
11
|
+
# worker has completed the desired work, it can signal the process engine to continue process execution after the service
|
12
|
+
# task (step 3)."
|
3
13
|
class Camunda::ExternalTask < Camunda::Model
|
14
|
+
# Camunda engine doesn't searching on snake_case variables.
|
4
15
|
include Camunda::VariableSerialization
|
16
|
+
# collection_path sets the path for Her in Camunda::Model
|
5
17
|
collection_path 'external-task'
|
6
18
|
custom_post :fetchAndLock, :unlock
|
7
19
|
|
20
|
+
# @note long_polling_duration is defaulted to 30 seconds in Camunda::Workflow.configuration.
|
21
|
+
# @return [Integer] default polling duration from Camunda::Workflow configuration
|
8
22
|
def self.long_polling_duration
|
9
23
|
Camunda::Workflow.configuration.long_polling_duration.in_milliseconds
|
10
24
|
end
|
11
25
|
|
26
|
+
# @note Max polling tasks is defaulted to 2 in Camunda::Workflow.configuration.
|
27
|
+
# @return [Integer] sets the max polling tasks
|
12
28
|
def self.max_polling_tasks
|
13
29
|
Camunda::Workflow.configuration.max_polling_tasks
|
14
30
|
end
|
15
31
|
|
32
|
+
# Default lock duration time is set to 14 days in Camunda::Workflow.configuration.
|
33
|
+
# @return [Integer] default lock duration time
|
16
34
|
def self.lock_duration
|
17
35
|
Camunda::Workflow.configuration.lock_duration.in_milliseconds
|
18
36
|
end
|
19
37
|
|
38
|
+
# Reports a failure to Camunda process definition and creates an incident for a process instance.
|
39
|
+
# @param input_variables [Hash] process variables
|
20
40
|
def failure(exception, input_variables={})
|
21
41
|
variables_information = "Input variables are #{input_variables.inspect}\n\n" if input_variables.present?
|
22
42
|
self.class.post_raw("#{collection_path}/#{id}/failure",
|
@@ -24,12 +44,17 @@ class Camunda::ExternalTask < Camunda::Model
|
|
24
44
|
errorDetails: variables_information.to_s + exception.full_message)[:response]
|
25
45
|
end
|
26
46
|
|
47
|
+
# Reports the error to Camunda and creates an incident for the process instance.
|
48
|
+
# @param bpmn_exception [Camunda::BpmnError]
|
27
49
|
def bpmn_error(bpmn_exception)
|
28
50
|
self.class.post_raw("#{collection_path}/#{id}/bpmnError",
|
29
51
|
workerId: worker_id, variables: serialize_variables(bpmn_exception.variables),
|
30
52
|
errorCode: bpmn_exception.error_code, errorMessage: bpmn_exception.message)[:response]
|
31
53
|
end
|
32
54
|
|
55
|
+
# Completes the process instance of a fetched task
|
56
|
+
# @param variables [Hash] submitted when starting the process definition
|
57
|
+
# @raise [Camunda::ExternalTask::SubmissionError] if Camunda does not accept the task submission
|
33
58
|
def complete(variables={})
|
34
59
|
self.class.post_raw("#{collection_path}/#{id}/complete",
|
35
60
|
workerId: worker_id, variables: serialize_variables(variables))[:response]
|
@@ -38,14 +63,20 @@ class Camunda::ExternalTask < Camunda::Model
|
|
38
63
|
end
|
39
64
|
end
|
40
65
|
|
66
|
+
# Returns the worker id for an external task
|
67
|
+
# @note default is set to '0' in Camunda::Workflow.configuration
|
68
|
+
# @return [String]
|
41
69
|
def worker_id
|
42
70
|
self.class.worker_id
|
43
71
|
end
|
44
72
|
|
73
|
+
# Helper method for instances since collection_path is a class method
|
74
|
+
# @return [String]
|
45
75
|
def collection_path
|
46
76
|
self.class.collection_path
|
47
77
|
end
|
48
78
|
|
79
|
+
# deserializes JSON attributes from variables returned by Camunda API
|
49
80
|
def variables
|
50
81
|
super.transform_values do |details|
|
51
82
|
if details['type'] == 'Json'
|
@@ -56,14 +87,39 @@ class Camunda::ExternalTask < Camunda::Model
|
|
56
87
|
end
|
57
88
|
end
|
58
89
|
|
90
|
+
# Queues the task to run at a specific time via ActiveJob
|
91
|
+
# @example
|
92
|
+
# # Below will retrieve current running process instances with the definition key "CamundaWorkflow"
|
93
|
+
# # and queues the instances to be run at a specific time.
|
94
|
+
# task = Camunda::ExternalTask.fetch_and_lock("CamundaWorkflow")
|
95
|
+
# task.each(&:queue_task)
|
96
|
+
# @return [Camunda::ExternalTask]
|
59
97
|
def queue_task
|
60
98
|
task_class.perform_later(id, variables)
|
61
99
|
end
|
62
100
|
|
101
|
+
# Runs the task using ActiveJob based on the classes created by bpmn_classes_generator. Before an external task
|
102
|
+
# can be run, you must #fetch_and_lock the task.
|
103
|
+
# @see fetch_and_lock
|
104
|
+
# @example
|
105
|
+
# # Below will retrieve current running process instances with the definition key "CamundaWorkflow"
|
106
|
+
# # and run the instances.
|
107
|
+
# task = Camunda::ExternalTask.fetch_and_lock("CamundaWorkflow")
|
108
|
+
# task.each(&:run_now)
|
109
|
+
# @return [Camunda::ExternalTask]
|
63
110
|
def run_now
|
64
111
|
task_class_name.safe_constantize.perform_now id, variables
|
65
112
|
end
|
66
113
|
|
114
|
+
# Locking means that the task is reserved for this worker for a certain duration beginning with the time of fetching and
|
115
|
+
# prevents that another worker can fetch the same task while the lock is valid. Locking duration is set in the the
|
116
|
+
# Camunda::Workflow configuration. Before an external task can be completed, it must be locked.
|
117
|
+
# @example
|
118
|
+
# task = Camunda::ExternalTask.fetch_and_lock("CamundaWorkflow")
|
119
|
+
# @param topics [Array<String>] definition keys
|
120
|
+
# @param lock_duration [Integer]
|
121
|
+
# @param long_polling_duration [Integer]
|
122
|
+
# @return [Camunda::ExternalTask]
|
67
123
|
def self.fetch_and_lock(topics, lock_duration: nil, long_polling_duration: nil)
|
68
124
|
long_polling_duration ||= long_polling_duration()
|
69
125
|
lock_duration ||= lock_duration()
|
@@ -74,16 +130,22 @@ class Camunda::ExternalTask < Camunda::Model
|
|
74
130
|
topics: topic_details
|
75
131
|
end
|
76
132
|
|
133
|
+
# Returns the class name which is supposed to implement this task
|
134
|
+
# @return [String] modularized class name of bpmn task implementation
|
77
135
|
def task_class_name
|
78
136
|
"#{process_definition_key}::#{activity_id}"
|
79
137
|
end
|
80
138
|
|
139
|
+
# Checks to make sure an implementation class is available
|
140
|
+
# @return [Module] return class name
|
141
|
+
# @raise [Camunda::MissingImplementationClass] if the class does not exist
|
81
142
|
def task_class
|
82
143
|
task_class_name.safe_constantize.tap do |klass|
|
83
144
|
raise Camunda::MissingImplementationClass, task_class_name unless klass
|
84
145
|
end
|
85
146
|
end
|
86
|
-
|
147
|
+
# If the BPMN file expects a variable and the variable isn't supplied with an SubmissionError will be raised
|
148
|
+
# indicating that the variable does not exist.
|
87
149
|
class SubmissionError < StandardError
|
88
150
|
end
|
89
151
|
end
|
@@ -1,4 +1,16 @@
|
|
1
|
+
# Camunda::ExternalTaskJob module is included in the generated bpmn_classes for ActiveJob and handles
|
2
|
+
# the task completion or failure for a given worker that has been locked to be performed.
|
3
|
+
# @see Camunda::ExternalTask
|
1
4
|
module Camunda::ExternalTaskJob
|
5
|
+
# Performs the external task for the process definition and processes completion or throws an error. The below example
|
6
|
+
# shows how to run a task based off of our generated classes from the bpmn_classes generator from the sample.bpmn file
|
7
|
+
# provided.
|
8
|
+
# @example
|
9
|
+
# task = Camunda::ExternalTask.fetch_and_lock('CamundaWorkflow').first
|
10
|
+
# CamundaWorkflow::DoSomething.new.perform(task.id, x: 'abcd')
|
11
|
+
# @param id [Integer] of the worker for the locked task
|
12
|
+
# @param input_variables [Hash]
|
13
|
+
# @raise [Camunda::ExternalTask::SubmissionError] if Camunda does not accept the submission of the task
|
2
14
|
def perform(id, input_variables)
|
3
15
|
output_variables = bpmn_perform(input_variables)
|
4
16
|
output_variables = {} if output_variables.nil?
|
@@ -14,24 +26,35 @@ module Camunda::ExternalTaskJob
|
|
14
26
|
report_failure id, e, input_variables
|
15
27
|
end
|
16
28
|
|
29
|
+
# Reports completion for an external task with output variable set in bpmn_perform.
|
30
|
+
# @param id [Integer] of the worker
|
31
|
+
# @param variables [Hash] output variables declared in bpmn_perform
|
17
32
|
def report_completion(id, variables)
|
18
33
|
# Submit to Camunda using
|
19
34
|
# POST /external-task/{id}/complete
|
20
35
|
Camunda::ExternalTask.new(id: id).complete(variables)
|
21
36
|
end
|
22
37
|
|
38
|
+
# Reports external task failure to the Camunda process definition and creates an incident report
|
39
|
+
# @param id [Integer] of the worker for the process instance
|
40
|
+
# @param exception [Object] the exception for the failed task
|
41
|
+
# @param input_variables [Hash] given to the process definition
|
23
42
|
def report_failure(id, exception, input_variables)
|
24
43
|
# Submit error state to Camunda using
|
25
44
|
# POST /external-task/{id}/failure
|
26
45
|
Camunda::ExternalTask.new(id: id).failure(exception, input_variables)
|
27
46
|
end
|
28
47
|
|
48
|
+
# Reports an error if there is a problem with bpmn_perform
|
49
|
+
# @param id [Integer] of the process instance
|
50
|
+
# @param exception [Camunda::BpmnError] instance of Camunda::BpmnError
|
29
51
|
def report_bpmn_error(id, exception)
|
30
52
|
# Submit bpmn error state to Camunda using
|
31
53
|
# POST /external-task/{id}/bpmnError
|
32
54
|
Camunda::ExternalTask.new(id: id).bpmn_error(exception)
|
33
55
|
end
|
34
56
|
|
57
|
+
# Default bpmn_perform which raises an error. Forces user to create their own implementation
|
35
58
|
def bpmn_perform(_variables)
|
36
59
|
raise StandardError, "Please define this method which takes a hash of variables and returns a hash of variables"
|
37
60
|
end
|
data/lib/camunda/incident.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# Allows for incidents to be reported to Camunda. Incidents are notable events
|
2
|
+
# that happen in the process engine. Such incidents usually indicate some kind of problem
|
3
|
+
# related to process execution. Incidents are reported on failures that occur.
|
1
4
|
class Camunda::Incident < Camunda::Model
|
2
5
|
collection_path 'incident'
|
3
6
|
end
|
data/lib/camunda/matchers.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
# RSpec matcher for topic names used for testing bpmn files
|
1
2
|
RSpec::Matchers.define :have_topics do |topic_names|
|
2
3
|
match { |bpmn_xml| topic_names.sort == bpmn_xml.topics.sort }
|
3
4
|
failure_message { |bpmn_xml| "Expected #{topic_names}. Found #{bpmn_xml.topics.sort}" }
|
4
5
|
end
|
5
|
-
|
6
|
+
# RSpec matcher used for testing bpmn files
|
6
7
|
RSpec::Matchers.define :have_module do |module_name_expected|
|
7
8
|
match { |bpmn_xml| module_name_expected == bpmn_xml.module_name }
|
8
9
|
failure_message { |bpmn_xml| "ID of the BPMN process is #{bpmn_xml.module_name}. Expected #{module_name_expected}" }
|
data/lib/camunda/model.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'her/model'
|
2
|
+
# This class in the main element of Her. It defines which API models will be bound to.
|
2
3
|
class Camunda::Model
|
3
4
|
include Her::Model
|
4
5
|
|
6
|
+
# We use a lambda so that this is evaluated after Camunda::Workflow.configuration is set
|
5
7
|
api = lambda do
|
8
|
+
# Configuration for Her and Faraday requests and responses
|
6
9
|
Her::API.new(url: File.join(Camunda::Workflow.configuration.engine_url)) do |c|
|
7
10
|
c.path_prefix = Camunda::Workflow.configuration.engine_route_prefix
|
8
11
|
# Request
|
@@ -22,7 +25,23 @@ class Camunda::Model
|
|
22
25
|
|
23
26
|
use_api api
|
24
27
|
|
28
|
+
# Returns result of find_by but raises an exception instead of returning nil
|
29
|
+
# @param params [Hash] query parameters
|
30
|
+
# @return [Camunda::Model]
|
31
|
+
# @raise [Camunda::Model::RecordNotFound] if query returns no results
|
32
|
+
def self.find_by!(params)
|
33
|
+
find_by(params).tap do |result|
|
34
|
+
raise Camunda::Model::RecordNotFound unless result
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the worker id
|
39
|
+
# @note default worker id is set in Camunda::Workflow.configuration
|
40
|
+
# @return [String] id of worker
|
25
41
|
def self.worker_id
|
26
42
|
Camunda::Workflow.configuration.worker_id
|
27
43
|
end
|
44
|
+
|
45
|
+
class RecordNotFound < StandardError
|
46
|
+
end
|
28
47
|
end
|
data/lib/camunda/poller.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
+
# The poller will run as an infinite loop with long polling to fetch tasks, queue, and run them.
|
2
|
+
# Topic is the process definition key. Below will run the poller to fetch, lock, and run a task for the
|
3
|
+
# example process definition with an id of CamundaWorkflow.
|
4
|
+
# @example
|
5
|
+
# Camunda::Poller.fetch_and_execute %w[CamundaWorkflow]
|
1
6
|
class Camunda::Poller
|
7
|
+
# @param topics [Array] process definition keys
|
8
|
+
# @param lock_duration [Integer] lock duration time, default time is set in Camunda::Workflow.configuration
|
9
|
+
# @param long_polling_duration [Integer] long polling time, default is set to Camunda::Workflow.configuration
|
2
10
|
def self.fetch_and_execute(topics, lock_duration: nil, long_polling_duration: nil)
|
3
11
|
loop do
|
4
12
|
Camunda::ExternalTask
|
@@ -1,7 +1,22 @@
|
|
1
|
+
##
|
2
|
+
# A process definition defines the structure of a process. The `key` of a process definition is the logical
|
3
|
+
# identifier of the process. It is used throughout the API, most prominently for starting a process instances.
|
4
|
+
# The key of a process definition is defined using the `id` property of the corresponding process element in the BPMN XML file.
|
5
|
+
# @see https://docs.camunda.org/manual/7.7/user-guide/process-engine/process-engine-concepts/
|
6
|
+
# @see Camunda::ProcessInstance
|
1
7
|
class Camunda::ProcessDefinition < Camunda::Model
|
2
8
|
include Camunda::VariableSerialization
|
3
9
|
collection_path 'process-definition'
|
4
|
-
|
10
|
+
# Starts an individual process instance by key and supplies process variables to be included in the process instance. In
|
11
|
+
# the example below a business key is provided. A business key is a domain-specific identifier of a process instance,
|
12
|
+
# it makes querying for task more efficient. The business key is displayed prominently in applications like Camunda Cockpit.
|
13
|
+
# @see https://blog.camunda.com/post/2018/10/business-key/
|
14
|
+
# @example
|
15
|
+
# pd = Camunda::ProcessDefinition.start_by_key 'CamundaWorkflow', variables: { x: 'abcd' }, businessKey: 'WorkflowBusinessKey'
|
16
|
+
# @param key [String] process definition identifier
|
17
|
+
# @param hash [Hash] sets variables to be included with starting a process definition
|
18
|
+
# @return [Camunda::ProcessInstance]
|
19
|
+
# @raise [Camunda::ProcessEngineException] if submission was unsuccessful
|
5
20
|
def self.start_by_key(key, hash={})
|
6
21
|
hash[:variables] = serialize_variables(hash[:variables]) if hash[:variables]
|
7
22
|
tenant_id = hash.delete(:tenant_id)
|
@@ -13,6 +28,15 @@ class Camunda::ProcessDefinition < Camunda::Model
|
|
13
28
|
Camunda::ProcessInstance.new response[:parsed_data][:data]
|
14
29
|
end
|
15
30
|
|
31
|
+
# Starts an individual process instance for a process definition. The below example shows how to start a process
|
32
|
+
# definition after deployment.
|
33
|
+
# @example
|
34
|
+
# pd = Camunda::Deployment.create(file_names: ['bpmn/diagrams/sample.bpmn']).first
|
35
|
+
# pd.start
|
36
|
+
# Starts the process instance by sending a request to the Camunda engine
|
37
|
+
# @param hash [Hash] defaults to {} if no variables are provided
|
38
|
+
# @return [Camunda::ProcessInstance]
|
39
|
+
# @raise [Camunda::ProcessEngineException] if submission was unsuccessful
|
16
40
|
def start(hash={})
|
17
41
|
hash[:variables] = serialize_variables(hash[:variables]) if hash[:variables]
|
18
42
|
response = self.class.post_raw "process-definition/#{id}/start", hash
|
@@ -21,6 +45,7 @@ class Camunda::ProcessDefinition < Camunda::Model
|
|
21
45
|
Camunda::ProcessInstance.new response[:parsed_data][:data]
|
22
46
|
end
|
23
47
|
|
48
|
+
# Sets path to include tenant_id if a tenant_id is provided with a process definition on deployment.
|
24
49
|
def self.start_path_for_key(key, tenant_id)
|
25
50
|
path = "process-definition/key/#{key}"
|
26
51
|
path << "/tenant-id/#{tenant_id}" if tenant_id
|
@@ -1,6 +1,11 @@
|
|
1
|
+
# A process instance is an individual execution of a process definition. The relation of the process instance to the process
|
2
|
+
# definition is the same as the relation between Class and Class instance in OOP. When a process definition is started,
|
3
|
+
# a process instance is created.
|
4
|
+
# @see https://docs.camunda.org/manual/7.4/user-guide/process-engine/process-engine-concepts/
|
5
|
+
# @see Camunda::ProcessDefinition
|
1
6
|
class Camunda::ProcessInstance < Camunda::Model
|
2
7
|
collection_path 'process-instance'
|
3
|
-
|
8
|
+
# GETs the process instance and deserializes the variables
|
4
9
|
def variables
|
5
10
|
response = self.class.get_raw "process-instance/#{id}/variables"
|
6
11
|
deserialize_variables response[:parsed_data][:data]
|
@@ -8,6 +13,8 @@ class Camunda::ProcessInstance < Camunda::Model
|
|
8
13
|
|
9
14
|
private
|
10
15
|
|
16
|
+
# Deserialize variables and convert variable names from CamelCase to snake_case.
|
17
|
+
# @param hash [Hash] Transforms a hash of Camunda serialized variables to a simple Ruby hash and snake_cases variable names
|
11
18
|
def deserialize_variables(hash)
|
12
19
|
hash.transform_values do |value_hash|
|
13
20
|
case value_hash[:type]
|
data/lib/camunda/signal.rb
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
+
##
|
2
|
+
# Signal events are events which reference a named signal. Camunda::Signal is used to
|
3
|
+
# create a signal with variables.
|
4
|
+
# @example
|
5
|
+
# `Camunda::Signal.create name: 'Signal Name', variables: {foo: "bar"}`
|
1
6
|
class Camunda::Signal < Camunda::Model
|
2
7
|
include Camunda::VariableSerialization
|
3
8
|
collection_path 'signal'
|
4
|
-
|
9
|
+
# Creates a signal within the process definition on the Camunda engine
|
10
|
+
# @param hash [Hash] variables that are sent to Camunda engine
|
11
|
+
# @return [{Symbol => Hash,Faraday::Response}]
|
5
12
|
def self.create(hash={})
|
6
13
|
hash[:variables] = serialize_variables(hash[:variables]) if hash[:variables]
|
7
14
|
post_raw collection_path, hash
|
data/lib/camunda/task.rb
CHANGED
@@ -1,16 +1,33 @@
|
|
1
|
+
# Finds tasks by business key and task definition and allows you to report a task complete and update process variables.
|
2
|
+
# If a business key isn't supplied when creating a process definition, you can still retrieve UserTasks by using
|
3
|
+
# the `.find_by` helper provided by Her.
|
4
|
+
# @see Camunda::ProcessDefinition
|
5
|
+
# @see https://github.com/remi/her
|
6
|
+
# @example
|
7
|
+
# Camunda::Task.find_by(taskDefinitionKey: 'UserTask')
|
8
|
+
# @example
|
9
|
+
# # You can get all tasks with the `.all.each` helper
|
10
|
+
# tasks = Camunda::Task.all.each
|
11
|
+
# # And then complete all tasks like so
|
12
|
+
# tasks.each(&:complete!)
|
1
13
|
class Camunda::Task < Camunda::Model
|
2
14
|
include Camunda::VariableSerialization
|
3
15
|
collection_path 'task'
|
4
16
|
|
17
|
+
# @example
|
18
|
+
# user_task = Camunda::Task.find_by_business_key_and_task_definition_key!('WorkflowBusinessKey','UserTask')
|
19
|
+
# @param instance_business_key [String] the process instance business key
|
20
|
+
# @param task_key [String] id/key of the user task
|
21
|
+
# @return [Camunda::Task]
|
5
22
|
def self.find_by_business_key_and_task_definition_key!(instance_business_key, task_key)
|
6
|
-
find_by(processInstanceBusinessKey: instance_business_key, taskDefinitionKey: task_key)
|
7
|
-
unless ct
|
8
|
-
raise MissingTask, "Could not find Camunda Task with processInstanceBusinessKey: #{instance_business_key} " \
|
9
|
-
"and taskDefinitionKey #{task_key}"
|
10
|
-
end
|
11
|
-
end
|
23
|
+
find_by!(processInstanceBusinessKey: instance_business_key, taskDefinitionKey: task_key)
|
12
24
|
end
|
13
25
|
|
26
|
+
# Complete a task and updates process variables.
|
27
|
+
# @example
|
28
|
+
# user_task = Camunda::Task.find_by_business_key_and_task_definition_key!('WorkflowBusinessKey','UserTask')
|
29
|
+
# user_task.complete!
|
30
|
+
# @param vars [Hash] variables to be submitted as part of task completion
|
14
31
|
def complete!(vars={})
|
15
32
|
self.class.post_raw("#{self.class.collection_path}/#{id}/complete", variables: serialize_variables(vars))[:response]
|
16
33
|
.tap do |response|
|
@@ -18,9 +35,8 @@ class Camunda::Task < Camunda::Model
|
|
18
35
|
end
|
19
36
|
end
|
20
37
|
|
21
|
-
class
|
22
|
-
|
23
|
-
|
38
|
+
# Error class when the task cannot be submitted. For instance if the bpmn process expects a variable and the variable
|
39
|
+
# isn't supplied, Camunda will not accept the task
|
24
40
|
class SubmissionError < StandardError
|
25
41
|
end
|
26
42
|
end
|
@@ -1,14 +1,21 @@
|
|
1
1
|
require 'active_support/concern'
|
2
2
|
module Camunda
|
3
|
+
# The VariableSerialization module adds information to variables so Camunda can parse them. It adds types annotations and
|
4
|
+
# serializes hashes and array to JSON. Camunda engine cannot search on snake_case variables so it changes variable names
|
5
|
+
# to camelCase.
|
6
|
+
# @see Camunda::ProcessDefinition
|
3
7
|
module VariableSerialization
|
4
8
|
extend ActiveSupport::Concern
|
5
|
-
|
9
|
+
# Wrapper for class level method
|
6
10
|
def serialize_variables(variables)
|
7
11
|
self.class.serialize_variables(variables)
|
8
12
|
end
|
9
13
|
|
10
14
|
class_methods do
|
11
15
|
# rubocop:disable Metrics/MethodLength
|
16
|
+
# @param variables [Hash]
|
17
|
+
# @return {String,Symbol => {String,Symbol => Object}}
|
18
|
+
# @raise [ArgumentError] if a class instance is passed
|
12
19
|
def serialize_variables(variables)
|
13
20
|
hash = variables.transform_values do |value|
|
14
21
|
case value
|
@@ -30,6 +37,9 @@ module Camunda
|
|
30
37
|
end
|
31
38
|
# rubocop:enable Metrics/MethodLength
|
32
39
|
|
40
|
+
# Transforms keys of a JSON like object (Array,Hash) from snake_case to CamelCase
|
41
|
+
# @param json [Array,Hash]
|
42
|
+
# @return [Hash] returns hash with camelCase keys
|
33
43
|
def transform_json(json)
|
34
44
|
if json.is_a?(Array)
|
35
45
|
json.map { |element| transform_json(element) }
|
data/lib/camunda/workflow.rb
CHANGED
@@ -1,22 +1,65 @@
|
|
1
1
|
module Camunda
|
2
|
+
##
|
3
|
+
# Default configuration file for camunda-workflow. These defaults can be overridden using an
|
4
|
+
# initializer file within a Rails application.
|
5
|
+
# @example override default values
|
6
|
+
# Camunda::Workflow.configure do |config|
|
7
|
+
# config.engine_url = 'http://localhost:8080'
|
8
|
+
# config.engine_route_prefix = 'rest'
|
9
|
+
# end
|
2
10
|
module Workflow
|
11
|
+
# Implements Configuration class and sets default instance variables. The default variables can be overridden by creating an
|
12
|
+
# initializer file within your rails application and setting the variables like in the example below.
|
13
|
+
# @note if HTTP Basic Auth is used with the Camunda engine, this is where you would set a camunda_user and camunda_password
|
14
|
+
# using the creditials from a user setup in Camunda Admin.
|
15
|
+
# @example
|
16
|
+
# 'Camunda::Workflow.configure do |config|
|
17
|
+
# config.engine_url = 'http://localhost:8080'
|
18
|
+
# config.engine_route_prefix = 'rest'
|
19
|
+
# end'
|
3
20
|
def self.configure
|
4
21
|
yield(configuration)
|
5
22
|
end
|
6
23
|
|
24
|
+
# Access the Configuration class
|
25
|
+
# @return [Configuration]
|
7
26
|
def self.configuration
|
8
27
|
@configuration ||= Configuration.new
|
9
28
|
end
|
10
|
-
|
29
|
+
# Default instance variables configurations for Her and camunda-workflow
|
11
30
|
class Configuration
|
31
|
+
# Sets the deult engine url for Camunda REST Api
|
32
|
+
# @return [String] the url for Camunda deployment
|
12
33
|
attr_accessor :engine_url
|
34
|
+
# Engine route prefix that determines the path for the REST Api
|
35
|
+
# Default route for Java spring app is `/rest`
|
36
|
+
# Default route for Camunda deployment is `/rest-engine`
|
37
|
+
# @return [String] the prefix for Camunda REST Api
|
13
38
|
attr_accessor :engine_route_prefix
|
39
|
+
# Name of worker, defaults to '0'
|
40
|
+
# @return [String] name of worker
|
14
41
|
attr_accessor :worker_id
|
42
|
+
# The default fetch_and_lock time duration when fetching a task
|
43
|
+
# @return [Integer] time in days to lock task
|
15
44
|
attr_accessor :lock_duration
|
45
|
+
# Max polling tasks when using the command line to fetch and lock tasks
|
46
|
+
# @return [Integer] default is set to fetch and lock 2 tasks
|
16
47
|
attr_accessor :max_polling_tasks
|
48
|
+
# With the aid of log polling, a request is suspended by the server if no external tasks are available.
|
49
|
+
# Long polling significantly reduces the number of request and enables using resources more
|
50
|
+
# efficiently on both the server and client.
|
51
|
+
# @return [Integer]
|
17
52
|
attr_accessor :long_polling_duration
|
53
|
+
# The tenant identifier is specified on the deployment and is propagated to all data
|
54
|
+
# that is created from the deployment(e.g. process definitions, process instances, tacks).
|
55
|
+
# @return [String] name for tenant identifier
|
18
56
|
attr_accessor :tenant_id
|
57
|
+
# When HTTP Basic Auth is turned on for Camunda, a user needs to be created in Camunda Admin
|
58
|
+
# and set in to be used in the configuration.
|
59
|
+
# @return [String] Camunda user name for HTTP Basic Auth
|
19
60
|
attr_accessor :camunda_user
|
61
|
+
# Camunda password is supplied with the Camunda user to authenticate using HTTP Basic Auth.
|
62
|
+
# @return [String] Camunda password for HTTP Basic Auth
|
20
63
|
attr_accessor :camunda_password
|
21
64
|
|
22
65
|
def initialize
|
@@ -1,15 +1,20 @@
|
|
1
1
|
module Camunda
|
2
2
|
module Generators
|
3
|
+
# Parses the BPMN file and creates task classes according to the ID of the process file and the ID of
|
4
|
+
# each task. It checks each task and only creates it if the topic name is the same as the process ID. This
|
5
|
+
# allows one to have some tasks be handled outside the Rails app. It confirms that the ID's are valid Ruby constant names.
|
3
6
|
class BpmnClassesGenerator < Rails::Generators::Base
|
4
7
|
source_root File.expand_path('templates', __dir__)
|
5
8
|
argument :bpmn_file, type: :string
|
6
9
|
class_option :model_path, type: :string, default: 'app/bpmn'
|
7
10
|
|
11
|
+
# @return [String] The id of the BPMN process
|
8
12
|
def validate_module_name
|
9
13
|
puts "The id of the BPMN process is: #{colored_module_name}. That will be your module name."
|
10
14
|
validate_constant_name(module_name)
|
11
15
|
end
|
12
16
|
|
17
|
+
# Creates a class name to be used for the task classes created to perform external tasks.
|
13
18
|
def validate_class_names
|
14
19
|
bpmn_xml.modularized_class_names.each do |class_name|
|
15
20
|
validate_constant_name(class_name.demodulize, module_name)
|
@@ -19,10 +24,13 @@ module Camunda
|
|
19
24
|
puts colorized_class_names.join("\n")
|
20
25
|
end
|
21
26
|
|
27
|
+
# Creates module names to be used for the task classes to perform external tasks.
|
22
28
|
def create_module
|
23
29
|
template 'bpmn_module.rb.template', File.join(model_path, "#{module_name.underscore}.rb")
|
24
30
|
end
|
25
31
|
|
32
|
+
# Creates the correct classes from the bpmn file to be used in the provided generator template for the classes
|
33
|
+
# needed to run external tasks.
|
26
34
|
def create_classes
|
27
35
|
bpmn_xml.class_names_with_same_bpmn_id_as_topic.each do |class_name|
|
28
36
|
template 'bpmn_class.rb.template',
|
@@ -32,6 +40,7 @@ module Camunda
|
|
32
40
|
|
33
41
|
private
|
34
42
|
|
43
|
+
# Validates constant names by attempting to create a Ruby constant
|
35
44
|
def validate_constant_name(name, module_name=nil)
|
36
45
|
top_level = module_name.nil? ? Module.new : module_name.constantize
|
37
46
|
colorized_name = set_color name, :red
|
@@ -1,8 +1,12 @@
|
|
1
1
|
module Camunda
|
2
|
+
# Generator to run and install camunda_job.rb that includes ExternalTaskJob to be used with task classes.
|
2
3
|
module Generators
|
4
|
+
# Creates `app/jobs/camunda_job.rb`. A class which inherits from ApplicationJob and includes `ExternalTaskJob`.
|
5
|
+
# It can be changed to include Sidekiq::Worker instead.
|
6
|
+
# All of the BPMN worker classes will inherit from this class
|
3
7
|
class InstallGenerator < Rails::Generators::Base
|
4
8
|
source_root File.expand_path('templates', __dir__)
|
5
|
-
|
9
|
+
# Copies the camunda_job file to the Rails application.
|
6
10
|
def copy_camunda_application_job
|
7
11
|
copy_file 'camunda_job.rb', 'app/jobs/camunda_job.rb'
|
8
12
|
end
|
@@ -1,10 +1,13 @@
|
|
1
1
|
module Camunda
|
2
2
|
module Generators
|
3
|
+
# Creates a skeleton Java Spring Boot app, which also contains the minimal files to run unit tests on a BPMN file.
|
4
|
+
# This can be used to start a Camunda instance with a REST api. This can also be deployed to PCF by generating a
|
5
|
+
# Spring Boot jar and pushing it.
|
3
6
|
class SpringBootGenerator < Rails::Generators::Base
|
4
7
|
source_root File.expand_path('templates', __dir__)
|
5
8
|
class_option :app_path, type: :string, default: 'bpmn/java_app'
|
6
9
|
class_option :diagram_path, type: :string, default: 'bpmn/diagrams'
|
7
|
-
|
10
|
+
# Copys all spring boot files into a rails application and provides a Camunda engine for testing.
|
8
11
|
def copy_java_app_files
|
9
12
|
copy_file 'pom.xml', File.join(bpmn_app_path, 'pom.xml')
|
10
13
|
copy_file 'camunda.cfg.xml', File.join(bpmn_app_path, 'src/test/resources/camunda.cfg.xml')
|
@@ -13,10 +16,12 @@ module Camunda
|
|
13
16
|
copy_file 'Camunda.java', File.join(bpmn_app_path, 'src/main/java/camunda/Camunda.java')
|
14
17
|
end
|
15
18
|
|
19
|
+
# Copys a sample bpmn file to help demonstrate the usage for camunda-workflow
|
16
20
|
def link_resources_folder
|
17
21
|
copy_file 'sample.bpmn', File.join(diagram_path, 'sample.bpmn'), ''
|
18
22
|
end
|
19
23
|
|
24
|
+
# Add spring boot files to .gitignore
|
20
25
|
def add_to_ignores
|
21
26
|
%w[.gitignore .cfignore].each do |file|
|
22
27
|
append_to_file file do
|
@@ -27,6 +32,7 @@ module Camunda
|
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
35
|
+
# Provides instruction regarding an error with EventedFileChecker listening on the entire Rails folder.
|
30
36
|
def output_error_instructions
|
31
37
|
puts <<~DOC
|
32
38
|
If you get an error when starting your Rails app
|