cocina-models 0.101.1 → 0.103.1

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: 020bb1af47ff01f6e95a8d126cabaae16a19a1cd92ae8bdade1e18f97f519af6
4
- data.tar.gz: e05e3b0a0a6122a1297fe3d12e3b9737b618ed03ae246d8b4b24e0740254ad9a
3
+ metadata.gz: 439375f55b48b22cc891dde1fb31519f9b08a42b9128894cf04f643a5644a027
4
+ data.tar.gz: 7f7a68b92f272e867d6243485d4ed68c1741128c6e93785a1879b811ca0ece63
5
5
  SHA512:
6
- metadata.gz: fd8a640dfe907eaebfc3f0b6b72f044b8b149718601d8845b315d529f861634fc0ce194f684236802e2799378a5a01920d8facf7f3669a95ac9e6d1ede066ce5
7
- data.tar.gz: eb7d1fc6c14ebadb308e7c7b53f00640d20de07ca337523e33cc77e7b039b00d737fa94079282e29254c8f46b6dffb654ae5c3c5dbfb7fe5cc7cabc592e1fa93
6
+ metadata.gz: e23f7d1949ee04c1dba3bea6b64620f0ad816bde8ee02666e8af6b3c3057c86d326f586f696572e8cf0f3ba01c191444cd7501f81a8eede6fcaa45682b69fdfb
7
+ data.tar.gz: 1b215531fa86e0f049f7c38bd8819c3ae47f849d66b7217da376761e09131f1c23e60b448ae404c66ee6024f6b4f570966a07398719360739182c99e5a2649d1
data/.rubocop.yml CHANGED
@@ -512,3 +512,12 @@ Style/ItAssignment: # new in 1.70
512
512
  Enabled: true
513
513
  Style/RedundantFormat: # new in 1.72
514
514
  Enabled: true
515
+
516
+ Style/ComparableBetween: # new in 1.74
517
+ Enabled: true
518
+ Style/HashFetchChain: # new in 1.75
519
+ Enabled: true
520
+ Style/ItBlockParameter: # new in 1.75
521
+ Enabled: true
522
+ RSpec/IncludeExamples: # new in 3.6
523
+ Enabled: true
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cocina-models (0.101.1)
4
+ cocina-models (0.103.1)
5
5
  activesupport
6
6
  deprecation
7
7
  dry-struct (~> 1.0)
@@ -43,7 +43,7 @@ GEM
43
43
  openapi_parser (~> 1.0)
44
44
  rack (>= 1.5)
45
45
  concurrent-ruby (1.3.5)
46
- connection_pool (2.5.0)
46
+ connection_pool (2.5.2)
47
47
  deprecation (1.1.0)
48
48
  activesupport
49
49
  diff-lcs (1.6.1)
@@ -78,7 +78,7 @@ GEM
78
78
  i18n (1.14.7)
79
79
  concurrent-ruby (~> 1.0)
80
80
  ice_nine (0.11.2)
81
- json (2.10.2)
81
+ json (2.11.3)
82
82
  json_schema (0.21.0)
83
83
  jsonpath (1.1.5)
84
84
  multi_json
@@ -88,12 +88,12 @@ GEM
88
88
  mini_portile2 (2.8.8)
89
89
  minitest (5.25.5)
90
90
  multi_json (1.15.0)
91
- nokogiri (1.18.7)
91
+ nokogiri (1.18.8)
92
92
  mini_portile2 (~> 2.8.2)
93
93
  racc (~> 1.4)
94
94
  openapi_parser (1.0.0)
95
95
  optimist (3.2.1)
96
- parallel (1.26.3)
96
+ parallel (1.27.0)
97
97
  parser (3.3.8.0)
98
98
  ast (~> 2.4.1)
99
99
  racc
@@ -120,7 +120,7 @@ GEM
120
120
  rspec-support (3.13.2)
121
121
  rspec_junit_formatter (0.6.0)
122
122
  rspec-core (>= 2, < 4, != 2.12.0)
123
- rubocop (1.75.2)
123
+ rubocop (1.75.3)
124
124
  json (~> 2.3)
125
125
  language_server-protocol (~> 3.17.0.2)
126
126
  lint_roller (~> 1.1.0)
@@ -137,7 +137,7 @@ GEM
137
137
  rubocop-rake (0.7.1)
138
138
  lint_roller (~> 1.1)
139
139
  rubocop (>= 1.72.1)
140
- rubocop-rspec (3.5.0)
140
+ rubocop-rspec (3.6.0)
141
141
  lint_roller (~> 1.1)
