spree_core 5.4.0.rc5 → 5.4.0.rc7

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/app/mailers/spree/base_mailer.rb +2 -0
  3. data/app/models/concerns/spree/default_price.rb +108 -6
  4. data/app/models/concerns/spree/stores/markets.rb +4 -2
  5. data/app/models/spree/exports/product_translations.rb +45 -0
  6. data/app/models/spree/import_schemas/product_translations.rb +14 -0
  7. data/app/models/spree/imports/product_translations.rb +17 -0
  8. data/app/models/spree/market.rb +1 -0
  9. data/app/models/spree/metafield.rb +1 -1
  10. data/app/models/spree/metafield_definition.rb +10 -0
  11. data/app/models/spree/option_type.rb +20 -2
  12. data/app/models/spree/option_value.rb +17 -1
  13. data/app/models/spree/order.rb +22 -2
  14. data/app/models/spree/price.rb +1 -1
  15. data/app/models/spree/product.rb +40 -13
  16. data/app/models/spree/search_provider/meilisearch.rb +41 -8
  17. data/app/models/spree/stock_location.rb +1 -1
  18. data/app/models/spree/stock_movement.rb +2 -1
  19. data/app/models/spree/variant.rb +13 -11
  20. data/app/presenters/spree/csv/product_translation_presenter.rb +31 -0
  21. data/app/presenters/spree/csv/product_variant_presenter.rb +16 -3
  22. data/app/presenters/spree/search_provider/product_presenter.rb +8 -13
  23. data/app/services/spree/cart/create.rb +1 -0
  24. data/app/services/spree/carts/create.rb +1 -0
  25. data/app/services/spree/carts/update.rb +21 -0
  26. data/app/services/spree/imports/row_processors/product_translation.rb +45 -0
  27. data/app/services/spree/imports/row_processors/product_variant.rb +11 -3
  28. data/app/services/spree/products/prepare_nested_attributes.rb +18 -1
  29. data/app/services/spree/sample_data/loader.rb +31 -20
  30. data/app/services/spree/seeds/all.rb +22 -20
  31. data/app/views/spree/shared/_mailer_line_item.html.erb +2 -2
  32. data/config/locales/en.yml +12 -0
  33. data/db/migrate/20250217171018_create_action_text_video_embeds.rb +11 -0
  34. data/db/migrate/20260402000001_add_kind_to_spree_option_types.rb +13 -0
  35. data/db/migrate/20260402000002_add_color_code_to_spree_option_values.rb +5 -0
  36. data/db/migrate/20260403000000_add_market_to_spree_orders.rb +5 -0
  37. data/db/sample_data/markets.rb +30 -0
  38. data/db/sample_data/metafield_definitions.rb +2 -2
  39. data/db/sample_data/options.rb +4 -0
  40. data/db/sample_data/orders.rb +2 -2
  41. data/db/sample_data/product_translations.csv +75 -0
  42. data/db/sample_data/products.csv +212 -1083
  43. data/lib/spree/core/configuration.rb +1 -0
  44. data/lib/spree/core/controller_helpers/order.rb +12 -10
  45. data/lib/spree/core/engine.rb +2 -0
  46. data/lib/spree/core/permission_configuration.rb +12 -0
  47. data/lib/spree/core/pricing/resolver.rb +5 -3
  48. data/lib/spree/core/version.rb +1 -1
  49. data/lib/spree/permitted_attributes.rb +3 -3
  50. data/lib/spree/testing_support/authorization_helpers.rb +16 -16
  51. data/lib/spree/testing_support/factories/import_factory.rb +12 -0
  52. data/lib/spree/testing_support/factories/options_factory.rb +11 -0
  53. data/lib/spree/testing_support/factories/product_factory.rb +12 -2
  54. data/lib/spree/testing_support/factories/variant_factory.rb +8 -2
  55. data/lib/tasks/markets.rake +5 -2
  56. data/lib/tasks/search.rake +3 -3
  57. data/lib/tasks/variants.rake +2 -2
  58. data/spec/fixtures/files/product_translations_import.csv +3 -0
  59. metadata +26 -7
  60. /data/lib/tasks/{images.rake → media.rake} +0 -0
