spree_core 6.0.0.rc7 → 6.0.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 +4 -4
- data/app/jobs/spree/maintenance_tasks/run_job.rb +321 -0
- data/app/jobs/spree/seller_transfers/execute_pending_due_job.rb +7 -5
- data/app/jobs/spree/seller_transfers/execute_pending_job.rb +37 -17
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade/backfill_order_markets.rb +48 -0
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade/capture_methods.rb +40 -0
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade/deliveries.rb +15 -0
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade/order_coupon_codes.rb +15 -0
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade/promotion_option_value_rules.rb +15 -0
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade/rake_step.rb +83 -0
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade/returns.rb +20 -0
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade/store_regional_settings.rb +63 -0
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade/users_to_customers.rb +28 -0
- data/app/maintenance_tasks/spree/maintenance_tasks/upgrade_step.rb +44 -0
- data/app/models/concerns/spree/translatable_resource.rb +19 -0
- data/app/models/spree/ability.rb +9 -0
- data/app/models/spree/invitation.rb +11 -2
- data/app/models/spree/maintenance_task.rb +221 -0
- data/app/models/spree/maintenance_task_run.rb +78 -0
- data/app/models/spree/order_routing/strategy/rules.rb +8 -48
- data/app/models/spree/seller_transfer.rb +51 -0
- data/app/models/spree/stock/coordinator.rb +37 -17
- data/app/models/spree/stock/packer.rb +19 -9
- data/app/models/spree/stock/prioritizer.rb +30 -15
- data/app/models/spree/store.rb +35 -2
- data/app/models/spree/upgrade_record.rb +62 -0
- data/app/services/spree/carts/update.rb +2 -1
- data/app/services/spree/maintenance_tasks/argument_parser.rb +23 -0
- data/app/services/spree/maintenance_tasks/cancel.rb +51 -0
- data/app/services/spree/maintenance_tasks/start.rb +127 -0
- data/app/services/spree/seeds/all.rb +22 -0
- data/app/services/spree/stock_reservations/reserve.rb +73 -25
- data/app/workflows/spree/seller_transfers/reverse.rb +5 -44
- data/config/locales/en.yml +1 -0
- data/db/migrate/20260813130001_add_capture_method_to_payment_methods.rb +1 -1
- data/db/migrate/20260815000001_create_spree_maintenance_task_runs.rb +40 -0
- data/db/migrate/20260816000001_create_spree_upgrade_records.rb +17 -0
- data/db/migrate/20261029100001_add_lockout_columns_to_spree_admin_users.rb +8 -0
- data/lib/generators/spree/api_resource/api_resource_generator.rb +2 -2
- data/lib/spree/checkout/default_requirements.rb +33 -5
- data/lib/spree/core/configuration.rb +6 -0
- data/lib/spree/core/engine.rb +10 -1
- data/lib/spree/core/permissions/default_catalog.rb +7 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +17 -1
- data/lib/spree/testing_support/factories/maintenance_task_run_factory.rb +7 -0
- data/lib/spree/time_zones.rb +34 -0
- data/lib/spree/upgrade.rb +189 -0
- data/lib/spree/upgrades/5_6_to_6_0/manifest.yml +30 -10
- data/lib/tasks/maintenance_tasks.rake +42 -0
- data/lib/tasks/upgrade.rake +81 -60
- metadata +28 -6
- data/lib/tasks/capture_methods_migration.rake +0 -30
- data/lib/tasks/order_market_backfill.rake +0 -27
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# Reads the upgrade manifests shipped inside spree_core — the list of data
|
|
3
|
+
# steps an installation must run after `db:migrate` for a given release
|
|
4
|
+
# boundary (docs/plans/6.0-maintenance-tasks.md).
|
|
5
|
+
#
|
|
6
|
+
# Extracted from lib/tasks/upgrade.rake so the dashboard and the maintenance
|
|
7
|
+
# task runner can read the same manifests the rake walk does; the rake file
|
|
8
|
+
# keeps the walking and printing.
|
|
9
|
+
module Upgrade
|
|
10
|
+
# The first release whose upgrade steps run as maintenance tasks. Nothing
|
|
11
|
+
# recorded the steps of earlier releases, so the dashboard starts here; the
|
|
12
|
+
# command line still walks every manifest.
|
|
13
|
+
FIRST_TRACKED_RELEASE = '6.0'.freeze
|
|
14
|
+
|
|
15
|
+
# Two-segment "5.5" form of the installed Spree version.
|
|
16
|
+
#
|
|
17
|
+
# @return [String]
|
|
18
|
+
def self.installed_minor_version
|
|
19
|
+
Spree.version.split('.').first(2).join('.')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Root directory containing N_M_to_O_P/manifest.yml files inside the
|
|
23
|
+
# spree_core gem.
|
|
24
|
+
#
|
|
25
|
+
# @return [String]
|
|
26
|
+
def self.manifests_root
|
|
27
|
+
File.expand_path('upgrades', __dir__)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# All available manifest directories, parsed into { from:, to:, dir: }.
|
|
31
|
+
# Sorted by `to` ascending, with `from` as a tiebreaker (smallest first)
|
|
32
|
+
# for the rare case where two manifests share a `to` boundary.
|
|
33
|
+
#
|
|
34
|
+
# @return [Array<Hash>]
|
|
35
|
+
def self.available_manifests
|
|
36
|
+
Dir.glob(File.join(manifests_root, '*_to_*')).filter_map do |dir|
|
|
37
|
+
name = File.basename(dir)
|
|
38
|
+
match = name.match(/\A([\d_]+)_to_([\d_]+)\z/)
|
|
39
|
+
next unless match
|
|
40
|
+
|
|
41
|
+
{ from: match[1].tr('_', '.'), to: match[2].tr('_', '.'), dir: dir }
|
|
42
|
+
end.sort_by { |manifest| version_parts(manifest[:to]) + version_parts(manifest[:from]) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Every manifest with its steps loaded, in walk order. Read once per
|
|
46
|
+
# process: the files ship inside the gem and change only with a deploy.
|
|
47
|
+
#
|
|
48
|
+
# @return [Array<Hash>]
|
|
49
|
+
def self.manifests
|
|
50
|
+
@manifests ||= available_manifests.map do |entry|
|
|
51
|
+
YAML.safe_load_file(File.join(entry[:dir], 'manifest.yml')).freeze
|
|
52
|
+
end.freeze
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Every step of every manifest, in walk order, each carrying the manifest
|
|
56
|
+
# boundary it belongs to so callers can group without re-reading the files.
|
|
57
|
+
#
|
|
58
|
+
# @return [Array<Hash>]
|
|
59
|
+
def self.steps
|
|
60
|
+
@steps ||= manifests.flat_map do |manifest|
|
|
61
|
+
manifest['steps'].map do |step|
|
|
62
|
+
step.merge('from' => manifest['from'], 'to' => manifest['to'], 'docs' => manifest['docs'])
|
|
63
|
+
end
|
|
64
|
+
end.freeze
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Whether a step belongs to a release whose runs are recorded, and so has a
|
|
68
|
+
# place in the dashboard's checklist.
|
|
69
|
+
#
|
|
70
|
+
# @param step [Hash] a manifest step
|
|
71
|
+
# @return [Boolean]
|
|
72
|
+
def self.tracked?(step)
|
|
73
|
+
compare(step['to'], FIRST_TRACKED_RELEASE) >= 0
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# The task a step runs: its own class, or the shared runner for a step
|
|
77
|
+
# that names a rake task.
|
|
78
|
+
#
|
|
79
|
+
# @param step [Hash] a manifest step
|
|
80
|
+
# @return [String] a task class name
|
|
81
|
+
def self.task_class_name(step)
|
|
82
|
+
step['task_class'] || 'Spree::MaintenanceTasks::UpgradeStep'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# The arguments that start a step's task: a rake-backed step is named by
|
|
86
|
+
# its id, so the shared runner knows which rake task to invoke.
|
|
87
|
+
#
|
|
88
|
+
# @param step [Hash] a manifest step
|
|
89
|
+
# @return [Hash]
|
|
90
|
+
def self.task_arguments(step)
|
|
91
|
+
step['task_class'] ? {} : { 'step_id' => step['id'] }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @param step_id [String]
|
|
95
|
+
# @return [Hash, nil]
|
|
96
|
+
def self.find_step(step_id)
|
|
97
|
+
return nil if step_id.blank?
|
|
98
|
+
|
|
99
|
+
steps.find { |step| step['id'] == step_id.to_s }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# The boundary this installation has already completed, and therefore the
|
|
103
|
+
# point a pending list starts from.
|
|
104
|
+
#
|
|
105
|
+
# Falls back to the release before the installed one when nothing has been
|
|
106
|
+
# stamped: an installation running 6.0 has, by far most often, come from
|
|
107
|
+
# 5.6, and showing every step of every manifest ever written is worse than
|
|
108
|
+
# showing the one boundary that is almost certainly right. A store that
|
|
109
|
+
# skipped releases runs the earlier steps from the command line, which
|
|
110
|
+
# walks every manifest whatever the boundary.
|
|
111
|
+
#
|
|
112
|
+
# @return [String, nil]
|
|
113
|
+
def self.completed_boundary
|
|
114
|
+
Spree::UpgradeRecord.current_version || previous_boundary
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# The `to` of the manifest immediately below the installed version.
|
|
118
|
+
#
|
|
119
|
+
# @return [String, nil]
|
|
120
|
+
def self.previous_boundary
|
|
121
|
+
boundaries = manifests.map { |manifest| manifest['from'] }.uniq
|
|
122
|
+
boundaries.select { |version| compare(version, installed_minor_version) < 0 }.
|
|
123
|
+
max_by { |version| version_parts(version) }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Whether an upgrade applies to this installation at all.
|
|
127
|
+
#
|
|
128
|
+
# False for a store installed fresh at its current version: it has no
|
|
129
|
+
# historical data to convert, so neither the outstanding steps nor the
|
|
130
|
+
# history of past releases describes anything real for it. True again
|
|
131
|
+
# once a later release ships steps it has not run.
|
|
132
|
+
#
|
|
133
|
+
# @return [Boolean]
|
|
134
|
+
def self.relevant?
|
|
135
|
+
!Spree::UpgradeRecord.exists? || Spree::UpgradeRecord.upgraded? || pending_steps.any?
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Whether a step can run here. An optional step belongs to a gem that may
|
|
139
|
+
# not be installed — a payment gateway, for instance — and is skipped
|
|
140
|
+
# where it is absent rather than offered as work that cannot start.
|
|
141
|
+
#
|
|
142
|
+
# @param step [Hash] a manifest step
|
|
143
|
+
# @return [Boolean]
|
|
144
|
+
def self.available?(step)
|
|
145
|
+
return true unless step['optional']
|
|
146
|
+
return Spree::MaintenanceTask.find_registered(step['task_class']).present? if step['task_class']
|
|
147
|
+
|
|
148
|
+
Spree::MaintenanceTask.new.rake_file_defining(step['task']).present?
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Steps this installation still has to run: every manifest above the
|
|
152
|
+
# boundary it has completed, up to and including the installed version.
|
|
153
|
+
#
|
|
154
|
+
# @return [Array<Hash>]
|
|
155
|
+
def self.pending_steps
|
|
156
|
+
boundary = completed_boundary
|
|
157
|
+
|
|
158
|
+
steps.select do |step|
|
|
159
|
+
next false if compare(step['to'], installed_minor_version) > 0
|
|
160
|
+
next false unless available?(step)
|
|
161
|
+
next true if boundary.nil?
|
|
162
|
+
|
|
163
|
+
compare(step['from'], boundary) >= 0
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Steps of manifests below the completed boundary — the ones a fresh or
|
|
168
|
+
# already-upgraded installation does not need. When the boundary was
|
|
169
|
+
# assumed rather than recorded the dashboard says so, and points a store
|
|
170
|
+
# that skipped a release at the command line, which still runs them.
|
|
171
|
+
#
|
|
172
|
+
# @return [Array<Hash>]
|
|
173
|
+
def self.superseded_steps
|
|
174
|
+
boundary = completed_boundary
|
|
175
|
+
return [] if boundary.nil?
|
|
176
|
+
|
|
177
|
+
steps.select { |step| compare(step['from'], boundary) < 0 }
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def self.version_parts(version)
|
|
181
|
+
version.split('.').map { |segment| Integer(segment, 10) rescue 0 }
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Compare two dotted-version strings (returns -1, 0, +1).
|
|
185
|
+
def self.compare(first, second)
|
|
186
|
+
version_parts(first) <=> version_parts(second)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
@@ -12,8 +12,15 @@
|
|
|
12
12
|
# live in the upgrade doc at docs/developer/upgrades/5.6-to-6.0.mdx.
|
|
13
13
|
#
|
|
14
14
|
# This manifest is the machine-runnable shape — what `bin/rake spree:upgrade`
|
|
15
|
-
# (in production) and `spree upgrade` (in dev) execute. Every step must be
|
|
16
|
-
#
|
|
15
|
+
# (in production) and `spree upgrade` (in dev) execute. Every step must be
|
|
16
|
+
# idempotent; re-running the full manifest is safe.
|
|
17
|
+
#
|
|
18
|
+
# Steps name a `task_class` — a Spree::MaintenanceTask that the walk runs
|
|
19
|
+
# through the maintenance task runner, so a shell walk and a dashboard run
|
|
20
|
+
# leave the same audit record and the same resume behaviour
|
|
21
|
+
# (docs/plans/6.0-maintenance-tasks.md). Released manifests keep their `task`
|
|
22
|
+
# rake names, which have shipped and may be scripted; the walker runs both
|
|
23
|
+
# kinds.
|
|
17
24
|
---
|
|
18
25
|
from: "5.6"
|
|
19
26
|
to: "6.0"
|
|
@@ -151,7 +158,7 @@ steps:
|
|
|
151
158
|
|
|
152
159
|
- id: migrate_users_to_customers
|
|
153
160
|
name: "Move users onto the gem-owned Customer/AdminUser models"
|
|
154
|
-
|
|
161
|
+
task_class: "Spree::MaintenanceTasks::Upgrade::UsersToCustomers"
|
|
155
162
|
notes: |
|
|
156
163
|
Copies the legacy Devise user table (default spree_users) into
|
|
157
164
|
spree_customers, preserving ids so the renamed customer_id foreign keys
|
|
@@ -261,7 +268,7 @@ steps:
|
|
|
261
268
|
|
|
262
269
|
- id: migrate_deliveries
|
|
263
270
|
name: "Move tracking numbers onto deliveries"
|
|
264
|
-
|
|
271
|
+
task_class: "Spree::MaintenanceTasks::Upgrade::Deliveries"
|
|
265
272
|
notes: |
|
|
266
273
|
Every fulfillment carrying a 5.6 tracking number gets one delivery row
|
|
267
274
|
with that number: the carrier axis (tracking number, carrier, carrier
|
|
@@ -322,7 +329,7 @@ steps:
|
|
|
322
329
|
|
|
323
330
|
- id: migrate_promotion_option_value_rules
|
|
324
331
|
name: "Rewrite Option Value promotion rules to stable option value ids"
|
|
325
|
-
|
|
332
|
+
task_class: "Spree::MaintenanceTasks::Upgrade::PromotionOptionValueRules"
|
|
326
333
|
notes: |
|
|
327
334
|
Spree 6.0 stores Option Value promotion rules against Spree::OptionValue
|
|
328
335
|
ids. Upgrades from 5.6 may still carry join-row ids from
|
|
@@ -365,7 +372,7 @@ steps:
|
|
|
365
372
|
|
|
366
373
|
- id: migrate_returns
|
|
367
374
|
name: "Move returns onto the new returns models"
|
|
368
|
-
|
|
375
|
+
task_class: "Spree::MaintenanceTasks::Upgrade::Returns"
|
|
369
376
|
notes: |
|
|
370
377
|
Converts each ReturnAuthorization into a Spree::Return, or a
|
|
371
378
|
Spree::Exchange when any of its return items named an exchange variant,
|
|
@@ -494,7 +501,7 @@ steps:
|
|
|
494
501
|
|
|
495
502
|
- id: backfill_order_coupon_codes
|
|
496
503
|
name: "Backfill coupon codes on placed orders"
|
|
497
|
-
|
|
504
|
+
task_class: "Spree::MaintenanceTasks::Upgrade::OrderCouponCodes"
|
|
498
505
|
notes: |
|
|
499
506
|
spree_orders gains a coupon_code column in Spree 6, matching carts.
|
|
500
507
|
Historical placed orders applied coupons only through the promotion
|
|
@@ -510,7 +517,7 @@ steps:
|
|
|
510
517
|
|
|
511
518
|
- id: backfill_order_markets
|
|
512
519
|
name: "Backfill order markets"
|
|
513
|
-
|
|
520
|
+
task_class: "Spree::MaintenanceTasks::Upgrade::BackfillOrderMarkets"
|
|
514
521
|
notes: |
|
|
515
522
|
Market is mandatory in Spree 6. Assigns the store's default market to
|
|
516
523
|
orders that predate markets. Channel needs no step here — the 5.4→5.5
|
|
@@ -573,7 +580,7 @@ steps:
|
|
|
573
580
|
|
|
574
581
|
- id: migrate_capture_methods
|
|
575
582
|
name: "Convert payment method auto_capture into capture_method"
|
|
576
|
-
|
|
583
|
+
task_class: "Spree::MaintenanceTasks::Upgrade::CaptureMethods"
|
|
577
584
|
notes: |
|
|
578
585
|
Payment methods say when they charge with a capture_method string
|
|
579
586
|
(checkout, on_dispatch or manual) rather than an auto_capture boolean,
|
|
@@ -590,6 +597,19 @@ steps:
|
|
|
590
597
|
is dropped in 6.1. Idempotent — only rows without a capture_method are
|
|
591
598
|
written.
|
|
592
599
|
|
|
600
|
+
- id: store_regional_settings
|
|
601
|
+
name: "Convert store time zones and admin languages to standard codes"
|
|
602
|
+
task_class: "Spree::MaintenanceTasks::Upgrade::StoreRegionalSettings"
|
|
603
|
+
notes: |
|
|
604
|
+
A store's time zone is now always an IANA name such as America/New_York,
|
|
605
|
+
and its admin language a locale code Spree lists, the forms the API
|
|
606
|
+
accepts and browsers understand. Rails time zone names such as
|
|
607
|
+
"Eastern Time (US & Canada)" and locale spellings such as en_US are
|
|
608
|
+
converted. A time zone that names no zone is reset to the store default,
|
|
609
|
+
which is what the store already ran on; an admin language Spree does not
|
|
610
|
+
list is cleared, so staff see their own language. Idempotent — stores
|
|
611
|
+
already on standard codes are skipped.
|
|
612
|
+
|
|
593
613
|
- id: product_types_backfill
|
|
594
614
|
name: "Backfill product type store ownership"
|
|
595
615
|
task: "spree:product_types:backfill"
|
|
@@ -625,7 +645,7 @@ steps:
|
|
|
625
645
|
|
|
626
646
|
- id: migrate_stripe_webhook_keys
|
|
627
647
|
name: "Move Stripe webhook signing secrets onto the gateway"
|
|
628
|
-
|
|
648
|
+
task_class: "SpreeStripe::MaintenanceTasks::MigrateWebhookKeys"
|
|
629
649
|
optional: true
|
|
630
650
|
notes: |
|
|
631
651
|
Only runs when spree_stripe is installed; skipped otherwise.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Command-line entry to the same runner the dashboard drives, so a shell run
|
|
4
|
+
# is audited exactly like an operator's (docs/plans/6.0-maintenance-tasks.md).
|
|
5
|
+
#
|
|
6
|
+
# bin/rake "spree:maintenance_tasks:perform[backfill_order_markets]"
|
|
7
|
+
# DRY_RUN=1 bin/rake "spree:maintenance_tasks:perform[capture_methods]"
|
|
8
|
+
# ARGS='batch_size=200' bin/rake "spree:maintenance_tasks:perform[deliveries]"
|
|
9
|
+
namespace :spree do
|
|
10
|
+
namespace :maintenance_tasks do
|
|
11
|
+
desc 'Run a maintenance task synchronously'
|
|
12
|
+
task :perform, [:task_name] => :environment do |_task, args|
|
|
13
|
+
task_name = args[:task_name] || ENV['TASK']
|
|
14
|
+
abort ' Pass a task name: rake "spree:maintenance_tasks:perform[Your::Task]"' if task_name.blank?
|
|
15
|
+
|
|
16
|
+
# Either the class name or the short name the dashboard shows.
|
|
17
|
+
lookup = Spree::MaintenanceTask.find_registered(task_name) ? { task_name: task_name } : { api_type: task_name }
|
|
18
|
+
|
|
19
|
+
result = Spree::MaintenanceTasks::Start.call(
|
|
20
|
+
**lookup,
|
|
21
|
+
arguments: Spree::MaintenanceTasks::ArgumentParser.parse(ENV['ARGS']),
|
|
22
|
+
dry_run: ENV['DRY_RUN'] == '1',
|
|
23
|
+
initiated_via: 'cli',
|
|
24
|
+
inline: true
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
abort " #{result.error}" if result.failure?
|
|
28
|
+
|
|
29
|
+
run = result.value.reload
|
|
30
|
+
puts " #{run.task_name}: #{run.status} — #{run.tick_count} processed#{run.dry_run? ? ' (dry run)' : ''}"
|
|
31
|
+
(run.tallies || {}).each { |key, value| puts " #{key}: #{value}" }
|
|
32
|
+
|
|
33
|
+
if run.errored?
|
|
34
|
+
puts " #{run.error_class}: #{run.error_message}"
|
|
35
|
+
abort ' The run failed. Fix the cause, then re-run this task.'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# A refused duplicate or a cancellation did not do the work either.
|
|
39
|
+
abort " The run did not finish (#{run.status})." unless run.succeeded?
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/tasks/upgrade.rake
CHANGED
|
@@ -33,41 +33,10 @@ namespace :spree do
|
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
require 'spree/upgrade'
|
|
37
|
+
|
|
36
38
|
module Spree
|
|
37
39
|
module Upgrade
|
|
38
|
-
# Two-segment "5.5" form of the installed Spree version.
|
|
39
|
-
def self.installed_minor_version
|
|
40
|
-
Spree.version.split('.').first(2).join('.')
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Root directory containing N_M_to_O_P/manifest.yml files inside
|
|
44
|
-
# the spree_core gem.
|
|
45
|
-
def self.manifests_root
|
|
46
|
-
File.expand_path('../spree/upgrades', __dir__)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# All available manifest directories, parsed into { from:, to:, dir: }.
|
|
50
|
-
# Sorted by `to` ascending, with `from` as a tiebreaker (smallest first)
|
|
51
|
-
# for the rare case where two manifests share a `to` boundary.
|
|
52
|
-
def self.available_manifests
|
|
53
|
-
Dir.glob(File.join(manifests_root, '*_to_*')).filter_map do |dir|
|
|
54
|
-
name = File.basename(dir)
|
|
55
|
-
match = name.match(/\A([\d_]+)_to_([\d_]+)\z/)
|
|
56
|
-
next unless match
|
|
57
|
-
|
|
58
|
-
{ from: match[1].tr('_', '.'), to: match[2].tr('_', '.'), dir: dir }
|
|
59
|
-
end.sort_by { |m| version_parts(m[:to]) + version_parts(m[:from]) }
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def self.version_parts(v)
|
|
63
|
-
v.split('.').map { |s| Integer(s, 10) rescue 0 }
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Compare two dotted-version strings (returns -1, 0, +1).
|
|
67
|
-
def self.compare(a, b)
|
|
68
|
-
version_parts(a) <=> version_parts(b)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
40
|
# The runner is a class (not a method) so individual concerns (selection,
|
|
72
41
|
# rendering, invocation) stay separable and the plan can be inspected
|
|
73
42
|
# without execution.
|
|
@@ -100,13 +69,7 @@ module Spree
|
|
|
100
69
|
# Plan mode selects exactly what a real run executes, so a dry run after
|
|
101
70
|
# bumping the gem lists every backfill the upgrade is about to perform.
|
|
102
71
|
def eligible_manifests
|
|
103
|
-
Spree::Upgrade.
|
|
104
|
-
.select { |manifest| Spree::Upgrade.compare(manifest[:to], target_version) <= 0 }
|
|
105
|
-
.map { |entry| load_manifest_yaml(entry) }
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def load_manifest_yaml(entry)
|
|
109
|
-
YAML.safe_load_file(File.join(entry[:dir], 'manifest.yml'))
|
|
72
|
+
Spree::Upgrade.manifests.select { |manifest| Spree::Upgrade.compare(manifest['to'], target_version) <= 0 }
|
|
110
73
|
end
|
|
111
74
|
|
|
112
75
|
def run_full_walk(manifests)
|
|
@@ -122,10 +85,22 @@ module Spree
|
|
|
122
85
|
end
|
|
123
86
|
end
|
|
124
87
|
|
|
88
|
+
stamp_completed_boundaries(manifests) unless dry_run
|
|
89
|
+
|
|
125
90
|
puts
|
|
126
91
|
puts dry_run ? ' (dry run — nothing executed)' : ' Upgrade tasks complete.'
|
|
127
92
|
end
|
|
128
93
|
|
|
94
|
+
# Records the boundaries this walk finished, so a later dashboard visit
|
|
95
|
+
# shows only what is still outstanding rather than every step of every
|
|
96
|
+
# manifest ever written. A partial walk stamps nothing — `invoke` aborts
|
|
97
|
+
# on a failed step, so reaching here means every step succeeded.
|
|
98
|
+
def stamp_completed_boundaries(manifests)
|
|
99
|
+
manifests.each do |manifest|
|
|
100
|
+
Spree::UpgradeRecord.stamp!(manifest['to'], source: 'walk')
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
129
104
|
# STEP=<id> looks across every eligible manifest; we need exactly one
|
|
130
105
|
# match. Multiple matches are likely a manifest bug (two manifests
|
|
131
106
|
# referencing the same step id) but we surface it rather than picking
|
|
@@ -162,38 +137,84 @@ module Spree
|
|
|
162
137
|
puts
|
|
163
138
|
puts " Step #{index}/#{total} [#{step['id']}]"
|
|
164
139
|
puts " #{step['name']}"
|
|
165
|
-
puts " >
|
|
140
|
+
puts " > #{step_command(step)}"
|
|
166
141
|
return unless step['notes']
|
|
167
142
|
|
|
168
143
|
step['notes'].each_line { |line| puts " #{line.chomp}" }
|
|
169
144
|
end
|
|
170
145
|
|
|
171
146
|
def print_step_complete(step)
|
|
172
|
-
puts " ✓ #{step
|
|
147
|
+
puts " ✓ #{step_label(step)} done."
|
|
173
148
|
end
|
|
174
149
|
|
|
150
|
+
def step_label(step)
|
|
151
|
+
step['task_class'] || step['task']
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def step_command(step)
|
|
155
|
+
if step['task_class']
|
|
156
|
+
"bin/rake \"spree:maintenance_tasks:perform[#{step['task_class']}]\""
|
|
157
|
+
else
|
|
158
|
+
"bin/rake #{step['task']}"
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Both step kinds run through the maintenance task runner, so a shell
|
|
163
|
+
# walk records the same audit rows a dashboard run does: a class-backed
|
|
164
|
+
# step runs its own task, a rake-backed step runs inside UpgradeStep.
|
|
165
|
+
#
|
|
166
|
+
# Returns false when the step was skipped, so the caller can leave the
|
|
167
|
+
# "done" line off a step that never ran.
|
|
175
168
|
def invoke(step)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
169
|
+
return false if skip_uninstalled?(step)
|
|
170
|
+
|
|
171
|
+
puts " Running #{step_label(step)}..."
|
|
172
|
+
|
|
173
|
+
result = Spree::MaintenanceTasks::Start.call(
|
|
174
|
+
task_name: Spree::Upgrade.task_class_name(step),
|
|
175
|
+
arguments: step_arguments(step),
|
|
176
|
+
initiated_via: 'cli',
|
|
177
|
+
inline: true
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
abort " #{result.error}" if result.failure?
|
|
181
|
+
|
|
182
|
+
run = result.value.reload
|
|
183
|
+
(run.tallies || {}).each { |key, value| puts " #{key}: #{value}" }
|
|
184
|
+
|
|
185
|
+
if run.errored?
|
|
186
|
+
puts " #{run.error_class}: #{run.error_message}"
|
|
187
|
+
abort ' Step failed. Fix the cause, then re-run this step.'
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Anything short of success — cancelled or still running — means
|
|
191
|
+
# the step's data is not converted, and the steps after it depend on it.
|
|
192
|
+
unless run.succeeded?
|
|
193
|
+
puts " The step did not finish (#{run.status})."
|
|
194
|
+
abort ' Re-run this step once it can finish.'
|
|
185
195
|
end
|
|
186
196
|
|
|
187
|
-
|
|
197
|
+
true
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# A rake-backed step is named by id; a class-backed step that reads
|
|
201
|
+
# environment variables gets the ones the operator exported, so
|
|
202
|
+
# `CONFIRM_NO_PEPPER=true bin/rake spree:upgrade` reaches it.
|
|
203
|
+
def step_arguments(step)
|
|
204
|
+
return Spree::Upgrade.task_arguments(step) unless step['task_class']
|
|
205
|
+
|
|
206
|
+
task_class = Spree::MaintenanceTask.find_registered(step['task_class'])
|
|
207
|
+
task_class.respond_to?(:arguments_from_environment) ? task_class.arguments_from_environment : {}
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Steps contributed by optional gems (payment gateways, for instance)
|
|
211
|
+
# are absent unless that gem is installed. Skipping keeps the upgrade
|
|
212
|
+
# runnable on installs that never had the gem, while an install that
|
|
213
|
+
# does have it still gets the backfill.
|
|
214
|
+
def skip_uninstalled?(step)
|
|
215
|
+
return false if Spree::Upgrade.available?(step)
|
|
188
216
|
|
|
189
|
-
|
|
190
|
-
# single `rake spree:upgrade` run re-invoke aggregators that share
|
|
191
|
-
# subtasks across multiple manifests (e.g. two manifests both
|
|
192
|
-
# depending on `spree:install:migrations` would otherwise only
|
|
193
|
-
# invoke it once).
|
|
194
|
-
rake_task = Rake::Task[task]
|
|
195
|
-
rake_task.reenable
|
|
196
|
-
rake_task.invoke
|
|
217
|
+
puts " Skipping #{step_label(step)} — not installed."
|
|
197
218
|
true
|
|
198
219
|
end
|
|
199
220
|
end
|
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: 6.0.
|
|
4
|
+
version: 6.0.1
|
|
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-10-
|
|
13
|
+
date: 2026-10-29 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: i18n-tasks
|
|
@@ -745,6 +745,7 @@ files:
|
|
|
745
745
|
- app/jobs/spree/imports/process_group_job.rb
|
|
746
746
|
- app/jobs/spree/imports/process_job.rb
|
|
747
747
|
- app/jobs/spree/imports/process_rows_job.rb
|
|
748
|
+
- app/jobs/spree/maintenance_tasks/run_job.rb
|
|
748
749
|
- app/jobs/spree/orders/finalize_stale_drafts_job.rb
|
|
749
750
|
- app/jobs/spree/payments/cancel_unused_sessions_job.rb
|
|
750
751
|
- app/jobs/spree/payments/handle_webhook_job.rb
|
|
@@ -777,6 +778,16 @@ files:
|
|
|
777
778
|
- app/mailers/spree/invitation_mailer.rb
|
|
778
779
|
- app/mailers/spree/seller_user_mailer.rb
|
|
779
780
|
- app/mailers/spree/webhook_mailer.rb
|
|
781
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade/backfill_order_markets.rb
|
|
782
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade/capture_methods.rb
|
|
783
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade/deliveries.rb
|
|
784
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade/order_coupon_codes.rb
|
|
785
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade/promotion_option_value_rules.rb
|
|
786
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade/rake_step.rb
|
|
787
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade/returns.rb
|
|
788
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade/store_regional_settings.rb
|
|
789
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade/users_to_customers.rb
|
|
790
|
+
- app/maintenance_tasks/spree/maintenance_tasks/upgrade_step.rb
|
|
780
791
|
- app/models/concerns/spree/account_deactivation.rb
|
|
781
792
|
- app/models/concerns/spree/account_lockout.rb
|
|
782
793
|
- app/models/concerns/spree/acted_by.rb
|
|
@@ -1064,6 +1075,8 @@ files:
|
|
|
1064
1075
|
- app/models/spree/label_purchase.rb
|
|
1065
1076
|
- app/models/spree/line_item.rb
|
|
1066
1077
|
- app/models/spree/locale.rb
|
|
1078
|
+
- app/models/spree/maintenance_task.rb
|
|
1079
|
+
- app/models/spree/maintenance_task_run.rb
|
|
1067
1080
|
- app/models/spree/market.rb
|
|
1068
1081
|
- app/models/spree/market_country.rb
|
|
1069
1082
|
- app/models/spree/media.rb
|
|
@@ -1291,6 +1304,7 @@ files:
|
|
|
1291
1304
|
- app/models/spree/taxonomy.rb
|
|
1292
1305
|
- app/models/spree/translations/batch.rb
|
|
1293
1306
|
- app/models/spree/update_status.rb
|
|
1307
|
+
- app/models/spree/upgrade_record.rb
|
|
1294
1308
|
- app/models/spree/user_identity.rb
|
|
1295
1309
|
- app/models/spree/variant.rb
|
|
1296
1310
|
- app/models/spree/variant_media.rb
|
|
@@ -1389,6 +1403,9 @@ files:
|
|
|
1389
1403
|
- app/services/spree/imports/row_processors/purchase_order.rb
|
|
1390
1404
|
- app/services/spree/locales.rb
|
|
1391
1405
|
- app/services/spree/locales/set_fallback_locale_for_store.rb
|
|
1406
|
+
- app/services/spree/maintenance_tasks/argument_parser.rb
|
|
1407
|
+
- app/services/spree/maintenance_tasks/cancel.rb
|
|
1408
|
+
- app/services/spree/maintenance_tasks/start.rb
|
|
1392
1409
|
- app/services/spree/media/destroy.rb
|
|
1393
1410
|
- app/services/spree/media/usage.rb
|
|
1394
1411
|
- app/services/spree/newsletter/link_user.rb
|
|
@@ -1931,8 +1948,10 @@ files:
|
|
|
1931
1948
|
- db/migrate/20260814000001_rename_stock_items_to_stock_levels.rb
|
|
1932
1949
|
- db/migrate/20260814000002_add_typed_stock_movements.rb
|
|
1933
1950
|
- db/migrate/20260815000001_add_audience_to_spree_refresh_tokens.rb
|
|
1951
|
+
- db/migrate/20260815000001_create_spree_maintenance_task_runs.rb
|
|
1934
1952
|
- db/migrate/20260815000002_add_resource_to_spree_roles.rb
|
|
1935
1953
|
- db/migrate/20260816000001_create_spree_sellers.rb
|
|
1954
|
+
- db/migrate/20260816000001_create_spree_upgrade_records.rb
|
|
1936
1955
|
- db/migrate/20260816000002_add_seller_to_spree_products.rb
|
|
1937
1956
|
- db/migrate/20260816210001_create_spree_commission_rates.rb
|
|
1938
1957
|
- db/migrate/20260816210002_create_spree_commission_lines.rb
|
|
@@ -2009,6 +2028,7 @@ files:
|
|
|
2009
2028
|
- db/migrate/20261017100001_add_tax_exemption_reason_to_spree_tax_exemption_certificates.rb
|
|
2010
2029
|
- db/migrate/20261022000001_store_credit_actor_polymorphic.rb
|
|
2011
2030
|
- db/migrate/20261023100001_add_deactivated_at_to_spree_admin_users.rb
|
|
2031
|
+
- db/migrate/20261029100001_add_lockout_columns_to_spree_admin_users.rb
|
|
2012
2032
|
- db/sample_data/channels.rb
|
|
2013
2033
|
- db/sample_data/collections.rb
|
|
2014
2034
|
- db/sample_data/custom_field_definitions.rb
|
|
@@ -2198,6 +2218,7 @@ files:
|
|
|
2198
2218
|
- lib/spree/testing_support/factories/integration_factory.rb
|
|
2199
2219
|
- lib/spree/testing_support/factories/invitation_factory.rb
|
|
2200
2220
|
- lib/spree/testing_support/factories/line_item_factory.rb
|
|
2221
|
+
- lib/spree/testing_support/factories/maintenance_task_run_factory.rb
|
|
2201
2222
|
- lib/spree/testing_support/factories/market_factory.rb
|
|
2202
2223
|
- lib/spree/testing_support/factories/media_factory.rb
|
|
2203
2224
|
- lib/spree/testing_support/factories/newsletter_subscriber_factory.rb
|
|
@@ -2293,7 +2314,9 @@ files:
|
|
|
2293
2314
|
- lib/spree/testing_support/store.rb
|
|
2294
2315
|
- lib/spree/testing_support/tax_identifier_validators.rb
|
|
2295
2316
|
- lib/spree/testing_support/url_helpers.rb
|
|
2317
|
+
- lib/spree/time_zones.rb
|
|
2296
2318
|
- lib/spree/translations.rb
|
|
2319
|
+
- lib/spree/upgrade.rb
|
|
2297
2320
|
- lib/spree/upgrades/5_4_to_5_5/manifest.yml
|
|
2298
2321
|
- lib/spree/upgrades/5_5_to_5_6/manifest.yml
|
|
2299
2322
|
- lib/spree/upgrades/5_6_to_6_0/manifest.yml
|
|
@@ -2308,7 +2331,6 @@ files:
|
|
|
2308
2331
|
- lib/tasks/backfill_media_store_ids.rake
|
|
2309
2332
|
- lib/tasks/backfill_reason_store_ids.rake
|
|
2310
2333
|
- lib/tasks/backfill_tagging_tenants.rake
|
|
2311
|
-
- lib/tasks/capture_methods_migration.rake
|
|
2312
2334
|
- lib/tasks/carts_migration.rake
|
|
2313
2335
|
- lib/tasks/categories_and_collections.rake
|
|
2314
2336
|
- lib/tasks/channels.rake
|
|
@@ -2323,6 +2345,7 @@ files:
|
|
|
2323
2345
|
- lib/tasks/fold_store_credit_categories.rake
|
|
2324
2346
|
- lib/tasks/fulfillment_statuses_migration.rake
|
|
2325
2347
|
- lib/tasks/inventory_operations_migration.rake
|
|
2348
|
+
- lib/tasks/maintenance_tasks.rake
|
|
2326
2349
|
- lib/tasks/markets.rake
|
|
2327
2350
|
- lib/tasks/media.rake
|
|
2328
2351
|
- lib/tasks/media_class_rename.rake
|
|
@@ -2333,7 +2356,6 @@ files:
|
|
|
2333
2356
|
- lib/tasks/migrate_users_to_customers.rake
|
|
2334
2357
|
- lib/tasks/money.rake
|
|
2335
2358
|
- lib/tasks/order_coupon_code_backfill.rake
|
|
2336
|
-
- lib/tasks/order_market_backfill.rake
|
|
2337
2359
|
- lib/tasks/package_types.rake
|
|
2338
2360
|
- lib/tasks/preferences_json.rake
|
|
2339
2361
|
- lib/tasks/price_history.rake
|
|
@@ -2378,9 +2400,9 @@ licenses:
|
|
|
2378
2400
|
- BSD-3-Clause
|
|
2379
2401
|
metadata:
|
|
2380
2402
|
bug_tracker_uri: https://github.com/spree/spree/issues
|
|
2381
|
-
changelog_uri: https://github.com/spree/spree/releases/tag/v6.0.
|
|
2403
|
+
changelog_uri: https://github.com/spree/spree/releases/tag/v6.0.1
|
|
2382
2404
|
documentation_uri: https://docs.spreecommerce.org/
|
|
2383
|
-
source_code_uri: https://github.com/spree/spree/tree/v6.0.
|
|
2405
|
+
source_code_uri: https://github.com/spree/spree/tree/v6.0.1
|
|
2384
2406
|
post_install_message:
|
|
2385
2407
|
rdoc_options: []
|
|
2386
2408
|
require_paths:
|