142
142
  rubocop (~> 1.72, >= 1.72.1)
143
143
  ruby-progressbar (1.13.0)
data/README.md CHANGED
@@ -123,23 +123,28 @@ A patch change is a change that (1) does not affect the data model; (2) does not
123
123
 
124
124
  A patch change can be released as part of regular dependency updates or selectively released for individual applications.
125
125
 
126
- ## Releasing major or minor change
127
-
128
- NOTE: If dependency updates are about to be released, you have the option of shortening the process and stopping after Step 3. This is because Steps 4 onwards will be taken care of by the regular dependency updates process (basically the updating of cocina-models, dor-services-client and sdr-client as needed in the rest of the associated apps). You still do need to manually bump some gems and the pinned version of cocina-models in a couple apps and get those PRs approved and merged, as described in Steps 1-3 below.
129
-
130
- IMPORTANT: If you do opt to skip steps 4 onward, you should NOT merge the cocina-models bump dor-services-app and sdr-api PRs you created in step 3 until you are ready to finish the dependency updates process. You can have them reviewed and approved, but if you merge, you will greatly increase the risk of issues if the main branch of DSA or sdr-api are deployed after steps 1-3 are complete but before the rest of the apps are updated to use the new cocina-models via regular dependency updates. The fix for this is to either roll-back DSA and sdr-api to the previous release tag, or proceed forwards with step 4-5.
126
+ ## Releasing a major or minor change
131
127
 
132
128
  Before you release a major or minor change, think about if this release will include new validations. Even if your change didn't make any changes that would affect validation, there may be other unreleased changes since the previous version of the gem was cut and released. Best practice is to scan back through the commit history until you get to the last version bump and see if there any significant changes that may affect validation.
133
129
 
134
130
  If unsure, ask the team or ask for help to just run the validation report anyway (as described above).
135
131
 
132
+ ### Partial release process
133
+ NOTE: If dependency updates are about to be released, you have the option of shortening the process and stopping after Step 3. This is because Steps 4 onwards will be taken care of by the regular dependency updates process (basically the updating of cocina-models, dor-services-client and sdr-client as needed in the rest of the associated apps). You still do need to manually bump some gems and the pinned version of cocina-models in the directly coupled apps and get those PRs approved and merged, as described in Steps 1-3 below.
134
+
135
+ IMPORTANT: If you do opt to skip steps 4 onward, you should NOT merge the dor-services-app and sdr-api PRs you created in step 3 until you are ready to finish the dependency updates process. You can have them reviewed and approved, but if you merge, you will greatly increase the risk of issues if the main branch of DSA or sdr-api are deployed after steps 1-3 are complete but before the rest of the apps are updated to use the new cocina-models via regular dependency updates. The fix for this is to either roll back DSA and sdr-api to the previous release tag, or proceed forwards with step 4-5.
136
+
136
137
  ### Step 0: Share intent to change the models
137
138
 
138
139
  Send a note to `#dlss-infra-chg-mgmt` on Slack to let people know what is changing and when.
139
140
 
140
141
  ### Step 1: Cut the release
141
142
 
142
- The release process is much like any other gem. First bump the version in `lib/cocina/models/version.rb`, then `bundle install` so that `Gemfile.lock` is updated, then commit and push those changes. Then run:
143
+ The release process is much like any other gem. While on main:
144
+ 1. Bump the version in `lib/cocina/models/version.rb`
145
+ 2. `bundle install` so that `Gemfile.lock` is updated.
146
+ 3. Commit those changes.
147
+ 4. Run:
143
148
  ```
144
149
  bundle exec rake release
145
150
  ```
@@ -147,7 +152,11 @@ which pushes the gem to rubygems.org.
147
152
 
148
153
  ### Step 2: Update client gems coupled to the models
149
154
 
