dor-workflow-service 1.5.1 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.yardopts +1 -0
- data/README.md +6 -3
- data/dor-workflow-service.gemspec +6 -6
- data/lib/dor/services/workflow_service.rb +173 -39
- data/lib/dor/workflow_version.rb +1 -1
- data/spec/workflow_service_spec.rb +54 -1
- metadata +25 -22
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
Mzg4NWZmMjc0OWU3NGRjNWJlZTRlNTYyNzA4NTU4ZDJjNGQzMDE4NA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OWQ2ZWQ3NThiODc1MWU2ODY4ZWY0MDY5ZmI3MTI4YmU0YjE5Mjg3MA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Mzg0MzkzMmI3OWVmMzZhOGI4ZjFjN2QxMTE1ZmQxMDRlMGU5ZTVlODQwMjU0
|
10
|
+
NTYzYWY0YmU0MTc4ZDQzZmM0NDIyYTc3OWFmNjZmNTc2NjQ4NWJhMTEzMGU3
|
11
|
+
ZDZjOGUyYzZkY2U5MmFkNDg4NzYxMTg5M2MxOGY5OGY5NGE3YTE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZGRjZTE2NzUxMDc3NTM4NzY1NjVhNDc5ZGIyY2M3Zjc1NDdjYTFkMjEzMmM0
|
14
|
+
OTA5YjlmNmJhNzI5MGYxYzA4YWNkNDNiMzBkZGQxZjkyYTQyZWRmOGQwMTI2
|
15
|
+
N2E4YmJlM2ExY2M0NGQxN2M3YzU1NmEwMDllYWVhNjU2OTUzNWU=
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
|
1
2
|
# dor-workflow-service gem
|
2
3
|
|
3
|
-
Provides Ruby convenience methods to work with the DOR Workflow REST Service.
|
4
|
+
Provides Ruby convenience methods to work with the DOR Workflow REST Service. The REST API is defined here:
|
4
5
|
https://consul.stanford.edu/display/DOR/DOR+services#DORservices-initializeworkflow
|
5
6
|
|
6
7
|
## Usage
|
7
8
|
|
8
|
-
To initialize usage of the service, you need to call Dor::WorkflowService.configure
|
9
|
+
To initialize usage of the service, you need to call `Dor::WorkflowService.configure`, like in a bootup or startup method,
|
10
|
+
e.g.:
|
9
11
|
|
10
12
|
Dor::WorkflowService.configure('https://test-server.edu/workflow/')
|
11
13
|
|
@@ -13,4 +15,5 @@ If you plan to archive workflows, then you need to set the URL to the Dor REST s
|
|
13
15
|
|
14
16
|
Dor::WorkflowService.configure('https://test-server.edu/workflow/', :dor_services_url => 'https://sul-lyberservices-dev.stanford.edu/dor')
|
15
17
|
|
16
|
-
There's no need to call Dor::WorkflowService.configure if using the dor-services gem and using the Dor::Config
|
18
|
+
There's no need to call `Dor::WorkflowService.configure` if using the `dor-services` gem and using the `Dor::Config`
|
19
|
+
object. The latest versions of `dor-services` will configure the workflow service for you.
|
@@ -6,7 +6,7 @@ require 'dor/workflow_version'
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = "dor-workflow-service"
|
8
8
|
gem.version = Dor::Workflow::Service::VERSION
|
9
|
-
gem.authors = ["Willy Mene"]
|
9
|
+
gem.authors = ["Willy Mene", "Darren Hardy"]
|
10
10
|
gem.email = ["wmene@stanford.edu"]
|
11
11
|
gem.description = "Enables Ruby manipulation of the DOR Workflow Service via its REST API"
|
12
12
|
gem.summary = "Provides convenience methods to work with the DOR Workflow Service"
|
@@ -17,14 +17,14 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
|
-
gem.add_dependency "activesupport"
|
21
|
-
gem.add_dependency "nokogiri"
|
22
|
-
gem.add_dependency "rest-client"
|
23
|
-
gem.add_dependency "confstruct"
|
20
|
+
gem.add_dependency "activesupport", '~> 4.0.4'
|
21
|
+
gem.add_dependency "nokogiri", '~> 1.6.0'
|
22
|
+
gem.add_dependency "rest-client", '~> 1.6.7'
|
23
|
+
gem.add_dependency "confstruct", '~> 0.2.7'
|
24
24
|
|
25
25
|
gem.add_development_dependency "rake"
|
26
26
|
gem.add_development_dependency "rspec"
|
27
27
|
gem.add_development_dependency "yard"
|
28
28
|
gem.add_development_dependency "redcarpet"
|
29
|
-
gem.add_development_dependency "equivalent-xml"
|
29
|
+
gem.add_development_dependency "equivalent-xml", '~> 0.3.0'
|
30
30
|
end
|
@@ -11,11 +11,13 @@ module Dor
|
|
11
11
|
@@resource = nil
|
12
12
|
@@dor_services_url = nil
|
13
13
|
|
14
|
+
# From Workflow Service's admin/Process.java
|
15
|
+
VALID_STATUS = %w{waiting completed error queued skipped hold}
|
16
|
+
|
14
17
|
# Creates a workflow for a given object in the repository. If this particular workflow for this objects exists,
|
15
18
|
# it will replace the old workflow with wf_xml passed to this method. You have the option of creating a datastream or not.
|
16
19
|
# Returns true on success. Caller must handle any exceptions
|
17
20
|
#
|
18
|
-
# == Parameters
|
19
21
|
# @param [String] repo The repository the object resides in. The service recoginzes "dor" and "sdr" at the moment
|
20
22
|
# @param [String] druid The id of the object
|
21
23
|
# @param [String] workflow_name The name of the workflow you want to create
|
@@ -24,6 +26,7 @@ module Dor
|
|
24
26
|
# @option opts [Boolean] :create_ds if true, a workflow datastream will be created in Fedora. Set to false if you do not want a datastream to be created
|
25
27
|
# If you do not pass in an <b>opts</b> Hash, then :create_ds is set to true by default
|
26
28
|
# @option opts [Integer] :priority adds priority to all process elements in the wf_xml workflow xml
|
29
|
+
# @return [Boolean] always true
|
27
30
|
#
|
28
31
|
def create_workflow(repo, druid, workflow_name, wf_xml, opts = {:create_ds => true})
|
29
32
|
xml = wf_xml
|
@@ -51,29 +54,42 @@ module Dor
|
|
51
54
|
# @param [String] repo The repository the object resides in. The service recoginzes "dor" and "sdr" at the moment
|
52
55
|
# @param [String] druid The id of the object
|
53
56
|
# @param [String] workflow The name of the workflow
|
54
|
-
# @param [String]
|
57
|
+
# @param [String] process The name of the process step
|
58
|
+
# @param [String] status The status that you want to set -- using one of the values in VALID_STATUS
|
55
59
|
# @param [Hash] opts optional values for the workflow step
|
56
60
|
# @option opts [Float] :elapsed The number of seconds it took to complete this step. Can have a decimal. Is set to 0 if not passed in.
|
57
61
|
# @option opts [String] :lifecycle Bookeeping label for this particular workflow step. Examples are: 'registered', 'shelved'
|
58
62
|
# @option opts [String] :note Any kind of string annotation that you want to attach to the workflow
|
59
|
-
# @option opts [Integer] :priority Processing priority
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
63
|
+
# @option opts [Integer] :priority Processing priority. Recommended range is -100..100, 100 being the highest priority, and -100 being the lowest priority. Workflow queues are returned in order of highest to lowest priority value. Default is 0.
|
64
|
+
# @option opts [String] :current_status Setting this string tells the workflow service to compare the current status to this value. If the current value does not match this value, the update is not performed
|
65
|
+
# @return [Boolean] always true
|
66
|
+
# Http Call
|
67
|
+
# ==
|
68
|
+
# The method does an HTTP PUT to the URL defined in `Dor::WF_URI`. As an example:
|
69
|
+
#
|
70
|
+
# PUT "/dor/objects/pid:123/workflows/GoogleScannedWF/convert"
|
71
|
+
# <process name=\"convert\" status=\"completed\" />"
|
64
72
|
def update_workflow_status(repo, druid, workflow, process, status, opts = {})
|
73
|
+
raise ArgumentError, "Unknown status value #{status}" unless VALID_STATUS.include?(status.downcase)
|
65
74
|
opts = {:elapsed => 0, :lifecycle => nil, :note => nil}.merge!(opts)
|
66
75
|
opts[:elapsed] = opts[:elapsed].to_s
|
67
|
-
|
68
|
-
|
76
|
+
current_status = opts.delete(:current_status)
|
77
|
+
xml = create_process_xml({:name => process, :status => status.downcase}.merge!(opts))
|
78
|
+
uri = "#{repo}/objects/#{druid}/workflows/#{workflow}/#{process}"
|
79
|
+
uri << "?current-status=#{current_status.downcase}" if current_status
|
80
|
+
workflow_resource[uri].put(xml, :content_type => 'application/xml')
|
69
81
|
return true
|
70
82
|
end
|
71
83
|
|
72
84
|
#
|
73
85
|
# Retrieves the process status of the given workflow for the given object identifier
|
74
|
-
#
|
86
|
+
# @param [String] repo The repository the object resides in. The service recoginzes "dor" and "sdr" at the moment
|
87
|
+
# @param [String] druid The id of the object
|
88
|
+
# @param [String] workflow The name of the workflow
|
89
|
+
# @param [String] process The name of the process step
|
90
|
+
# @return [String] status for repo-workflow-process-druid
|
75
91
|
def get_workflow_status(repo, druid, workflow, process)
|
76
|
-
workflow_md =
|
92
|
+
workflow_md = get_workflow_xml(repo, druid, workflow)
|
77
93
|
doc = Nokogiri::XML(workflow_md)
|
78
94
|
raise Exception.new("Unable to parse response:\n#{workflow_md}") if(doc.root.nil?)
|
79
95
|
|
@@ -84,6 +100,12 @@ module Dor
|
|
84
100
|
return status
|
85
101
|
end
|
86
102
|
|
103
|
+
#
|
104
|
+
# Retrieves the raw XML for the given workflow
|
105
|
+
# @param [String] repo The repository the object resides in. The service recoginzes "dor" and "sdr" at the moment
|
106
|
+
# @param [String] druid The id of the object
|
107
|
+
# @param [String] workflow The name of the workflow
|
108
|
+
# @return [String] XML of the workflow
|
87
109
|
def get_workflow_xml(repo, druid, workflow)
|
88
110
|
workflow_resource["#{repo}/objects/#{druid}/workflows/#{workflow}"].get
|
89
111
|
end
|
@@ -93,7 +115,8 @@ module Dor
|
|
93
115
|
#
|
94
116
|
# @param [String] pid of druid
|
95
117
|
# @return [Array<String>] list of worklows
|
96
|
-
# @example
|
118
|
+
# @example
|
119
|
+
# Dor::WorkflowService.get_workflows('druid:sr100hp0609')
|
97
120
|
# => ["accessionWF", "assemblyWF", "disseminationWF"]
|
98
121
|
def get_workflows(pid)
|
99
122
|
xml_doc=Nokogiri::XML(get_workflow_xml('dor',pid,''))
|
@@ -106,7 +129,8 @@ module Dor
|
|
106
129
|
# @param [String] repo repository of the object
|
107
130
|
# @param [String] pid id of object
|
108
131
|
# @return [Array<String>] list of active worklows. Returns an empty Array if none are found
|
109
|
-
# @example
|
132
|
+
# @example
|
133
|
+
# Dor::WorkflowService.get_workflows('dor', 'druid:sr100hp0609')
|
110
134
|
# => ["accessionWF", "assemblyWF", "disseminationWF"]
|
111
135
|
def get_active_workflows(repo, pid)
|
112
136
|
doc = Nokogiri::XML(get_workflow_xml(repo,pid,''))
|
@@ -122,11 +146,14 @@ module Dor
|
|
122
146
|
# @param [String] error_msg The error message. Ideally, this is a brief message describing the error
|
123
147
|
# @param [Hash] opts optional values for the workflow step
|
124
148
|
# @option opts [String] :error_txt A slot to hold more information about the error, like a full stacktrace
|
149
|
+
# @return [Boolean] always true
|
125
150
|
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
151
|
+
# Http Call
|
152
|
+
# ==
|
153
|
+
# The method does an HTTP PUT to the URL defined in `Dor::WF_URI`.
|
154
|
+
#
|
155
|
+
# PUT "/dor/objects/pid:123/workflows/GoogleScannedWF/convert"
|
156
|
+
# <process name=\"convert\" status=\"error\" />"
|
130
157
|
def update_workflow_error_status(repo, druid, workflow, process, error_msg, opts = {})
|
131
158
|
opts = {:error_txt => nil}.merge!(opts)
|
132
159
|
xml = create_process_xml({:name => process, :status => 'error', :errorMessage => error_msg}.merge!(opts))
|
@@ -138,13 +165,14 @@ module Dor
|
|
138
165
|
# @param [String] repo The repository the object resides in. The service recoginzes "dor" and "sdr" at the moment
|
139
166
|
# @param [String] druid The id of the object to delete the workflow from
|
140
167
|
# @param [String] workflow The name of the workflow to be deleted
|
168
|
+
# @return [Boolean] always true
|
141
169
|
def delete_workflow(repo, druid, workflow)
|
142
170
|
workflow_resource["#{repo}/objects/#{druid}/workflows/#{workflow}"].delete
|
143
171
|
return true
|
144
172
|
end
|
145
173
|
|
146
174
|
# Returns the Date for a requested milestone from workflow lifecycle
|
147
|
-
# @param [String] repo
|
175
|
+
# @param [String] repo repository name
|
148
176
|
# @param [String] druid object id
|
149
177
|
# @param [String] milestone name of the milestone being queried for
|
150
178
|
# @return [Time] when the milestone was achieved. Returns nil if the milestone does not exist
|
@@ -185,6 +213,7 @@ module Dor
|
|
185
213
|
nil
|
186
214
|
end
|
187
215
|
|
216
|
+
# @return [Hash]
|
188
217
|
def get_milestones(repo, druid)
|
189
218
|
doc = self.query_lifecycle(repo, druid)
|
190
219
|
doc.xpath("//lifecycle/milestone").collect do |node|
|
@@ -192,6 +221,16 @@ module Dor
|
|
192
221
|
end
|
193
222
|
end
|
194
223
|
|
224
|
+
# Converts repo-workflow-step into repo:workflow:step
|
225
|
+
# @param [String] default_repository
|
226
|
+
# @param [String] default_workflow
|
227
|
+
# @param [String] step if contains colon :, then uses
|
228
|
+
# the value for workflow and/or workflow/repository.
|
229
|
+
# for example, jp2-create, or assemblyWF:jp2-create,
|
230
|
+
# or dor:assemblyWF:jp2-create
|
231
|
+
# @return [String] repo:workflow:step
|
232
|
+
# @example
|
233
|
+
# dor:assemblyWF:jp2-create
|
195
234
|
def qualify_step(default_repository, default_workflow, step)
|
196
235
|
current = step.split(/:/,3)
|
197
236
|
current.unshift(default_workflow) if current.length < 3
|
@@ -199,41 +238,77 @@ module Dor
|
|
199
238
|
current.join(':')
|
200
239
|
end
|
201
240
|
|
202
|
-
|
203
241
|
# Returns a list of druids from the WorkflowService that meet the criteria of the passed in completed and waiting params
|
204
242
|
#
|
205
|
-
# @param [Array<String>, String] completed An array or single String of the completed steps, should use the qualified format:
|
206
|
-
# repository:workflow:step-name
|
243
|
+
# @param [Array<String>, String] completed An array or single String of the completed steps, should use the qualified format: `repository:workflow:step-name`
|
207
244
|
# @param [String] waiting name of the waiting step
|
208
245
|
# @param [String] repository default repository to use if it isn't passed in the qualified-step-name
|
209
246
|
# @param [String] workflow default workflow to use if it isn't passed in the qualified-step-name
|
210
|
-
|
247
|
+
# @param [Hash] options
|
248
|
+
# @option options [Boolean] :with_priority include the priority with each druid
|
249
|
+
# @option options [Integer] :limit maximum number of druids to return (nil for no limit)
|
250
|
+
# @return [Array<String>, Hash] if with_priority, hash with druids as keys with their Integer priority as value; else Array of druids
|
251
|
+
#
|
252
|
+
# @example
|
253
|
+
# get_objects_for_workstep(...)
|
254
|
+
# => [
|
255
|
+
# "druid:py156ps0477",
|
256
|
+
# "druid:tt628cb6479",
|
257
|
+
# "druid:ct021wp7863"
|
258
|
+
# ]
|
259
|
+
#
|
260
|
+
# @example
|
261
|
+
# get_objects_for_workstep(..., with_priority: true)
|
262
|
+
# => {
|
263
|
+
# "druid:py156ps0477" => 100,
|
264
|
+
# "druid:tt628cb6479" => 0,
|
265
|
+
# "druid:ct021wp7863" => -100
|
266
|
+
# }
|
267
|
+
#
|
268
|
+
def get_objects_for_workstep completed, waiting, repository=nil, workflow=nil, options = {}
|
211
269
|
result = nil
|
270
|
+
uri_string = "workflow_queue?waiting=#{qualify_step(repository,workflow,waiting)}"
|
212
271
|
if(completed)
|
213
|
-
uri_string = "workflow_queue?waiting=#{qualify_step(repository,workflow,waiting)}"
|
214
272
|
Array(completed).each do |step|
|
215
273
|
uri_string << "&completed=#{qualify_step(repository,workflow,step)}"
|
216
274
|
end
|
217
|
-
else
|
218
|
-
uri_string = "workflow_queue?waiting=#{qualify_step(repository,workflow,waiting)}"
|
219
275
|
end
|
276
|
+
|
277
|
+
if options[:limit] and options[:limit].to_i > 0
|
278
|
+
uri_string << "&limit=#{options[:limit].to_i}"
|
279
|
+
end
|
280
|
+
|
220
281
|
workflow_resource.options[:timeout] = 5 * 60 unless(workflow_resource.options.include?(:timeout))
|
221
282
|
resp = workflow_resource[uri_string].get
|
222
|
-
|
283
|
+
#
|
284
|
+
# response looks like:
|
285
|
+
# <objects count="2">
|
286
|
+
# <object id="druid:ab123de4567" priority="2"/>
|
287
|
+
# <object id="druid:ab123de9012" priority="1"/> #
|
288
|
+
# </objects>
|
289
|
+
#
|
290
|
+
# convert into:
|
291
|
+
# { 'druid:ab123de4567' => 2, 'druid:ab123de9012' => 1}
|
292
|
+
#
|
293
|
+
result = Nokogiri::XML(resp).xpath('//object[@id]').inject({}) do |h, node|
|
294
|
+
h[node['id']] = node['priority'] ? node['priority'].to_i : 0
|
295
|
+
h
|
296
|
+
end
|
223
297
|
|
224
|
-
result
|
298
|
+
options[:with_priority] ? result : result.keys
|
225
299
|
end
|
226
300
|
|
227
301
|
# Get a list of druids that have errored out in a particular workflow and step
|
228
302
|
#
|
229
|
-
# @param [
|
230
|
-
# @param [
|
231
|
-
# @param [
|
303
|
+
# @param [String] workflow name
|
304
|
+
# @param [String] step name
|
305
|
+
# @param [String] repository -- optional, default=dor
|
232
306
|
#
|
233
|
-
# @return [
|
234
|
-
#
|
235
|
-
#
|
236
|
-
#
|
307
|
+
# @return [Hash] hash of results, with key has a druid, and value as the error message
|
308
|
+
# @example
|
309
|
+
# Dor::WorkflowService.get_errored_objects_for_workstep('accessionWF','content-metadata')
|
310
|
+
# => {"druid:qd556jq0580"=>"druid:qd556jq0580 - Item error; caused by
|
311
|
+
# #<Rubydora::FedoraInvalidRequest: Error modifying datastream contentMetadata for druid:qd556jq0580. See logger for details>"}
|
237
312
|
def get_errored_objects_for_workstep workflow, step, repository='dor'
|
238
313
|
result = {}
|
239
314
|
uri_string = "workflow_queue?repository=#{repository}&workflow=#{workflow}&error=#{step}"
|
@@ -244,6 +319,34 @@ module Dor
|
|
244
319
|
result
|
245
320
|
end
|
246
321
|
|
322
|
+
# Gets all of the workflow steps that have a status of 'queued' that have a last-updated timestamp older than the number of hours passed in
|
323
|
+
# This will enable re-queueing of jobs that have been lost by the job manager
|
324
|
+
# @param [String] repository name of the repository you want to query, like 'dor' or 'sdr'
|
325
|
+
# @param [Hash] opts optional values for query
|
326
|
+
# @option opts [Integer] :hours_ago steps older than this value will be returned by the query. If not passed in, the service defaults to 24 hours
|
327
|
+
# @option opts [Integer] :limit sets the maximum number of workflow steps that can be returned. Defaults to no limit
|
328
|
+
# @return [Array[Hash]] each Hash represents a workflow step. It will have the following keys:
|
329
|
+
# :workflow, :step, :druid, :priority
|
330
|
+
def get_stale_queued_workflows(repository, opts = {})
|
331
|
+
uri_string = build_queued_uri(repository, opts)
|
332
|
+
xml = workflow_resource[uri_string].get
|
333
|
+
parse_queued_workflows_response xml
|
334
|
+
end
|
335
|
+
|
336
|
+
# Returns a count of workflow steps that have a status of 'queued' that have a last-updated timestamp older than the number of hours passed in
|
337
|
+
# @param [String] repository name of the repository you want to query, like 'dor' or 'sdr'
|
338
|
+
# @param [Hash] opts optional values for query
|
339
|
+
# @option opts [Integer] :hours_ago steps older than this value will be returned by the query. If not passed in, the service defaults to 24 hours
|
340
|
+
# @return [Integer] number of stale, queued steps if the :count_only option was set to true
|
341
|
+
def count_stale_queued_workflows(repository, opts = {})
|
342
|
+
uri_string = build_queued_uri(repository, opts)
|
343
|
+
uri_string << "&count-only=true"
|
344
|
+
xml = workflow_resource[uri_string].get
|
345
|
+
doc = Nokogiri::XML(xml)
|
346
|
+
return doc.at_xpath('/objects/@count').value.to_i
|
347
|
+
end
|
348
|
+
|
349
|
+
# @return [String]
|
247
350
|
def create_process_xml(params)
|
248
351
|
builder = Nokogiri::XML::Builder.new do |xml|
|
249
352
|
attrs = params.reject { |k,v| v.nil? }
|
@@ -252,6 +355,7 @@ module Dor
|
|
252
355
|
return builder.to_xml
|
253
356
|
end
|
254
357
|
|
358
|
+
# @return [Nokogiri::XML::Document]
|
255
359
|
def query_lifecycle(repo, druid, active_only = false)
|
256
360
|
req = "#{repo}/objects/#{druid}/lifecycle"
|
257
361
|
req << '?active-only=true' if active_only
|
@@ -276,8 +380,10 @@ module Dor
|
|
276
380
|
end
|
277
381
|
|
278
382
|
# Calls the versionClose endpoint of the WorkflowService:
|
279
|
-
#
|
280
|
-
#
|
383
|
+
#
|
384
|
+
# - completes the versioningWF:submit-version and versioningWF:start-accession steps
|
385
|
+
# - initiates accesssionWF
|
386
|
+
#
|
281
387
|
# @param [String] repo The repository the object resides in. The service recoginzes "dor" and "sdr" at the moment
|
282
388
|
# @param [String] druid The id of the object to delete the workflow from
|
283
389
|
# @param [Boolean] create_accession_wf Option to create accessionWF when closing a version. Defaults to true
|
@@ -288,17 +394,22 @@ module Dor
|
|
288
394
|
return true
|
289
395
|
end
|
290
396
|
|
397
|
+
# @return [RestClient::Resource] the REST client resource
|
291
398
|
def workflow_resource
|
292
399
|
raise "Please call Dor::WorkflowService.configure(url) once before calling any WorkflowService methods" if(@@resource.nil?)
|
293
400
|
@@resource
|
294
401
|
end
|
295
402
|
|
403
|
+
# Configure the workflow service
|
404
|
+
#
|
296
405
|
# @param [String] url points to the workflow service
|
297
406
|
# @param [Hash] opts optional params
|
298
|
-
# @option opts [String] :client_cert_file path to an SSL client certificate
|
299
|
-
# @option opts [String] :client_key_file path to an SSL key file
|
300
|
-
# @option opts [String] :client_key_pass password for the key file
|
301
407
|
# @option opts [String] :dor_services_uri uri to the DOR REST service
|
408
|
+
# @option opts [Integer] :timeout number of seconds for RestClient timeout
|
409
|
+
# @option opts [String] :client_cert_file path to an SSL client certificate (deprecated)
|
410
|
+
# @option opts [String] :client_key_file path to an SSL key file (deprecated)
|
411
|
+
# @option opts [String] :client_key_pass password for the key file (deprecated)
|
412
|
+
# @return [RestClient::Resource] the REST client resource
|
302
413
|
def configure(url, opts={})
|
303
414
|
params = {}
|
304
415
|
params[:timeout] = opts[:timeout] if opts[:timeout]
|
@@ -308,6 +419,29 @@ module Dor
|
|
308
419
|
@@resource = RestClient::Resource.new(url, params)
|
309
420
|
end
|
310
421
|
|
422
|
+
protected
|
423
|
+
|
424
|
+
def build_queued_uri(repository, opts = {})
|
425
|
+
uri_string = "workflow_queue/all_queued?repository=#{repository}"
|
426
|
+
uri_string << "&hours-ago=#{opts[:hours_ago]}" if opts[:hours_ago]
|
427
|
+
uri_string << "&limit=#{opts[:limit]}" if opts[:limit]
|
428
|
+
uri_string
|
429
|
+
end
|
430
|
+
|
431
|
+
def parse_queued_workflows_response(xml)
|
432
|
+
res = []
|
433
|
+
doc = Nokogiri::XML(xml)
|
434
|
+
doc.xpath('/workflows/workflow').each do |wf_node|
|
435
|
+
wf = {}
|
436
|
+
wf[:workflow] = wf_node['name']
|
437
|
+
wf[:step] = wf_node['process']
|
438
|
+
wf[:druid] = wf_node['druid']
|
439
|
+
wf[:priority] = wf_node['priority'].to_i
|
440
|
+
res << wf
|
441
|
+
end
|
442
|
+
res
|
443
|
+
end
|
444
|
+
|
311
445
|
end
|
312
446
|
end
|
313
447
|
end
|
data/lib/dor/workflow_version.rb
CHANGED
@@ -85,6 +85,12 @@ describe Dor::WorkflowService do
|
|
85
85
|
@mock_resource.should_receive(:put).with(@xml_re, { :content_type => 'application/xml' }).and_raise(ex)
|
86
86
|
lambda{ Dor::WorkflowService.update_workflow_status(@repo, @druid, "etdSubmitWF", "reader-approval", "completed") }.should raise_error(Exception, "exception thrown")
|
87
87
|
end
|
88
|
+
|
89
|
+
it "performs a conditional update when current-status is passed as a parameter" do
|
90
|
+
@mock_resource.should_receive(:[]).with("dor/objects/druid:123/workflows/etdSubmitWF/reader-approval?current-status=queued")
|
91
|
+
@mock_resource.should_receive(:put).with(@xml_re, { :content_type => 'application/xml' }).and_return('')
|
92
|
+
Dor::WorkflowService.update_workflow_status(@repo, @druid, "etdSubmitWF", "reader-approval", "completed", :version => 2, :note => 'annotation', :priority => 34, :current_status => 'queued').should be_true
|
93
|
+
end
|
88
94
|
end
|
89
95
|
|
90
96
|
describe "#update_workflow_error_status" do
|
@@ -188,10 +194,24 @@ describe Dor::WorkflowService do
|
|
188
194
|
qualified_completed2 = "#{repo2}:#{workflow2}:#{completed2}"
|
189
195
|
qualified_completed3 = "#{repo2}:#{workflow2}:#{completed3}"
|
190
196
|
@mock_resource.should_receive(:[]).with("workflow_queue?waiting=#{qualified_waiting}&completed=#{qualified_completed}&completed=#{qualified_completed2}&completed=#{qualified_completed3}")
|
191
|
-
@mock_resource.should_receive(:get).and_return(%{<objects count="2"><object id="druid:ab123de4567" priority="
|
197
|
+
@mock_resource.should_receive(:get).and_return(%{<objects count="2"><object id="druid:ab123de4567" priority="1"/><object id="druid:ab123de9012" priority="0"/></objects>})
|
192
198
|
Dor::WorkflowService.get_objects_for_workstep([qualified_completed, qualified_completed2, qualified_completed3], qualified_waiting).should == ['druid:ab123de4567', 'druid:ab123de9012']
|
193
199
|
end
|
194
200
|
|
201
|
+
it "same but with priority" do
|
202
|
+
qualified_waiting = "#{@repository}:#{@workflow}:#{@waiting}"
|
203
|
+
qualified_completed = "#{@repository}:#{@workflow}:#{@completed}"
|
204
|
+
repo2 = "sdr"
|
205
|
+
workflow2 = "sdrIngestWF"
|
206
|
+
completed2="complete-deposit"
|
207
|
+
completed3="ingest-transfer"
|
208
|
+
qualified_completed2 = "#{repo2}:#{workflow2}:#{completed2}"
|
209
|
+
qualified_completed3 = "#{repo2}:#{workflow2}:#{completed3}"
|
210
|
+
@mock_resource.should_receive(:[]).with("workflow_queue?waiting=#{qualified_waiting}&completed=#{qualified_completed}&completed=#{qualified_completed2}&completed=#{qualified_completed3}")
|
211
|
+
@mock_resource.should_receive(:get).and_return(%{<objects count="2"><object id="druid:ab123de4567" priority="2"/><object id="druid:ab123de9012" priority="1"/></objects>})
|
212
|
+
Dor::WorkflowService.get_objects_for_workstep([qualified_completed, qualified_completed2, qualified_completed3], qualified_waiting, nil, nil, with_priority: true).should == { 'druid:ab123de4567' => 2, 'druid:ab123de9012' => 1}
|
213
|
+
end
|
214
|
+
|
195
215
|
it "creates the URI string with only one completed step passed in as a String" do
|
196
216
|
qualified_waiting = "#{@repository}:#{@workflow}:#{@waiting}"
|
197
217
|
qualified_completed = "#{@repository}:#{@workflow}:#{@completed}"
|
@@ -209,6 +229,14 @@ describe Dor::WorkflowService do
|
|
209
229
|
@mock_resource.should_receive(:get).and_return(%{<objects count="1"><object id="druid:ab123de4567"/></objects>})
|
210
230
|
Dor::WorkflowService.get_objects_for_workstep(nil, qualified_waiting).should == ['druid:ab123de4567']
|
211
231
|
end
|
232
|
+
|
233
|
+
it "same but with priority" do
|
234
|
+
qualified_waiting = "#{@repository}:#{@workflow}:#{@waiting}"
|
235
|
+
|
236
|
+
@mock_resource.should_receive(:[]).with("workflow_queue?waiting=#{qualified_waiting}")
|
237
|
+
@mock_resource.should_receive(:get).and_return(%{<objects count="1"><object id="druid:ab123de4567" priority="33"/></objects>})
|
238
|
+
Dor::WorkflowService.get_objects_for_workstep(nil, qualified_waiting, nil, nil, with_priority: true).should == { 'druid:ab123de4567' => 33 }
|
239
|
+
end
|
212
240
|
end
|
213
241
|
end
|
214
242
|
|
@@ -275,4 +303,29 @@ describe Dor::WorkflowService do
|
|
275
303
|
end
|
276
304
|
end
|
277
305
|
|
306
|
+
describe ".parse_queued_workflows_response" do
|
307
|
+
it "returns an Array of Hashes containing each workflow step" do
|
308
|
+
xml = <<-XML
|
309
|
+
<workflows>
|
310
|
+
<workflow priority="30" note="annotation" lifecycle="in-process" errorText="stacktrace" errorMessage="NullPointerException" elapsed="1.173" repository="dor" attempts="0" datetime="2008-11-15T13:30:00-0800" status="waiting" process="content-metadata" name="accessionWF" druid="dr:123"/>
|
311
|
+
<workflow priority="30" note="annotation" lifecycle="in-process" errorText="stacktrace" errorMessage="NullPointerException" elapsed="1.173" repository="dor" attempts="0" datetime="2008-11-15T13:30:00-0800" status="waiting" process="jp2-create" name="assemblyWF" druid="dr:456"/>
|
312
|
+
</workflows>
|
313
|
+
XML
|
314
|
+
expected = [ { :workflow => 'accessionWF', :step => 'content-metadata', :druid => 'dr:123', :priority => 30},
|
315
|
+
{ :workflow => 'assemblyWF', :step => 'jp2-create', :druid => 'dr:456', :priority => 30} ]
|
316
|
+
|
317
|
+
ah = Dor::WorkflowService.parse_queued_workflows_response(xml)
|
318
|
+
ah.should eql(expected)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe ".count_stale_queued_workflows" do
|
323
|
+
it "returns the number of queued workflow steps" do
|
324
|
+
@mock_resource.should_receive(:[]).with("workflow_queue/all_queued?repository=dor&hours-ago=48&count-only=true")
|
325
|
+
@mock_resource.should_receive(:get).and_return(%{<objects count="10"/>})
|
326
|
+
|
327
|
+
Dor::WorkflowService.count_stale_queued_workflows('dor', :hours_ago => 48).should == 10
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
278
331
|
end
|
metadata
CHANGED
@@ -1,71 +1,72 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dor-workflow-service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Willy Mene
|
8
|
+
- Darren Hardy
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2014-
|
12
|
+
date: 2014-04-02 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: activesupport
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
16
17
|
requirements:
|
17
|
-
- -
|
18
|
+
- - ~>
|
18
19
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
+
version: 4.0.4
|
20
21
|
type: :runtime
|
21
22
|
prerelease: false
|
22
23
|
version_requirements: !ruby/object:Gem::Requirement
|
23
24
|
requirements:
|
24
|
-
- -
|
25
|
+
- - ~>
|
25
26
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
+
version: 4.0.4
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
29
|
name: nokogiri
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
|
-
- -
|
32
|
+
- - ~>
|
32
33
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
+
version: 1.6.0
|
34
35
|
type: :runtime
|
35
36
|
prerelease: false
|
36
37
|
version_requirements: !ruby/object:Gem::Requirement
|
37
38
|
requirements:
|
38
|
-
- -
|
39
|
+
- - ~>
|
39
40
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
41
|
+
version: 1.6.0
|
41
42
|
- !ruby/object:Gem::Dependency
|
42
43
|
name: rest-client
|
43
44
|
requirement: !ruby/object:Gem::Requirement
|
44
45
|
requirements:
|
45
|
-
- -
|
46
|
+
- - ~>
|
46
47
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
48
|
+
version: 1.6.7
|
48
49
|
type: :runtime
|
49
50
|
prerelease: false
|
50
51
|
version_requirements: !ruby/object:Gem::Requirement
|
51
52
|
requirements:
|
52
|
-
- -
|
53
|
+
- - ~>
|
53
54
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
55
|
+
version: 1.6.7
|
55
56
|
- !ruby/object:Gem::Dependency
|
56
57
|
name: confstruct
|
57
58
|
requirement: !ruby/object:Gem::Requirement
|
58
59
|
requirements:
|
59
|
-
- -
|
60
|
+
- - ~>
|
60
61
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
+
version: 0.2.7
|
62
63
|
type: :runtime
|
63
64
|
prerelease: false
|
64
65
|
version_requirements: !ruby/object:Gem::Requirement
|
65
66
|
requirements:
|
66
|
-
- -
|
67
|
+
- - ~>
|
67
68
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
69
|
+
version: 0.2.7
|
69
70
|
- !ruby/object:Gem::Dependency
|
70
71
|
name: rake
|
71
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,16 +127,16 @@ dependencies:
|
|
126
127
|
name: equivalent-xml
|
127
128
|
requirement: !ruby/object:Gem::Requirement
|
128
129
|
requirements:
|
129
|
-
- -
|
130
|
+
- - ~>
|
130
131
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
132
|
+
version: 0.3.0
|
132
133
|
type: :development
|
133
134
|
prerelease: false
|
134
135
|
version_requirements: !ruby/object:Gem::Requirement
|
135
136
|
requirements:
|
136
|
-
- -
|
137
|
+
- - ~>
|
137
138
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
139
|
+
version: 0.3.0
|
139
140
|
description: Enables Ruby manipulation of the DOR Workflow Service via its REST API
|
140
141
|
email:
|
141
142
|
- wmene@stanford.edu
|
@@ -146,6 +147,7 @@ extra_rdoc_files: []
|
|
146
147
|
files:
|
147
148
|
- .gitignore
|
148
149
|
- .travis.yml
|
150
|
+
- .yardopts
|
149
151
|
- Gemfile
|
150
152
|
- LICENSE.txt
|
151
153
|
- README.md
|
@@ -183,3 +185,4 @@ summary: Provides convenience methods to work with the DOR Workflow Service
|
|
183
185
|
test_files:
|
184
186
|
- spec/spec_helper.rb
|
185
187
|
- spec/workflow_service_spec.rb
|
188
|
+
has_rdoc:
|