camunda-workflow 0.1.3 → 0.1.4
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 +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
|