150
- Release new versions of [sdr-client](https://github.com/sul-dlss/sdr-client) and [dor-services-client](https://github.com/sul-dlss/dor-services-client/) pinned to use the new cocina-models version because applications such as [Argo](https://github.com/sul-dlss/argo) and [Dor-Services-App](https://github.com/sul-dlss/dor-services-app) depend on these gems using the same models.
155
+ Release new versions of [sdr-client](https://github.com/sul-dlss/sdr-client) and [dor-services-client](https://github.com/sul-dlss/dor-services-client/):
156
+ 1. Pin the new cocina-models version in the clients' `gemspec` files.
157
+ 2. Bump the version as described in each client's README release instructions.
158
+
159
+ Applications such as [Argo](https://github.com/sul-dlss/argo) and [Dor-Services-App](https://github.com/sul-dlss/dor-services-app) depend on these gems using the same models.
151
160
 
152
161
  ### Step 3: Update services directly coupled to the models
153
162
 
@@ -156,27 +165,31 @@ This list of services is known to include:
156
165
  * [sul-dlss/sdr-api](https://github.com/sul-dlss/sdr-api)
157
166
  * [sul-dlss/dor-services-app](https://github.com/sul-dlss/dor-services-app/)
158
167
 
159
- **NOTE**: You can skip step 3A if there have not been any changes to the `cocina-models` OpenAPI spec since the prior release.
160
168
 
161
169
  #### Step 3A: Update API specifications
162
170
 
163
- The cocina-models gem is used in applications that have an API specification that accepts Cocina models. Make sure that the `openapi.yml` for these applications include the `openapi.yml` schema changes made in cocina-models.
171
+ **NOTE**: You can skip step 3A if there have not been any changes to the `cocina-models` OpenAPI spec since the prior release.
172
+
173
+ The cocina-models gem is used in applications that have an API specification that accepts Cocina models. Make sure that the `openapi.yml` for these two applications includes the `openapi.yml` schema changes made in cocina-models.
164
174
 
165
- This can be accomplished by copying and pasting the cocina-models schemas to the openapi.yml of the associated project. By convention, these schemas are listed first in the `openapi.yml` of the associated projects, followed by the application-specific schemas.
175
+ Copy and paste the cocina-models schemas to each project's `openapi.yml`. By convention, these schemas are listed first, followed by the application-specific schemas.
166
176
 
167
177
  #### Step 3B: Bump gems and create the PRs
168
178
 
169
- If step 3A was needed, use the same PRs to also bump the versions of cocina-models, sdr-client, and dor-services-client in these applications/services. Why? When [dor-services-app](https://github.com/sul-dlss/dor-services-app), for example, is updated to use the new models (via the auto-update script), these clients should be updated at the same time or there is risk of models produced by dor-services-app not being acceptable to the clients.
179
+ If you updated the `openapi.yml` in step 3A, use the same PR for step 3B. Why? When [dor-services-app](https://github.com/sul-dlss/dor-services-app), for example, is updated to use the new models (via the auto-update script), these clients should be updated at the same time or there is risk of models produced by dor-services-app not being acceptable to the clients.
170
180
 
171
- With or without step 3A, perform `bundle update` for cocina-models, sdr-client, and dor-services-client gems in the listed services and then make PRs for those repos. You may first need to update how these gems are pinned in the `Gemfile` in order to bump them. Note that dor-services-app only needs a bump to cocina-models gem and sdr-api only needs a bump to cocina-models and dor-services-client gems.
181
+ 1. Perform `bundle update --conservative cocina-models dor-services-client` in the services above and make PRs for those repos if they don't already exist. You may first need to update how these gems are pinned in the `Gemfile` in order to bump them.
182
+ 2. Note that sdr-client is not currently used in these applications, but if it were, would also need to be bumped to the latest release.
172
183
 
173
184
  #### Step 3C: Merge 'em
174
185
 
175
- Get the directly coupled services PRs merged before the deploy in step 5.
186
+ Get the directly coupled services PRs merged before the deploy in step 5.
187
+
188
+ See the IMPORTANT note above about the timing of merging these PRs if you are waiting for dependency updates to make the updates to other dependent applications.
176
189
 
177
190
  ### Step 4: Update other dependent applications
178
191
 
179
- Once the above listed steps have been completed, all applications that use cocina-models should be updated and released at the same time. "Cocina Level 2" describes this set of updates. The applications that use cocina-models are those in [this list](https://github.com/sul-dlss/access-update-scripts/blob/master/infrastructure/projects.yml) that are NOT marked with `cocina_level2: false`.
192
+ All applications that use cocina-models should be updated and released at the same time. "Cocina Level 2" describes this set of updates. The applications that use cocina-models are those in [this list](https://github.com/sul-dlss/access-update-scripts/blob/master/infrastructure/projects.yml) that are NOT marked with `cocina_level2: false`.
180
193
 
181
194
  There are scripts to help with updating other dependent applications:
182
195
 
@@ -192,14 +205,13 @@ If for some reason the above method does not work, the sul-dlss/access-update-sc
192
205
  ```
193
206
  REPOS_PATH=infrastructure GH_ACCESS_TOKEN=abc123 COCINA_LEVEL2= ./merge-all.rb
194
207
  ```
195
- ### Step 5: Deploy all affected applications together
208
+ ### Step 5: Deploy and test
196
209
 
210
+ #### Step 5A: Deploy to Stage or QA
197
211
  [sul-dlss/sdr-deploy](https://github.com/sul-dlss/sdr-deploy) has a flag (-c) in the deploy script to limit deploys to cocina dependent applications. Refer to instructions in the [sdr-deploy/README](https://github.com/sul-dlss/sdr-deploy/blob/main/README.md#only-deploy-repos-related-to-cocina-models-update).
198
212
 
199
213
  Note that running the integration tests is currently the best way we have to check for unintended effects and/or bugs when rolling out cocina-models changes.
200
214
 
201
- #### Step 5A: Deploy to QA and/or Stage
202
-
203
215
  #### Step 5B: Run infrastructure_integration_tests
204
216
 
205
217
  It is safest to ensure _all_ the integration tests run cleanly. However, patch releases of cocina-models may only warrant running individual tests that exercise the changes.
@@ -38,9 +38,11 @@ module Cocina
38
38
  # the "full title" is the title WITH subtitle, part name, etc. We want to able able to index it separately so
39
39
  # we can boost matches on it in search results (boost matching this string higher than other titles present)
40
40
  # @param [Array<Cocina::Models::Title,Cocina::Models::DescriptiveValue>] titles the titles to consider
41
+ # @param [Array<Cocina::Models::FolioCatalogLink>] catalog_links the folio catalog links to check for digital serials part labels
41
42
  # @return [Array<String>] the full title value(s) for Solr - array due to possible parallelValue
42
- def self.full_title(titles)
43
- [new(strategy: :first, add_punctuation: false, only_one_parallel_value: false).build(titles)].flatten.compact
43
+ def self.full_title(titles, catalog_links: [])
44
+ part_label = catalog_links.find { |link| link.catalog == 'folio' }&.partLabel
45
+ [new(strategy: :first, add_punctuation: false, only_one_parallel_value: false, part_label: part_label).build(titles)].flatten.compact
44
46
  end
45
47
 
46
48
  # "additional titles" are all title data except for full_title. We want to able able to index it separately so
@@ -68,7 +70,6 @@ module Cocina
68
70
  end
69
71
 
70
72
  # @param [Array<Cocina::Models::Title>] cocina_titles the titles to consider
71
- # @param [String, nil] part_label the partLabel to add to the title for digital serials
72
73
  # @return [String, Array] the title value for Solr - for :first strategy, a string; for :all strategy, an array
73
74
  # (e.g. title displayed in blacklight search results vs boosting values for search result rankings)
74
75
  #
@@ -78,7 +79,8 @@ module Cocina
78
79
  cocina_title = other_title(cocina_titles) if cocina_title.blank?
79
80
  if strategy == :first
80
81
  result = extract_title(cocina_title)
81
- add_part_label(result)
82
+ result = add_part_label(result) if part_label.present?
83
+ result
82
84
  else
83
85
  result = cocina_titles.map { |ctitle| extract_title(ctitle) }.flatten
84
86
  if only_one_parallel_value? && result.length == 1
@@ -106,8 +108,8 @@ module Cocina
106
108
 
107
109
  def add_part_label(title)
108
110
  # when a digital serial
109
- title = "#{title.sub(/[ .,]*$/, '')}, #{part_label}" if part_label.present?
110
- title
111
+ title = title.sub(/[ .,]*$/, '').to_s
112
+ add_punctuation? ? "#{title}, #{part_label}" : "#{title} #{part_label}"
111
113
  end
112
114
 
113
115
  def extract_title(cocina_title)
@@ -245,6 +247,8 @@ module Cocina
245
247
  padding = non_sorting_padding(cocina_title, value)
246
248
  result = add_non_sorting_value(result, value, padding)
247
249
  when 'part name', 'part number'
250
+ # even if there is a partLabel, use any existing structuredValue
251
+ # part name/number that remains for non-digital serials purposes
248
252
  if part_name_number.blank?
249
253
  part_name_number = part_name_number(cocina_title.structuredValue)
250
254
  result = if !add_punctuation?
@@ -11,30 +11,29 @@ module Cocina
11
11
  TAG_NAME = Cocina::Models::Mapping::FromMods::Title::TYPES.invert.merge('activity dates' => 'date').freeze
12
12
  NAME_TYPES = ['name', 'forename', 'surname', 'life dates', 'term of address'].freeze
13
13
 
14
+ def self.write(...)
15
+ new(...).write
16
+ end
17
+
14
18
  # @params [Nokogiri::XML::Builder] xml
15
19
  # @params [Array<Cocina::Models::Title>] titles
20
+ # @params [IdGenerator] id_generator
16
21
  # @params [Array<Cocina::Models::Contributor>] contributors
17
22
  # @params [Hash] additional_attrs for title
18
- # @params [IdGenerator] id_generator
19
- def self.write(xml:, titles:, id_generator:, contributors: [], additional_attrs: {})
20
- new(xml: xml, titles: titles, contributors: contributors, additional_attrs: additional_attrs,
21
- id_generator: id_generator).write
22
- end
23
-
24
- def initialize(xml:, titles:, additional_attrs:, contributors: [], id_generator: {})
23
+ # @params [Array<Cocina::Models::CatalogLink>] catalog_links a list of catalog
24
+ # links which may contain part label and sort key information
25
+ def initialize(xml:, titles:, id_generator:, contributors: [], additional_attrs: {}, catalog_links: []) # rubocop:disable Metrics/ParameterLists
25
26
  @xml = xml
26
27
  @titles = titles
28
+ @id_generator = id_generator
27
29
  @contributors = contributors
28
- @name_title_vals_index = {}
29
30
  @additional_attrs = additional_attrs
30
- @id_generator = id_generator
31
+ @catalog_links = catalog_links
32
+ @name_title_vals_index = {}
31
33
  end
32
34
 
33
- # rubocop:disable Metrics/AbcSize
34
- # rubocop:disable Metrics/BlockLength
35
- # rubocop:disable Metrics/CyclomaticComplexity
36
- def write
37
- titles.each do |title|
35
+ def write # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
36
+ titles.each do |title| # rubocop:disable Metrics/BlockLength
38
37
  name_title_vals_index = name_title_vals_index_for(title)
39
38
 
40
39
  if title.valueAt
@@ -78,13 +77,10 @@ module Cocina
78
77
  end
79
78
  end
80
79
  end
81
- # rubocop:enable Metrics/AbcSize
82
- # rubocop:enable Metrics/BlockLength
83
- # rubocop:enable Metrics/CyclomaticComplexity
84
80
 
85
81
  private
86
82
 
87
- attr_reader :xml, :titles, :contributors, :name_title_vals_index, :id_generator, :additional_attrs
83
+ attr_reader :xml, :titles, :contributors, :name_title_vals_index, :id_generator, :additional_attrs, :catalog_links
88
84
 
89
85
  def write_xlink(title:)
90
86
  attrs = { 'xlink:href' => title.valueAt }
@@ -173,10 +169,24 @@ module Cocina
173
169
  title_info_attrs = title_info_attrs_for(title).merge(title_info_attrs)
174
170
  xml.titleInfo(with_uri_info(title, title_info_attrs)) do
175
171
  title_parts = flatten_structured_value(title)
176
- title_parts_without_names = title_parts_without_names(title_parts)
172
+ write_title_parts!(title_parts: title_parts_without_names(title_parts), title: title)
173
+ end
174
+ end
177
175
 
178
- title_parts_without_names.each do |title_part|
176
+ def write_title_parts!(title_parts:, title:)
177
+ # If title parts contain the main title and a part label has been
178
+ # recorded in a catalog link, short-circuit the usual title part
179
+ # parsing and pull the part label from the catalog link instead of
180
+ # from descriptive metadata
181
+ if (main_title = title_parts.find { |part| part.type == 'main title' }&.value) &&
182
+ (part_label = catalog_links.find { |link| link.catalog == 'folio' && link.partLabel.present? }&.partLabel)
183
+ xml.title(main_title)
184
+ xml.partNumber(part_label)
185
+ else
186
+ title_parts.each do |title_part|
179
187
  title_type = tag_name_for(title_part)
188
+ raise "Unknown title type for: #{title_part.to_h}" unless title_type
189
+
180
190
  title_value = title_value_for(title_part, title_type, title)
181
191
  xml.public_send(title_type, title_value) if title_part.note.blank?
182
192
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Cocina
4
4
  module Models
5
- VERSION = '0.101.1'
5
+ VERSION = '0.103.1'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocina-models
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.101.1
4
+ version: 0.103.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Coyne
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-18 00:00:00.000000000 Z
10
+ date: 2025-04-29 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport