switchman 1.5.21 → 2.1.5

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 (56) hide show
  1. checksums.yaml +5 -5
  2. data/app/models/switchman/shard.rb +757 -11
  3. data/db/migrate/20130328212039_create_switchman_shards.rb +3 -1
  4. data/db/migrate/20130328224244_create_default_shard.rb +4 -2
  5. data/db/migrate/20161206323434_add_back_default_string_limits_switchman.rb +13 -0
  6. data/db/migrate/20180828183945_add_default_shard_index.rb +15 -0
  7. data/db/migrate/20180828192111_add_timestamps_to_shards.rb +17 -0
  8. data/db/migrate/20190114212900_add_unique_name_indexes.rb +9 -0
  9. data/lib/switchman/action_controller/caching.rb +2 -0
  10. data/lib/switchman/active_record/abstract_adapter.rb +14 -4
  11. data/lib/switchman/active_record/association.rb +64 -37
  12. data/lib/switchman/active_record/attribute_methods.rb +54 -22
  13. data/lib/switchman/active_record/base.rb +76 -31
  14. data/lib/switchman/active_record/batches.rb +3 -1
  15. data/lib/switchman/active_record/calculations.rb +17 -22
  16. data/lib/switchman/active_record/connection_handler.rb +88 -78
  17. data/lib/switchman/active_record/connection_pool.rb +28 -23
  18. data/lib/switchman/active_record/finder_methods.rb +37 -28
  19. data/lib/switchman/active_record/log_subscriber.rb +14 -19
  20. data/lib/switchman/active_record/migration.rb +80 -0
  21. data/lib/switchman/active_record/model_schema.rb +3 -1
  22. data/lib/switchman/active_record/persistence.rb +9 -1
  23. data/lib/switchman/active_record/postgresql_adapter.rb +170 -126
  24. data/lib/switchman/active_record/predicate_builder.rb +3 -1
  25. data/lib/switchman/active_record/query_cache.rb +22 -87
  26. data/lib/switchman/active_record/query_methods.rb +139 -125
  27. data/lib/switchman/active_record/reflection.rb +42 -14
  28. data/lib/switchman/active_record/relation.rb +108 -33
  29. data/lib/switchman/active_record/spawn_methods.rb +2 -0
  30. data/lib/switchman/active_record/statement_cache.rb +44 -52
  31. data/lib/switchman/active_record/table_definition.rb +4 -2
  32. data/lib/switchman/active_record/type_caster.rb +2 -0
  33. data/lib/switchman/active_record/where_clause_factory.rb +5 -2
  34. data/lib/switchman/active_support/cache.rb +18 -0
  35. data/lib/switchman/arel.rb +8 -25
  36. data/lib/switchman/call_super.rb +19 -0
  37. data/lib/switchman/connection_pool_proxy.rb +70 -24
  38. data/lib/switchman/database_server.rb +69 -59
  39. data/lib/switchman/default_shard.rb +3 -0
  40. data/lib/switchman/engine.rb +44 -41
  41. data/lib/switchman/environment.rb +2 -0
  42. data/lib/switchman/errors.rb +2 -0
  43. data/lib/switchman/{shackles → guard_rail}/relation.rb +7 -5
  44. data/lib/switchman/{shackles.rb → guard_rail.rb} +6 -4
  45. data/lib/switchman/open4.rb +2 -0
  46. data/lib/switchman/r_spec_helper.rb +14 -8
  47. data/lib/switchman/rails.rb +2 -0
  48. data/lib/switchman/schema_cache.rb +17 -0
  49. data/lib/switchman/sharded_instrumenter.rb +4 -2
  50. data/lib/switchman/standard_error.rb +4 -2
  51. data/lib/switchman/test_helper.rb +7 -10
  52. data/lib/switchman/version.rb +3 -1
  53. data/lib/switchman.rb +5 -1
  54. data/lib/tasks/switchman.rake +53 -72
  55. metadata +84 -38
  56. data/app/models/switchman/shard_internal.rb +0 -692
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
4
  module TestHelper
3
5
  class << self
4
6
  def recreate_persistent_test_shards(dont_create: false)
5
7
  # recreate the default shard (it got buhleted)
