dor-workflow-client 7.2.0 → 7.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29157476de970bf333e7ca643d49b79ef4e03cf0bf9e18aab8277767492aab3f
4
- data.tar.gz: c25c23a411be47575be4c3d91e912c4d5b48b698423d302d8263a7ca0f1170f7
3
+ metadata.gz: 7e57b379b07c024d6add2d3746c30f042ee10cecef9e5373b85cf697d5538a35
4
+ data.tar.gz: ae9ba93b8d724464772962044363428ba045716682b35011087b88af6dc5aa05
5
5
  SHA512:
6
- metadata.gz: 32b74f669d2ec51717389c34e6ab113f1271ba05b84f3a9ac5a2e5e95da562ada8d2e7cb85ed78a8d4c80e14862e7658b15bf18b9933f0be4223933d80dcc0c2
7
- data.tar.gz: af1f2bbbb802ebd84ccb239ea62e29b8bfdfb3a0947d0729a9e16caea8594b9bc224750085674b28c7448ff47f4fd8525830b8627ad5dab2f31f0c861d8dafcd
6
+ metadata.gz: 14d6da0f6d3075f8fa335bcc550419a9534974ab76cab28bd2adf39a75ba1eabf75231c207bca89fee8251ee3f7be5549c7378ee68579a7647b0fd261927aff8
7
+ data.tar.gz: 4331412a8b8b4d6a87f072b79835c377909d7636f7519e8937e91ae844e59ef4ec592aa68bb7205b870b9b98a4e3c33cd4c85cc5c8428b14368cce3a560d54b5
data/.gitignore CHANGED
@@ -15,5 +15,6 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ workflow_service.log*
18
19
  .ruby-version
19
20
  .ruby-gemset
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dor-workflow-client (7.2.0)
4
+ dor-workflow-client (7.4.0)
5
5
  activesupport (>= 3.2.1, < 8)
6
6
  deprecation (>= 0.99.0)
7
7
  faraday (~> 2.0)
@@ -42,29 +42,29 @@ GEM
42
42
  faraday-net_http (>= 2.0, < 3.2)
43
43
  faraday-net_http (3.1.0)
44
44
  net-http
45
- faraday-retry (2.2.0)
45
+ faraday-retry (2.2.1)
46
46
  faraday (~> 2.0)
47
47
  hashdiff (1.1.0)
48
48
  i18n (1.14.4)
49
49
  concurrent-ruby (~> 1.0)
50
- json (2.7.1)
50
+ json (2.7.2)
51
51
  language_server-protocol (3.17.0.3)
52
- mini_portile2 (2.8.5)
52
+ mini_portile2 (2.8.6)
53
53
  minitest (5.22.3)
54
54
  mutex_m (0.2.0)
55
55
  net-http (0.4.1)
56
56
  uri
57
- nokogiri (1.16.3)
57
+ nokogiri (1.16.4)
58
58
  mini_portile2 (~> 2.8.2)
59
59
  racc (~> 1.4)
60
60
  parallel (1.24.0)
61
- parser (3.3.0.5)
61
+ parser (3.3.1.0)
62
62
  ast (~> 2.4.1)
63
63
  racc
64
- public_suffix (5.0.4)
64
+ public_suffix (5.0.5)
65
65
  racc (1.7.3)
66
66
  rainbow (3.1.1)
67
- rake (13.1.0)
67
+ rake (13.2.1)
68
68
  regexp_parser (2.9.0)
69
69
  rexml (3.2.6)
70
70
  rspec (3.13.0)
@@ -82,7 +82,7 @@ GEM
82
82
  rspec-support (3.13.1)
83
83
  rspec_junit_formatter (0.6.0)
84
84
  rspec-core (>= 2, < 4, != 2.12.0)
85
- rubocop (1.62.1)
85
+ rubocop (1.63.4)
86
86
  json (~> 2.3)
87
87
  language_server-protocol (>= 3.17.0)
88
88
  parallel (~> 1.10)
@@ -101,12 +101,12 @@ GEM
101
101
  rubocop (~> 1.41)
102
102
  rubocop-rake (0.6.0)
103
103
  rubocop (~> 1.0)
104
- rubocop-rspec (2.28.0)
104
+ rubocop-rspec (2.29.1)
105
105
  rubocop (~> 1.40)
106
106
  rubocop-capybara (~> 2.17)
107
107
  rubocop-factory_bot (~> 2.22)
108
108
  rubocop-rspec_rails (~> 2.28)
109
- rubocop-rspec_rails (2.28.2)
109
+ rubocop-rspec_rails (2.28.3)
110
110
  rubocop (~> 1.40)