@@ -40,6 +40,7 @@ module Spree
40
40
  preference :currency, :string, default: 'USD', deprecated: true
41
41
  preference :credit_to_new_allocation, :boolean, default: false
42
42
  preference :disable_migration_check, :boolean, default: false # when turned on disables the startup warning about missing engine migrations
43
+ preference :enable_legacy_default_price, :boolean, default: false # when enabled, keeps the legacy DefaultPrice concern active (has_one :default_price, variant.price= delegation, check_price validation). Disable (default) to use set_price exclusively.
43
44
  preference :disable_sku_validation, :boolean, default: false # when turned off disables the built-in SKU uniqueness validation
44
45
  preference :disable_store_presence_validation, :boolean, default: false # when turned off disables Store presence validation for Products and Payment Methods
45
46
  preference :events_log_enabled, :boolean, default: true # Log all Spree events to Rails logger
@@ -168,18 +168,20 @@ module Spree
168
168
  end
169
169
 
170
170
  def order_includes
171
+ variant_includes = [
172
+ :images,
173
+ :prices,
174
+ :stock_items,
175
+ :stock_locations,
176
+ { option_values: :option_type },
177
+ { stock_items: :stock_location },
178
+ { product: :master }
179
+ ]
180
+ variant_includes << :default_price if Spree::Config.enable_legacy_default_price
181
+
171
182
  {
172
183
  line_items: {
173
- variant: [
174
- :images,
175
- :prices,
176
- :default_price,
177
- :stock_items,
178
- :stock_locations,
179
- { option_values: :option_type },
180
- { stock_items: :stock_location },
181
- { product: :master }
182
- ]
184
+ variant: variant_includes
183
185
  }
184
186
  }
185
187
  end
@@ -182,6 +182,7 @@ module Spree
182
182
 
183
183
  Rails.application.config.spree.export_types = [
184
184
  Spree::Exports::Products,
185
+ Spree::Exports::ProductTranslations,
185
186
  Spree::Exports::Orders,
186
187
  Spree::Exports::Customers,
187
188
  Spree::Exports::GiftCards,
@@ -191,6 +192,7 @@ module Spree
191
192
 
192
193
  Rails.application.config.spree.import_types = [
193
194
  Spree::Imports::Products,
195
+ Spree::Imports::ProductTranslations,
194
196
  Spree::Imports::Customers,
195
197
  ]
196
198
 
@@ -45,6 +45,18 @@ module Spree
45
45
  @role_permissions[role_key] |= Array(permission_sets)
46
46
  end
47
47
 
48
+ # Removes specific permission set(s) from a role.
49
+ #
50
+ # @param role_name [Symbol, String] the name of the role
51
+ # @param permission_sets [Array<Class>, Class] permission set class(es) to remove
52
+ # @return [Array<Class>] the remaining permission sets
53
+ def unassign(role_name, permission_sets)
54
+ role_key = normalize_role_name(role_name)
55
+ return [] unless @role_permissions[role_key]
56
+
57
+ @role_permissions[role_key] -= Array(permission_sets)
58
+ end
59
+
48
60
  # Clears all permission sets from a role.
49
61
  #
50
62
  # @param role_name [Symbol, String] the name of the role
@@ -106,11 +106,13 @@ module Spree
106
106
  context.variant.prices
107
107
  end
108
108
 
109
- # Builds an empty price for the variant
109
+ # Returns an empty price placeholder for the variant.
110
+ # Uses Price.new instead of prices.build to avoid polluting the association
111
+ # with an unsaved record that would fail validation on variant save.
110
112
  # @return [Spree::Price]
111
113
  def build_empty_price
112
- context.variant.prices.build(
113
- variant: context.variant,
114
+ Spree::Price.new(
115
+ variant_id: context.variant.id,
114
116
  currency: context.currency,
115
117
  amount: nil,
116
118
  price_list_id: nil
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- VERSION = '5.4.0.rc5'.freeze
2
+ VERSION = '5.4.0.rc7'.freeze
3
3
 
4
4
  def self.version
5
5
  VERSION
@@ -154,10 +154,10 @@ module Spree
154
154
 
155
155
  @@metafield_definition_attributes = [:key, :name, :namespace, :metafield_type, :resource_type, :display_on]
156
156
 
157
- @@option_type_attributes = [:name, :presentation, :position, :filterable,
158
- option_values_attributes: [:id, :name, :presentation, :position, :_destroy]]
157
+ @@option_type_attributes = [:name, :presentation, :position, :filterable, :kind,
158
+ option_values_attributes: [:id, :name, :presentation, :position, :color_code, :image, :_destroy]]
159
159
 
160
- @@option_value_attributes = [:name, :presentation, :position]
160
+ @@option_value_attributes = [:name, :presentation, :position, :color_code, :image]
161
161
 
162
162
  @@page_attributes = [:name, :slug, :meta_title, :meta_description, :meta_keywords]
163
163
 
@@ -2,11 +2,12 @@ module Spree
2
2
  module TestingSupport
3
3
  module AuthorizationHelpers
4
4
  module CustomAbility
5
- def build_ability(&block)
5
+ def build_permission_set(&block)
6
6
  block ||= proc { |_u| can :manage, :all }
7
- Class.new do
8
- include CanCan::Ability
9
- define_method(:initialize, block)
7
+ Class.new(Spree::PermissionSets::Base) do
8
+ define_method(:activate!) do
9
+ instance_exec(user, &block)
10
+ end
10
11
  end
11
12
  end
12
13
  end
@@ -29,15 +30,14 @@ module Spree
29
30
  include CustomAbility
30
31
 
31
32
  def stub_authorization!
32
- ability = build_ability
33
- ability_class = Spree.ability_class
33
+ permission_set = build_permission_set
34
34
 
35
- after(:all) do
36
- ability_class.remove_ability(ability)
35
+ before(:all) do
36
+ Spree.permissions.assign(:admin, permission_set)
37
37
  end
38
38
 
39
- before(:all) do
40
- ability_class.register_ability(ability)
39
+ after(:all) do
40
+ Spree.permissions.unassign(:admin, permission_set)
41
41
  end
42
42
 
43
43
  let(:admin_user) { FactoryBot.create(:admin_user) }
@@ -50,14 +50,14 @@ module Spree
50
50
  end
51
51
 
52
52
  def custom_authorization!(&block)
53
- ability = build_ability(&block)
54
- ability_class = Spree.ability_class
53
+ permission_set = build_permission_set(&block)
55
54
 
56
- after(:all) do
57
- ability_class.remove_ability(ability)
58
- end
59
55
  before(:all) do
60
- ability_class.register_ability(ability)
56
+ Spree.permissions.assign(:admin, permission_set)
57
+ end
58
+
59
+ after(:all) do
60
+ Spree.permissions.unassign(:admin, permission_set)
61
61
  end
62
62
  end
63
63
  end
@@ -17,6 +17,18 @@ FactoryBot.define do
17
17
  end
18
18
  end
19
19
 
20
+ factory :product_translation_import, class: 'Spree::Imports::ProductTranslations', parent: :import do
21
+ type { 'Spree::Imports::ProductTranslations' }
22
+
23
+ after(:create) do |import|
24
+ import.attachment.attach(
25
+ io: File.open(Spree::Core::Engine.root.join('spec', 'fixtures', 'files', 'product_translations_import.csv')),
26
+ filename: 'product_translations_import.csv',
27
+ content_type: 'text/csv'
28
+ )
29
+ end
30
+ end
31
+
20
32
  factory :customer_import, class: 'Spree::Imports::Customers', parent: :import do
21
33
  type { 'Spree::Imports::Customers' }
22
34
 
@@ -22,6 +22,17 @@ FactoryBot.define do
22
22
  trait :color do
23
23
  name { 'color' }
24
24
  presentation { 'Color' }
25
+ kind { 'color_swatch' }
26
+ end
27
+
28
+ trait :color_swatch do
29
+ name { 'color' }
30
+ presentation { 'Color' }
31
+ kind { 'color_swatch' }
32
+ end
33
+
34
+ trait :buttons do
35
+ kind { 'buttons' }
25
36
  end
26
37
  end
27
38
  end
@@ -2,7 +2,6 @@ FactoryBot.define do
2
2
  factory :base_product, class: Spree::Product do
3
3
  sequence(:name) { |n| "Product #{n}#{Kernel.rand(9999)}" }
4
4
  description { generate(:random_description) }
5
- price { 19.99 }
6
5
  cost_price { 17.00 }
7
6
  sku { generate(:sku) }
8
7
  available_on { 1.year.ago }
@@ -12,17 +11,28 @@ FactoryBot.define do
12
11
  status { 'active' }
13
12
  stores { [Spree::Store.default] }
14
13
 
14
+ transient do
15
+ price { 19.99 }
16
+ compare_at_price { nil }
17
+ currency { nil }
18
+ end
19
+
15
20
  # ensure stock item will be created for this products master
16
21
  # also attach this product to the default store if no stores are passed in
17
22
  before(:create) do |_product|
18
23
  create(:stock_location) unless Spree::StockLocation.any?
19
24
  create(:store, default: true) unless Spree::Store.any?
20
25
  end
21
- after(:create) do |product|
26
+ after(:create) do |product, evaluator|
22
27
  existing_location_ids = product.master.stock_items.pluck(:stock_location_id)
23
28
  Spree::StockLocation.where.not(id: existing_location_ids).find_each do |stock_location|
24
29
  stock_location.propagate_variant(product.master)
25
30
  end
31
+
32
+ if evaluator.price.present?
33
+ price_currency = evaluator.currency || product.stores.first&.default_currency || 'USD'
34
+ product.master.set_price(price_currency, evaluator.price, evaluator.compare_at_price)
35
+ end
26
36
  end
27
37
 
28
38
  factory :custom_product do
@@ -2,7 +2,6 @@ FactoryBot.define do
2
2
  sequence(:random_float) { BigDecimal("#{rand(200)}.#{rand(99)}") }
3
3
 
4
4
  factory :base_variant, class: Spree::Variant do
5
- price { 19.99 }
6
5
  cost_price { 17.00 }
7
6
  sku { generate(:sku) }
8
7
  weight { generate(:random_float) }
@@ -16,6 +15,9 @@ FactoryBot.define do
16
15
  option_values { [build(:option_value)] }
17
16
 
18
17
  transient do
18
+ price { 19.99 }
19
+ compare_at_price { nil }
20
+ currency { nil }
19
21
  create_stock { true }
20
22
  end
21
23
 
@@ -31,6 +33,11 @@ FactoryBot.define do
31
33
  stock_location.propagate_variant(variant)
32
34
  end
33
35
  end
36
+
37
+ if evaluator.price.present?
38
+ price_currency = evaluator.currency || variant.product&.stores&.first&.default_currency || 'USD'
39
+ variant.set_price(price_currency, evaluator.price, evaluator.compare_at_price)
40
+ end
34
41
  end
35
42
 
36
43
  factory :variant do
@@ -44,7 +51,6 @@ FactoryBot.define do
44
51
  trait :with_no_price do
45
52
  price { nil }
46
53
  cost_price { nil }
47
- currency { nil }
48
54
  end
49
55
  end
50
56
 
@@ -27,10 +27,13 @@ namespace :spree do
27
27
  name: primary_country&.name || 'Default',
28
28
  currency: iso_country&.currency_code || store.read_attribute(:default_currency) || 'USD',
29
29
  default_locale: iso_country&.languages_official&.first || store.read_attribute(:default_locale) || 'en',
30
- default: true,
31
- countries: countries
30
+ default: true
32
31
  )
33
32
 
33
+ countries.each do |country|
34
+ market.market_countries.build(country: country).save!(validate: false)
35
+ end
36
+
34
37
  store.update_column(:checkout_zone_id, nil) if checkout_zone_id
35
38
 
36
39
  puts " Created market '#{market.name}' with #{countries.size} countries for store '#{store.name}' (#{store.code})"
@@ -6,9 +6,9 @@ namespace :spree do
6
6
  provider = Spree.search_provider.constantize.new(store)
7
7
  total = store.products.count
8
8
 
9
- puts "Reindexing #{store.name} (#{total} products)..."
10
- provider.reindex(store.products)
11
- puts "Done."
9
+ puts "Reindexing #{store.name} (#{total} products) using #{Spree.search_provider}..."
10
+ indexed = provider.reindex(store.products.preload_associations_lazily)
11
+ puts "Done. #{indexed || total} documents enqueued."
12
12
  end
13
13
  end
14
14
  end
@@ -1,12 +1,12 @@
1
1
  namespace :spree do
2
2
  namespace :variants do
3
- desc 'Reset image_count counter cache on variants'
3
+ desc 'Reset media_count counter cache on variants'
4
4
  task reset_counter_caches: :environment do |_t, _args|
5
5
  puts 'Resetting variant counter caches...'
6
6
 
7
7
  Spree::Variant.find_each do |variant|
8
8
  variant.update_columns(
9
- image_count: variant.images.count,
9
+ media_count: variant.images.count,
10
10
  updated_at: Time.current
11
11
  )
12
12
  print '.'
@@ -0,0 +1,3 @@
1
+ slug,locale,name,description,meta_title,meta_description
2
+ denim-shirt,de,Jeanshemd,"Ein klassisches Jeanshemd aus 100% Baumwolle.",Jeanshemd | Demo Store,"Klassisches Jeanshemd aus Baumwolle."
3
+ denim-shirt,fr,Chemise en Jean,"Une chemise en jean classique en 100% coton.",Chemise en Jean | Demo Store,"Chemise en jean classique en coton."
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.0.rc5
4
+ version: 5.4.0.rc7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Schofield
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2026-03-30 00:00:00.000000000 Z
13
+ date: 2026-04-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: i18n-tasks
@@ -494,16 +494,22 @@ dependencies:
494
494
  name: safely_block
495
495
  requirement: !ruby/object:Gem::Requirement
496
496
  requirements:
497
- - - "~>"
497
+ - - ">="
498
498
  - !ruby/object:Gem::Version
499
499
  version: '0.4'
500
+ - - "<"
501
+ - !ruby/object:Gem::Version
502
+ version: '2.0'
500
503
  type: :runtime
501
504
  prerelease: false
502
505
  version_requirements: !ruby/object:Gem::Requirement
503
506
  requirements:
504
- - - "~>"
507
+ - - ">="
505
508
  - !ruby/object:Gem::Version
506
509
  version: '0.4'
510
+ - - "<"
511
+ - !ruby/object:Gem::Version
512
+ version: '2.0'
507
513
  - !ruby/object:Gem::Dependency
508
514
  name: phonelib
509
515
  requirement: !ruby/object:Gem::Requirement
@@ -967,6 +973,7 @@ files:
967
973
  - app/models/spree/exports/gift_cards.rb
968
974
  - app/models/spree/exports/newsletter_subscribers.rb
969
975
  - app/models/spree/exports/orders.rb
976
+ - app/models/spree/exports/product_translations.rb
970
977
  - app/models/spree/exports/products.rb
971
978
  - app/models/spree/fulfilment_changer.rb
972
979
  - app/models/spree/gateway.rb
@@ -982,8 +989,10 @@ files:
982
989
  - app/models/spree/import_row.rb
983
990
  - app/models/spree/import_schema.rb
984
991
  - app/models/spree/import_schemas/customers.rb
992
+ - app/models/spree/import_schemas/product_translations.rb
985
993
  - app/models/spree/import_schemas/products.rb
986
994
  - app/models/spree/imports/customers.rb
995
+ - app/models/spree/imports/product_translations.rb
987
996
  - app/models/spree/imports/products.rb
988
997
  - app/models/spree/integration.rb
989
998
  - app/models/spree/inventory_unit.rb
@@ -1205,6 +1214,7 @@ files:
1205
1214
  - app/presenters/spree/csv/metafields_helper.rb
1206
1215
  - app/presenters/spree/csv/newsletter_subscriber_presenter.rb
1207
1216
  - app/presenters/spree/csv/order_line_item_presenter.rb
1217
+ - app/presenters/spree/csv/product_translation_presenter.rb
1208
1218
  - app/presenters/spree/csv/product_variant_presenter.rb
1209
1219
  - app/presenters/spree/data_feeds/base_presenter.rb
1210
1220
  - app/presenters/spree/data_feeds/google_presenter.rb
@@ -1261,6 +1271,7 @@ files:
1261
1271
  - app/services/spree/gift_cards/remove.rb
1262
1272
  - app/services/spree/imports/row_processors/base.rb
1263
1273
  - app/services/spree/imports/row_processors/customer.rb
1274
+ - app/services/spree/imports/row_processors/product_translation.rb
1264
1275
  - app/services/spree/imports/row_processors/product_variant.rb
1265
1276
  - app/services/spree/line_items/create.rb
1266
1277
  - app/services/spree/line_items/destroy.rb
@@ -1433,6 +1444,7 @@ files:
1433
1444
  - db/migrate/20250127151258_add_phone_to_spree_users.rb
1434
1445
  - db/migrate/20250204162453_create_spree_reports.rb
1435
1446
  - db/migrate/20250207084000_add_accepts_email_marketing_field_to_spree_users_table.rb
1447
+ - db/migrate/20250217171018_create_action_text_video_embeds.rb
1436
1448
  - db/migrate/20250304115943_add_performed_by_to_spree_reimbursements.rb
1437
1449
  - db/migrate/20250311105934_create_spree_gateway_customers.rb
1438
1450
  - db/migrate/20250312202705_add_unique_index_on_promotion_rules_associations.rb
@@ -1487,10 +1499,16 @@ files:
1487
1499
  - db/migrate/20260317000000_create_spree_refresh_tokens.rb
1488
1500
  - db/migrate/20260323000000_create_spree_price_histories.rb
1489
1501
  - db/migrate/20260326000001_improve_spree_webhooks.rb
1502
+ - db/migrate/20260402000001_add_kind_to_spree_option_types.rb
1503
+ - db/migrate/20260402000002_add_color_code_to_spree_option_values.rb
1504
+ - db/migrate/20260403000000_add_market_to_spree_orders.rb
1490
1505
  - db/sample_data/customers.csv
1506
+ - db/sample_data/markets.rb
1491
1507
  - db/sample_data/metafield_definitions.rb
1508
+ - db/sample_data/options.rb
1492
1509
  - db/sample_data/orders.rb
1493
1510
  - db/sample_data/payment_methods.rb
1511
+ - db/sample_data/product_translations.csv
1494
1512
  - db/sample_data/products.csv
1495
1513
  - db/sample_data/promotions.rb
1496
1514
  - db/sample_data/shipping_methods.rb
@@ -1685,8 +1703,8 @@ files:
1685
1703
  - lib/tasks/cli.rake
1686
1704
  - lib/tasks/core.rake
1687
1705
  - lib/tasks/dependencies.rake
1688
- - lib/tasks/images.rake
1689
1706
  - lib/tasks/markets.rake
1707
+ - lib/tasks/media.rake
1690
1708
  - lib/tasks/price_history.rake
1691
1709
  - lib/tasks/products.rake
1692
1710
  - lib/tasks/sample_data.rake
@@ -1700,6 +1718,7 @@ files:
1700
1718
  - spec/fixtures/files/icon_256x256.png
1701
1719
  - spec/fixtures/files/icon_512x512.png
1702
1720
  - spec/fixtures/files/img_256x128.png
1721
+ - spec/fixtures/files/product_translations_import.csv
1703
1722
  - spec/fixtures/files/products_import.csv
1704
1723
  - spec/fixtures/text-file.txt
1705
1724
  - spec/fixtures/thinking-cat.jpg
@@ -1713,9 +1732,9 @@ licenses:
1713
1732
  - BSD-3-Clause
1714
1733
  metadata:
1715
1734
  bug_tracker_uri: https://github.com/spree/spree/issues
1716
- changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.0.rc5
1735
+ changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.0.rc7
1717
1736
  documentation_uri: https://docs.spreecommerce.org/
1718
- source_code_uri: https://github.com/spree/spree/tree/v5.4.0.rc5
1737
+ source_code_uri: https://github.com/spree/spree/tree/v5.4.0.rc7
1719
1738
  post_install_message:
1720
1739
  rdoc_options: []
1721
1740
  require_paths:
File without changes