6
- if Shard.default(true).is_a?(DefaultShard)
8
+ ::GuardRail.activate(:deploy) { Switchman.cache.clear }
9
+ if Shard.default(reload: true).is_a?(DefaultShard)
7
10
  begin
8
11
  Shard.create!(default: true)
9
12
  rescue
@@ -11,17 +14,11 @@ module Switchman
11
14
  # database doesn't exist yet, presumably cause we're creating it right now
12
15
  return [nil, nil]
13
16
  end
14
- Shard.default(true)
17
+ Shard.default(reload: true)
15
18
  end
16
19
 
17
- # can't auto-create a new shard on the default shard's db server if the
18
- # default shard is split across multiple db servers
19
- if ::ActiveRecord::Base.connection_handler.connection_pool_list.length > 1
20
- server1 = DatabaseServer.create(Shard.default.database_server.config)
21
- else
22
- server1 = Shard.default.database_server
23
- end
24
- server2 = DatabaseServer.create(Shard.default.database_server.config)
20
+ server1 = Shard.default.database_server
21
+ server2 = DatabaseServer.create(Shard.default.database_server.config.merge(server2: true))
25
22
 
26
23
  if server1 == Shard.default.database_server && server1.config[:shard1] && server1.config[:shard2]
27
24
  # look for the shards in the db already
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
- VERSION = "1.5.21"
4
+ VERSION = "2.1.5"
3
5
  end
data/lib/switchman.rb CHANGED
@@ -1,4 +1,6 @@
1
- require "shackles"
1
+ # frozen_string_literal: true
2
+
3
+ require "guard_rail"
2
4
  require "switchman/open4"
3
5
  require "switchman/engine"
4
6
 
@@ -15,4 +17,6 @@ module Switchman
15
17
  def self.cache=(cache)
16
18
  @cache = cache
17
19
  end
20
+
21
+ class OrderOnMultiShardQuery < RuntimeError; end
18
22
  end
@@ -20,13 +20,18 @@ module Switchman
20
20
  open = servers.delete('open')
21
21
 
22
22
  servers = servers.map { |server| DatabaseServer.find(server) }.compact
23
- servers.concat(DatabaseServer.all.select { |server| server.config[:open] }) if open
23
+ if open
24
+ open_servers = DatabaseServer.all.select { |server| server.config[:open] }
25
+ servers.concat(open_servers)
26
+ servers << DatabaseServer.find(nil) if open_servers.empty?
27
+ servers.uniq!
28
+ end
24
29
  servers = DatabaseServer.all - servers if negative
25
30
  end
26
31
 
27
32
  servers = filter_database_servers_chain.call(servers)
28
33
 
29
- scope = base_scope.order("database_server_id IS NOT NULL, database_server_id, id")
34
+ scope = base_scope.order(::Arel.sql("database_server_id IS NOT NULL, database_server_id, id"))
30
35
  if servers != DatabaseServer.all
31
36
  conditions = ["database_server_id IN (?)", servers.map(&:id)]
32
37
  conditions.first << " OR database_server_id IS NULL" if servers.include?(Shard.default.database_server)
@@ -44,7 +49,11 @@ module Switchman
44
49
  { parallel: ENV['PARALLEL'].to_i, max_procs: ENV['MAX_PARALLEL_PROCS'] }
45
50
  end
46
51
 
47
- def self.shardify_task(task_name)
52
+ # categories - an array or proc, to activate as the current shard during the
53
+ # task. tasks which modify the schema may want to pass all categories in
54
+ # so that schema updates for non-default tables happen against all shards.
55
+ # this is handled automatically for the default migration tasks, below.
56
+ def self.shardify_task(task_name, categories: [:primary])
48
57
  old_task = ::Rake::Task[task_name]
49
58
  old_actions = old_task.actions.dup
50
59
  old_task.actions.clear
@@ -55,27 +64,42 @@ module Switchman
55
64
  TestHelper.recreate_persistent_test_shards(dont_create: true)
56
65
  end
57
66
 
58
- ::Shackles.activate(:deploy) do
59
- begin
60
- Shard.with_each_shard(scope, Shard.categories, options) do
61
- shard = Shard.current
62
- puts "#{shard.id}: #{shard.description}"
63
- ::ActiveRecord::Base.connection_pool.spec.config[:shard_name] = Shard.current.name
64
- ::ActiveRecord::Base.configurations[::Rails.env] = ::ActiveRecord::Base.connection_pool.spec.config.stringify_keys
65
- shard.database_server.unshackle do
66
- old_actions.each { |action| action.call(*task_args) }
67
+ ::GuardRail.activate(:deploy) do
68
+ Shard.default.database_server.unguard do
69
+ begin
70
+ categories = categories.call if categories.respond_to?(:call)
71
+ Shard.with_each_shard(scope, categories, options) do
72
+ shard = Shard.current
73
+ puts "#{shard.id}: #{shard.description}"
74
+ ::ActiveRecord::Base.connection_pool.spec.config[:shard_name] = Shard.current.name
75
+ if ::Rails.version < '6.0'
76
+ ::ActiveRecord::Base.configurations[::Rails.env] = ::ActiveRecord::Base.connection_pool.spec.config.stringify_keys
77
+ else
78
+ # Adopted from the deprecated code that currently lives in rails proper
79
+ remaining_configs = ::ActiveRecord::Base.configurations.configurations.reject { |db_config| db_config.env_name == ::Rails.env }
80
+ new_config = ::ActiveRecord::DatabaseConfigurations.new(::Rails.env =>
81
+ ::ActiveRecord::Base.connection_pool.spec.config.stringify_keys).configurations
82
+ new_configs = remaining_configs + new_config
83
+
84
+ ::ActiveRecord::Base.configurations = new_configs
85
+ end
86
+ shard.database_server.unguard do
87
+ old_actions.each { |action| action.call(*task_args) }
88
+ end
89
+ nil
67
90
  end
68
- nil
91
+ rescue => e
92
+ puts "Exception from #{e.current_shard.id}: #{e.current_shard.description}" if options[:parallel] != 0
93
+ raise
69
94
  end
70
- rescue => e
71
- puts "Exception from #{e.current_shard.id}: #{e.current_shard.description}" if options[:parallel] != 0
72
- raise
73
95
  end
74
96
  end
75
97
  end
76
98
  end
77
99
 
78
- %w{db:migrate db:migrate:up db:migrate:down db:rollback}.each { |task_name| shardify_task(task_name) }
100
+ %w{db:migrate db:migrate:up db:migrate:down db:rollback}.each do |task_name|
101
+ shardify_task(task_name, categories: ->{ Shard.categories })
102
+ end
79
103
 
80
104
  private
81
105
 
@@ -186,64 +210,21 @@ module Switchman
186
210
  @filter_database_servers_chain ||= ->(servers) { servers }
187
211
  end
188
212
  end
189
- end
190
213
 
191
- module Switchman
192
214
  module ActiveRecord
193
215
  module PostgreSQLDatabaseTasks
194
- if ::Rails.version < '4.2'
195
- def structure_dump(filename)
196
- set_psql_env
197
- search_path = configuration['schema_search_path']
198
- unless search_path.blank?
199
- search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
200
- serialized_search_path = ::ActiveRecord::Base.connection.schema_search_path
201
- end
202
- if configuration['use_qualified_names']
203
- shard = Shard.current.name
204
- serialized_search_path = shard
205
- search_path = "--schema=#{Shellwords.escape(shard)}"
206
- end
207
-
208
- command = "pg_dump -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
209
- raise 'Error dumping database' unless Kernel.system(command)
210
-
211
- File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
212
- end
213
- else
214
- def structure_dump(filename)
215
- set_psql_env
216
- args = ['-s', '-x', '-O', '-f', filename]
217
- search_path = configuration['schema_search_path']
218
- if configuration['use_qualified_names']
219
- shard = Shard.current.name
220
- serialized_search_path = shard
221
- args << "--schema=#{Shellwords.escape(shard)}"
222
- elsif !search_path.blank?
223
- args << search_path.split(',').map do |part|
224
- "--schema=#{part.strip}"
225
- end.join(' ')
226
- serialized_search_path = connection.schema_search_path
227
- end
228
-
229
- args << configuration['database']
230
- run_cmd('pg_dump', args, 'dumping')
231
- File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
232
- end
233
-
234
- if ::Rails.version < '4.2.5'
235
- # These methods are backported from rails 4.2.5 to work with the above
236
- def run_cmd(cmd, args, action)
237
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
238
- end
239
-
240
- def run_cmd_error(cmd, args, action)
241
- msg = "failed to execute:\n"
242
- msg << "#{cmd} #{args.join(' ')}\n\n"
243
- msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
244
- msg
245
- end
246
- end
216
+ def structure_dump(filename, extra_flags=nil)
217
+ set_psql_env
218
+ args = ['-s', '-x', '-O', '-f', filename]
219
+ args.concat(Array(extra_flags)) if extra_flags
220
+ search_path = configuration['schema_search_path']
221
+ shard = Shard.current.name
222
+ serialized_search_path = shard
223
+ args << "--schema=#{Shellwords.escape(shard)}"
224
+
225
+ args << configuration['database']
226
+ run_cmd('pg_dump', args, 'dumping')
227
+ File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
247
228
  end