111
111
  ruby-progressbar (1.13.0)
112
112
  simplecov (0.22.0)
data/README.md CHANGED
@@ -19,15 +19,47 @@ client = Dor::Workflow::Client.new(url: 'https://test-server.edu/workflow/')
19
19
 
20
20
  Consumers of recent versions of the [dor-services](https://github.com/sul-dlss/dor-services) gem can access the configured `Dor::Workflow::Client` object via `Dor::Config`.
21
21
 
22
+ ## Console
23
+
24
+ During development, you can test the gem locally on your laptop, hitting a local instance of workflow-server-rails via the console:
25
+
26
+ ```ruby
27
+ bin/console
28
+
29
+ client = Dor::Workflow::Client.new(url: 'http://localhost:3000')
30
+ client.create_workflow_by_name('druid:bc123df4567', 'accessionWF', version: '1', context: { 'requireOCR' => true})
31
+
32
+ client.workflows('druid:bc123df4567')
33
+ => ["accessionWF"]
34
+
35
+ client.workflow(pid: 'druid:bc123df4567', workflow_name: 'accessionWF')
36
+ => #<Dor::Workflow::Response::Workflow:0x0000000105c8b440
37
+
38
+ client.process(pid: 'druid:bc123df4567', workflow_name: 'accessionWF', process: 'start-accession').context
39
+ => {"requireOCR"=>true}
40
+
41
+ client.all_workflows(pid: 'druid:bc123df4567')
42
+ => #<Dor::Workflow::Response::Workflows:0x00000001055d29a0>.....
43
+ ```
44
+
22
45
  ## API
23
46
  [Rubydoc](https://www.rubydoc.info/github/sul-dlss/dor-workflow-client/main)
24
47
 
48
+ ### Workflow Variables
49
+
50
+ If a workflow or workflows for a particular object require data to be persisted and available between steps, workflow variables can be set. These are per object/version pair and thus available to any step in any workflow for a given version of an object once set. Pass in a context variable as a Hash as shown in the example below. The context will be returned as a hash when fetching workflows data for an object.
51
+
25
52
  ### Example usage
26
53
  Create a workflow
27
54
  ```
28
55
  client.create_workflow_by_name('druid:bc123df4567', 'etdSubmitWF', version: '1')
29
56
  ```
30
57
 
58
+ Create a workflow and send in context
59
+ ```
60
+ client.create_workflow_by_name('druid:bc123df4567', 'etdSubmitWF', version: '1', context: { foo: 'bar'} )
61
+ ```
62
+
31
63
  Update a workflow step's status
32
64
  ```ruby
33
65
  client.update_status(druid: 'druid:bc123df4567',
@@ -36,6 +68,24 @@ client.update_status(druid: 'druid:bc123df4567',
36
68
  status: 'completed')
37
69
  ```
38
70
 
71
+ Fetch information about a workflow:
72
+ ```ruby
73
+ client.workflow(pid: 'druid:bc123df4567', workflow_name: 'etdSubmitWF')
74
+ => #<Dor::Workflow::Response::Workflow:0x000000010cb28588
75
+ ```
76
+
77
+ Fetch information about a workflow step:
78
+ ```ruby
79
+ client.process(pid: 'druid:bc123df4567', workflow_name: 'etdSubmitWF', process: 'registrar-approval')
80
+ => #<Dor::Workflow::Response::Process:0x000000010c505098
81
+ ```
82
+
83
+ Fetch version context about a workflow step:
84
+ ```ruby
85
+ client.process(pid: 'druid:bc123df4567', workflow_name: 'etdSubmitWF', process: 'registrar-approval').context
86
+ => {"foo"=>"bar"}
87
+ ```
88
+
39
89
  Show "milestones" for an object
40
90
  ```ruby
41
91
  client.milestones(druid: 'druid:gv054hp4128')
data/bin/console ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'dor/workflow/client'
6
+
7
+ require 'irb'
8
+ IRB.start(__FILE__)
@@ -11,7 +11,6 @@ module Dor
11
11
 
12
12
  # Returns the Date for a requested milestone from workflow lifecycle
13
13
  #
14
- # @param [String] repo The repository the object resides in. This parameter is deprecated
15
14
  # @param [String] druid object id
16
15
  # @param [String] milestone_name the name of the milestone being queried for
17
16
  # @param [Number] version (nil) the version to query for
@@ -3,7 +3,7 @@
3
3
  module Dor
4
4
  module Workflow
5
5
  class Client
6
- VERSION = '7.2.0'
6
+ VERSION = '7.4.0'
7
7
  end
8
8
  end
9
9
  end
@@ -14,7 +14,6 @@ module Dor
14
14
  # - completes the versioningWF:submit-version and versioningWF:start-accession steps
15
15
  # - initiates accesssionWF
16
16
  #
17
- # @param [String] repo The repository the object resides in. This parameter is deprecated
18
17
  # @param [String] druid The id of the object to delete the workflow from
19
18
  # @param [Boolean] create_accession_wf Option to create accessionWF when closing a version. Defaults to true
20
19
  def close_version(druid:, version:, create_accession_wf: true)
@@ -17,13 +17,15 @@ module Dor
17
17
  # @param [String] workflow_name The name of the workflow you want to create. This must correspond with a workflow
18
18
  # name that is known by the workflow service.
19
19
  # @param [String] lane_id adds laneId attribute to all process elements in the wf_xml workflow xml. Defaults to a value of 'default'
20
+ # @param [Hash] context optional context to be included in the workflow (same for all processes for a given druid/version pair)
20
21
  # @param [Integer] version specifies the version so that workflow service doesn't need to query dor-services.
21
22
  # @return [Boolean] always true
22
23
  #
23
- def create_workflow_by_name(druid, workflow_name, version:, lane_id: 'default')
24
+ def create_workflow_by_name(druid, workflow_name, version:, lane_id: 'default', context: nil)
24
25
  params = { 'lane-id' => lane_id, 'version' => version }
25
- requestor.request "objects/#{druid}/workflows/#{workflow_name}", 'post', '',
26
- content_type: 'application/xml',
26
+ body = context ? { 'context' => context }.to_json : ''
27
+ requestor.request "objects/#{druid}/workflows/#{workflow_name}", 'post', body,
28
+ content_type: 'application/json',
27
29
  params: params
28
30
  true
29
31
  end
@@ -31,7 +33,6 @@ module Dor
31
33
  # Updates the status of one step in a workflow.
32
34
  # Returns true on success. Caller must handle any exceptions
33
35
  #
34
- # @param [String] repo The repository the object resides in. The service recoginzes "dor" and "sdr" at the moment
35
36
  # @param [String] druid The id of the object
36
37
  # @param [String] workflow The name of the workflow
37
38
  # @param [String] process The name of the process step
@@ -61,7 +62,6 @@ module Dor
61
62
 
62
63
  #
63
64
  # Retrieves the process status of the given workflow for the given object identifier
64
- # @param [String] repo The repository the object resides in. Currently recoginzes "dor" and "sdr".
65
65
  # @param [String] druid The id of the object
66
66
  # @param [String] workflow The name of the workflow
67
67
  # @param [String] process The name of the process step
@@ -40,7 +40,7 @@ module Dor
40
40
  @requestor = Requestor.new(connection: connection || ConnectionFactory.build_connection(url, timeout: timeout, logger: logger))
41
41
  end
42
42
 
43
- delegate :create_workflow_by_name, :workflow_status, :workflows,
43
+ delegate :create_workflow_by_name, :workflow_status, :workflows, :all_workflows,
44
44
  :workflow, :process, :delete_workflow, :delete_all_workflows, :update_status, :update_error_status,
45
45
  to: :workflow_routes
46
46
 
@@ -51,6 +51,13 @@ module Dor
51
51
  @attributes[:laneId].presence
52
52
  end
53
53
 
54
+ # @return [Hash] the context for the process (or empty hash if none present)
55
+ def context
56
+ return {} unless @attributes[:context].present?
57
+
58
+ JSON.parse(@attributes[:context])
59
+ end
60
+
54
61
  delegate :pid, :workflow_name, to: :parent
55
62
 
56
63
  private
@@ -28,8 +28,7 @@ module Dor
28
28
  def process_for_recent_version(name:)
29
29
  nodes = process_nodes_for(name: name)
30
30
  node = nodes.max { |a, b| a.attr('version').to_i <=> b.attr('version').to_i }
31
- attributes = node ? node.attributes.to_h { |k, v| [k.to_sym, v.value] } : {}
32
- Process.new(parent: self, **attributes)
31
+ to_process(node)
33
32
  end
34
33
 
35
34
  def empty?
@@ -39,13 +38,24 @@ module Dor
39
38
  # Check if all processes are skipped or complete for the provided version.
40
39
  # @param [Integer] version the version we are checking for.
41
40
  def complete_for?(version:)
42
- ng_xml.xpath("/workflow/process[@version=#{version}]/@status").map(&:value).all? { |p| %w[skipped completed].include?(p) }
41
+ # ng_xml.xpath("/workflow/process[@version=#{version}]/@status").map(&:value).all? { |p| %w[skipped completed].include?(p) }
42
+ incomplete_processes_for(version: version).empty?
43
43
  end
44
44
 
45
45
  def complete?
46
46
  complete_for?(version: version)
47
47
  end
48
48
 
49
+ def incomplete_processes_for(version:)
50
+ process_nodes = ng_xml.xpath("/workflow/process[@version=#{version}]")
51
+ incomplete_process_nodes = process_nodes.reject { |process_node| %w[skipped completed].include?(process_node.attr('status')) }
52
+ incomplete_process_nodes.map { |process_node| to_process(process_node) }
53
+ end
54
+
55
+ def incomplete_processes
56
+ incomplete_processes_for(version: version)
57
+ end
58
+
49
59
  attr_reader :xml
50
60
 
51
61
  private
@@ -66,6 +76,11 @@ module Dor
66
76
  def ng_xml
67
77
  @ng_xml ||= Nokogiri::XML(@xml)
68
78
  end
79
+
80
+ def to_process(node)
81
+ attributes = node ? node.attributes.to_h { |k, v| [k.to_sym, v.value] } : {}
82
+ Process.new(parent: self, **attributes)
83
+ end
69
84
  end
70
85
  end
71
86
  end
@@ -169,8 +169,48 @@ RSpec.describe Dor::Workflow::Client::WorkflowRoutes do
169
169
  end
170
170
 
171
171
  describe '#create_workflow_by_name' do
172
- it 'need to write these specs', skip: 'need to write specs' do
173
- # something
172
+ let(:mock_requestor) { instance_double(Dor::Workflow::Client::Requestor, request: nil) }
173
+
174
+ context 'with default lane_id and no context' do
175
+ subject(:create_workflow_by_name) do
176
+ routes.create_workflow_by_name('druid:mw971zk1113', 'accessionWF', version: '1')
177
+ end
178
+
179
+ it 'sends a create request with default lane_id and without any context param' do
180
+ create_workflow_by_name
181
+ expect(mock_requestor).to have_received(:request)
182
+ .with('objects/druid:mw971zk1113/workflows/accessionWF', 'post', '',
183
+ { content_type: 'application/json',
184
+ params: { 'lane-id' => 'default', 'version' => '1' } })
185
+ end
186
+ end
187
+
188
+ context 'with a custom lane_id' do
189
+ subject(:create_workflow_by_name) do
190
+ routes.create_workflow_by_name('druid:mw971zk1113', 'accessionWF', version: '1', lane_id: 'hamburgers')
191
+ end
192
+
193
+ it 'sends a create request without any context param' do
194
+ create_workflow_by_name
195
+ expect(mock_requestor).to have_received(:request)
196
+ .with('objects/druid:mw971zk1113/workflows/accessionWF', 'post', '',
197
+ { content_type: 'application/json',
198
+ params: { 'lane-id' => 'hamburgers', 'version' => '1' } })
199
+ end
200
+ end
201
+
202
+ context 'when context is sent' do
203
+ subject(:create_workflow_by_name) do
204
+ routes.create_workflow_by_name('druid:mw971zk1113', 'accessionWF', version: '1', lane_id: 'default', context: { foo: 'bar' })
205
+ end
206
+
207
+ it 'sends a create request with the context in the body' do
208
+ create_workflow_by_name
209
+ expect(mock_requestor).to have_received(:request)
210
+ .with('objects/druid:mw971zk1113/workflows/accessionWF', 'post', '{"context":{"foo":"bar"}}',
211
+ { content_type: 'application/json',
212
+ params: { 'lane-id' => 'default', 'version' => '1' } })
213
+ end
174
214
  end
175
215
  end
176
216
  end
@@ -225,6 +225,29 @@ RSpec.describe Dor::Workflow::Client do
225
225
  end
226
226
  end
227
227
 
228
+ describe '#all_workflows' do
229
+ let(:xml) do
230
+ <<~XML
231
+ <workflows objectId="druid:123">
232
+ <workflow repository="dor" objectId="druid:123" id="accessionWF">
233
+ <process laneId="default" lifecycle="submitted" elapsed="0.0" attempts="1" datetime="2013-02-18T15:08:10-0800" status="completed" name="start-accession"/>
234
+ </workflow>
235
+ </workflows>
236
+ XML
237
+ end
238
+ let(:stubs) do
239
+ Faraday::Adapter::Test::Stubs.new do |stub|
240
+ stub.get("/objects/#{@druid}/workflows") do |_env|
241
+ [200, {}, xml]
242
+ end
243
+ end
244
+ end
245
+
246
+ it 'returns the workflow details associated with druid' do
247
+ expect(client.all_workflows(pid: @druid).xml).to eq(xml)
248
+ end
249
+ end
250
+
228
251
  describe '#lifecycle' do
229
252
  let(:stubs) do
230
253
  Faraday::Adapter::Test::Stubs.new do |stub|
@@ -62,4 +62,32 @@ RSpec.describe Dor::Workflow::Response::Process do
62
62
 
63
63
  it { is_expected.to eq 'default' }
64
64
  end
65
+
66
+ describe '#context' do
67
+ subject { instance.context }
68
+
69
+ context 'when context exists' do
70
+ let(:xml) do
71
+ <<~XML
72
+ <workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
73
+ <process name="start-assembly" laneId="default" context="{&quot;requireOCR&quot;:true}">
74
+ </workflow>
75
+ XML
76
+ end
77
+
78
+ it { is_expected.to eq({ 'requireOCR' => true }) }
79
+ end
80
+
81
+ context 'when no context exists' do
82
+ let(:xml) do
83
+ <<~XML
84
+ <workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
85
+ <process name="start-assembly" laneId="default" context="">
86
+ </workflow>
87
+ XML
88
+ end
89
+
90
+ it { is_expected.to eq({}) }
91
+ end
92
+ end
65
93
  end
@@ -198,4 +198,62 @@ RSpec.describe Dor::Workflow::Response::Workflow do
198
198
  end
199
199
  end
200
200
  end
201
+
202
+ describe '#incomplete_processes' do
203
+ subject(:processes) { instance.incomplete_processes }
204
+
205
+ context 'when all steps are complete' do
206
+ let(:xml) do
207
+ <<~XML
208
+ <workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
209
+ <process version="1" laneId="default" elapsed="0.0" attempts="1" datetime="2013-02-18T14:40:25-0800" status="completed" name="start-assembly"/>
210
+ <process version="1" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="completed" name="jp2-create"/>
211
+ </workflow>
212
+ XML
213
+ end
214
+
215
+ it { is_expected.to be_empty }
216
+ end
217
+
218
+ context 'when some steps are not complete' do
219
+ let(:xml) do
220
+ <<~XML
221
+ <workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
222
+ <process version="1" laneId="default" elapsed="0.0" attempts="1" datetime="2013-02-18T14:40:25-0800" status="completed" name="start-assembly"/>
223
+ <process version="1" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="waiting" name="jp2-create"/>
224
+ </workflow>
225
+ XML
226
+ end
227
+
228
+ it 'returns the incomplete processes' do
229
+ expect(processes.size).to eq 1
230
+ expect(processes.first.name).to eq 'jp2-create'
231
+ end
232
+ end
233
+ end
234
+
235
+ describe '#incomplete_processes_for' do
236
+ let(:xml) do
237
+ <<~XML
238
+ <workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
239
+ <process version="1" laneId="default" elapsed="0.0" attempts="1" datetime="2013-02-18T14:40:25-0800" status="completed" name="start-assembly"/>
240
+ <process version="1" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="waiting" name="jp2-create"/>
241
+ <process version="2" laneId="default" elapsed="0.0" attempts="1" datetime="2013-02-18T14:40:25-0800" status="completed" name="start-assembly"/>
242
+ <process version="2" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="completed" name="jp2-create"/>
243
+ </workflow>
244
+ XML
245
+ end
246
+
247
+ context 'when all steps are complete' do
248
+ it 'returns empty' do
249
+ expect(instance.incomplete_processes_for(version: 2)).to be_empty
250
+ end
251
+ end
252
+
253
+ context 'when some steps are not complete' do
254
+ it 'returns false' do
255
+ expect(instance.incomplete_processes_for(version: 1).size).to eq 1
256
+ end
257
+ end
258
+ end
201
259
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dor-workflow-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0
4
+ version: 7.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willy Mene
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-04-02 00:00:00.000000000 Z
12
+ date: 2024-05-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -120,6 +120,7 @@ files:
120
120
  - LICENSE.txt
121
121
  - README.md
122
122
  - Rakefile
123
+ - bin/console
123
124
  - dor-workflow-client.gemspec
124
125
  - lib/dor/missing_workflow_exception.rb
125
126
  - lib/dor/workflow/client.rb
@@ -168,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
169
  - !ruby/object:Gem::Version
169
170
  version: '0'
170
171
  requirements: []
171
- rubygems_version: 3.4.10
172
+ rubygems_version: 3.5.9
172
173
  signing_key:
173
174
  specification_version: 4
174
175
  summary: Provides convenience methods to work with the DOR Workflow Service