lyber-core 6.1.1 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72f25a04a8a79879923e52f8a0ba9e8fbb7d7a92deaf195961548cab5898baf2
4
- data.tar.gz: 9dd75e18b11858d897a1dcdeabb0841595bc1a5db02fed17fe84bdf78c7a249d
3
+ metadata.gz: 9594bf0c91b30860cdc8580d1e7e53b47ab5cbf64b9c7be0738e43e9020d9dc8
4
+ data.tar.gz: 1e3bfe3e564263ee64b681c38df4c0ca84a3d1b90716b68be4654ac4b23ebbbb
5
5
  SHA512:
6
- metadata.gz: 479c21c2be8a01e3545035009cfda6c2655e5d78f8e191a5e901be7e33eec7ff2f5b3a0623afce4d73edab1b31f79da0c43f3e0afa379dd40914079ee248476f
7
- data.tar.gz: edeed4efdf04ee301091f104c1e40047a9f124cfe269be8de88103a0b8ec27632298d9f9a06a1c379b98c0d019131f785721777be41fba924cf92280d6d60b4a
6
+ metadata.gz: 6dc1ddef3619e90a55e8f1dc8d8b5ce1fdb832fe0f36a1d14ab7be9e0e2ff2ac76753d7822bea43bf44fc33e846e603a6a328b29562bb526ec4a555bf9b323f9
7
+ data.tar.gz: 881fbd6acd736e7e1c020bd50149436359ac880b0804188662a039e97a70f3fc15e8e7e259b71b3a37d6f56742bb605fa2847f87358759f9e9801e333fb14493
data/README.md CHANGED
@@ -1,31 +1,30 @@
1
- [![Build Status](https://travis-ci.org/sul-dlss/lyber-core.svg?branch=master)](https://travis-ci.org/sul-dlss/lyber-core)
2
- [![Coverage Status](https://coveralls.io/repos/github/sul-dlss/lyber-core/badge.svg?branch=master)](https://coveralls.io/github/sul-dlss/lyber-core?branch=master)
1
+ [![CircleCI](https://circleci.com/gh/sul-dlss/lyber-core/tree/main.svg?style=svg)](https://circleci.com/gh/sul-dlss/lyber-core/tree/main)
2
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/472f67659e513e3d8ffa/test_coverage)](https://codeclimate.com/github/sul-dlss/lyber-core/test_coverage)
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/472f67659e513e3d8ffa/maintainability)](https://codeclimate.com/github/sul-dlss/lyber-core/maintainability)
3
4
  [![Gem Version](https://badge.fury.io/rb/lyber-core.svg)](https://badge.fury.io/rb/lyber-core)
4
5
 
5
6
  # lyber_core
6
7
 
7
8
  ## Robot Creation
8
9
 
9
- Create a class that mixes in `LyberCore::Robot`
10
+ Create a class that subclasses `LyberCore::Robot`
10
11
 
11
- * In the initializer, call `super` with the repository, workflow name, step name
12
- * Your class `#perform` method will perform the actual work, with `druid` passed in as the one and only argument
12
+ * In the initializer, call `super` with the workflow name, step name
13
+ * Your class `#perform_work` method will perform the actual work; `druid` is available as an instance variable.
13
14
 
14
15
  ```ruby
15
16
  module Robots
16
17
  module DorRepo
17
18
  module Accession
18
19
 
19
- class Shelve
20
- include LyberCore::Robot
20
+ class Shelve < LyberCore::Robot
21
21
 
22
22
  def initialize
23
- super('dor', 'accessionWF', 'shelve')
23
+ super('accessionWF', 'shelve')
24
24
  end
25
25
 
26
- def perform druid
27
- obj = Dor::Item.find(druid)
28
- obj.shelve
26
+ def perform_work
27
+ cocina_object.shelve
29
28
  end
30
29
 
31
30
  end
@@ -42,24 +41,22 @@ module Robots
42
41
  module DorRepo
43
42
  module Accession
44
43
 
45
- class Shelve
46
- include LyberCore::Robot
44
+ class Shelve < LyberCore::Robot
47
45
 
48
46
  def initialize
49
- super('dor', 'accessionWF', 'shelve')
47
+ super('accessionWF', 'shelve')
50
48
  end
51
49
 
52
- def perform druid
53
- obj = Dor::Item.find(druid)
50
+ def perform
54
51
  if some_logic_here_to_determine_if_shelving_occurs
55
- obj.shelve
56
- return LyberCore::Robot::ReturnState.new(status: 'completed') # set the final state to completed
57
- # return LyberCore::Robot::ReturnState.new(status: 'completed', note: 'some custom note to pass back to workflow') # set the final state to completed with a custom note
52
+ cocina_object.shelve
53
+ return LyberCore::ReturnState.new(status: 'completed') # set the final state to completed
54
+ # return LyberCore::ReturnState.new(status: 'completed', note: 'some custom note to pass back to workflow') # set the final state to completed with a custom note
58
55
 
59
56
  else
60
57
  # just return skipped if we did nothing
61
- return LyberCore::Robot::ReturnState.new(status: 'skipped') # set the final state to skipped
62
- # return LyberCore::Robot::ReturnState.new(status: 'skipped', note: 'some custom note to pass back to workflow') # set the final state to skipped with a custom note
58
+ return LyberCore::ReturnState.new(status: 'skipped') # set the final state to skipped
59
+ # return LyberCore::ReturnState.new(status: 'skipped', note: 'some custom note to pass back to workflow') # set the final state to skipped with a custom note
63
60
  end
64
61
  end
65
62
 
@@ -72,50 +69,58 @@ end
72
69
 
73
70
  ## Robot Environment Setup
74
71
 
75
- * Create a `config/boot.rb` file to load the classpath, classes and configuration that your robot will need in order to run.
76
- See the [boot.rb file from the Common-Accessioning robot suite](https://github.com/sul-dlss/common-accessioning/blob/master/config/boot.rb) as an example
77
-
78
- * Add `require 'resque/tasks'` to your `Rakefile`
72
+ Create a `config/boot.rb` containing:
73
+ ```
74
+ require 'rubygems'
75
+ require 'bundler/setup'
76
+ Bundler.require(:default)
79
77
 
80
- * Create an `environment` task within your `Rakefile` that requires your `config/boot.rb` file
78
+ LyberCore::Boot.up(__dir__)
81
79
 
82
- #### Example Rakefile modifications
83
- ```ruby
84
- require 'robot-controller/tasks'
85
- ...
86
- task :environment do
87
- require_relative 'config/boot'
88
- end
80
+ # Any additional robot-specific configuratio.
89
81
  ```
90
82
 
91
- ## Start the Robot
92
-
93
- * Use rake to start your robot, specifying the Resque queue as the environment variable `QUEUE`
83
+ The configuration must include:
84
+ ```
85
+ redis_url: ~
94
86
 
87
+ workflow:
88
+ url: http://workflow.example.com/workflow
89
+ logfile: 'log/workflow_service.log'
90
+ shift_age: 'weekly'
91
+ timeout: 60
95
92
  ```
96
- $ QUEUE=accessionWF_shelve rake environment workers
93
+
94
+ And optionally:
97
95
  ```
96
+ # For Dor Services Client
97
+ dor_services:
98
+ url: 'https://dor-services-test.stanford.test'
99
+ token: secret-token
98
100
 
99
- ## Enqueing a Job
101
+ # For Cocina::Models::Mapping::Purl
102
+ purl_url: 'https://purl-example.stanford.edu'
100
103
 
101
- ```ruby
102
- require 'resque'
103
- Resque.enqueue_to('accessionWF_shelve'.to_sym, Robot::DorRepo::Accession::Shelve, 'druid:aa123bb4567')
104
+ # For DruidTools::Druid
105
+ stacks:
106
+ local_workspace_root: ~
104
107
  ```
105
108
 
109
+ The following environment variables can optionally be set:
110
+ * ROBOT_ENVIRONMENT
111
+ * ROBOT_LOG_LEVEL
106
112
 
107
- ## Releases
108
- * **4.0** Remove unused classes and dependencies
109
- * **3.0** Robot overhaul. Use `resque` for job management and `bluepill` for process management
110
- * **2.1.1** Relax dor-services-gem version requirement
111
- * **2.0** Moved what was left of DorService (namely get_objects_for_workstep()) to dor-services' Dor::WorkflowService. Removed IdentityMetadata and DublinCore XML models. Factored out all remaining global constants. Removed unnecessary dependencies.
112
- * **1.3** Started to use Dor::Config for workspace configuration
113
- * **1.0.0** Factored all Dor::* classes and object models out of lyber-core and into a separate dor-services gem. WARNING: MAY BREAK COMPATIBILITY WITH PREVIOUS DOR-ENABLED CODE.
114
- * **0.9.8** Created branch for legacy work "0.9-legacy". Robots can now be configured with fully qualified workflows for prerequisites
115
- eg <i>dor:googleScannedBookWF:register-object</i>
116
- * **0.9.2** Workflow bug fixes. Last version that supports active-fedora 1.0.7
117
- * We recommend that you **DO NOT USE** any version older than these
113
+ ## Robot Testing
114
+ Include the following in `rspec/spec_helper.rb`:
115
+ ```
116
+ ENV['ROBOT_ENVIRONMENT'] = 'test'
117
+ require File.expand_path("#{__dir__}/../config/boot")
118
118
 
119
- ## Copyright
119
+ include LyberCore::Rspec
120
+ ```
120
121
 
121
- Copyright (c) 2014-16 Stanford University Library. See LICENSE for details.
122
+ Robots can be invoked with:
123
+ ```
124
+ test_perform(robot, druid)
125
+ ```
126
+ to avoid the workflow updates in `perform()`.
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The following is required in config/boot.rb
4
+ # require 'rubygems'
5
+ # require 'bundler/setup'
6
+ # Bundler.require(:default)
7
+
8
+ # LyberCore::Boot.up(__dir__)
9
+
10
+ module LyberCore
11
+ # Boots up the robot environment, including configuration, logging, clients, and Sidekiq.
12
+ class Boot
13
+ def self.up(config_dir)
14
+ new(config_dir).perform
15
+ end
16
+
17
+ def initialize(config_dir)
18
+ @config_dir = config_dir
19
+ end
20
+
21
+ def perform
22
+ boot_config
23
+ boot_dsa
24
+ boot_cocina_models
25
+ boot_sidekiq
26
+ end
27
+
28
+ def environment
29
+ @environment ||= ENV['ROBOT_ENVIRONMENT'] ||= 'development'
30
+ end
31
+
32
+ def boot_config
33
+ Config.setup do |config|
34
+ config.const_name = 'Settings'
35
+ config.use_env = true
36
+ config.env_prefix = 'SETTINGS'
37
+ config.env_separator = '__'
38
+ end
39
+ Config.load_and_set_settings(
40
+ Config.setting_files(File.expand_path(config_dir), environment)
41
+ )
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader :config_dir
47
+
48
+ def robot_root
49
+ @robot_root ||= File.expand_path("#{config_dir}/..")
50
+ end
51
+
52
+ def robot_log
53
+ Sidekiq::Logger.new(File.join(robot_root, "log/#{environment}.log")).tap do |log|
54
+ log.level = Logger::SEV_LABEL.index(ENV.fetch('ROBOT_LOG_LEVEL', nil)) || Logger::INFO
55
+ end
56
+ end
57
+
58
+ def boot_dsa
59
+ return unless Settings.dor_services&.url
60
+
61
+ Dor::Services::Client.configure(url: Settings.dor_services.url,
62
+ token: Settings.dor_services.token,
63
+ enable_get_retries: true)
64
+ end
65
+
66
+ def boot_cocina_models
67
+ Cocina::Models::Mapping::Purl.base_url = Settings.purl_url if Settings.purl_url
68
+ end
69
+
70
+ def boot_sidekiq
71
+ return if environment == 'test'
72
+
73
+ Sidekiq.configure_server do |config|
74
+ config.logger = robot_log
75
+ config.redis = { url: Settings.redis_url }
76
+ # For Sidekiq Pro
77
+ config.super_fetch!
78
+ end
79
+ end
80
+ end
81
+ end
@@ -1,27 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # this object defines the allowed states robots can optionally return upon completion
4
- # if the return value of the "perform" step is an object of this type and the status value is set an allowed value,
5
- # it will be used to set the final workflow state for that druid
6
3
  module LyberCore
7
- module Robot
8
- class ReturnState
9
- attr_reader :status
10
- attr_accessor :note
11
- ALLOWED_RETURN_STATES = %w[completed skipped waiting noop].freeze
12
- DEFAULT_RETURN_STATE = 'completed'
4
+ # this object defines the allowed states robots can optionally return upon completion
5
+ # if the return value of the "perform" step is an object of this type and the status value is set an allowed value,
6
+ # it will be used to set the final workflow state for that druid
7
+ class ReturnState
8
+ attr_reader :status
9
+ attr_accessor :note
13
10
 
14
- def initialize(params = {})
15
- self.status = params[:status] || DEFAULT_RETURN_STATE
16
- self.note = params[:note] || ''
17
- end
11
+ ALLOWED_RETURN_STATES = %w[completed skipped waiting noop].freeze
12
+ DEFAULT_RETURN_STATE = 'completed'
18
13
 
19
- def status=(value)
20
- state = value.to_s.downcase
21
- raise 'invalid return state' unless ALLOWED_RETURN_STATES.include? state
14
+ def initialize(params = {})
15
+ self.status = params[:status] || DEFAULT_RETURN_STATE
16
+ self.note = params[:note] || ''
17
+ end
18
+
19
+ def status=(value)
20
+ state = value.to_s.downcase
21
+ raise 'invalid return state' unless ALLOWED_RETURN_STATES.include? state
22
22
 
23
- @status = state
24
- end
23
+ @status = state
25
24
  end
26
25
  end
27
26
  end
@@ -1,112 +1,119 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'benchmark'
4
-
5
3
  module LyberCore
6
- module Robot
7
- # Add the ClassMethods to the class this is being mixed into
8
- def self.included(base)
9
- base.extend ClassMethods
10
- end
4
+ # Base class for all robots.
5
+ # Subclasses should implement the #perform_work method.
6
+ class Robot
7
+ include Sidekiq::Job
8
+ sidekiq_options retry: 0
11
9
 
12
- module ClassMethods
13
- # Called by job-manager on derived-class
14
- # Instantiate the Robot and call #work with the passed in druid
15
- def perform(druid, *context)
16
- bot = new
17
- bot.work druid, context
18
- end
19
- end
10
+ attr_reader :workflow_name, :process, :druid
20
11
 
21
- attr_accessor :check_queued_status
22
- attr_reader :workflow_name, :process
12
+ delegate :lane_id, to: :workflow
23
13
 
24
- def initialize(workflow_name, process, check_queued_status: true)
25
- Signal.trap('QUIT') { puts "#{Process.pid} ignoring SIGQUIT" } # SIGQUIT ignored to let the robot finish
14
+ def initialize(workflow_name, process)
26
15
  @workflow_name = workflow_name
27
16
  @process = process
28
- @check_queued_status = check_queued_status
29
17
  end
30
18
 
31
19
  def workflow_service
32
- raise 'The workflow_service method must be implemented on the class that includes LyberCore::Robot'
20
+ @workflow_service ||= WorkflowClientFactory.build(logger: logger)
21
+ end
22
+
23
+ def object_client
24
+ @object_client ||= Dor::Services::Client.object(druid)
25
+ end
26
+
27
+ def cocina_object
28
+ @cocina_object ||= object_client.find
29
+ end
30
+
31
+ def druid_object
32
+ @druid_object ||= DruidTools::Druid.new(druid, Settings.stacks.local_workspace_root)
33
33
  end
34
34
 
35
35
  # Sets up logging, timing and error handling of the job
36
- # Calls the #perform method, then sets workflow to 'completed' or 'error' depending on success
36
+ # Calls the #perform_work method, then sets workflow to 'completed' or 'error' depending on success
37
37
  # rubocop:disable Metrics/AbcSize
38
- # rubocop:disable Metrics/CyclomaticComplexity
39
- # rubocop:disable Metrics/PerceivedComplexity
40
- def work(druid, context)
41
- Honeybadger.context(druid: druid, process: process, workflow_name: workflow_name) if defined? Honeybadger
42
- workflow = workflow(druid)
43
- LyberCore::Log.set_logfile($stdout) # let process manager handle logging
44
- LyberCore::Log.info "#{druid} processing #{process} (#{workflow_name})"
45
- return if check_queued_status && !item_queued?(druid)
38
+ # rubocop:disable Metrics/MethodLength
39
+ def perform(druid)
40
+ @druid = druid
41
+ Honeybadger.context(druid: druid, process: process, workflow_name: workflow_name)
42
+
43
+ logger.info "#{druid} processing #{process} (#{workflow_name})"
44
+ return unless check_item_queued?
46
45
 
47
46
  # this is the default note to pass back to workflow service,
48
- # but it can be overriden by a robot that uses the Lybercore::Robot::ReturnState
47
+ # but it can be overriden by a robot that uses the Robots::ReturnState
49
48
  # object to return a status
50
49
  note = Socket.gethostname
51
50
 
52
51
  # update the workflow status to indicate that started
53
- workflow.start(note)
52
+ workflow.start!(note)
54
53
 
55
54
  result = nil
56
55
  elapsed = Benchmark.realtime do
57
- result = if method(:perform).arity == 1
58
- perform druid # implemented in the mixed-in robot class
59
- else
60
- perform druid, context
61
- end
56
+ result = perform_work
62
57
  end
63
58
 
64
59
  # the final workflow state is determined by the return value of the perform step, if it is a ReturnState object,
65
60
  # we will use the defined status, otherwise default to completed
66
61
  # if a note is passed back, we will also use that instead of the default
67
- if result.class == LyberCore::Robot::ReturnState
62
+ if result.instance_of?(ReturnState)
68
63
  workflow_state = result.status
69
64
  note = result.note unless result.note.blank?
70
65
  else
71
66
  workflow_state = 'completed'
72
67
  end
73
- # update the workflow status from its current state to the state returned by perform (or 'completed' as the default)
68
+ # update the workflow status from its current state to the state returned by perform
69
+ # (or 'completed' as the default)
74
70
  # noop allows a robot to not set a workflow as complete, e.g., if that is delegated to another service.
75
- workflow.complete(workflow_state, elapsed, note) unless workflow_state == 'noop'
71
+ workflow.complete!(workflow_state, elapsed, note) unless workflow_state == 'noop'
76
72
 
77
- LyberCore::Log.info "Finished #{druid} in #{sprintf('%0.4f', elapsed)}s"
73
+ logger.info "Finished #{druid} in #{format('%0.4f', elapsed)}s"
78
74
  rescue StandardError => e
79
- Honeybadger.notify(e) if defined? Honeybadger
80
- begin
81
- LyberCore::Log.error e.message + "\n" + e.backtrace.join("\n")
82
- workflow.error(e.message, Socket.gethostname)
83
- rescue StandardError => e
84
- LyberCore::Log.error "Cannot set #{druid} to status='error'\n#{e.message}\n#{e.backtrace.join("\n")}"
85
- raise e # send exception to Resque failed queue
86
- end
75
+ handle_error(e)
76
+ end
77
+ # rubocop:enable Metrics/AbcSize
78
+ # rubocop:enable Metrics/MethodLength
79
+
80
+ # Work performed by the robot.
81
+ # This method is to be implemented by robot subclasses.
82
+ def perform_work
83
+ raise NotImplementedError
84
+ end
85
+
86
+ def bare_druid
87
+ @bare_druid = druid.delete_prefix('druid:')
87
88
  end
88
- # rubocop:enable Metrics/AbcSize
89
- # rubocop:enable Metrics/CyclomaticComplexity
90
- # rubocop:enable Metrics/PerceivedComplexity
91
89
 
92
- private
90
+ private
91
+
92
+ # rubocop:disable Metrics/AbcSize
93
+ def handle_error(error)
94
+ Honeybadger.notify(error)
95
+ logger.error "#{error.message}\n#{error.backtrace.join("\n")}"
96
+ workflow.error!(error.message, Socket.gethostname)
97
+ rescue StandardError => e
98
+ logger.error "Cannot set #{druid} to status='error'\n#{e.message}\n#{e.backtrace.join("\n")}"
99
+ raise e # send exception to Sidekiq failed queue
100
+ end
101
+ # rubocop:enable Metrics/AbcSize
93
102
 
94
- def workflow(druid)
95
- Workflow.new(workflow_service: workflow_service,
96
- druid: druid,
97
- workflow_name: workflow_name,
98
- process: process)
103
+ def workflow
104
+ @workflow ||= Workflow.new(workflow_service: workflow_service,
105
+ druid: druid,
106
+ workflow_name: workflow_name,
107
+ process: process)
99
108
  end
100
109
 
101
- def item_queued?(druid)
102
- status = workflow_service.workflow_status(druid: druid,
103
- workflow: workflow_name,
104
- process: process)
105
- return true if status =~ /queued/i
110
+ def check_item_queued?
111
+ return true if /queued/i.match?(workflow.status)
106
112
 
107
- msg = "Item #{druid} is not queued for #{process} (#{workflow_name}), but has status of '#{status}'. Will skip processing"
108
- Honeybadger.notify(msg) if defined? Honeybadger
109
- LyberCore::Log.warn msg
113
+ msg = "Item #{druid} is not queued for #{process} (#{workflow_name}), " \
114
+ "but has status of '#{workflow.status}'. Will skip processing"
115
+ Honeybadger.notify(msg)
116
+ logger.warn(msg)
110
117
  false
111
118
  end
112
119
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LyberCore
4
+ # Methods to support testing robots
5
+ module Rspec
6
+ def test_perform(robot, druid)
7
+ allow(robot).to receive(:druid).and_return(druid)
8
+ robot.perform_work
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LyberCore
4
+ VERSION = '7.0.0'
5
+ end
@@ -10,7 +10,7 @@ module LyberCore
10
10
  @process = process
11
11
  end
12
12
 
13
- def start(note)
13
+ def start!(note)
14
14
  workflow_service.update_status(druid: druid,
15
15
  workflow: workflow_name,
16
16
  process: process,
@@ -19,7 +19,7 @@ module LyberCore
19
19
  note: note)
20
20
  end
21
21
 
22
- def complete(status, elapsed, note)
22
+ def complete!(status, elapsed, note)
23
23
  workflow_service.update_status(druid: druid,
24
24
  workflow: workflow_name,
25
25
  process: process,
@@ -28,7 +28,7 @@ module LyberCore
28
28
  note: note)
29
29
  end
30
30
 
31
- def error(error_msg, error_text)
31
+ def error!(error_msg, error_text)
32
32
  workflow_service.update_error_status(druid: druid,
33
33
  workflow: workflow_name,
34
34
  process: process,
@@ -36,7 +36,17 @@ module LyberCore
36
36
  error_text: error_text)
37
37
  end
38
38
 
39
- private
39
+ def status
40
+ @status ||= workflow_service.workflow_status(druid: druid,
41
+ workflow: workflow_name,
42
+ process: process)
43
+ end
44
+
45
+ def lane_id
46
+ @lane_id ||= workflow_service.process(pid: druid, workflow_name: workflow_name, process: process).lane_id
47
+ end
48
+
49
+ private
40
50
 
41
51
  attr_reader :workflow_service, :druid, :workflow_name, :process
42
52
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LyberCore
4
+ # Factory for creating a workflow client
5
+ class WorkflowClientFactory
6
+ def self.build(logger:)
7
+ Dor::Workflow::Client.new(url: Settings.workflow.url, logger: logger, timeout: Settings.workflow.timeout)
8
+ end
9
+ end
10
+ end
data/lib/lyber_core.rb CHANGED
@@ -1,6 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'lyber_core/log'
4
- require 'lyber_core/workflow'
5
- require 'lyber_core/robot'
6
- require 'lyber_core/return_state'
3
+ require 'benchmark'
4
+ require 'socket'
5
+ require 'active_support'
6
+ require 'active_support/core_ext/object/blank' # String#blank?
7
+ require 'active_support/core_ext/module/delegation'
8
+ require 'sidekiq'
9
+ require 'honeybadger'
10
+ require 'dor/workflow/client'
11
+ require 'dor/services/client'
12
+ require 'druid-tools'
13
+ require 'zeitwerk'
14
+
15
+ loader = Zeitwerk::Loader.for_gem
16
+ loader.ignore("#{__dir__}/lyber-core.rb")
17
+ loader.setup
18
+
19
+ # Elon Musk: "Robots will be able to do everything better than us"
20
+ module LyberCore
21
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lyber-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.1.1
4
+ version: 7.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alpana Pande
@@ -13,19 +13,19 @@ authors:
13
13
  - Michael Klein
14
14
  - Darren Weber
15
15
  - Peter Mangiafico
16
- autorequire:
16
+ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
- date: 2020-03-29 00:00:00.000000000 Z
19
+ date: 2023-02-21 00:00:00.000000000 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: coveralls
22
+ name: activesupport
23
23
  requirement: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
- type: :development
28
+ type: :runtime
29
29
  prerelease: false
30
30
  version_requirements: !ruby/object:Gem::Requirement
31
31
  requirements:
@@ -33,27 +33,55 @@ dependencies:
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  - !ruby/object:Gem::Dependency
36
- name: rake
36
+ name: config
37
37
  requirement: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: 0.8.7
42
- type: :development
41
+ version: '0'
42
+ type: :runtime
43
43
  prerelease: false
44
44
  version_requirements: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: 0.8.7
48
+ version: '0'
49
49
  - !ruby/object:Gem::Dependency
50
- name: rdoc
50
+ name: dor-services-client
51
+ requirement: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '12.10'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '12.10'
63
+ - !ruby/object:Gem::Dependency
64
+ name: dor-workflow-client
65
+ requirement: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '5.0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '5.0'
77
+ - !ruby/object:Gem::Dependency
78
+ name: druid-tools
51
79
  requirement: !ruby/object:Gem::Requirement
52
80
  requirements:
53
81
  - - ">="
54
82
  - !ruby/object:Gem::Version
55
83
  version: '0'
56
- type: :development
84
+ type: :runtime
57
85
  prerelease: false
58
86
  version_requirements: !ruby/object:Gem::Requirement
59
87
  requirements:
@@ -61,27 +89,41 @@ dependencies:
61
89
  - !ruby/object:Gem::Version
62
90
  version: '0'
63
91
  - !ruby/object:Gem::Dependency
64
- name: rspec
92
+ name: honeybadger
93
+ requirement: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ type: :runtime
99
+ prerelease: false
100
+ version_requirements: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ - !ruby/object:Gem::Dependency
106
+ name: sidekiq
65
107
  requirement: !ruby/object:Gem::Requirement
66
108
  requirements:
67
109
  - - "~>"
68
110
  - !ruby/object:Gem::Version
69
- version: '3.0'
70
- type: :development
111
+ version: '6.2'
112
+ type: :runtime
71
113
  prerelease: false
72
114
  version_requirements: !ruby/object:Gem::Requirement
73
115
  requirements:
74
116
  - - "~>"
75
117
  - !ruby/object:Gem::Version
76
- version: '3.0'
118
+ version: '6.2'
77
119
  - !ruby/object:Gem::Dependency
78
- name: rubocop
120
+ name: zeitwerk
79
121
  requirement: !ruby/object:Gem::Requirement
80
122
  requirements:
81
123
  - - ">="
82
124
  - !ruby/object:Gem::Version
83
125
  version: '0'
84
- type: :development
126
+ type: :runtime
85
127
  prerelease: false
86
128
  version_requirements: !ruby/object:Gem::Requirement
87
129
  requirements:
@@ -89,7 +131,35 @@ dependencies:
89
131
  - !ruby/object:Gem::Version
90
132
  version: '0'
91
133
  - !ruby/object:Gem::Dependency
92
- name: rubocop-rspec
134
+ name: rake
135
+ requirement: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: 0.8.7
140
+ type: :development
141
+ prerelease: false
142
+ version_requirements: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: 0.8.7
147
+ - !ruby/object:Gem::Dependency
148
+ name: rspec
149
+ requirement: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '3.0'
154
+ type: :development
155
+ prerelease: false
156
+ version_requirements: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: '3.0'
161
+ - !ruby/object:Gem::Dependency
162
+ name: rubocop
93
163
  requirement: !ruby/object:Gem::Requirement
94
164
  requirements:
95
165
  - - "~>"
@@ -103,7 +173,21 @@ dependencies:
103
173
  - !ruby/object:Gem::Version
104
174
  version: '1.24'
105
175
  - !ruby/object:Gem::Dependency
106
- name: yard
176
+ name: rubocop-rspec
177
+ requirement: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ type: :development
183
+ prerelease: false
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ - !ruby/object:Gem::Dependency
190
+ name: simplecov
107
191
  requirement: !ruby/object:Gem::Requirement
108
192
  requirements:
109
193
  - - ">="
@@ -129,16 +213,18 @@ files:
129
213
  - README.md
130
214
  - lib/lyber-core.rb
131
215
  - lib/lyber_core.rb
132
- - lib/lyber_core/log.rb
216
+ - lib/lyber_core/boot.rb
133
217
  - lib/lyber_core/return_state.rb
134
218
  - lib/lyber_core/robot.rb
219
+ - lib/lyber_core/rspec.rb
220
+ - lib/lyber_core/version.rb
135
221
  - lib/lyber_core/workflow.rb
136
- - lib/tasks/rdoc.rake
222
+ - lib/lyber_core/workflow_client_factory.rb
137
223
  homepage: http://github.com/sul-dlss/lyber-core
138
224
  licenses:
139
225
  - Apache-2.0
140
226
  metadata: {}
141
- post_install_message:
227
+ post_install_message:
142
228
  rdoc_options: []
143
229
  require_paths:
144
230
  - lib
@@ -146,15 +232,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
146
232
  requirements:
147
233
  - - ">="
148
234
  - !ruby/object:Gem::Version
149
- version: '0'
235
+ version: '3.0'
150
236
  required_rubygems_version: !ruby/object:Gem::Requirement
151
237
  requirements:
152
238
  - - ">="
153
239
  - !ruby/object:Gem::Version
154
240
  version: 1.3.6
155
241
  requirements: []
156
- rubygems_version: 3.1.2
157
- signing_key:
242
+ rubygems_version: 3.3.7
243
+ signing_key:
158
244
  specification_version: 4
159
245
  summary: Core services used by the SUL Digital Library
160
246
  test_files: []
@@ -1,105 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LyberCore
4
- class LyberCore::Log
5
- require 'logger'
6
-
7
- # Default values
8
- DEFAULT_LOGFILE = '/tmp/lybercore_log.log' # TODO: change to STDOUT?
9
- DEFAULT_LOG_LEVEL = Logger::INFO
10
- DEFAULT_FORMATTER = proc do |s, t, p, m|
11
- "%5s [%s] (%s) %s :: %s\n" % [s, t.strftime('%Y-%m-%d %H:%M:%S'), $$, p, m]
12
- end
13
-
14
- # Initial state
15
- @@logfile = DEFAULT_LOGFILE
16
- @@log ||= Logger.new(@@logfile)
17
- # $stdout.reopen(@@logfile)
18
- # $stderr.reopen(@@logfile)
19
- @@log.level = DEFAULT_LOG_LEVEL
20
- @@log.formatter = DEFAULT_FORMATTER
21
-
22
- # Restore LyberCore::Log to its default state
23
- def Log.restore_defaults
24
- @@log.level = DEFAULT_LOG_LEVEL
25
- Log.set_logfile(DEFAULT_LOGFILE)
26
- @@log.formatter = DEFAULT_FORMATTER
27
- end
28
-
29
- # The current location of the logfile
30
- def Log.logfile
31
- @@logfile
32
- end
33
-
34
- # Accepts a filename as an argument, and checks to see whether that file can be
35
- # opened for writing. If it can be opened, it closes the existing Logger object
36
- # and re-opens it with the new logfile location. It raises an exception if it
37
- # cannot write to the specified logfile.
38
- def Log.set_logfile(new_logfile)
39
- current_log_level = @@log.level
40
- current_formatter = @@log.formatter
41
- @@log = Logger.new(new_logfile)
42
- @@logfile = new_logfile
43
- @@log.level = current_log_level
44
- @@log.formatter = current_formatter
45
- rescue Exception => e
46
- raise e, "Couldn't initialize logfile #{new_logfile} because\n#{e.message}: #{e.backtrace.join(%(\n))}}"
47
- end
48
-
49
- # Set the log level.
50
- # See http://ruby-doc.org/core/classes/Logger.html for more info.
51
- # Possible values are:
52
- # Logger::FATAL (4): an unhandleable error that results in a program crash
53
- # Logger::ERROR (3): a handleable error condition
54
- # Logger::WARN (2): a warning
55
- # Logger::INFO (1): generic (useful) information about system operation
56
- # Logger::DEBUG (0): low-level information for developers
57
- def Log.set_level(loglevel)
58
- if [0, 1, 2, 3, 4].include? loglevel
59
- @@log.level = loglevel
60
- @@log.debug "Setting LyberCore::Log.level to #{loglevel}"
61
- else
62
- @@log.warn "I received an invalid option for log level. I expected a number between 0 and 4 but I got #{loglevel}"
63
- @@log.warn "I'm setting the loglevel to 0 (debug) because you seem to be having trouble."
64
- @@log.level = 0
65
- end
66
- rescue Exception => e
67
- raise e, "Couldn't set log level because\n#{e.message}: #{e.backtrace.join(%(\n))}"
68
- end
69
-
70
- # Return the current log level
71
- def Log.level
72
- @@log.level
73
- end
74
-
75
- def Log.fatal(msg)
76
- @@log.add(Logger::FATAL) { msg }
77
- end
78
-
79
- def Log.error(msg)
80
- @@log.add(Logger::ERROR) { msg }
81
- end
82
-
83
- def Log.warn(msg)
84
- @@log.add(Logger::WARN) { msg }
85
- end
86
-
87
- def Log.info(msg)
88
- @@log.add(Logger::INFO) { msg }
89
- end
90
-
91
- def Log.debug(msg)
92
- @@log.add(Logger::DEBUG) { msg }
93
- end
94
-
95
- def Log.exception(exc)
96
- msg = Log.exception_message(exc)
97
- Log.error(msg)
98
- end
99
-
100
- def Log.exception_message(exc)
101
- msg = exc.inspect.split($/).join('; ') + "\n"
102
- msg << exc.backtrace.join("\n") if exc.backtrace
103
- end
104
- end
105
- end
data/lib/tasks/rdoc.rake DELETED
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- desc 'Generate RDoc'
4
- task doc: ['doc:generate']
5
-
6
- namespace :doc do
7
- project_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
8
- doc_destination = File.join(project_root, 'rdoc')
9
-
10
- begin
11
- require 'yard'
12
- require 'yard/rake/yardoc_task'
13
-
14
- YARD::Rake::YardocTask.new(:generate) do |yt|
15
- yt.files = Dir.glob(File.join(project_root, 'lib', '*.rb')) +
16
- Dir.glob(File.join(project_root, 'lib', '**', '*.rb')) +
17
- [File.join(project_root, 'README.rdoc')] +
18
- [File.join(project_root, 'LICENSE')]
19
-
20
- yt.options = ['--output-dir', doc_destination, '--readme', 'README.rdoc']
21
- end
22
- rescue LoadError
23
- desc 'Generate YARD Documentation'
24
- task :generate do
25
- abort 'Please install the YARD gem to generate rdoc.'
26
- end
27
- end
28
-
29
- desc 'Remove generated documenation'
30
- task :clean do
31
- rm_r doc_destination if File.exist?(doc_destination)
32
- end
33
- end