248
229
  end
249
230
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switchman
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.21
4
+ version: 2.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-09-09 00:00:00.000000000 Z
13
+ date: 2021-08-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: railties
@@ -18,82 +18,110 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: '4.0'
22
- - - "<="
21
+ version: '5.1'
22
+ - - "<"
23
23
  - !ruby/object:Gem::Version
24
- version: 5.0.0.beta3
24
+ version: '6.1'
25
25
  type: :runtime
26
26
  prerelease: false
27
27
  version_requirements: !ruby/object:Gem::Requirement
28
28
  requirements:
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: '4.0'
32
- - - "<="
31
+ version: '5.1'
32
+ - - "<"
33
33
  - !ruby/object:Gem::Version
34
- version: 5.0.0.beta3
34
+ version: '6.1'
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: activerecord
37
37
  requirement: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '4.0'
42
- - - "<="
41
+ version: '5.1'
42
+ - - "<"
43
43
  - !ruby/object:Gem::Version
44
- version: 5.0.0.beta3
44
+ version: '6.1'
45
45
  type: :runtime
46
46
  prerelease: false
47
47
  version_requirements: !ruby/object:Gem::Requirement
48
48
  requirements:
49
49
  - - ">="
50
50
  - !ruby/object:Gem::Version
51
- version: '4.0'
52
- - - "<="
51
+ version: '5.1'
52
+ - - "<"
53
53
  - !ruby/object:Gem::Version
54
- version: 5.0.0.beta3
54
+ version: '6.1'
55
55
  - !ruby/object:Gem::Dependency
56
- name: shackles
56
+ name: guardrail
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 1.1.0
61
+ version: 2.0.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 1.1.0
68
+ version: 2.0.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: open4
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '='
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: 1.3.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '='
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 1.3.0
83
83
  - !ruby/object:Gem::Dependency
84
- name: mysql2
84
+ name: appraisal
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.3'
89
+ version: '2.1'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.3'
96
+ version: '2.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: pg
99
127
  requirement: !ruby/object:Gem::Requirement
@@ -112,44 +140,58 @@ dependencies:
112
140
  name: rspec-rails
113
141
  requirement: !ruby/object:Gem::Requirement
114
142
  requirements:
115
- - - '='
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.5'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.5'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rspec-mocks
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
116
158
  - !ruby/object:Gem::Version
117
- version: 3.1.0
159
+ version: '3.5'
118
160
  type: :development
119
161
  prerelease: false
120
162
  version_requirements: !ruby/object:Gem::Requirement
121
163
  requirements:
122
- - - '='
164
+ - - "~>"
123
165
  - !ruby/object:Gem::Version
124
- version: 3.1.0
166
+ version: '3.5'
125
167
  - !ruby/object:Gem::Dependency
126
- name: sqlite3
168
+ name: simplecov
127
169
  requirement: !ruby/object:Gem::Requirement
128
170
  requirements:
129
171
  - - "~>"
130
172
  - !ruby/object:Gem::Version
131
- version: '1.3'
173
+ version: '0.15'
132
174
  type: :development
133
175
  prerelease: false
134
176
  version_requirements: !ruby/object:Gem::Requirement
135
177
  requirements:
136
178
  - - "~>"
137
179
  - !ruby/object:Gem::Version
138
- version: '1.3'
180
+ version: '0.15'
139
181
  - !ruby/object:Gem::Dependency
140
182
  name: rake
141
183
  requirement: !ruby/object:Gem::Requirement
142
184
  requirements:
143
185
  - - "~>"
144
186
  - !ruby/object:Gem::Version
145
- version: '10.0'
187
+ version: '12.0'
146
188
  type: :development
147
189
  prerelease: false
148
190
  version_requirements: !ruby/object:Gem::Requirement
149
191
  requirements:
150
192
  - - "~>"
151
193
  - !ruby/object:Gem::Version
152
- version: '10.0'
194
+ version: '12.0'
153
195
  description: Sharding
154
196
  email:
155
197
  - cody@instructure.com
@@ -159,9 +201,12 @@ extra_rdoc_files: []
159
201
  files:
160
202
  - Rakefile
161
203
  - app/models/switchman/shard.rb
162
- - app/models/switchman/shard_internal.rb
163
204
  - db/migrate/20130328212039_create_switchman_shards.rb
164
205
  - db/migrate/20130328224244_create_default_shard.rb
206
+ - db/migrate/20161206323434_add_back_default_string_limits_switchman.rb
207
+ - db/migrate/20180828183945_add_default_shard_index.rb
208
+ - db/migrate/20180828192111_add_timestamps_to_shards.rb
209
+ - db/migrate/20190114212900_add_unique_name_indexes.rb
165
210
  - lib/switchman.rb
166
211
  - lib/switchman/action_controller/caching.rb
167
212
  - lib/switchman/active_record/abstract_adapter.rb
@@ -174,6 +219,7 @@ files:
174
219
  - lib/switchman/active_record/connection_pool.rb
175
220
  - lib/switchman/active_record/finder_methods.rb
176
221
  - lib/switchman/active_record/log_subscriber.rb
222
+ - lib/switchman/active_record/migration.rb
177
223
  - lib/switchman/active_record/model_schema.rb
178
224
  - lib/switchman/active_record/persistence.rb
179
225
  - lib/switchman/active_record/postgresql_adapter.rb
@@ -189,18 +235,19 @@ files:
189
235
  - lib/switchman/active_record/where_clause_factory.rb
190
236
  - lib/switchman/active_support/cache.rb
191
237
  - lib/switchman/arel.rb
238
+ - lib/switchman/call_super.rb
192
239
  - lib/switchman/connection_pool_proxy.rb
193
240
  - lib/switchman/database_server.rb
194
241
  - lib/switchman/default_shard.rb
195
242
  - lib/switchman/engine.rb
196
243
  - lib/switchman/environment.rb
197
244
  - lib/switchman/errors.rb
245
+ - lib/switchman/guard_rail.rb
246
+ - lib/switchman/guard_rail/relation.rb
198
247
  - lib/switchman/open4.rb
199
248
  - lib/switchman/r_spec_helper.rb
200
249
  - lib/switchman/rails.rb
201
250
  - lib/switchman/schema_cache.rb
202
- - lib/switchman/shackles.rb
203
- - lib/switchman/shackles/relation.rb
204
251
  - lib/switchman/sharded_instrumenter.rb
205
252
  - lib/switchman/standard_error.rb
206
253
  - lib/switchman/test_helper.rb
@@ -218,16 +265,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
218
265
  requirements:
219
266
  - - ">="
220
267
  - !ruby/object:Gem::Version
221
- version: '2.0'
268
+ version: '2.5'
222
269
  required_rubygems_version: !ruby/object:Gem::Requirement
223
270
  requirements:
224
271
  - - ">="
225
272
  - !ruby/object:Gem::Version
226
273
  version: '0'
227
274
  requirements: []
228
- rubyforge_project:
229
- rubygems_version: 2.6.4
275
+ rubygems_version: 3.0.3
230
276
  signing_key:
231
277
  specification_version: 4
232
- summary: Rails 4 sharding magic
278
+ summary: Rails sharding magic
233
279
  test_files: []