├── .github └── workflows │ ├── build.yml │ └── gempush.yml ├── .gitignore ├── .hound.yml ├── .overcommit.yml ├── .rbenv-gemsets ├── .rspec ├── .rubocop.yml ├── .ruby-style.yml ├── Appraisals ├── Changelog.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── data_migrate.gemspec ├── gemfiles ├── rails_6.1.gemfile ├── rails_6.1.gemfile.lock ├── rails_7.0.gemfile ├── rails_7.0.gemfile.lock ├── rails_7.1.gemfile ├── rails_7.1.gemfile.lock ├── rails_7.2.gemfile ├── rails_7.2.gemfile.lock ├── rails_8.0.gemfile └── rails_8.0.gemfile.lock ├── lib ├── capistrano │ ├── data_migrate.rb │ └── data_migrate │ │ └── migrate.rb ├── data_migrate.rb ├── data_migrate │ ├── config.rb │ ├── data_migrator.rb │ ├── data_schema.rb │ ├── data_schema_migration.rb │ ├── database_configurations_wrapper.rb │ ├── database_tasks.rb │ ├── migration_context.rb │ ├── rails_helper.rb │ ├── railtie.rb │ ├── schema_dumper.rb │ ├── schema_migration.rb │ ├── status_service.rb │ ├── tasks │ │ └── data_migrate_tasks.rb │ └── version.rb └── generators │ ├── data_migrate.rb │ └── data_migration │ ├── data_migration_generator.rb │ └── templates │ ├── data_migration.rb │ └── migration.rb ├── screenshot.png ├── spec ├── data_migrate │ ├── config_spec.rb │ ├── data_migrator_spec.rb │ ├── data_schema_migration_spec.rb │ ├── data_spec.rb │ ├── database_tasks_spec.rb │ ├── migration.rb │ ├── migration_context_spec.rb │ ├── schema_dumper_spec.rb │ ├── schema_migration_spec.rb │ ├── status_service_spec.rb │ └── tasks │ │ └── data_migrate_tasks_spec.rb ├── db │ ├── data │ │ ├── 20091231235959_some_name.rb │ │ ├── 20171231235959_super_update.rb │ │ ├── 20181128000207_excluded_file.rb.other_ext │ │ ├── partial_schema │ │ │ ├── data_schema.rb │ │ │ └── test_data_schema.rb │ │ └── schema │ │ │ ├── data_schema.rb │ │ │ └── test_data_schema.rb │ ├── data_two │ │ └── 20241231235959_data_two_update.rb │ └── migrate │ │ ├── 20131111111111_late_migration.rb │ │ └── 20202020202011_db_migration.rb ├── generators │ └── data_migration │ │ └── data_migration_generator_spec.rb └── spec_helper.rb └── tasks ├── .gitkeep └── databases.rake /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | test: 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | os: [ "ubuntu-24.04" ] 13 | ruby: 14 | - '3.1' 15 | - '3.2' 16 | - '3.3' 17 | - '3.4' 18 | gemfile: 19 | - gemfiles/rails_6.1.gemfile 20 | - gemfiles/rails_7.0.gemfile 21 | - gemfiles/rails_7.1.gemfile 22 | - gemfiles/rails_7.2.gemfile 23 | - gemfiles/rails_8.0.gemfile 24 | exclude: 25 | - ruby: '3.1' 26 | gemfile: 'gemfiles/rails_8.0.gemfile' 27 | - ruby: '3.4' 28 | gemfile: 'gemfiles/rails_6.1.gemfile' 29 | - ruby: '3.4' 30 | gemfile: 'gemfiles/rails_7.0.gemfile' 31 | - ruby: '3.4' 32 | gemfile: 'gemfiles/rails_7.1.gemfile' 33 | runs-on: ubuntu-latest 34 | env: 35 | BUNDLE_GEMFILE: ${{ matrix.gemfile }} 36 | RAILS_ENV: test 37 | steps: 38 | - name: Checkout code 39 | uses: actions/checkout@v4 40 | - name: Set up Ruby 41 | uses: ruby/setup-ruby@v1 42 | with: 43 | ruby-version: ${{ matrix.ruby }} 44 | bundler-cache: true 45 | - name: Run tests 46 | run: bundle exec rspec 47 | -------------------------------------------------------------------------------- /.github/workflows/gempush.yml: -------------------------------------------------------------------------------- 1 | name: Release Gem 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | build: 9 | name: Build + Publish 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@master 14 | - name: Set up Ruby 3.2 15 | uses: ruby/setup-ruby@v1 16 | with: 17 | ruby-version: '3.2' 18 | 19 | - name: Publish to RubyGems 20 | run: | 21 | mkdir -p $HOME/.gem 22 | touch $HOME/.gem/credentials 23 | chmod 0600 $HOME/.gem/credentials 24 | printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials 25 | gem build *.gemspec 26 | gem push *.gem 27 | env: 28 | GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}} 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.rvmrc 2 | *.gem 3 | gemfiles/.bundle 4 | spec/db/test.db 5 | spec/db/other_test.db 6 | spec/db/data_schema.rb 7 | .vscode/ 8 | .DS_Store 9 | .ruby-gemset 10 | .ruby-version 11 | .idea/ 12 | vendor/ 13 | Gemfile.lock 14 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | fail_on_violations: true 2 | 3 | ruby: 4 | config_file: .rubocop.yml 5 | -------------------------------------------------------------------------------- /.overcommit.yml: -------------------------------------------------------------------------------- 1 | # Use this file to configure the Overcommit hooks you wish to use. This will 2 | # extend the default configuration defined in: 3 | # https://github.com/brigade/overcommit/blob/master/config/default.yml 4 | # 5 | # At the topmost level of this YAML file is a key representing type of hook 6 | # being run (e.g. pre-commit, commit-msg, etc.). Within each type you can 7 | # customize each hook, such as whether to only run it on certain files (via 8 | # `include`), whether to only display output if it fails (via `quiet`), etc. 9 | # 10 | # For a complete list of hooks, see: 11 | # https://github.com/brigade/overcommit/tree/master/lib/overcommit/hook 12 | # 13 | # For a complete list of options that you can use to customize hooks, see: 14 | # https://github.com/brigade/overcommit#configuration 15 | # 16 | # Uncomment the following lines to make the configuration take effect. 17 | 18 | PreCommit: 19 | RuboCop: 20 | enabled: true 21 | on_warn: fail # Treat all warnings as failures -------------------------------------------------------------------------------- /.rbenv-gemsets: -------------------------------------------------------------------------------- 1 | data-migrate 2 | -global 3 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format d 3 | 4 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | # Use same configration as used by HoundCI 2 | inherit_from: .ruby-style.yml 3 | -------------------------------------------------------------------------------- /.ruby-style.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | TargetRubyVersion: 3.1 3 | Include: 4 | - "**/*.podspec" 5 | - "**/*.jbuilder" 6 | - "**/*.rake" 7 | - "**/*.opal" 8 | - "**/Gemfile" 9 | - "**/Rakefile" 10 | - "**/Capfile" 11 | - "**/Guardfile" 12 | - "**/Podfile" 13 | - "**/Thorfile" 14 | - "**/Vagrantfile" 15 | - "**/Berksfile" 16 | - "**/Cheffile" 17 | - "**/Vagabondfile" 18 | Exclude: 19 | - "**/*.gemspec" 20 | - "vendor/**/*" 21 | - "**/schema.rb" 22 | - "db/migrate/*" 23 | - "db/data/*" 24 | - "db/data_schema.rb" 25 | - "tasks/databases.rake" 26 | Rails/Date: 27 | EnforcedStyle: strict 28 | Style/FrozenStringLiteralComment: 29 | Enabled: false 30 | Layout/AccessModifierIndentation: 31 | Description: Check indentation of private/protected visibility modifiers. 32 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#indent-public-private-protected 33 | Enabled: true 34 | EnforcedStyle: indent 35 | SupportedStyles: 36 | - outdent 37 | - indent 38 | Layout/AlignHash: 39 | Description: Align the elements of a hash literal if they span more than one line. 40 | Enabled: true 41 | EnforcedHashRocketStyle: key 42 | EnforcedColonStyle: key 43 | EnforcedLastArgumentHashStyle: always_inspect 44 | SupportedLastArgumentHashStyles: 45 | - always_inspect 46 | - always_ignore 47 | - ignore_implicit 48 | - ignore_explicit 49 | Layout/AlignParameters: 50 | Description: Align the parameters of a method call if they span more than one line. 51 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-double-indent 52 | Enabled: true 53 | EnforcedStyle: with_first_parameter 54 | SupportedStyles: 55 | - with_first_parameter 56 | - with_fixed_indentation 57 | Style/AndOr: 58 | Description: Use &&/|| instead of and/or. 59 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-and-or-or 60 | Enabled: false 61 | EnforcedStyle: always 62 | SupportedStyles: 63 | - always 64 | - conditionals 65 | Style/BarePercentLiterals: 66 | Description: Checks if usage of %() or %Q() matches configuration. 67 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-q-shorthand 68 | Enabled: true 69 | EnforcedStyle: bare_percent 70 | SupportedStyles: 71 | - percent_q 72 | - bare_percent 73 | Style/BracesAroundHashParameters: 74 | Description: Enforce braces style around hash parameters. 75 | Enabled: false 76 | EnforcedStyle: no_braces 77 | SupportedStyles: 78 | - braces 79 | - no_braces 80 | - context_dependent 81 | Layout/CaseIndentation: 82 | Description: Indentation of when in a case/when/[else/]end. 83 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#indent-when-to-case 84 | Enabled: true 85 | EnforcedStyle: case 86 | SupportedStyles: 87 | - case 88 | - end 89 | IndentOneStep: false 90 | Style/ClassAndModuleChildren: 91 | Description: Checks style of children classes and modules. 92 | Enabled: false 93 | EnforcedStyle: nested 94 | SupportedStyles: 95 | - nested 96 | - compact 97 | Style/ClassCheck: 98 | Description: Enforces consistent use of `Object#is_a?` or `Object#kind_of?`. 99 | Enabled: true 100 | EnforcedStyle: is_a? 101 | SupportedStyles: 102 | - is_a? 103 | - kind_of? 104 | Style/CollectionMethods: 105 | Description: Preferred collection methods. 106 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#map-find-select-reduce-size 107 | Enabled: false 108 | PreferredMethods: 109 | collect: map 110 | collect!: map! 111 | find: detect 112 | find_all: select 113 | reduce: inject 114 | Style/CommentAnnotation: 115 | Description: Checks formatting of special comments (TODO, FIXME, OPTIMIZE, HACK, 116 | REVIEW). 117 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#annotate-keywords 118 | Enabled: false 119 | Keywords: 120 | - TODO 121 | - FIXME 122 | - OPTIMIZE 123 | - HACK 124 | - REVIEW 125 | Layout/MultilineMethodCallIndentation: 126 | EnforcedStyle: indented 127 | Enabled: true 128 | SupportedStyles: 129 | - aligned 130 | - indented 131 | - indented_relative_to_receiver 132 | Layout/DotPosition: 133 | Description: Checks the position of the dot in multi-line method calls. 134 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains 135 | Enabled: false 136 | EnforcedStyle: leading 137 | SupportedStyles: 138 | - leading 139 | - trailing 140 | Layout/EmptyLineBetweenDefs: 141 | Description: Use empty lines between defs. 142 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#empty-lines-between-methods 143 | Enabled: true 144 | AllowAdjacentOneLineDefs: false 145 | Layout/EmptyLinesAroundBlockBody: 146 | Description: Keeps track of empty lines around block bodies. 147 | Enabled: false 148 | EnforcedStyle: no_empty_lines 149 | SupportedStyles: 150 | - empty_lines 151 | - no_empty_lines 152 | Layout/EmptyLinesAroundClassBody: 153 | Description: Keeps track of empty lines around class bodies. 154 | Enabled: false 155 | EnforcedStyle: no_empty_lines 156 | SupportedStyles: 157 | - empty_lines 158 | - no_empty_lines 159 | Layout/EmptyLinesAroundModuleBody: 160 | Description: Keeps track of empty lines around module bodies. 161 | Enabled: true 162 | EnforcedStyle: no_empty_lines 163 | SupportedStyles: 164 | - empty_lines 165 | - no_empty_lines 166 | Style/Encoding: 167 | Description: Use UTF-8 as the source file encoding. 168 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#utf-8 169 | Enabled: false 170 | Naming/FileName: 171 | Description: Use snake_case for source file names. 172 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#snake-case-files 173 | Enabled: false 174 | Exclude: [] 175 | Layout/FirstParameterIndentation: 176 | Description: Checks the indentation of the first parameter in a method call. 177 | Enabled: true 178 | EnforcedStyle: special_for_inner_method_call_in_parentheses 179 | SupportedStyles: 180 | - consistent 181 | - special_for_inner_method_call 182 | - special_for_inner_method_call_in_parentheses 183 | Style/For: 184 | Description: Checks use of for or each in multiline loops. 185 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-for-loops 186 | Enabled: true 187 | EnforcedStyle: each 188 | SupportedStyles: 189 | - for 190 | - each 191 | Style/FormatString: 192 | Description: Enforce the use of Kernel#sprintf, Kernel#format or String#%. 193 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#sprintf 194 | Enabled: false 195 | EnforcedStyle: format 196 | SupportedStyles: 197 | - format 198 | - sprintf 199 | - percent 200 | Style/GlobalVars: 201 | Description: Do not introduce global variables. 202 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#instance-vars 203 | Enabled: false 204 | AllowedVariables: [] 205 | Style/GuardClause: 206 | Description: Check for conditionals that can be replaced with guard clauses 207 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals 208 | Enabled: false 209 | MinBodyLength: 1 210 | Style/HashSyntax: 211 | Description: 'Prefer Ruby 1.9 hash syntax { a: 1, b: 2 } over 1.8 syntax { :a => 212 | 1, :b => 2 }.' 213 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#hash-literals 214 | Enabled: true 215 | EnforcedStyle: ruby19 216 | SupportedStyles: 217 | - ruby19 218 | - hash_rockets 219 | Style/IdenticalConditionalBranches: 220 | Description: >- 221 | Checks that conditional statements do not have an identical 222 | line at the end of each branch, which can validly be moved 223 | out of the conditional. 224 | Enabled: true 225 | Style/IfInsideElse: 226 | Description: 'Finds if nodes inside else, which can be converted to elsif.' 227 | Enabled: true 228 | Style/IfUnlessModifier: 229 | Description: >- 230 | Favor modifier if/unless usage when you have a 231 | single-line body. 232 | StyleGuide: '#if-as-a-modifier' 233 | Enabled: false 234 | 235 | Style/IfUnlessModifierOfIfUnless: 236 | Description: >- 237 | Avoid modifier if/unless usage on conditionals. 238 | Enabled: true 239 | 240 | Style/IfWithSemicolon: 241 | Description: 'Do not use if x; .... Use the ternary operator instead.' 242 | StyleGuide: '#no-semicolon-ifs' 243 | Enabled: true 244 | 245 | Style/InfiniteLoop: 246 | Description: 'Use Kernel#loop for infinite loops.' 247 | StyleGuide: '#infinite-loop' 248 | Enabled: true 249 | 250 | Style/InverseMethods: 251 | Description: >- 252 | Use the inverse method instead of `!.method` 253 | if an inverse method is defined. 254 | Enabled: true 255 | Layout/IndentationWidth: 256 | Description: Use 2 spaces for indentation. 257 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-indentation 258 | Enabled: true 259 | Width: 2 260 | Layout/IndentHash: 261 | Description: Checks the indentation of the first key in a hash literal. 262 | Enabled: true 263 | EnforcedStyle: consistent 264 | SupportedStyles: 265 | - consistent 266 | IndentationWidth: ~ 267 | Style/LambdaCall: 268 | Description: Use lambda.call(...) instead of lambda.(...). 269 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#proc-call 270 | Enabled: false 271 | EnforcedStyle: call 272 | SupportedStyles: 273 | - call 274 | - braces 275 | Style/Next: 276 | Description: Use `next` to skip iteration instead of a condition at the end. 277 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals 278 | Enabled: false 279 | EnforcedStyle: skip_modifier_ifs 280 | MinBodyLength: 3 281 | SupportedStyles: 282 | - skip_modifier_ifs 283 | - always 284 | Style/NonNilCheck: 285 | Description: Checks for redundant nil checks. 286 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-non-nil-checks 287 | Enabled: true 288 | IncludeSemanticChanges: false 289 | Style/MethodDefParentheses: 290 | Description: Checks if the method definitions have or don't have parentheses. 291 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#method-parens 292 | Enabled: true 293 | EnforcedStyle: require_parentheses 294 | SupportedStyles: 295 | - require_parentheses 296 | - require_no_parentheses 297 | Naming/MethodName: 298 | Description: Use the configured style when naming methods. 299 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#snake-case-symbols-methods-vars 300 | Enabled: true 301 | EnforcedStyle: snake_case 302 | SupportedStyles: 303 | - snake_case 304 | - camelCase 305 | Layout/MultilineOperationIndentation: 306 | Description: Checks indentation of binary operations that span more than one line. 307 | Enabled: true 308 | EnforcedStyle: aligned 309 | SupportedStyles: 310 | - aligned 311 | - indented 312 | Style/NumericLiterals: 313 | Description: Add underscores to large numeric literals to improve their readability. 314 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#underscores-in-numerics 315 | Enabled: false 316 | MinDigits: 5 317 | Style/ParenthesesAroundCondition: 318 | Description: Don't use parentheses around the condition of an if/unless/while. 319 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-parens-if 320 | Enabled: true 321 | AllowSafeAssignment: true 322 | Style/PercentLiteralDelimiters: 323 | Description: Use `%`-literal delimiters consistently 324 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-literal-braces 325 | Enabled: false 326 | PreferredDelimiters: 327 | "%": "()" 328 | "%i": "()" 329 | "%q": "()" 330 | "%Q": "()" 331 | "%r": "{}" 332 | "%s": "()" 333 | "%w": "()" 334 | "%W": "()" 335 | "%x": "()" 336 | Style/PercentQLiterals: 337 | Description: Checks if uses of %Q/%q match the configured preference. 338 | Enabled: true 339 | EnforcedStyle: lower_case_q 340 | SupportedStyles: 341 | - lower_case_q 342 | - upper_case_q 343 | Naming/PredicateName: 344 | Description: Check the names of predicate methods. 345 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark 346 | Enabled: true 347 | NamePrefix: 348 | - is_ 349 | - has_ 350 | - have_ 351 | NamePrefixBlacklist: 352 | - is_ 353 | Exclude: 354 | - spec/**/* 355 | Style/RaiseArgs: 356 | Description: Checks the arguments passed to raise/fail. 357 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#exception-class-messages 358 | Enabled: false 359 | EnforcedStyle: exploded 360 | SupportedStyles: 361 | - compact 362 | - exploded 363 | Style/RedundantReturn: 364 | Description: Don't use return where it's not required. 365 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-explicit-return 366 | Enabled: true 367 | AllowMultipleReturnValues: false 368 | Style/RegexpLiteral: 369 | Description: Use %r for regular expressions matching more than `MaxSlashes` '/' 370 | characters. Use %r only for regular expressions matching more than `MaxSlashes` 371 | '/' character. 372 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-r 373 | Enabled: false 374 | Style/Semicolon: 375 | Description: Don't use semicolons to terminate expressions. 376 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-semicolon 377 | Enabled: true 378 | AllowAsExpressionSeparator: false 379 | Style/SignalException: 380 | Description: Checks for proper usage of fail and raise. 381 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#fail-method 382 | Enabled: false 383 | EnforcedStyle: semantic 384 | SupportedStyles: 385 | - only_raise 386 | - only_fail 387 | - semantic 388 | Style/SingleLineBlockParams: 389 | Description: Enforces the names of some block params. 390 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#reduce-blocks 391 | Enabled: false 392 | Methods: 393 | - reduce: 394 | - a 395 | - e 396 | - inject: 397 | - a 398 | - e 399 | Style/SingleLineMethods: 400 | Description: Avoid single-line methods. 401 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-single-line-methods 402 | Enabled: false 403 | AllowIfMethodIsEmpty: true 404 | Style/StringLiterals: 405 | Description: Checks if uses of quotes match the configured preference. 406 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-string-literals 407 | Enabled: true 408 | EnforcedStyle: double_quotes 409 | SupportedStyles: 410 | - single_quotes 411 | - double_quotes 412 | Style/StringLiteralsInInterpolation: 413 | Description: Checks if uses of quotes inside expressions in interpolated strings 414 | match the configured preference. 415 | Enabled: false 416 | EnforcedStyle: single_quotes 417 | SupportedStyles: 418 | - single_quotes 419 | - double_quotes 420 | Layout/SpaceAroundBlockParameters: 421 | Description: Checks the spacing inside and after block parameters pipes. 422 | Enabled: false 423 | EnforcedStyleInsidePipes: no_space 424 | Layout/SpaceAroundEqualsInParameterDefault: 425 | Description: Checks that the equals signs in parameter default assignments have 426 | or don't have surrounding space depending on configuration. 427 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-around-equals 428 | Enabled: true 429 | EnforcedStyle: space 430 | SupportedStyles: 431 | - space 432 | - no_space 433 | Layout/SpaceBeforeBlockBraces: 434 | Description: Checks that the left block brace has or doesn't have space before it. 435 | Enabled: true 436 | EnforcedStyle: space 437 | SupportedStyles: 438 | - space 439 | - no_space 440 | Layout/SpaceInsideBlockBraces: 441 | Description: Checks that block braces have or don't have surrounding space. For 442 | blocks taking parameters, checks that the left brace has or doesn't have trailing 443 | space. 444 | Enabled: false 445 | EnforcedStyle: space 446 | SupportedStyles: 447 | - space 448 | - no_space 449 | EnforcedStyleForEmptyBraces: no_space 450 | SpaceBeforeBlockParameters: true 451 | Layout/SpaceInsideHashLiteralBraces: 452 | Description: Use spaces inside hash literal braces - or don't. 453 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-operators 454 | Enabled: false 455 | EnforcedStyle: space 456 | EnforcedStyleForEmptyBraces: no_space 457 | SupportedStyles: 458 | - space 459 | - no_space 460 | Style/SymbolProc: 461 | Description: Use symbols as procs instead of blocks when possible. 462 | Enabled: true 463 | IgnoredMethods: 464 | - respond_to 465 | Layout/TrailingBlankLines: 466 | Description: Checks trailing blank lines and final newline. 467 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#newline-eof 468 | Enabled: true 469 | EnforcedStyle: final_newline 470 | SupportedStyles: 471 | - final_newline 472 | - final_blank_line 473 | Style/TrivialAccessors: 474 | Description: Prefer attr_* methods to trivial readers/writers. 475 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#attr_family 476 | Enabled: false 477 | ExactNameMatch: false 478 | AllowPredicates: false 479 | AllowDSLWriters: false 480 | Whitelist: 481 | - to_ary 482 | - to_a 483 | - to_c 484 | - to_enum 485 | - to_h 486 | - to_hash 487 | - to_i 488 | - to_int 489 | - to_io 490 | - to_open 491 | - to_path 492 | - to_proc 493 | - to_r 494 | - to_regexp 495 | - to_str 496 | - to_s 497 | - to_sym 498 | Naming/VariableName: 499 | Description: Use the configured style when naming variables. 500 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#snake-case-symbols-methods-vars 501 | Enabled: true 502 | EnforcedStyle: snake_case 503 | SupportedStyles: 504 | - snake_case 505 | - camelCase 506 | Style/WhileUntilModifier: 507 | Description: Favor modifier while/until usage when you have a single-line body. 508 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#while-as-a-modifier 509 | Enabled: false 510 | Style/WordArray: 511 | Description: Use %w or %W for arrays of words. 512 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-w 513 | Enabled: false 514 | MinSize: 0 515 | WordRegex: !ruby/regexp /\A[\p{Word}]+\z/ 516 | Metrics/BlockLength: 517 | Enabled: true 518 | Exclude: 519 | - '**/spec/**/*' 520 | - '**/script/**/*' 521 | Metrics/AbcSize: 522 | Description: A calculated magnitude based on number of assignments, branches, and 523 | conditions. 524 | Enabled: true 525 | Max: 27 526 | Exclude: 527 | - "db/data/*.rb" 528 | Metrics/BlockNesting: 529 | Description: Avoid excessive block nesting 530 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#three-is-the-number-thou-shalt-count 531 | Enabled: false 532 | Max: 3 533 | Metrics/ClassLength: 534 | Description: Avoid classes longer than 100 lines of code. 535 | Enabled: false 536 | CountComments: false 537 | Max: 100 538 | Metrics/CyclomaticComplexity: 539 | Description: A complexity metric that is strongly correlated to the number of test 540 | cases needed to validate a method. 541 | Enabled: false 542 | Max: 6 543 | Metrics/LineLength: 544 | Description: Limit lines to 120 characters. 545 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#80-character-limits 546 | Enabled: true 547 | Max: 120 548 | AllowURI: true 549 | URISchemes: 550 | - http 551 | - https 552 | Metrics/MethodLength: 553 | Description: Avoid methods longer than 10 lines of code. 554 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#short-methods 555 | Enabled: true 556 | CountComments: true 557 | Max: 20 558 | Exclude: 559 | - "db/data/*.rb" 560 | Metrics/ParameterLists: 561 | Description: Avoid parameter lists longer than three or four parameters. 562 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#too-many-params 563 | Enabled: false 564 | Max: 5 565 | CountKeywordArgs: true 566 | Metrics/PerceivedComplexity: 567 | Description: A complexity metric geared towards measuring complexity for a human 568 | reader. 569 | Enabled: false 570 | Max: 7 571 | Lint/AssignmentInCondition: 572 | Description: Don't use assignment in conditions. 573 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#safe-assignment-in-condition 574 | Enabled: false 575 | AllowSafeAssignment: true 576 | Rails/ActionFilter: 577 | Description: Enforces consistent use of action filter methods. 578 | Enabled: false 579 | EnforcedStyle: action 580 | SupportedStyles: 581 | - action 582 | - filter 583 | Include: 584 | - app/controllers/**/*.rb 585 | Rails/HasAndBelongsToMany: 586 | Description: Prefer has_many :through to has_and_belongs_to_many. 587 | Enabled: true 588 | Include: 589 | - app/models/**/*.rb 590 | Rails/Output: 591 | Description: Checks for calls to puts, print, etc. 592 | Enabled: true 593 | Include: 594 | - app/**/*.rb 595 | - config/**/*.rb 596 | - db/**/*.rb 597 | - lib/**/*.rb 598 | Rails/ReadWriteAttribute: 599 | Description: Checks for read_attribute(:attr) and write_attribute(:attr, val). 600 | Enabled: true 601 | Include: 602 | - app/models/**/*.rb 603 | Rails/ScopeArgs: 604 | Description: Checks the arguments of ActiveRecord scopes. 605 | Enabled: true 606 | Include: 607 | - app/models/**/*.rb 608 | Rails/Validation: 609 | Description: Use validates :attribute, hash of validations. 610 | Enabled: true 611 | Include: 612 | - app/models/**/*.rb 613 | Style/InlineComment: 614 | Description: Avoid inline comments. 615 | Enabled: false 616 | Style/MethodCalledOnDoEndBlock: 617 | Description: Avoid chaining a method call on a do...end block. 618 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#single-line-blocks 619 | Enabled: false 620 | Style/SymbolArray: 621 | Description: Use %i or %I for arrays of symbols. 622 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-i 623 | Enabled: false 624 | Layout/ExtraSpacing: 625 | Description: Do not use unnecessary spacing. 626 | Enabled: false 627 | Naming/AccessorMethodName: 628 | Description: Check the naming of accessor methods for get_/set_. 629 | Enabled: false 630 | Style/Alias: 631 | Description: Use alias_method instead of alias. 632 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#alias-method 633 | Enabled: false 634 | Layout/AlignArray: 635 | Description: Align the elements of an array literal if they span more than one line. 636 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#align-multiline-arrays 637 | Enabled: true 638 | Style/ArrayJoin: 639 | Description: Use Array#join instead of Array#*. 640 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#array-join 641 | Enabled: false 642 | Style/AsciiComments: 643 | Description: Use only ascii symbols in comments. 644 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#english-comments 645 | Enabled: false 646 | Naming/AsciiIdentifiers: 647 | Description: Use only ascii symbols in identifiers. 648 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#english-identifiers 649 | Enabled: false 650 | Style/Attr: 651 | Description: Checks for uses of Module#attr. 652 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#attr 653 | Enabled: false 654 | Style/BeginBlock: 655 | Description: Avoid the use of BEGIN blocks. 656 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-BEGIN-blocks 657 | Enabled: true 658 | Style/BlockComments: 659 | Description: Do not use block comments. 660 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-block-comments 661 | Enabled: true 662 | Layout/BlockEndNewline: 663 | Description: Put end statement of multiline block on its own line. 664 | Enabled: true 665 | Style/BlockDelimiters: 666 | Enabled: false 667 | Style/CaseEquality: 668 | Description: Avoid explicit use of the case equality operator(===). 669 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-case-equality 670 | Enabled: false 671 | Style/CharacterLiteral: 672 | Description: Checks for uses of character literals. 673 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-character-literals 674 | Enabled: false 675 | Naming/ClassAndModuleCamelCase: 676 | Description: Use CamelCase for classes and modules. 677 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#camelcase-classes 678 | Enabled: true 679 | Style/ClassMethods: 680 | Description: Use self when defining module/class methods. 681 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#def-self-singletons 682 | Enabled: true 683 | Style/ClassVars: 684 | Description: Avoid the use of class variables. 685 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-class-vars 686 | Enabled: false 687 | Style/ColonMethodCall: 688 | Description: 'Do not use :: for method call.' 689 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#double-colons 690 | Enabled: false 691 | Layout/CommentIndentation: 692 | Description: Indentation of comments. 693 | Enabled: true 694 | Naming/ConstantName: 695 | Description: Constants should use SCREAMING_SNAKE_CASE. 696 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#screaming-snake-case 697 | Enabled: true 698 | Style/DefWithParentheses: 699 | Description: Use def with parentheses when there are arguments. 700 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#method-parens 701 | Enabled: true 702 | Style/PreferredHashMethods: 703 | Description: Checks for use of deprecated Hash methods. 704 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#hash-key 705 | Enabled: false 706 | Style/Documentation: 707 | Description: Document classes and non-namespace modules. 708 | Enabled: false 709 | Style/DoubleNegation: 710 | Description: Checks for uses of double negation (!!). 711 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-bang-bang 712 | Enabled: false 713 | Style/EachWithObject: 714 | Description: Prefer `each_with_object` over `inject` or `reduce`. 715 | Enabled: false 716 | Layout/ElseAlignment: 717 | Description: Align elses and elsifs correctly. 718 | Enabled: true 719 | Style/EmptyElse: 720 | Description: Avoid empty else-clauses. 721 | Enabled: true 722 | Layout/EmptyLines: 723 | Description: Don't use several empty lines in a row. 724 | Enabled: false 725 | Layout/EmptyLinesAroundAccessModifier: 726 | Description: Keep blank lines around access modifiers. 727 | Enabled: true 728 | Layout/EmptyLinesAroundMethodBody: 729 | Description: Keeps track of empty lines around method bodies. 730 | Enabled: true 731 | Style/EmptyLiteral: 732 | Description: Prefer literals to Array.new/Hash.new/String.new. 733 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#literal-array-hash 734 | Enabled: false 735 | Style/EndBlock: 736 | Description: Avoid the use of END blocks. 737 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-END-blocks 738 | Enabled: true 739 | Layout/EndOfLine: 740 | Description: Use Unix-style line endings. 741 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#crlf 742 | Enabled: true 743 | EnforcedStyle: lf 744 | Style/EvenOdd: 745 | Description: Favor the use of Fixnum#even? && Fixnum#odd? 746 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#predicate-methods 747 | Enabled: false 748 | Style/FlipFlop: 749 | Description: Checks for flip flops 750 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-flip-flops 751 | Enabled: false 752 | Style/IfWithSemicolon: 753 | Description: Do not use if x; .... Use the ternary operator instead. 754 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-semicolon-ifs 755 | Enabled: false 756 | Layout/IndentationConsistency: 757 | Description: Keep indentation straight. 758 | Enabled: true 759 | Layout/IndentArray: 760 | Description: Checks the indentation of the first element in an array literal. 761 | Enabled: true 762 | Style/InfiniteLoop: 763 | Description: Use Kernel#loop for infinite loops. 764 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#infinite-loop 765 | Enabled: true 766 | Style/Lambda: 767 | Description: Use the new lambda literal syntax for single-line blocks. 768 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#lambda-multi-line 769 | Enabled: false 770 | Layout/LeadingCommentSpace: 771 | Description: Comments should start with a space. 772 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#hash-space 773 | Enabled: false 774 | Style/LineEndConcatenation: 775 | Description: Use \ instead of + or << to concatenate two string literals at line 776 | end. 777 | Enabled: false 778 | Style/MethodCallWithoutArgsParentheses: 779 | Description: Do not use parentheses for method calls with no arguments. 780 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-args-no-parens 781 | Enabled: true 782 | Style/ModuleFunction: 783 | Description: Checks for usage of `extend self` in modules. 784 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#module-function 785 | Enabled: false 786 | Style/MultilineBlockChain: 787 | Description: Avoid multi-line chains of blocks. 788 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#single-line-blocks 789 | Enabled: false 790 | Layout/MultilineBlockLayout: 791 | Description: Ensures newlines after multiline block do statements. 792 | Enabled: true 793 | Style/MultilineIfThen: 794 | Description: Do not use then for multi-line if/unless. 795 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-then 796 | Enabled: true 797 | Style/MultilineTernaryOperator: 798 | Description: 'Avoid multi-line ?: (the ternary operator); use if/unless instead.' 799 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-multiline-ternary 800 | Enabled: false 801 | Style/NegatedIf: 802 | Description: Favor unless over if for negative conditions (or control flow or). 803 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#unless-for-negatives 804 | Enabled: false 805 | Style/NegatedWhile: 806 | Description: Favor until over while for negative conditions. 807 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#until-for-negatives 808 | Enabled: false 809 | Style/NestedTernaryOperator: 810 | Description: Use one expression per branch in a ternary operator. 811 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-ternary 812 | Enabled: true 813 | Style/NilComparison: 814 | Description: Prefer x.nil? to x == nil. 815 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#predicate-methods 816 | Enabled: false 817 | Style/Not: 818 | Description: Use ! instead of not. 819 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#bang-not-not 820 | Enabled: false 821 | Style/OneLineConditional: 822 | Description: Favor the ternary operator(?:) over if/then/else/end constructs. 823 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#ternary-operator 824 | Enabled: false 825 | Style/PerlBackrefs: 826 | Description: Avoid Perl-style regex back references. 827 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers 828 | Enabled: false 829 | Style/Proc: 830 | Description: Use proc instead of Proc.new. 831 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#proc 832 | Enabled: false 833 | Style/RedundantBegin: 834 | Description: Don't use begin blocks when they are not needed. 835 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#begin-implicit 836 | Enabled: true 837 | Style/RedundantException: 838 | Description: Checks for an obsolete RuntimeException argument in raise/fail. 839 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-explicit-runtimeerror 840 | Enabled: true 841 | Style/RedundantSelf: 842 | Description: Don't use self where it's not needed. 843 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-self-unless-required 844 | Enabled: false 845 | Style/RescueModifier: 846 | Description: Avoid using rescue in its modifier form. 847 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-rescue-modifiers 848 | Enabled: true 849 | Style/SelfAssignment: 850 | Description: Checks for places where self-assignment shorthand should have been 851 | used. 852 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#self-assignment 853 | Enabled: false 854 | Layout/SpaceAfterColon: 855 | Description: Use spaces after colons. 856 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-operators 857 | Enabled: true 858 | Layout/SpaceAfterComma: 859 | Description: Use spaces after commas. 860 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-operators 861 | Enabled: true 862 | Layout/SpaceAfterMethodName: 863 | Description: Do not put a space between a method name and the opening parenthesis 864 | in a method definition. 865 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#parens-no-spaces 866 | Enabled: true 867 | Layout/SpaceAfterNot: 868 | Description: Tracks redundant space after the ! operator. 869 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-space-bang 870 | Enabled: true 871 | Layout/SpaceAfterSemicolon: 872 | Description: Use spaces after semicolons. 873 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-operators 874 | Enabled: true 875 | Layout/SpaceBeforeComma: 876 | Description: No spaces before commas. 877 | Enabled: true 878 | Layout/SpaceBeforeComment: 879 | Description: Checks for missing space between code and a comment on the same line. 880 | Enabled: false 881 | Layout/SpaceBeforeSemicolon: 882 | Description: No spaces before semicolons. 883 | Enabled: true 884 | Layout/SpaceAroundOperators: 885 | Description: Use spaces around operators. 886 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-operators 887 | Enabled: false 888 | Layout/SpaceInsideParens: 889 | Description: No spaces after ( or before ). 890 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-spaces-braces 891 | Enabled: false 892 | Layout/SpaceInsideRangeLiteral: 893 | Description: No spaces inside range literals. 894 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-space-inside-range-literals 895 | Enabled: true 896 | Style/SpecialGlobalVars: 897 | Description: Avoid Perl-style global variables. 898 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms 899 | Enabled: false 900 | 901 | Style/StructInheritance: 902 | Description: Checks for inheritance from Struct.new. 903 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-extend-struct-new 904 | Enabled: true 905 | Layout/Tab: 906 | Description: No hard tabs. 907 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-indentation 908 | Enabled: true 909 | Layout/TrailingWhitespace: 910 | Description: Avoid trailing whitespace. 911 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-trailing-whitespace 912 | Enabled: true 913 | Style/UnlessElse: 914 | Description: Do not use unless with else. Rewrite these with the positive case first. 915 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-else-with-unless 916 | Enabled: true 917 | Style/UnneededCapitalW: 918 | Description: Checks for %W when interpolation is not needed. 919 | Enabled: true 920 | Style/UnneededPercentQ: 921 | Description: Checks for %q/%Q when single quotes or double quotes would do. 922 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-q 923 | Enabled: true 924 | Style/VariableInterpolation: 925 | Description: Don't interpolate global, instance and class variables directly in 926 | strings. 927 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#curlies-interpolate 928 | Enabled: false 929 | Style/WhenThen: 930 | Description: Use when x then ... for one-line cases. 931 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#one-line-cases 932 | Enabled: false 933 | Style/WhileUntilDo: 934 | Description: Checks for redundant do after while or until. 935 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-multiline-while-do 936 | Enabled: true 937 | Lint/AmbiguousOperator: 938 | Description: Checks for ambiguous operators in the first argument of a method invocation 939 | without parentheses. 940 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#parens-as-args 941 | Enabled: false 942 | Lint/AmbiguousRegexpLiteral: 943 | Description: Checks for ambiguous regexp literals in the first argument of a method 944 | invocation without parenthesis. 945 | Enabled: false 946 | Lint/BlockAlignment: 947 | Description: Align block ends correctly. 948 | Enabled: true 949 | Lint/ConditionPosition: 950 | Description: Checks for condition placed in a confusing position relative to the 951 | keyword. 952 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#same-line-condition 953 | Enabled: false 954 | Lint/Debugger: 955 | Description: Check for debugger calls. 956 | Enabled: false 957 | Lint/DeprecatedClassMethods: 958 | Description: Check for deprecated class method calls. 959 | Enabled: false 960 | Lint/DuplicateMethods: 961 | Description: Check for duplicate methods calls. 962 | Enabled: true 963 | Lint/ElseLayout: 964 | Description: Check for odd code arrangement in an else block. 965 | Enabled: false 966 | Lint/EmptyEnsure: 967 | Description: Checks for empty ensure block. 968 | Enabled: true 969 | Lint/EmptyInterpolation: 970 | Description: Checks for empty string interpolation. 971 | Enabled: true 972 | Lint/EndInMethod: 973 | Description: END blocks should not be placed inside method definitions. 974 | Enabled: true 975 | Lint/EnsureReturn: 976 | Description: Do not use return in an ensure block. 977 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-return-ensure 978 | Enabled: true 979 | Security/Eval: 980 | Description: The use of eval represents a serious security risk. 981 | Enabled: true 982 | Lint/HandleExceptions: 983 | Description: Don't suppress exception. 984 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions 985 | Enabled: false 986 | Lint/LiteralInInterpolation: 987 | Description: Checks for literals used in interpolation. 988 | Enabled: false 989 | Lint/Loop: 990 | Description: Use Kernel#loop with break rather than begin/end/until or begin/end/while 991 | for post-loop tests. 992 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#loop-with-break 993 | Enabled: false 994 | Lint/ParenthesesAsGroupedExpression: 995 | Description: Checks for method calls with a space before the opening parenthesis. 996 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#parens-no-spaces 997 | Enabled: false 998 | Lint/RequireParentheses: 999 | Description: Use parentheses in the method call to avoid confusion about precedence. 1000 | Enabled: false 1001 | Lint/RescueException: 1002 | Description: Avoid rescuing the Exception class. 1003 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-blind-rescues 1004 | Enabled: true 1005 | Lint/ShadowingOuterLocalVariable: 1006 | Description: Do not use the same name as outer local variable for block arguments 1007 | or block local variables. 1008 | Enabled: true 1009 | Layout/SpaceBeforeFirstArg: 1010 | Description: Put a space between a method name and the first argument in a method 1011 | call without parentheses. 1012 | Enabled: true 1013 | Lint/StringConversionInInterpolation: 1014 | Description: Checks for Object#to_s usage in string interpolation. 1015 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-to-s 1016 | Enabled: true 1017 | Lint/UnderscorePrefixedVariableName: 1018 | Description: Do not use prefix `_` for a variable that is used. 1019 | Enabled: false 1020 | Lint/UnusedBlockArgument: 1021 | Description: Checks for unused block arguments. 1022 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars 1023 | Enabled: true 1024 | Lint/UnusedMethodArgument: 1025 | Description: Checks for unused method arguments. 1026 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars 1027 | Enabled: true 1028 | Lint/UnreachableCode: 1029 | Description: Unreachable code. 1030 | Enabled: true 1031 | Lint/UselessAccessModifier: 1032 | Description: Checks for useless access modifiers. 1033 | Enabled: true 1034 | Lint/UselessAssignment: 1035 | Description: Checks for useless assignment to a local variable. 1036 | StyleGuide: https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars 1037 | Enabled: true 1038 | Lint/UselessComparison: 1039 | Description: Checks for comparison of something with itself. 1040 | Enabled: true 1041 | Lint/UselessElseWithoutRescue: 1042 | Description: Checks for useless `else` in `begin..end` without `rescue`. 1043 | Enabled: true 1044 | Lint/UselessSetterCall: 1045 | Description: Checks for useless setter call to a local variable. 1046 | Enabled: true 1047 | Lint/Void: 1048 | Description: Possible use of operator/literal/variable in void context. 1049 | Enabled: false 1050 | Rails/Delegate: 1051 | Description: Prefer delegate method for delegations. 1052 | Enabled: false 1053 | Style/FrozenStringLiteralComment: 1054 | Description: >- 1055 | Add the frozen_string_literal comment to the top of files 1056 | to help transition from Ruby 2.3.0 to Ruby 3.0. 1057 | Enabled: false 1058 | Layout/SpaceBeforeFirstArg: 1059 | Enabled: false 1060 | Style/FormatStringToken: 1061 | Enabled: false 1062 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise 'rails-6.1' do 2 | gem 'rails', '~> 6.1.0' 3 | end 4 | 5 | appraise 'rails-7.0' do 6 | gem 'rails', '~> 7.0.0' 7 | end 8 | 9 | appraise 'rails-7.1' do 10 | gem 'rails', '~> 7.1.0' 11 | end 12 | 13 | appraise 'rails-7.2' do 14 | gem 'rails', '~> 7.2.0' 15 | end 16 | 17 | appraise 'rails-8.0' do 18 | gem 'rails', '~> 8.0.0' 19 | end 20 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | # 11.3.0 4 | - Make table_name configurable https://github.com/ilyakatz/data-migrate/pull/361 5 | - Use lease_connection over deprecated connection for rails 8 https://github.com/ilyakatz/data-migrate/pull/353 6 | - Add Ruby 3.4 to CI matrix 7 | 8 | # 11.2.0 9 | - Remove committed Gemfile.lock, reduce bundled file list when running `gem install` https://github.com/ilyakatz/data-migrate/pull/351 10 | - [Bump actionpack from 7.1.3.4 to 7.1.4.1](https://github.com/ilyakatz/data-migrate/pull/348) 11 | - [Bump rexml from 3.3.6 to 3.3.9](https://github.com/ilyakatz/data-migrate/pull/349) 12 | - Fix db_config_with_versions arity change and backport https://github.com/ilyakatz/data-migrate/pull/337 13 | 14 | # 11.1.0 15 | - Allow multiple data migration paths https://github.com/ilyakatz/data-migrate/pull/331 16 | - Fix db:prepare:with_data task on [Rails 7.2](https://github.com/ilyakatz/data-migrate/pull/339) 17 | - Fix ConnectionPool deprecation warnings on [Rails 7.2](https://github.com/ilyakatz/data-migrate/pull/341) 18 | - Add Rails 8.0 to testing grounds https://github.com/ilyakatz/data-migrate/pull/341 19 | - [Bump webrick from 1.8.1 to 1.8.2](https://github.com/ilyakatz/data-migrate/pull/345) 20 | 21 | # 11.0.0 22 | - [Update rexml to 3.3.6](https://github.com/ilyakatz/data-migrate/pull/329) 23 | - Fixes a bug which ignored migrations on [Rails 7.1 and higher](https://github.com/ilyakatz/data-migrate/pull/326) 24 | 25 | # 11.0.0rc 26 | - Remove Ruby 3.0 from build matrix 27 | - Support Rails 7.2.0 https://github.com/ilyakatz/data-migrate/pull/312 28 | - Update gemfile.lock builds 29 | 30 | ## 9.4.2 31 | - Fix db:prepare:with_data task 32 | 33 | ## 9.4.1 34 | - Add db:prepare task 35 | 36 | ## 9.4.0 37 | - Reset model schema cache before each data migration https://github.com/ilyakatz/data-migrate/pull/307 38 | - Run load_config rake task before db:migrate:with_data https://github.com/ilyakatz/data-migrate/pull/308 39 | 40 | ## 9.3.0 41 | - Improve with_data Rake task for multiple database https://github.com/ilyakatz/data-migrate/pull/296 42 | 43 | ## 9.2.0 44 | - Support Rails 7.1 https://github.com/ilyakatz/data-migrate/pull/278 45 | - Build and test against 7.1.0.rc1 https://github.com/ilyakatz/data-migrate/pull/286 46 | 47 | ## 9.1.0 48 | 49 | - Fix a bug that caused `schema_sha1` in `ar_internal_metadata` to be reset to the `data_schema.rb` file. (#272) 50 | - Remove the need for empty data_schema files for non-primary databases. (#273) 51 | 52 | ## [YANKED] 10.0.3.rc 53 | 54 | - Remove all travis references [leoarnold](https//:github.com/leoarnold) 55 | - Changing to rc because of ongoing discussion how to properly handle multiple database environments 56 | 57 | ## [YANKED] 10.0.2 58 | 59 | Change "rails" dependencies to "railties" 60 | 61 | ## [YANKED] 10.0.1 62 | 63 | - Bug fix for Rails 6 config [chaunce](https//:github.com/chaunce) 64 | - Railties bug fix by [opti](https://github.com/opti) 65 | 66 | ## [YANKED] 10.0.0 67 | 68 | Releasing 10.0.0 69 | 70 | !!! Breaking changes !!! 71 | 72 | - This version introduces a breaking change which may lead to undesired 73 | behavior in multi-database environments. See https://github.com/ilyakatz/data-migrate/issues/181 74 | 75 | ## [YANKED] 10.0.0.rc1 76 | 77 | - Changes by [chaunce](https//:github.com/chaunce) 78 | - Multiple databases support 79 | - Refactor to clean things up 80 | - Deprecate rails 5.2 support for real 81 | 82 | ## 9.0.0 83 | 84 | Ruby 3.2 support [mehanoid](https://github.com/mehanoid) 85 | Rails 5.2 is no longer supported 86 | 87 | ## 8.5.0 88 | 89 | Allow custom templates [bazay](https://github.com/bazay) 90 | 91 | ## 8.4.0 92 | 93 | Avoid Globally Accessible Functions for All Rake Tasks [berniechiu](https://github.com/berniechiu) 94 | 95 | ## 8.3.0 96 | 97 | Add delegation to exists? for use by third parties [foxondo](https://github.com/foxondo) 98 | 99 | ## 8.2.0 100 | 101 | Delegate to anonymous subclass of AR::SchemaMigration [foxondo](https://github.com/foxondo) 102 | 103 | ## 8.1.1 104 | 105 | Revert 8.1.0 changes 106 | 107 | ## 8.1.0 108 | 109 | Avoid globally accessible functions for all rake tasks [berniechiu](https://github.com/berniechiu) 110 | fixed `db:migrate:with_data` to compare data schema versions correctly [cadactive](https://github.com/cadactive) 111 | 112 | ## 8.0.0.rc2 113 | 114 | Bug fixes [gdott9](https://github.com/gdott9) 115 | 116 | ## 8.0.0.rc1 117 | Add support for Rails 7 118 | Removed support for Rails versions below 5.2. Now are supported only versions Rails 5.2 and up 119 | 120 | ## 7.0.2 121 | 122 | Remove magic comment in migration files [y-yagi](https://github.com/y-yagi) 123 | User frozen string [jonnay](https://github.com/jonnay) 124 | ## 7.0.1 125 | Use SchemaMigration.migrations_paths in main rake task [lewhit](https://github.com/lewhit) 126 | 127 | ## 6.8.0 128 | 129 | Specify database name for migrations_paths [lewhit](https://github.com/lewhit) 130 | ## 6.7.0 131 | 132 | Add configuration for which database name is to be used for database migrations [lewhit](https://github.com/lewhit) 133 | Add tests for Rails 6.1 [lewhit](https://github.com/lewhit) 134 | Migrations files should end only in .rb [kroehre](https://github.com/kroehre) 135 | 136 | ## 6.6.2 137 | ## 6.6.1 138 | 139 | configs_for deprecation notice [borama](https://github.com/borama) 140 | ## 6.6.0 141 | 142 | Allow data dump connection to be configured [lewhit](https://github.com/lewhit) 143 | 144 | ## 6.4.0 145 | 146 | Add primary key to data_migrations table [aandis](https://github.com/aandis) 147 | 148 | ## 6.3.0 149 | 150 | Add `abort_if_pending_migrations` rake tasks [tomgia](https://github.com/tomgia) 151 | 152 | ## 6.2.0 153 | 154 | Add `rake data:schema:load` [timkrins](https://github.com/timkrins) 155 | 156 | ## 6.1.0 157 | 158 | Fixing `rake db:schema:load:with_data` for Rails 6 159 | 160 | Note: 161 | 162 | Rails 5.0 is no longer maintained. The gem will still work but it is not being 163 | actively tested. 164 | 165 | ## 6.0.5 166 | 167 | Fixing `needs_migration?` method for Rails 5.2 and up [EnomaDebby](https://github.com/EnomaDebby) 168 | 169 | ## 6.0.4.beta 170 | 171 | Fix rolling back schema migrations failing for Rails 5.2 and above 172 | 173 | ## 6.0.3.beta 174 | 175 | Compatiblity with Rails 6 RC2 [y-yagi](https://github.com/y-yagi) 176 | 177 | ## 6.0.1.beta 178 | 179 | Fix migrations being generated in wrong folder 180 | 181 | ## 6.0.0 182 | 183 | Support for Rails 6 184 | No longer supporting Rails 4.2 185 | 186 | ## 5.3.3 187 | 188 | Ruby 2.2 and 2.3 are no longer actively validated with tests since they are both EOL 189 | 190 | ## 5.3.2 191 | 192 | Fix capistrano migration tasks to only skip migrations if there are no changes in the db/data and db/migrate folders 193 | 194 | ## 5.3.1 195 | 196 | Change database task to use data_migrations_path_configuration 197 | 198 | ## 5.3.0 199 | 200 | Add support to configure data migration path 201 | 202 | ## 5.1.0 203 | 204 | Fixes to `db:schema:load:with_data` + `db:structure:load:with_data` definition, thanks to [craineum](https://github.com/craineum) 205 | 206 | ## 5.0.0 207 | 208 | Remove support for legacy migrations (from v2). 209 | 210 | **IMPORTANT**: If you used this gem from before version 2, make sure to run migration script 211 | 212 | ``` 213 | DataMigrate::LegacyMigrator.new.migrate 214 | ``` 215 | 216 | **Failure to do so may cause re-running old migrations** 217 | 218 | ## 4.0.0 219 | 220 | Support for Rails 5.2 221 | Deprecated support for Rails 4.1 222 | Internal changes to make data-migrate behavior more similar to Rails migrations 223 | 224 | ## 3.5.0 225 | 226 | Deprecated support for rails 4.0 227 | Improvements to timestamped migrations, thanks to [Pierre-Michard](https://github.com/Pierre-Michard) 228 | 229 | ## 3.4.0 230 | 231 | `rake data:migrate:status` to return result in chronological order 232 | 233 | ## 3.3.1 234 | 235 | Regression fix, thanks to [subakva](https://github.com/subakva) 236 | 237 | ## 3.3.0 238 | 239 | The concept of schema:dump to data migrations, thanks to 240 | [tobyndockerill](https://github.com/tobyndockerill) 241 | 242 | ## 3.2.1 243 | 244 | data_migrate table into rails schema dump, thanks to 245 | [jturkel](https://github.com/jturkel) 246 | 247 | ## 3.2.0 248 | 249 | - Add support for Rails 5.1 250 | - No longer testing EOL rubies 251 | 252 | ## 3.1.0 253 | 254 | Rails 5.0 support thanks to 255 | [jturkel](https://github.com/jturkel) and [abreckner](https://github.com/abreckner) 256 | 257 | ## 3.0.1 258 | 259 | ([gacha](https://github.com/gacha)) Capistrano fixes 260 | 261 | ## 3.0.0 262 | 263 | `--skip-schema-migration` removed deprecated. This gem will no longer generate schema 264 | migrations. It still supports running schema/data migrations with one command. 265 | 266 | ## 2.2.0 267 | 268 | ([bilby91](https://github.com/bilby91)) Capistrano support 269 | 270 | ## 2.1.0 271 | 272 | User `Rails.application.config.paths["db/migrate"]` instead of hard coded 273 | path to db migrations 274 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2011 Andrew J Vargo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Data Migrate 2 | 3 | - [![Version](http://img.shields.io/gem/v/data_migrate.svg?style=flat-square)](https://rubygems.org/gems/data_migrate) 4 | - [![License](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](http://opensource.org/licenses/MIT) 5 | - ![.github/workflows/build.yml](https://github.com/ilyakatz/data-migrate/actions/workflows/.github/workflows/build.yml/badge.svg) 6 | - [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) 7 | 8 | Run data migrations alongside schema migrations. 9 | 10 | Data migrations are stored in `db/data`. They act like schema 11 | migrations, except they should be reserved for data migrations. For 12 | instance, if you realize you need to titleize all your titles, this 13 | is the place to do it. 14 | 15 | ![directory tree example](./screenshot.png) 16 | 17 | ## Why should I use this? 18 | 19 | With data-migrate you can generate your migrations for data as you would schema 20 | in your regular work flow. 21 | 22 | For setting tasks that don't require any intermediate AR activity, like 23 | dev and test, you stick with `db:migrate`. For production and QA, you 24 | change their scripts to `db:migrate:with_data`. Of course you want to 25 | test your migration, so you have the choice of `db:migrate:with_data` or 26 | `data:migrate` to just capture that data change. 27 | 28 | ## What does it do? 29 | 30 | Data migrations are stored in `db/data`. They act like schema 31 | migrations, except they should be reserved for data migrations. For 32 | instance, if you realize you need to titleize all yours titles, this 33 | is the place to do it. Running any of the provided rake tasks also 34 | creates a data schema table to mirror the usual schema migrations 35 | table to track all migrations. 36 | 37 | ## Rails Support 38 | 39 | Support Rails 6.1 through 8.0 40 | 41 | For **Rails 6.0** support, please use gem version `9.1.x`: 42 | 43 | ```ruby 44 | gem 'data_migrate', '~> 9.1.0' 45 | ``` 46 | 47 | #### v1 48 | 49 | If you've installed previous to v1.1.0, you'll want to delete the 50 | `create_data_migrations_table` migration. 51 | 52 | ## Installation 53 | 54 | Add the gem to your project 55 | 56 | # Gemfile 57 | gem 'data_migrate' 58 | 59 | Then `bundle install` and you are ready to go. 60 | 61 | So you know, when you use one of the provide rake tasks, a table 62 | called `data_migrations` will be created in your database. This 63 | is to mirror the way the standard `db` rake tasks work. 64 | 65 | ## Usage 66 | 67 | ### Generating Migrations 68 | 69 | You can generate a data migration as you would a schema migration: 70 | 71 | rails g data_migration add_this_to_that 72 | 73 | ### Rake Tasks 74 | 75 | $> rake -T data 76 | rake data:abort_if_pending_migrations # Raises an error if there are pending data migrations 77 | rake data:dump # Create a db/data_schema.rb file that stores the current data version 78 | rake data:forward # Pushes the schema to the next version (specify steps w/ STEP=n) 79 | rake data:migrate # Migrate data migrations (options: VERSION=x, VERBOSE=false) 80 | rake data:migrate:down # Runs the "down" for a given migration VERSION 81 | rake data:migrate:redo # Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x) 82 | rake data:migrate:status # Display status of data migrations 83 | rake data:migrate:up # Runs the "up" for a given migration VERSION 84 | rake data:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n) 85 | rake data:schema:load # Load data_schema.rb file into the database without running the data migrations 86 | rake data:version # Retrieves the current schema version number for data migrations 87 | rake db:abort_if_pending_migrations:with_data # Raises an error if there are pending migrations or data migrations 88 | rake db:forward:with_data # Pushes the schema to the next version (specify steps w/ STEP=n) 89 | rake db:migrate:down:with_data # Runs the "down" for a given migration VERSION 90 | rake db:migrate:redo:with_data # Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x) 91 | rake db:migrate:status:with_data # Display status of data and schema migrations 92 | rake db:migrate:up:with_data # Runs the "up" for a given migration VERSION 93 | rake db:migrate:with_data # Migrate the database data and schema (options: VERSION=x, VERBOSE=false) 94 | rake db:prepare:with_data # Runs setup if database does not exist, or runs data and schema migrations if it does 95 | rake db:rollback:with_data # Rolls the schema back to the previous version (specify steps w/ STEP=n) 96 | rake db:schema:load:with_data # Load both schema.rb and data_schema.rb file into the database 97 | rake db:structure:load:with_data # Load both structure.sql and data_schema.rb file into the database 98 | rake db:version:with_data # Retrieves the current schema version numbers for data and schema migrations 99 | 100 | 101 | Tasks work as they would with the 'vanilla' db version. The 'with_data' addition to the 'db' tasks will run the task in the context of both the data and schema migrations. That is, rake db:rollback:with_data will check to see if it was a schema or data migration invoked last, and do that. Tasks invoked in that space also have an additional line of output, indicating if the action is performed on data or schema. 102 | 103 | With 'up' and 'down', you can specify the option 'BOTH', which defaults to false. Using true, will migrate both the data and schema (in the desired direction) if they both match the version provided. Again, going up, schema is given precedence. Down its data. 104 | 105 | When using `rake db:migrate:with_data` migrations will be run in ascending order by their version. For example, if you have a data migration with version 20230410000000 and a schema migration with version 20230415000000, expect the data migration to run first. 106 | 107 | `rake db:migrate:status:with_data` provides an additional column to indicate which type of migration. 108 | 109 | ### Configuration 110 | 111 | `data_migrate` respects `ActiveRecord::Base.dump_schema_after_migration`. If it is set to `false`, data schema file will not be generated 112 | 113 | By default, data migrations are added to the `db/data/` path. 114 | You can override this setting in `config/initializers/data_migrate.rb` 115 | 116 | ```ruby 117 | DataMigrate.configure do |config| 118 | config.data_migrations_table_name = 'my_migrations_database_name' 119 | config.data_migrations_path = 'db/awesomepath/' 120 | config.data_template_path = Rails.root.join("lib", "awesomepath", "custom_data_migration.rb") 121 | config.db_configuration = { 122 | 'host' => '127.0.0.1', 123 | 'database' => 'awesome_database', 124 | 'adapter' => 'mysql2', 125 | 'username' => 'root', 126 | 'password' => nil, 127 | } 128 | config.spec_name = 'primary' 129 | end 130 | 131 | ``` 132 | 133 | ## Capistrano Support 134 | 135 | The gem comes with a capistrano task that can be used instead of `capistrano/rails/migrations`. 136 | 137 | Just add this line to your Capfile: 138 | 139 | ```ruby 140 | require 'capistrano/data_migrate' 141 | ``` 142 | 143 | From now on capistrano will run `rake db:migrate:with_data` in every deploy. 144 | 145 | ## Rails Engines support 146 | 147 | This gem also has a initial support for adding data migrations inside Rails engines. 148 | Just add your engines directory pattern to data_migrations initializer, for example 149 | in the case your engines are located in `engines` folder you can set it up like this: 150 | 151 | ```ruby 152 | DataMigrate.configure do |config| 153 | config.data_migrations_path = ['db/data'] + Dir['engines/**/db/data'] 154 | end 155 | ``` 156 | 157 | Then, in the Engine's `db/data` folder, you can add data migrations and run them as usual. 158 | 159 | ### Contributing 160 | 161 | ## Testing 162 | 163 | Run tests for a specific version of Rails 164 | 165 | ``` 166 | bundle exec appraisal rails-6.1 rspec 167 | bundle exec appraisal rails-7.0 rspec 168 | bundle exec appraisal rails-7.1 rspec 169 | bundle exec appraisal rails-7.2 rspec 170 | bundle exec appraisal rails-8.0 rspec 171 | ``` 172 | 173 | ## Releasing new version 174 | 175 | 1. Update version.rb file, run `bundle exec appraisal` to update the version in corresponding gemfile.lock 176 | 2. Create a new tag, eg `git tag 9.4.1` 177 | 3. Go to https://github.com/ilyakatz/data-migrate/tags 178 | 4. Click "Create release" under 9.4.1 179 | 5. CLick "Generate release notes" 180 | 6. Click "Publish release" 181 | 182 | ## Thanks 183 | 184 | [Andrew J Vargo](http://github.com/ajvargo) Andrew was the original creator and maintainer of this project! 185 | 186 | [Jeremy Durham](http://jeremydurham.com/) for fleshing out the idea and providing guidance. 187 | 188 | You! Yes, you. Thanks for checking it out. 189 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | Bundler::GemHelper.install_tasks 3 | -------------------------------------------------------------------------------- /data_migrate.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "data_migrate/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "data_migrate" 7 | s.version = DataMigrate::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["Andrew J Vargo", "Ilya Katz", "Deborah Enomah"] 10 | s.email = ["ajvargo@computer.org", "ilyakatz@gmail.com", "enomaomorogieva@gmail.com"] 11 | s.homepage = "https://github.com/ilyakatz/data-migrate" 12 | s.summary = %q{Rake tasks to migrate data alongside schema changes.} 13 | s.description = %q{Rake tasks to migrate data alongside schema changes.} 14 | s.license = "MIT" 15 | 16 | s.rubyforge_project = "data_migrate" 17 | 18 | s.files = Dir["{lib,tasks}/**/*", "Changelog.md", "LICENSE", "README.md"] 19 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 20 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 21 | s.require_paths = ["lib"] 22 | 23 | %w[ 24 | activerecord 25 | railties 26 | ].each do |rails_gem| 27 | s.add_dependency(rails_gem, '>= 6.1') 28 | end 29 | 30 | s.add_development_dependency "appraisal" 31 | s.add_development_dependency "rake" 32 | s.add_development_dependency "rspec" 33 | s.add_development_dependency "rspec-core" 34 | s.add_development_dependency "pry" 35 | s.add_development_dependency "rb-readline" 36 | s.add_development_dependency "sqlite3" 37 | s.add_development_dependency "timecop" 38 | s.add_development_dependency "rubocop" 39 | s.add_development_dependency "overcommit" 40 | end 41 | -------------------------------------------------------------------------------- /gemfiles/rails_6.1.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 6.1.0" 6 | 7 | gemspec path: "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_6.1.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | data_migrate (11.3.0) 5 | activerecord (>= 6.1) 6 | railties (>= 6.1) 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actioncable (6.1.7.8) 12 | actionpack (= 6.1.7.8) 13 | activesupport (= 6.1.7.8) 14 | nio4r (~> 2.0) 15 | websocket-driver (>= 0.6.1) 16 | actionmailbox (6.1.7.8) 17 | actionpack (= 6.1.7.8) 18 | activejob (= 6.1.7.8) 19 | activerecord (= 6.1.7.8) 20 | activestorage (= 6.1.7.8) 21 | activesupport (= 6.1.7.8) 22 | mail (>= 2.7.1) 23 | actionmailer (6.1.7.8) 24 | actionpack (= 6.1.7.8) 25 | actionview (= 6.1.7.8) 26 | activejob (= 6.1.7.8) 27 | activesupport (= 6.1.7.8) 28 | mail (~> 2.5, >= 2.5.4) 29 | rails-dom-testing (~> 2.0) 30 | actionpack (6.1.7.8) 31 | actionview (= 6.1.7.8) 32 | activesupport (= 6.1.7.8) 33 | rack (~> 2.0, >= 2.0.9) 34 | rack-test (>= 0.6.3) 35 | rails-dom-testing (~> 2.0) 36 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 37 | actiontext (6.1.7.8) 38 | actionpack (= 6.1.7.8) 39 | activerecord (= 6.1.7.8) 40 | activestorage (= 6.1.7.8) 41 | activesupport (= 6.1.7.8) 42 | nokogiri (>= 1.8.5) 43 | actionview (6.1.7.8) 44 | activesupport (= 6.1.7.8) 45 | builder (~> 3.1) 46 | erubi (~> 1.4) 47 | rails-dom-testing (~> 2.0) 48 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 49 | activejob (6.1.7.8) 50 | activesupport (= 6.1.7.8) 51 | globalid (>= 0.3.6) 52 | activemodel (6.1.7.8) 53 | activesupport (= 6.1.7.8) 54 | activerecord (6.1.7.8) 55 | activemodel (= 6.1.7.8) 56 | activesupport (= 6.1.7.8) 57 | activestorage (6.1.7.8) 58 | actionpack (= 6.1.7.8) 59 | activejob (= 6.1.7.8) 60 | activerecord (= 6.1.7.8) 61 | activesupport (= 6.1.7.8) 62 | marcel (~> 1.0) 63 | mini_mime (>= 1.1.0) 64 | activesupport (6.1.7.8) 65 | concurrent-ruby (~> 1.0, >= 1.0.2) 66 | i18n (>= 1.6, < 2) 67 | minitest (>= 5.1) 68 | tzinfo (~> 2.0) 69 | zeitwerk (~> 2.3) 70 | appraisal (2.4.1) 71 | bundler 72 | rake 73 | thor (>= 0.14.0) 74 | ast (2.4.2) 75 | builder (3.3.0) 76 | childprocess (4.1.0) 77 | coderay (1.1.3) 78 | concurrent-ruby (1.3.4) 79 | crass (1.0.6) 80 | date (3.3.4) 81 | diff-lcs (1.5.0) 82 | erubi (1.13.0) 83 | globalid (1.2.1) 84 | activesupport (>= 6.1) 85 | i18n (1.14.5) 86 | concurrent-ruby (~> 1.0) 87 | iniparse (1.5.0) 88 | json (2.6.3) 89 | loofah (2.22.0) 90 | crass (~> 1.0.2) 91 | nokogiri (>= 1.12.0) 92 | mail (2.8.1) 93 | mini_mime (>= 0.1.1) 94 | net-imap 95 | net-pop 96 | net-smtp 97 | marcel (1.0.4) 98 | method_source (1.1.0) 99 | mini_mime (1.1.5) 100 | minitest (5.25.1) 101 | net-imap (0.4.14) 102 | date 103 | net-protocol 104 | net-pop (0.1.2) 105 | net-protocol 106 | net-protocol (0.2.2) 107 | timeout 108 | net-smtp (0.5.0) 109 | net-protocol 110 | nio4r (2.7.3) 111 | nokogiri (1.16.7-aarch64-linux) 112 | racc (~> 1.4) 113 | nokogiri (1.16.7-arm64-darwin) 114 | racc (~> 1.4) 115 | nokogiri (1.16.7-x86_64-darwin) 116 | racc (~> 1.4) 117 | nokogiri (1.16.7-x86_64-linux) 118 | racc (~> 1.4) 119 | overcommit (0.60.0) 120 | childprocess (>= 0.6.3, < 5) 121 | iniparse (~> 1.4) 122 | rexml (~> 3.2) 123 | parallel (1.23.0) 124 | parser (3.2.2.3) 125 | ast (~> 2.4.1) 126 | racc 127 | pry (0.14.2) 128 | coderay (~> 1.1) 129 | method_source (~> 1.0) 130 | racc (1.8.1) 131 | rack (2.2.9) 132 | rack-test (2.1.0) 133 | rack (>= 1.3) 134 | rails (6.1.7.8) 135 | actioncable (= 6.1.7.8) 136 | actionmailbox (= 6.1.7.8) 137 | actionmailer (= 6.1.7.8) 138 | actionpack (= 6.1.7.8) 139 | actiontext (= 6.1.7.8) 140 | actionview (= 6.1.7.8) 141 | activejob (= 6.1.7.8) 142 | activemodel (= 6.1.7.8) 143 | activerecord (= 6.1.7.8) 144 | activestorage (= 6.1.7.8) 145 | activesupport (= 6.1.7.8) 146 | bundler (>= 1.15.0) 147 | railties (= 6.1.7.8) 148 | sprockets-rails (>= 2.0.0) 149 | rails-dom-testing (2.2.0) 150 | activesupport (>= 5.0.0) 151 | minitest 152 | nokogiri (>= 1.6) 153 | rails-html-sanitizer (1.6.0) 154 | loofah (~> 2.21) 155 | nokogiri (~> 1.14) 156 | railties (6.1.7.8) 157 | actionpack (= 6.1.7.8) 158 | activesupport (= 6.1.7.8) 159 | method_source 160 | rake (>= 12.2) 161 | thor (~> 1.0) 162 | rainbow (3.1.1) 163 | rake (13.2.1) 164 | rb-readline (0.5.5) 165 | regexp_parser (2.8.1) 166 | rexml (3.2.5) 167 | rspec (3.12.0) 168 | rspec-core (~> 3.12.0) 169 | rspec-expectations (~> 3.12.0) 170 | rspec-mocks (~> 3.12.0) 171 | rspec-core (3.12.2) 172 | rspec-support (~> 3.12.0) 173 | rspec-expectations (3.12.3) 174 | diff-lcs (>= 1.2.0, < 2.0) 175 | rspec-support (~> 3.12.0) 176 | rspec-mocks (3.12.5) 177 | diff-lcs (>= 1.2.0, < 2.0) 178 | rspec-support (~> 3.12.0) 179 | rspec-support (3.12.0) 180 | rubocop (1.52.1) 181 | json (~> 2.3) 182 | parallel (~> 1.10) 183 | parser (>= 3.2.2.3) 184 | rainbow (>= 2.2.2, < 4.0) 185 | regexp_parser (>= 1.8, < 3.0) 186 | rexml (>= 3.2.5, < 4.0) 187 | rubocop-ast (>= 1.28.0, < 2.0) 188 | ruby-progressbar (~> 1.7) 189 | unicode-display_width (>= 2.4.0, < 3.0) 190 | rubocop-ast (1.29.0) 191 | parser (>= 3.2.1.0) 192 | ruby-progressbar (1.13.0) 193 | sprockets (4.2.1) 194 | concurrent-ruby (~> 1.0) 195 | rack (>= 2.2.4, < 4) 196 | sprockets-rails (3.5.2) 197 | actionpack (>= 6.1) 198 | activesupport (>= 6.1) 199 | sprockets (>= 3.0.0) 200 | sqlite3 (1.7.2-aarch64-linux) 201 | sqlite3 (1.7.2-arm64-darwin) 202 | sqlite3 (1.7.2-x86_64-darwin) 203 | sqlite3 (1.7.2-x86_64-linux) 204 | thor (1.3.1) 205 | timecop (0.9.6) 206 | timeout (0.4.1) 207 | tzinfo (2.0.6) 208 | concurrent-ruby (~> 1.0) 209 | unicode-display_width (2.4.2) 210 | websocket-driver (0.7.6) 211 | websocket-extensions (>= 0.1.0) 212 | websocket-extensions (0.1.5) 213 | zeitwerk (2.6.17) 214 | 215 | PLATFORMS 216 | aarch64-linux 217 | arm64-darwin-22 218 | arm64-darwin-23 219 | x86_64-darwin-22 220 | x86_64-linux 221 | 222 | DEPENDENCIES 223 | appraisal 224 | data_migrate! 225 | overcommit 226 | pry 227 | rails (~> 6.1.0) 228 | rake 229 | rb-readline 230 | rspec 231 | rspec-core 232 | rubocop 233 | sqlite3 234 | timecop 235 | 236 | BUNDLED WITH 237 | 2.5.6 238 | -------------------------------------------------------------------------------- /gemfiles/rails_7.0.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 7.0.0" 6 | 7 | gemspec path: "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_7.0.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | data_migrate (11.3.0) 5 | activerecord (>= 6.1) 6 | railties (>= 6.1) 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actioncable (7.0.8.4) 12 | actionpack (= 7.0.8.4) 13 | activesupport (= 7.0.8.4) 14 | nio4r (~> 2.0) 15 | websocket-driver (>= 0.6.1) 16 | actionmailbox (7.0.8.4) 17 | actionpack (= 7.0.8.4) 18 | activejob (= 7.0.8.4) 19 | activerecord (= 7.0.8.4) 20 | activestorage (= 7.0.8.4) 21 | activesupport (= 7.0.8.4) 22 | mail (>= 2.7.1) 23 | net-imap 24 | net-pop 25 | net-smtp 26 | actionmailer (7.0.8.4) 27 | actionpack (= 7.0.8.4) 28 | actionview (= 7.0.8.4) 29 | activejob (= 7.0.8.4) 30 | activesupport (= 7.0.8.4) 31 | mail (~> 2.5, >= 2.5.4) 32 | net-imap 33 | net-pop 34 | net-smtp 35 | rails-dom-testing (~> 2.0) 36 | actionpack (7.0.8.4) 37 | actionview (= 7.0.8.4) 38 | activesupport (= 7.0.8.4) 39 | rack (~> 2.0, >= 2.2.4) 40 | rack-test (>= 0.6.3) 41 | rails-dom-testing (~> 2.0) 42 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 43 | actiontext (7.0.8.4) 44 | actionpack (= 7.0.8.4) 45 | activerecord (= 7.0.8.4) 46 | activestorage (= 7.0.8.4) 47 | activesupport (= 7.0.8.4) 48 | globalid (>= 0.6.0) 49 | nokogiri (>= 1.8.5) 50 | actionview (7.0.8.4) 51 | activesupport (= 7.0.8.4) 52 | builder (~> 3.1) 53 | erubi (~> 1.4) 54 | rails-dom-testing (~> 2.0) 55 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 56 | activejob (7.0.8.4) 57 | activesupport (= 7.0.8.4) 58 | globalid (>= 0.3.6) 59 | activemodel (7.0.8.4) 60 | activesupport (= 7.0.8.4) 61 | activerecord (7.0.8.4) 62 | activemodel (= 7.0.8.4) 63 | activesupport (= 7.0.8.4) 64 | activestorage (7.0.8.4) 65 | actionpack (= 7.0.8.4) 66 | activejob (= 7.0.8.4) 67 | activerecord (= 7.0.8.4) 68 | activesupport (= 7.0.8.4) 69 | marcel (~> 1.0) 70 | mini_mime (>= 1.1.0) 71 | activesupport (7.0.8.4) 72 | concurrent-ruby (~> 1.0, >= 1.0.2) 73 | i18n (>= 1.6, < 2) 74 | minitest (>= 5.1) 75 | tzinfo (~> 2.0) 76 | appraisal (2.4.1) 77 | bundler 78 | rake 79 | thor (>= 0.14.0) 80 | ast (2.4.2) 81 | builder (3.3.0) 82 | childprocess (4.1.0) 83 | coderay (1.1.3) 84 | concurrent-ruby (1.3.4) 85 | crass (1.0.6) 86 | date (3.3.4) 87 | diff-lcs (1.5.0) 88 | erubi (1.13.0) 89 | globalid (1.2.1) 90 | activesupport (>= 6.1) 91 | i18n (1.14.5) 92 | concurrent-ruby (~> 1.0) 93 | iniparse (1.5.0) 94 | json (2.6.3) 95 | language_server-protocol (3.17.0.3) 96 | loofah (2.22.0) 97 | crass (~> 1.0.2) 98 | nokogiri (>= 1.12.0) 99 | mail (2.8.1) 100 | mini_mime (>= 0.1.1) 101 | net-imap 102 | net-pop 103 | net-smtp 104 | marcel (1.0.4) 105 | method_source (1.1.0) 106 | mini_mime (1.1.5) 107 | minitest (5.25.1) 108 | net-imap (0.4.14) 109 | date 110 | net-protocol 111 | net-pop (0.1.2) 112 | net-protocol 113 | net-protocol (0.2.2) 114 | timeout 115 | net-smtp (0.5.0) 116 | net-protocol 117 | nio4r (2.7.3) 118 | nokogiri (1.16.7-aarch64-linux) 119 | racc (~> 1.4) 120 | nokogiri (1.16.7-arm64-darwin) 121 | racc (~> 1.4) 122 | nokogiri (1.16.7-x86_64-darwin) 123 | racc (~> 1.4) 124 | nokogiri (1.16.7-x86_64-linux) 125 | racc (~> 1.4) 126 | overcommit (0.60.0) 127 | childprocess (>= 0.6.3, < 5) 128 | iniparse (~> 1.4) 129 | rexml (~> 3.2) 130 | parallel (1.23.0) 131 | parser (3.2.2.3) 132 | ast (~> 2.4.1) 133 | racc 134 | pry (0.14.2) 135 | coderay (~> 1.1) 136 | method_source (~> 1.0) 137 | racc (1.8.1) 138 | rack (2.2.9) 139 | rack-test (2.1.0) 140 | rack (>= 1.3) 141 | rails (7.0.8.4) 142 | actioncable (= 7.0.8.4) 143 | actionmailbox (= 7.0.8.4) 144 | actionmailer (= 7.0.8.4) 145 | actionpack (= 7.0.8.4) 146 | actiontext (= 7.0.8.4) 147 | actionview (= 7.0.8.4) 148 | activejob (= 7.0.8.4) 149 | activemodel (= 7.0.8.4) 150 | activerecord (= 7.0.8.4) 151 | activestorage (= 7.0.8.4) 152 | activesupport (= 7.0.8.4) 153 | bundler (>= 1.15.0) 154 | railties (= 7.0.8.4) 155 | rails-dom-testing (2.2.0) 156 | activesupport (>= 5.0.0) 157 | minitest 158 | nokogiri (>= 1.6) 159 | rails-html-sanitizer (1.6.0) 160 | loofah (~> 2.21) 161 | nokogiri (~> 1.14) 162 | railties (7.0.8.4) 163 | actionpack (= 7.0.8.4) 164 | activesupport (= 7.0.8.4) 165 | method_source 166 | rake (>= 12.2) 167 | thor (~> 1.0) 168 | zeitwerk (~> 2.5) 169 | rainbow (3.1.1) 170 | rake (13.2.1) 171 | rb-readline (0.5.5) 172 | regexp_parser (2.8.1) 173 | rexml (3.2.5) 174 | rspec (3.12.0) 175 | rspec-core (~> 3.12.0) 176 | rspec-expectations (~> 3.12.0) 177 | rspec-mocks (~> 3.12.0) 178 | rspec-core (3.12.2) 179 | rspec-support (~> 3.12.0) 180 | rspec-expectations (3.12.3) 181 | diff-lcs (>= 1.2.0, < 2.0) 182 | rspec-support (~> 3.12.0) 183 | rspec-mocks (3.12.5) 184 | diff-lcs (>= 1.2.0, < 2.0) 185 | rspec-support (~> 3.12.0) 186 | rspec-support (3.12.1) 187 | rubocop (1.54.1) 188 | json (~> 2.3) 189 | language_server-protocol (>= 3.17.0) 190 | parallel (~> 1.10) 191 | parser (>= 3.2.2.3) 192 | rainbow (>= 2.2.2, < 4.0) 193 | regexp_parser (>= 1.8, < 3.0) 194 | rexml (>= 3.2.5, < 4.0) 195 | rubocop-ast (>= 1.28.0, < 2.0) 196 | ruby-progressbar (~> 1.7) 197 | unicode-display_width (>= 2.4.0, < 3.0) 198 | rubocop-ast (1.29.0) 199 | parser (>= 3.2.1.0) 200 | ruby-progressbar (1.13.0) 201 | sqlite3 (1.7.2-aarch64-linux) 202 | sqlite3 (1.7.2-arm64-darwin) 203 | sqlite3 (1.7.2-x86_64-darwin) 204 | sqlite3 (1.7.2-x86_64-linux) 205 | thor (1.3.1) 206 | timecop (0.9.6) 207 | timeout (0.4.1) 208 | tzinfo (2.0.6) 209 | concurrent-ruby (~> 1.0) 210 | unicode-display_width (2.4.2) 211 | websocket-driver (0.7.6) 212 | websocket-extensions (>= 0.1.0) 213 | websocket-extensions (0.1.5) 214 | zeitwerk (2.6.17) 215 | 216 | PLATFORMS 217 | aarch64-linux 218 | arm64-darwin-22 219 | arm64-darwin-23 220 | x86_64-darwin-22 221 | x86_64-linux 222 | 223 | DEPENDENCIES 224 | appraisal 225 | data_migrate! 226 | overcommit 227 | pry 228 | rails (~> 7.0.0) 229 | rake 230 | rb-readline 231 | rspec 232 | rspec-core 233 | rubocop 234 | sqlite3 235 | timecop 236 | 237 | BUNDLED WITH 238 | 2.5.6 239 | -------------------------------------------------------------------------------- /gemfiles/rails_7.1.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 7.1.0" 6 | 7 | gemspec path: "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_7.1.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | data_migrate (11.3.0) 5 | activerecord (>= 6.1) 6 | railties (>= 6.1) 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actioncable (7.1.3.4) 12 | actionpack (= 7.1.3.4) 13 | activesupport (= 7.1.3.4) 14 | nio4r (~> 2.0) 15 | websocket-driver (>= 0.6.1) 16 | zeitwerk (~> 2.6) 17 | actionmailbox (7.1.3.4) 18 | actionpack (= 7.1.3.4) 19 | activejob (= 7.1.3.4) 20 | activerecord (= 7.1.3.4) 21 | activestorage (= 7.1.3.4) 22 | activesupport (= 7.1.3.4) 23 | mail (>= 2.7.1) 24 | net-imap 25 | net-pop 26 | net-smtp 27 | actionmailer (7.1.3.4) 28 | actionpack (= 7.1.3.4) 29 | actionview (= 7.1.3.4) 30 | activejob (= 7.1.3.4) 31 | activesupport (= 7.1.3.4) 32 | mail (~> 2.5, >= 2.5.4) 33 | net-imap 34 | net-pop 35 | net-smtp 36 | rails-dom-testing (~> 2.2) 37 | actionpack (7.1.3.4) 38 | actionview (= 7.1.3.4) 39 | activesupport (= 7.1.3.4) 40 | nokogiri (>= 1.8.5) 41 | racc 42 | rack (>= 2.2.4) 43 | rack-session (>= 1.0.1) 44 | rack-test (>= 0.6.3) 45 | rails-dom-testing (~> 2.2) 46 | rails-html-sanitizer (~> 1.6) 47 | actiontext (7.1.3.4) 48 | actionpack (= 7.1.3.4) 49 | activerecord (= 7.1.3.4) 50 | activestorage (= 7.1.3.4) 51 | activesupport (= 7.1.3.4) 52 | globalid (>= 0.6.0) 53 | nokogiri (>= 1.8.5) 54 | actionview (7.1.3.4) 55 | activesupport (= 7.1.3.4) 56 | builder (~> 3.1) 57 | erubi (~> 1.11) 58 | rails-dom-testing (~> 2.2) 59 | rails-html-sanitizer (~> 1.6) 60 | activejob (7.1.3.4) 61 | activesupport (= 7.1.3.4) 62 | globalid (>= 0.3.6) 63 | activemodel (7.1.3.4) 64 | activesupport (= 7.1.3.4) 65 | activerecord (7.1.3.4) 66 | activemodel (= 7.1.3.4) 67 | activesupport (= 7.1.3.4) 68 | timeout (>= 0.4.0) 69 | activestorage (7.1.3.4) 70 | actionpack (= 7.1.3.4) 71 | activejob (= 7.1.3.4) 72 | activerecord (= 7.1.3.4) 73 | activesupport (= 7.1.3.4) 74 | marcel (~> 1.0) 75 | activesupport (7.1.3.4) 76 | base64 77 | bigdecimal 78 | concurrent-ruby (~> 1.0, >= 1.0.2) 79 | connection_pool (>= 2.2.5) 80 | drb 81 | i18n (>= 1.6, < 2) 82 | minitest (>= 5.1) 83 | mutex_m 84 | tzinfo (~> 2.0) 85 | appraisal (2.5.0) 86 | bundler 87 | rake 88 | thor (>= 0.14.0) 89 | ast (2.4.2) 90 | base64 (0.2.0) 91 | bigdecimal (3.1.8) 92 | builder (3.3.0) 93 | childprocess (4.1.0) 94 | coderay (1.1.3) 95 | concurrent-ruby (1.3.4) 96 | connection_pool (2.4.1) 97 | crass (1.0.6) 98 | date (3.3.4) 99 | diff-lcs (1.5.0) 100 | drb (2.2.1) 101 | erubi (1.13.0) 102 | globalid (1.2.1) 103 | activesupport (>= 6.1) 104 | i18n (1.14.5) 105 | concurrent-ruby (~> 1.0) 106 | iniparse (1.5.0) 107 | io-console (0.7.2) 108 | irb (1.14.0) 109 | rdoc (>= 4.0.0) 110 | reline (>= 0.4.2) 111 | json (2.6.3) 112 | language_server-protocol (3.17.0.3) 113 | loofah (2.22.0) 114 | crass (~> 1.0.2) 115 | nokogiri (>= 1.12.0) 116 | mail (2.8.1) 117 | mini_mime (>= 0.1.1) 118 | net-imap 119 | net-pop 120 | net-smtp 121 | marcel (1.0.4) 122 | method_source (1.0.0) 123 | mini_mime (1.1.5) 124 | mini_portile2 (2.8.7) 125 | minitest (5.25.1) 126 | mutex_m (0.2.0) 127 | net-imap (0.4.14) 128 | date 129 | net-protocol 130 | net-pop (0.1.2) 131 | net-protocol 132 | net-protocol (0.2.2) 133 | timeout 134 | net-smtp (0.5.0) 135 | net-protocol 136 | nio4r (2.7.3) 137 | nokogiri (1.16.7) 138 | mini_portile2 (~> 2.8.2) 139 | racc (~> 1.4) 140 | nokogiri (1.16.7-aarch64-linux) 141 | racc (~> 1.4) 142 | nokogiri (1.16.7-arm64-darwin) 143 | racc (~> 1.4) 144 | nokogiri (1.16.7-x86_64-darwin) 145 | racc (~> 1.4) 146 | nokogiri (1.16.7-x86_64-linux) 147 | racc (~> 1.4) 148 | overcommit (0.60.0) 149 | childprocess (>= 0.6.3, < 5) 150 | iniparse (~> 1.4) 151 | rexml (~> 3.2) 152 | parallel (1.23.0) 153 | parser (3.2.2.3) 154 | ast (~> 2.4.1) 155 | racc 156 | pry (0.14.2) 157 | coderay (~> 1.1) 158 | method_source (~> 1.0) 159 | psych (5.1.2) 160 | stringio 161 | racc (1.8.1) 162 | rack (3.1.7) 163 | rack-session (2.0.0) 164 | rack (>= 3.0.0) 165 | rack-test (2.1.0) 166 | rack (>= 1.3) 167 | rackup (2.1.0) 168 | rack (>= 3) 169 | webrick (~> 1.8) 170 | rails (7.1.3.4) 171 | actioncable (= 7.1.3.4) 172 | actionmailbox (= 7.1.3.4) 173 | actionmailer (= 7.1.3.4) 174 | actionpack (= 7.1.3.4) 175 | actiontext (= 7.1.3.4) 176 | actionview (= 7.1.3.4) 177 | activejob (= 7.1.3.4) 178 | activemodel (= 7.1.3.4) 179 | activerecord (= 7.1.3.4) 180 | activestorage (= 7.1.3.4) 181 | activesupport (= 7.1.3.4) 182 | bundler (>= 1.15.0) 183 | railties (= 7.1.3.4) 184 | rails-dom-testing (2.2.0) 185 | activesupport (>= 5.0.0) 186 | minitest 187 | nokogiri (>= 1.6) 188 | rails-html-sanitizer (1.6.0) 189 | loofah (~> 2.21) 190 | nokogiri (~> 1.14) 191 | railties (7.1.3.4) 192 | actionpack (= 7.1.3.4) 193 | activesupport (= 7.1.3.4) 194 | irb 195 | rackup (>= 1.0.0) 196 | rake (>= 12.2) 197 | thor (~> 1.0, >= 1.2.2) 198 | zeitwerk (~> 2.6) 199 | rainbow (3.1.1) 200 | rake (13.2.1) 201 | rb-readline (0.5.5) 202 | rdoc (6.7.0) 203 | psych (>= 4.0.0) 204 | regexp_parser (2.8.1) 205 | reline (0.5.9) 206 | io-console (~> 0.5) 207 | rexml (3.2.5) 208 | rspec (3.12.0) 209 | rspec-core (~> 3.12.0) 210 | rspec-expectations (~> 3.12.0) 211 | rspec-mocks (~> 3.12.0) 212 | rspec-core (3.12.2) 213 | rspec-support (~> 3.12.0) 214 | rspec-expectations (3.12.3) 215 | diff-lcs (>= 1.2.0, < 2.0) 216 | rspec-support (~> 3.12.0) 217 | rspec-mocks (3.12.6) 218 | diff-lcs (>= 1.2.0, < 2.0) 219 | rspec-support (~> 3.12.0) 220 | rspec-support (3.12.1) 221 | rubocop (1.54.2) 222 | json (~> 2.3) 223 | language_server-protocol (>= 3.17.0) 224 | parallel (~> 1.10) 225 | parser (>= 3.2.2.3) 226 | rainbow (>= 2.2.2, < 4.0) 227 | regexp_parser (>= 1.8, < 3.0) 228 | rexml (>= 3.2.5, < 4.0) 229 | rubocop-ast (>= 1.28.0, < 2.0) 230 | ruby-progressbar (~> 1.7) 231 | unicode-display_width (>= 2.4.0, < 3.0) 232 | rubocop-ast (1.29.0) 233 | parser (>= 3.2.1.0) 234 | ruby-progressbar (1.13.0) 235 | sqlite3 (1.7.2) 236 | mini_portile2 (~> 2.8.0) 237 | sqlite3 (1.7.2-aarch64-linux) 238 | sqlite3 (1.7.2-arm64-darwin) 239 | sqlite3 (1.7.2-x86_64-darwin) 240 | sqlite3 (1.7.2-x86_64-linux) 241 | stringio (3.1.1) 242 | thor (1.3.1) 243 | timecop (0.9.6) 244 | timeout (0.4.1) 245 | tzinfo (2.0.6) 246 | concurrent-ruby (~> 1.0) 247 | unicode-display_width (2.4.2) 248 | webrick (1.8.1) 249 | websocket-driver (0.7.6) 250 | websocket-extensions (>= 0.1.0) 251 | websocket-extensions (0.1.5) 252 | zeitwerk (2.6.17) 253 | 254 | PLATFORMS 255 | aarch64-linux 256 | arm64-darwin-22 257 | arm64-darwin-23 258 | ruby 259 | x86_64-darwin-22 260 | x86_64-linux 261 | 262 | DEPENDENCIES 263 | appraisal 264 | data_migrate! 265 | overcommit 266 | pry 267 | rails (~> 7.1.0) 268 | rake 269 | rb-readline 270 | rspec 271 | rspec-core 272 | rubocop 273 | sqlite3 274 | timecop 275 | 276 | BUNDLED WITH 277 | 2.4.17 278 | -------------------------------------------------------------------------------- /gemfiles/rails_7.2.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 7.2.0" 6 | 7 | gemspec path: "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_7.2.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | data_migrate (11.3.0) 5 | activerecord (>= 6.1) 6 | railties (>= 6.1) 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actioncable (7.2.0) 12 | actionpack (= 7.2.0) 13 | activesupport (= 7.2.0) 14 | nio4r (~> 2.0) 15 | websocket-driver (>= 0.6.1) 16 | zeitwerk (~> 2.6) 17 | actionmailbox (7.2.0) 18 | actionpack (= 7.2.0) 19 | activejob (= 7.2.0) 20 | activerecord (= 7.2.0) 21 | activestorage (= 7.2.0) 22 | activesupport (= 7.2.0) 23 | mail (>= 2.8.0) 24 | actionmailer (7.2.0) 25 | actionpack (= 7.2.0) 26 | actionview (= 7.2.0) 27 | activejob (= 7.2.0) 28 | activesupport (= 7.2.0) 29 | mail (>= 2.8.0) 30 | rails-dom-testing (~> 2.2) 31 | actionpack (7.2.0) 32 | actionview (= 7.2.0) 33 | activesupport (= 7.2.0) 34 | nokogiri (>= 1.8.5) 35 | racc 36 | rack (>= 2.2.4, < 3.2) 37 | rack-session (>= 1.0.1) 38 | rack-test (>= 0.6.3) 39 | rails-dom-testing (~> 2.2) 40 | rails-html-sanitizer (~> 1.6) 41 | useragent (~> 0.16) 42 | actiontext (7.2.0) 43 | actionpack (= 7.2.0) 44 | activerecord (= 7.2.0) 45 | activestorage (= 7.2.0) 46 | activesupport (= 7.2.0) 47 | globalid (>= 0.6.0) 48 | nokogiri (>= 1.8.5) 49 | actionview (7.2.0) 50 | activesupport (= 7.2.0) 51 | builder (~> 3.1) 52 | erubi (~> 1.11) 53 | rails-dom-testing (~> 2.2) 54 | rails-html-sanitizer (~> 1.6) 55 | activejob (7.2.0) 56 | activesupport (= 7.2.0) 57 | globalid (>= 0.3.6) 58 | activemodel (7.2.0) 59 | activesupport (= 7.2.0) 60 | activerecord (7.2.0) 61 | activemodel (= 7.2.0) 62 | activesupport (= 7.2.0) 63 | timeout (>= 0.4.0) 64 | activestorage (7.2.0) 65 | actionpack (= 7.2.0) 66 | activejob (= 7.2.0) 67 | activerecord (= 7.2.0) 68 | activesupport (= 7.2.0) 69 | marcel (~> 1.0) 70 | activesupport (7.2.0) 71 | base64 72 | bigdecimal 73 | concurrent-ruby (~> 1.0, >= 1.3.1) 74 | connection_pool (>= 2.2.5) 75 | drb 76 | i18n (>= 1.6, < 2) 77 | logger (>= 1.4.2) 78 | minitest (>= 5.1) 79 | securerandom (>= 0.3) 80 | tzinfo (~> 2.0, >= 2.0.5) 81 | appraisal (2.5.0) 82 | bundler 83 | rake 84 | thor (>= 0.14.0) 85 | ast (2.4.2) 86 | base64 (0.2.0) 87 | bigdecimal (3.1.8) 88 | builder (3.3.0) 89 | childprocess (5.0.0) 90 | coderay (1.1.3) 91 | concurrent-ruby (1.3.4) 92 | connection_pool (2.4.1) 93 | crass (1.0.6) 94 | date (3.3.4) 95 | diff-lcs (1.5.1) 96 | drb (2.2.1) 97 | erubi (1.13.0) 98 | globalid (1.2.1) 99 | activesupport (>= 6.1) 100 | i18n (1.14.5) 101 | concurrent-ruby (~> 1.0) 102 | iniparse (1.5.0) 103 | io-console (0.7.2) 104 | irb (1.14.0) 105 | rdoc (>= 4.0.0) 106 | reline (>= 0.4.2) 107 | json (2.7.2) 108 | language_server-protocol (3.17.0.3) 109 | logger (1.6.0) 110 | loofah (2.22.0) 111 | crass (~> 1.0.2) 112 | nokogiri (>= 1.12.0) 113 | mail (2.8.1) 114 | mini_mime (>= 0.1.1) 115 | net-imap 116 | net-pop 117 | net-smtp 118 | marcel (1.0.4) 119 | method_source (1.1.0) 120 | mini_mime (1.1.5) 121 | minitest (5.25.1) 122 | net-imap (0.4.14) 123 | date 124 | net-protocol 125 | net-pop (0.1.2) 126 | net-protocol 127 | net-protocol (0.2.2) 128 | timeout 129 | net-smtp (0.5.0) 130 | net-protocol 131 | nio4r (2.7.3) 132 | nokogiri (1.18.0-aarch64-linux-gnu) 133 | racc (~> 1.4) 134 | nokogiri (1.18.0-arm64-darwin) 135 | racc (~> 1.4) 136 | nokogiri (1.18.0-x86_64-darwin) 137 | racc (~> 1.4) 138 | nokogiri (1.18.0-x86_64-linux-gnu) 139 | racc (~> 1.4) 140 | overcommit (0.63.0) 141 | childprocess (>= 0.6.3, < 6) 142 | iniparse (~> 1.4) 143 | rexml (~> 3.2) 144 | parallel (1.24.0) 145 | parser (3.3.1.0) 146 | ast (~> 2.4.1) 147 | racc 148 | pry (0.14.2) 149 | coderay (~> 1.1) 150 | method_source (~> 1.0) 151 | psych (5.1.2) 152 | stringio 153 | racc (1.8.1) 154 | rack (3.1.7) 155 | rack-session (2.0.0) 156 | rack (>= 3.0.0) 157 | rack-test (2.1.0) 158 | rack (>= 1.3) 159 | rackup (2.1.0) 160 | rack (>= 3) 161 | webrick (~> 1.8) 162 | rails (7.2.0) 163 | actioncable (= 7.2.0) 164 | actionmailbox (= 7.2.0) 165 | actionmailer (= 7.2.0) 166 | actionpack (= 7.2.0) 167 | actiontext (= 7.2.0) 168 | actionview (= 7.2.0) 169 | activejob (= 7.2.0) 170 | activemodel (= 7.2.0) 171 | activerecord (= 7.2.0) 172 | activestorage (= 7.2.0) 173 | activesupport (= 7.2.0) 174 | bundler (>= 1.15.0) 175 | railties (= 7.2.0) 176 | rails-dom-testing (2.2.0) 177 | activesupport (>= 5.0.0) 178 | minitest 179 | nokogiri (>= 1.6) 180 | rails-html-sanitizer (1.6.0) 181 | loofah (~> 2.21) 182 | nokogiri (~> 1.14) 183 | railties (7.2.0) 184 | actionpack (= 7.2.0) 185 | activesupport (= 7.2.0) 186 | irb (~> 1.13) 187 | rackup (>= 1.0.0) 188 | rake (>= 12.2) 189 | thor (~> 1.0, >= 1.2.2) 190 | zeitwerk (~> 2.6) 191 | rainbow (3.1.1) 192 | rake (13.2.1) 193 | rb-readline (0.5.5) 194 | rdoc (6.7.0) 195 | psych (>= 4.0.0) 196 | regexp_parser (2.9.2) 197 | reline (0.5.9) 198 | io-console (~> 0.5) 199 | rexml (3.2.8) 200 | strscan (>= 3.0.9) 201 | rspec (3.13.0) 202 | rspec-core (~> 3.13.0) 203 | rspec-expectations (~> 3.13.0) 204 | rspec-mocks (~> 3.13.0) 205 | rspec-core (3.13.0) 206 | rspec-support (~> 3.13.0) 207 | rspec-expectations (3.13.0) 208 | diff-lcs (>= 1.2.0, < 2.0) 209 | rspec-support (~> 3.13.0) 210 | rspec-mocks (3.13.1) 211 | diff-lcs (>= 1.2.0, < 2.0) 212 | rspec-support (~> 3.13.0) 213 | rspec-support (3.13.1) 214 | rubocop (1.64.0) 215 | json (~> 2.3) 216 | language_server-protocol (>= 3.17.0) 217 | parallel (~> 1.10) 218 | parser (>= 3.3.0.2) 219 | rainbow (>= 2.2.2, < 4.0) 220 | regexp_parser (>= 1.8, < 3.0) 221 | rexml (>= 3.2.5, < 4.0) 222 | rubocop-ast (>= 1.31.1, < 2.0) 223 | ruby-progressbar (~> 1.7) 224 | unicode-display_width (>= 2.4.0, < 3.0) 225 | rubocop-ast (1.31.3) 226 | parser (>= 3.3.1.0) 227 | ruby-progressbar (1.13.0) 228 | securerandom (0.3.1) 229 | sqlite3 (2.5.0-aarch64-linux-gnu) 230 | sqlite3 (2.5.0-arm64-darwin) 231 | sqlite3 (2.5.0-x86_64-darwin) 232 | sqlite3 (2.5.0-x86_64-linux-gnu) 233 | stringio (3.1.1) 234 | strscan (3.1.0) 235 | thor (1.3.1) 236 | timecop (0.9.8) 237 | timeout (0.4.1) 238 | tzinfo (2.0.6) 239 | concurrent-ruby (~> 1.0) 240 | unicode-display_width (2.5.0) 241 | useragent (0.16.10) 242 | webrick (1.8.1) 243 | websocket-driver (0.7.6) 244 | websocket-extensions (>= 0.1.0) 245 | websocket-extensions (0.1.5) 246 | zeitwerk (2.6.17) 247 | 248 | PLATFORMS 249 | aarch64-linux 250 | arm64-darwin-23 251 | x86_64-darwin-22 252 | x86_64-linux 253 | 254 | DEPENDENCIES 255 | appraisal 256 | data_migrate! 257 | overcommit 258 | pry 259 | rails (~> 7.2.0) 260 | rake 261 | rb-readline 262 | rspec 263 | rspec-core 264 | rubocop 265 | sqlite3 266 | timecop 267 | 268 | BUNDLED WITH 269 | 2.4.17 270 | -------------------------------------------------------------------------------- /gemfiles/rails_8.0.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "rails", "~> 8.0.0" 6 | 7 | gemspec path: "../" 8 | -------------------------------------------------------------------------------- /gemfiles/rails_8.0.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | data_migrate (11.3.0) 5 | activerecord (>= 6.1) 6 | railties (>= 6.1) 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actioncable (8.0.0) 12 | actionpack (= 8.0.0) 13 | activesupport (= 8.0.0) 14 | nio4r (~> 2.0) 15 | websocket-driver (>= 0.6.1) 16 | zeitwerk (~> 2.6) 17 | actionmailbox (8.0.0) 18 | actionpack (= 8.0.0) 19 | activejob (= 8.0.0) 20 | activerecord (= 8.0.0) 21 | activestorage (= 8.0.0) 22 | activesupport (= 8.0.0) 23 | mail (>= 2.8.0) 24 | actionmailer (8.0.0) 25 | actionpack (= 8.0.0) 26 | actionview (= 8.0.0) 27 | activejob (= 8.0.0) 28 | activesupport (= 8.0.0) 29 | mail (>= 2.8.0) 30 | rails-dom-testing (~> 2.2) 31 | actionpack (8.0.0) 32 | actionview (= 8.0.0) 33 | activesupport (= 8.0.0) 34 | nokogiri (>= 1.8.5) 35 | rack (>= 2.2.4) 36 | rack-session (>= 1.0.1) 37 | rack-test (>= 0.6.3) 38 | rails-dom-testing (~> 2.2) 39 | rails-html-sanitizer (~> 1.6) 40 | useragent (~> 0.16) 41 | actiontext (8.0.0) 42 | actionpack (= 8.0.0) 43 | activerecord (= 8.0.0) 44 | activestorage (= 8.0.0) 45 | activesupport (= 8.0.0) 46 | globalid (>= 0.6.0) 47 | nokogiri (>= 1.8.5) 48 | actionview (8.0.0) 49 | activesupport (= 8.0.0) 50 | builder (~> 3.1) 51 | erubi (~> 1.11) 52 | rails-dom-testing (~> 2.2) 53 | rails-html-sanitizer (~> 1.6) 54 | activejob (8.0.0) 55 | activesupport (= 8.0.0) 56 | globalid (>= 0.3.6) 57 | activemodel (8.0.0) 58 | activesupport (= 8.0.0) 59 | activerecord (8.0.0) 60 | activemodel (= 8.0.0) 61 | activesupport (= 8.0.0) 62 | timeout (>= 0.4.0) 63 | activestorage (8.0.0) 64 | actionpack (= 8.0.0) 65 | activejob (= 8.0.0) 66 | activerecord (= 8.0.0) 67 | activesupport (= 8.0.0) 68 | marcel (~> 1.0) 69 | activesupport (8.0.0) 70 | base64 71 | benchmark (>= 0.3) 72 | bigdecimal 73 | concurrent-ruby (~> 1.0, >= 1.3.1) 74 | connection_pool (>= 2.2.5) 75 | drb 76 | i18n (>= 1.6, < 2) 77 | logger (>= 1.4.2) 78 | minitest (>= 5.1) 79 | securerandom (>= 0.3) 80 | tzinfo (~> 2.0, >= 2.0.5) 81 | uri (>= 0.13.1) 82 | appraisal (2.5.0) 83 | bundler 84 | rake 85 | thor (>= 0.14.0) 86 | ast (2.4.2) 87 | base64 (0.2.0) 88 | benchmark (0.3.0) 89 | bigdecimal (3.1.8) 90 | builder (3.3.0) 91 | childprocess (5.1.0) 92 | logger (~> 1.5) 93 | coderay (1.1.3) 94 | concurrent-ruby (1.3.4) 95 | connection_pool (2.4.1) 96 | crass (1.0.6) 97 | date (3.4.0) 98 | diff-lcs (1.5.1) 99 | drb (2.2.1) 100 | erubi (1.13.0) 101 | globalid (1.2.1) 102 | activesupport (>= 6.1) 103 | i18n (1.14.6) 104 | concurrent-ruby (~> 1.0) 105 | iniparse (1.5.0) 106 | io-console (0.7.2) 107 | irb (1.14.1) 108 | rdoc (>= 4.0.0) 109 | reline (>= 0.4.2) 110 | json (2.7.2) 111 | language_server-protocol (3.17.0.3) 112 | logger (1.6.1) 113 | loofah (2.22.0) 114 | crass (~> 1.0.2) 115 | nokogiri (>= 1.12.0) 116 | mail (2.8.1) 117 | mini_mime (>= 0.1.1) 118 | net-imap 119 | net-pop 120 | net-smtp 121 | marcel (1.0.4) 122 | method_source (1.1.0) 123 | mini_mime (1.1.5) 124 | mini_portile2 (2.8.7) 125 | minitest (5.25.1) 126 | net-imap (0.5.1) 127 | date 128 | net-protocol 129 | net-pop (0.1.2) 130 | net-protocol 131 | net-protocol (0.2.2) 132 | timeout 133 | net-smtp (0.5.0) 134 | net-protocol 135 | nio4r (2.7.4) 136 | nokogiri (1.18.0) 137 | mini_portile2 (~> 2.8.2) 138 | racc (~> 1.4) 139 | nokogiri (1.18.0-aarch64-linux-gnu) 140 | racc (~> 1.4) 141 | nokogiri (1.18.0-arm64-darwin) 142 | racc (~> 1.4) 143 | nokogiri (1.18.0-x86_64-darwin) 144 | racc (~> 1.4) 145 | nokogiri (1.18.0-x86_64-linux-gnu) 146 | racc (~> 1.4) 147 | overcommit (0.64.0) 148 | childprocess (>= 0.6.3, < 6) 149 | iniparse (~> 1.4) 150 | rexml (~> 3.2) 151 | parallel (1.26.3) 152 | parser (3.3.5.0) 153 | ast (~> 2.4.1) 154 | racc 155 | pry (0.14.2) 156 | coderay (~> 1.1) 157 | method_source (~> 1.0) 158 | psych (5.1.2) 159 | stringio 160 | racc (1.8.1) 161 | rack (3.1.7) 162 | rack-session (2.0.0) 163 | rack (>= 3.0.0) 164 | rack-test (2.1.0) 165 | rack (>= 1.3) 166 | rackup (2.1.0) 167 | rack (>= 3) 168 | webrick (~> 1.8) 169 | rails (8.0.0) 170 | actioncable (= 8.0.0) 171 | actionmailbox (= 8.0.0) 172 | actionmailer (= 8.0.0) 173 | actionpack (= 8.0.0) 174 | actiontext (= 8.0.0) 175 | actionview (= 8.0.0) 176 | activejob (= 8.0.0) 177 | activemodel (= 8.0.0) 178 | activerecord (= 8.0.0) 179 | activestorage (= 8.0.0) 180 | activesupport (= 8.0.0) 181 | bundler (>= 1.15.0) 182 | railties (= 8.0.0) 183 | rails-dom-testing (2.2.0) 184 | activesupport (>= 5.0.0) 185 | minitest 186 | nokogiri (>= 1.6) 187 | rails-html-sanitizer (1.6.0) 188 | loofah (~> 2.21) 189 | nokogiri (~> 1.14) 190 | railties (8.0.0) 191 | actionpack (= 8.0.0) 192 | activesupport (= 8.0.0) 193 | irb (~> 1.13) 194 | rackup (>= 1.0.0) 195 | rake (>= 12.2) 196 | thor (~> 1.0, >= 1.2.2) 197 | zeitwerk (~> 2.6) 198 | rainbow (3.1.1) 199 | rake (13.2.1) 200 | rb-readline (0.5.5) 201 | rdoc (6.7.0) 202 | psych (>= 4.0.0) 203 | regexp_parser (2.9.2) 204 | reline (0.5.10) 205 | io-console (~> 0.5) 206 | rexml (3.3.7) 207 | rspec (3.13.0) 208 | rspec-core (~> 3.13.0) 209 | rspec-expectations (~> 3.13.0) 210 | rspec-mocks (~> 3.13.0) 211 | rspec-core (3.13.1) 212 | rspec-support (~> 3.13.0) 213 | rspec-expectations (3.13.3) 214 | diff-lcs (>= 1.2.0, < 2.0) 215 | rspec-support (~> 3.13.0) 216 | rspec-mocks (3.13.1) 217 | diff-lcs (>= 1.2.0, < 2.0) 218 | rspec-support (~> 3.13.0) 219 | rspec-support (3.13.1) 220 | rubocop (1.66.1) 221 | json (~> 2.3) 222 | language_server-protocol (>= 3.17.0) 223 | parallel (~> 1.10) 224 | parser (>= 3.3.0.2) 225 | rainbow (>= 2.2.2, < 4.0) 226 | regexp_parser (>= 2.4, < 3.0) 227 | rubocop-ast (>= 1.32.2, < 2.0) 228 | ruby-progressbar (~> 1.7) 229 | unicode-display_width (>= 2.4.0, < 3.0) 230 | rubocop-ast (1.32.3) 231 | parser (>= 3.3.1.0) 232 | ruby-progressbar (1.13.0) 233 | securerandom (0.3.1) 234 | sqlite3 (2.5.0) 235 | mini_portile2 (~> 2.8.0) 236 | sqlite3 (2.5.0-aarch64-linux-gnu) 237 | sqlite3 (2.5.0-arm64-darwin) 238 | sqlite3 (2.5.0-x86_64-darwin) 239 | sqlite3 (2.5.0-x86_64-linux-gnu) 240 | stringio (3.1.1) 241 | thor (1.3.2) 242 | timecop (0.9.10) 243 | timeout (0.4.1) 244 | tzinfo (2.0.6) 245 | concurrent-ruby (~> 1.0) 246 | unicode-display_width (2.6.0) 247 | uri (0.13.1) 248 | useragent (0.16.10) 249 | webrick (1.8.2) 250 | websocket-driver (0.7.6) 251 | websocket-extensions (>= 0.1.0) 252 | websocket-extensions (0.1.5) 253 | zeitwerk (2.6.18) 254 | 255 | PLATFORMS 256 | aarch64-linux 257 | arm64-darwin-23 258 | ruby 259 | x86_64-darwin-22 260 | x86_64-linux 261 | 262 | DEPENDENCIES 263 | appraisal 264 | data_migrate! 265 | overcommit 266 | pry 267 | rails (~> 8.0.0) 268 | rake 269 | rb-readline 270 | rspec 271 | rspec-core 272 | rubocop 273 | sqlite3 274 | timecop 275 | 276 | BUNDLED WITH 277 | 2.4.17 278 | -------------------------------------------------------------------------------- /lib/capistrano/data_migrate.rb: -------------------------------------------------------------------------------- 1 | require 'capistrano' 2 | 3 | require File.expand_path("#{File.dirname(__FILE__)}/data_migrate/migrate") 4 | -------------------------------------------------------------------------------- /lib/capistrano/data_migrate/migrate.rb: -------------------------------------------------------------------------------- 1 | namespace :deploy do 2 | 3 | desc 'Runs rake data:migrate if migrations are set' 4 | Rake::Task['deploy:migrate'].clear_actions 5 | task :migrate => [:set_rails_env] do 6 | on fetch(:migration_servers) do 7 | conditionally_migrate = fetch(:conditionally_migrate) 8 | info '[deploy:migrate] Checking changes in db/migrate or db/data' if conditionally_migrate 9 | 10 | if conditionally_migrate && 11 | test("diff -q #{release_path}/db/migrate #{current_path}/db/migrate") && 12 | test("diff -q #{release_path}/db/data #{current_path}/db/data") 13 | info '[deploy:migrate] Skip `deploy:migrate` (nothing changed in db/migrate or db/data)' 14 | else 15 | info '[deploy:migrate] Run `rake db:migrate:with_data`' 16 | invoke :'deploy:migrating_with_data' 17 | end 18 | end 19 | end 20 | 21 | desc 'Runs rake db:migrate:with_data' 22 | task migrating_with_data: [:set_rails_env] do 23 | on fetch(:migration_servers) do 24 | within release_path do 25 | with rails_env: fetch(:rails_env) do 26 | execute :rake, 'db:migrate:with_data' 27 | end 28 | end 29 | end 30 | end 31 | 32 | after 'deploy:updated', 'deploy:migrate' 33 | end 34 | 35 | namespace :load do 36 | task :defaults do 37 | set :conditionally_migrate, fetch(:conditionally_migrate, false) 38 | set :migration_role, fetch(:migration_role, :db) 39 | set :migration_servers, -> { primary(fetch(:migration_role)) } 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/data_migrate.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require File.join(File.dirname(__FILE__), "data_migrate", "rails_helper") 4 | require File.join(File.dirname(__FILE__), "data_migrate", "data_migrator") 5 | require File.join(File.dirname(__FILE__), "data_migrate", "data_schema_migration") 6 | require File.join(File.dirname(__FILE__), "data_migrate", "data_schema") 7 | require File.join(File.dirname(__FILE__), "data_migrate", "database_tasks") 8 | require File.join(File.dirname(__FILE__), "data_migrate", "schema_dumper") 9 | require File.join(File.dirname(__FILE__), "data_migrate", "status_service") 10 | require File.join(File.dirname(__FILE__), "data_migrate", "migration_context") 11 | require File.join(File.dirname(__FILE__), "data_migrate", "railtie") 12 | require File.join(File.dirname(__FILE__), "data_migrate", "tasks/data_migrate_tasks") 13 | require File.join(File.dirname(__FILE__), "data_migrate", "config") 14 | require File.join(File.dirname(__FILE__), "data_migrate", "schema_migration") 15 | require File.join(File.dirname(__FILE__), "data_migrate", "database_configurations_wrapper") 16 | 17 | module DataMigrate 18 | def self.root 19 | File.dirname(__FILE__) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/data_migrate/config.rb: -------------------------------------------------------------------------------- 1 | module DataMigrate 2 | include ActiveSupport::Configurable 3 | class << self 4 | 5 | def configure 6 | yield config 7 | end 8 | 9 | def config 10 | @config ||= Config.new 11 | end 12 | end 13 | 14 | class Config 15 | attr_accessor :data_migrations_table_name, :data_migrations_path, :data_template_path, :db_configuration, :spec_name 16 | 17 | DEFAULT_DATA_TEMPLATE_PATH = "data_migration.rb" 18 | 19 | def initialize 20 | @data_migrations_table_name = "data_migrations" 21 | @data_migrations_path = "db/data/" 22 | @data_template_path = DEFAULT_DATA_TEMPLATE_PATH 23 | @db_configuration = nil 24 | @spec_name = nil 25 | end 26 | 27 | def data_template_path=(value) 28 | @data_template_path = value.tap do |path| 29 | raise ArgumentError, "File not found: '#{path}'" unless path == DEFAULT_DATA_TEMPLATE_PATH || File.exist?(path) 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/data_migrate/data_migrator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "active_record" 4 | require "data_migrate/config" 5 | 6 | module DataMigrate 7 | class DataMigrator < ActiveRecord::Migrator 8 | def load_migrated 9 | @migrated_versions = 10 | DataMigrate::RailsHelper.data_schema_migration.normalized_versions.map(&:to_i).sort 11 | end 12 | 13 | class << self 14 | def migrations_paths 15 | Array.wrap(DataMigrate.config.data_migrations_path) 16 | end 17 | 18 | def create_data_schema_table 19 | DataMigrate::RailsHelper.data_schema_migration.create_table 20 | end 21 | 22 | def current_version 23 | DataMigrate::MigrationContext.new(migrations_paths).current_version 24 | end 25 | 26 | ## 27 | # Compares the given filename with what we expect data migration 28 | # filenames to be, eg the "20091231235959_some_name.rb" pattern 29 | # @param (String) filename 30 | # @return (MatchData) 31 | def match(filename) 32 | /(\d{14})_(.+)\.rb$/.match(filename) 33 | end 34 | 35 | def needs_migration? 36 | DataMigrate::DatabaseTasks.pending_migrations.count.positive? 37 | end 38 | ## 39 | # Provides the full migrations_path filepath 40 | # @return (String) 41 | def full_migrations_path 42 | File.join(Rails.root, *migrations_paths.split(File::SEPARATOR)) 43 | end 44 | 45 | def migrations_status 46 | DataMigrate::MigrationContext.new(migrations_paths).migrations_status 47 | end 48 | 49 | # TODO: this was added to be backward compatible, need to re-evaluate 50 | def migrations(_migrations_paths) 51 | DataMigrate::MigrationContext.new(_migrations_paths).migrations 52 | end 53 | 54 | #TODO: this was added to be backward compatible, need to re-evaluate 55 | def run(direction, migration_paths, version) 56 | # Ensure all Active Record model cache is reset for each data migration 57 | # As recommended in: https://github.com/rails/rails/blob/da21c2e9812e5eb0698fba4a9aa38632fc004432/activerecord/lib/active_record/migration.rb#L467-L470 58 | ActiveRecord::Base.descendants.each(&:reset_column_information) 59 | 60 | DataMigrate::MigrationContext.new(migration_paths).run(direction, version) 61 | end 62 | 63 | def rollback(migrations_path, steps) 64 | DataMigrate::MigrationContext.new(migrations_path).rollback(steps) 65 | end 66 | end 67 | 68 | private 69 | 70 | def record_version_state_after_migrating(version) 71 | if down? 72 | migrated.delete(version) 73 | DataMigrate::RailsHelper.data_schema_delete_version(version.to_s) 74 | else 75 | migrated << version 76 | DataMigrate::RailsHelper.data_schema_migration.create_version(version.to_s) 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /lib/data_migrate/data_schema.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DataMigrate 4 | ## 5 | # Provides the definition method for data_schema.rb 6 | class Data < ActiveRecord::Schema 7 | # This method is based on the following two methods 8 | # ActiveRecord::Schema#define 9 | # ActiveRecord::ConnectionAdapters::SchemaStatements 10 | # #assume_migrated_upto_version 11 | def define(info) 12 | DataMigrate::DataMigrator.create_data_schema_table 13 | 14 | return if info[:version].blank? 15 | 16 | version = info[:version].to_i 17 | 18 | unless migrated.include?(version) 19 | execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')" 20 | end 21 | 22 | insert(version) 23 | end 24 | 25 | private 26 | 27 | def migrated 28 | @migrated ||= select_values("SELECT version FROM #{sm_table}").map(&:to_i) 29 | end 30 | 31 | def versions 32 | @versions ||= Set.new.tap do |versions| 33 | DataMigrate::DataMigrator.migrations_paths.each do |path| 34 | Dir.foreach(path) do |file| 35 | match_data = DataMigrate::DataMigrator.match(file) 36 | versions << match_data[1].to_i if match_data 37 | end 38 | end 39 | end 40 | end 41 | 42 | def insert(version) 43 | inserted = Set.new 44 | (versions - migrated).each do |v| 45 | if inserted.include?(v) 46 | raise "Duplicate data migration #{v}. Please renumber your data " \ 47 | "migrations to resolve the conflict." 48 | elsif v < version 49 | execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')" 50 | inserted << v 51 | end 52 | end 53 | end 54 | 55 | def sm_table 56 | quote_table_name(table_name) 57 | end 58 | 59 | def table_name 60 | DataMigrate::RailsHelper.data_schema_migration.table_name 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/data_migrate/data_schema_migration.rb: -------------------------------------------------------------------------------- 1 | module DataMigrate 2 | class DataSchemaMigration < ActiveRecord::SchemaMigration 3 | # In Rails 7.1+, ActiveRecord::SchemaMigration methods are instance methods 4 | # So we only load the appropriate methods depending on Rails version. 5 | if DataMigrate::RailsHelper.rails_version_equal_to_or_higher_than_7_1 6 | def table_name 7 | ActiveRecord::Base.table_name_prefix + DataMigrate.config.data_migrations_table_name + ActiveRecord::Base.table_name_suffix 8 | end 9 | 10 | def primary_key 11 | "version" 12 | end 13 | else 14 | class << self 15 | def table_name 16 | ActiveRecord::Base.table_name_prefix + DataMigrate.config.data_migrations_table_name + ActiveRecord::Base.table_name_suffix 17 | end 18 | 19 | def primary_key 20 | "version" 21 | end 22 | 23 | def create_version(version) 24 | # Note that SchemaMigration.create_version in Rails 7.1 does not 25 | # raise an error if validations fail but we retain this behaviour for now. 26 | create!(version: version) 27 | end 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/data_migrate/database_configurations_wrapper.rb: -------------------------------------------------------------------------------- 1 | module DataMigrate 2 | # This wrapper is used to differentiate between 3 | # a data and schema db config when running migrations 4 | class DatabaseConfigurationWrapper 5 | attr_reader :db_config 6 | 7 | def initialize(db_config) 8 | @db_config = db_config 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/data_migrate/database_tasks.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "data_migrate/config" 4 | 5 | module DataMigrate 6 | ## 7 | # This class extends DatabaseTasks to add a schema_file method. 8 | module DatabaseTasks 9 | extend ActiveRecord::Tasks::DatabaseTasks 10 | extend self 11 | 12 | if respond_to?(:register_task) 13 | register_task(/mysql/, "ActiveRecord::Tasks::MySQLDatabaseTasks") 14 | register_task(/trilogy/, "ActiveRecord::Tasks::MySQLDatabaseTasks") 15 | register_task(/postgresql/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks") 16 | register_task(/sqlite/, "ActiveRecord::Tasks::SQLiteDatabaseTasks") 17 | end 18 | 19 | # These method are only introduced in Rails 7.1 20 | unless respond_to?(:with_temporary_pool_for_each) 21 | def with_temporary_pool_for_each(env: ActiveRecord::Tasks::DatabaseTasks.env, name: nil, &block) # :nodoc: 22 | if name 23 | db_config = ActiveRecord::Base.configurations.configs_for(env_name: env, name: name) 24 | with_temporary_pool(db_config, &block) 25 | else 26 | ActiveRecord::Base.configurations.configs_for(env_name: env, name: name).each do |db_config| 27 | with_temporary_pool(db_config, &block) 28 | end 29 | end 30 | end 31 | 32 | def with_temporary_connection(db_config, &block) # :nodoc: 33 | with_temporary_pool(db_config) do |pool| 34 | pool.with_connection(&block) 35 | end 36 | end 37 | 38 | def migration_class # :nodoc: 39 | ActiveRecord::Base 40 | end 41 | 42 | def migration_connection # :nodoc: 43 | migration_class.connection 44 | end 45 | 46 | private def with_temporary_pool(db_config) 47 | original_db_config = migration_class.connection_db_config 48 | pool = migration_class.connection_handler.establish_connection(db_config) 49 | 50 | yield pool 51 | ensure 52 | migration_class.connection_handler.establish_connection(original_db_config) 53 | end 54 | end 55 | 56 | def db_configs_with_versions 57 | db_configs_with_versions = Hash.new { |h, k| h[k] = [] } 58 | 59 | with_temporary_pool_for_each do |pool| 60 | db_config = pool.db_config 61 | if db_config.primary? 62 | versions_to_run = DataMigrate::DatabaseTasks.pending_data_migrations.map { |m| m[:version] } 63 | target_version = ActiveRecord::Tasks::DatabaseTasks.target_version 64 | 65 | versions_to_run.each do |version| 66 | next if target_version && target_version != version 67 | db_configs_with_versions[version] << DatabaseConfigurationWrapper.new(db_config) 68 | end 69 | end 70 | end 71 | 72 | db_configs_with_versions 73 | end 74 | 75 | def schema_file(_format = nil) 76 | File.join(db_dir, "data_schema.rb") 77 | end 78 | 79 | def schema_file_type(_format = nil) 80 | "data_schema.rb" 81 | end 82 | 83 | # This method is removed in Rails 7.0 84 | def dump_filename(spec_name, format = ActiveRecord::Base.schema_format) 85 | filename = if spec_name == "primary" 86 | schema_file_type(format) 87 | else 88 | "#{spec_name}_#{schema_file_type(format)}" 89 | end 90 | 91 | ENV["DATA_SCHEMA"] || File.join(db_dir, filename) 92 | end 93 | 94 | def check_schema_file(filename) 95 | unless File.exist?(filename) 96 | message = +%{#{filename} doesn't exist yet. Run `rake data:migrate` to create it, then try again.} 97 | Kernel.abort message 98 | end 99 | end 100 | 101 | def pending_migrations 102 | sort_migrations( 103 | pending_schema_migrations, 104 | pending_data_migrations 105 | ) 106 | end 107 | 108 | def sort_migrations(*migrations) 109 | migrations.flatten.sort { |a, b| sort_string(a) <=> sort_string(b) } 110 | end 111 | 112 | def sort_string migration 113 | "#{migration[:version]}_#{migration[:kind] == :data ? 1 : 0}" 114 | end 115 | 116 | def data_migrations_path 117 | ::DataMigrate.config.data_migrations_path 118 | end 119 | 120 | def run_migration(migration, direction) 121 | if migration[:kind] == :data 122 | ::ActiveRecord::Migration.write("== %s %s" % ['Data', "=" * 71]) 123 | ::DataMigrate::DataMigrator.run(direction, data_migrations_path, migration[:version]) 124 | else 125 | ::ActiveRecord::Migration.write("== %s %s" % ['Schema', "=" * 69]) 126 | ::DataMigrate::SchemaMigration.run( 127 | direction, 128 | ::DataMigrate::SchemaMigration.migrations_paths, 129 | migration[:version] 130 | ) 131 | end 132 | end 133 | 134 | def schema_dump_path(db_config, format = ActiveRecord.schema_format) 135 | return ENV["DATA_SCHEMA"] if ENV["DATA_SCHEMA"] 136 | 137 | # We only require a schema.rb file for the primary database 138 | return unless db_config.primary? 139 | 140 | File.join(File.dirname(ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(db_config, format)), schema_file_type) 141 | end 142 | 143 | # Override this method from `ActiveRecord::Tasks::DatabaseTasks` 144 | # to ensure that the sha saved in ar_internal_metadata table 145 | # is from the original schema.rb file 146 | def schema_sha1(file) 147 | ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: "primary")) 148 | end 149 | 150 | def forward(step = 1) 151 | DataMigrate::DataMigrator.create_data_schema_table 152 | migrations = pending_migrations.reverse.pop(step).reverse 153 | migrations.each do | pending_migration | 154 | if pending_migration[:kind] == :data 155 | ActiveRecord::Migration.write("== %s %s" % ["Data", "=" * 71]) 156 | DataMigrate::DataMigrator.run(:up, data_migrations_path, pending_migration[:version]) 157 | elsif pending_migration[:kind] == :schema 158 | ActiveRecord::Migration.write("== %s %s" % ["Schema", "=" * 69]) 159 | DataMigrate::SchemaMigration.run(:up, DataMigrate::SchemaMigration.migrations_paths, pending_migration[:version]) 160 | end 161 | end 162 | end 163 | 164 | def pending_data_migrations 165 | data_migrations = DataMigrate::DataMigrator.migrations(data_migrations_path) 166 | data_migrator = DataMigrate::RailsHelper.data_migrator(:up, data_migrations) 167 | sort_migrations( 168 | data_migrator.pending_migrations.map { |m| { version: m.version, name: m.name, kind: :data } } 169 | ) 170 | end 171 | 172 | def pending_schema_migrations 173 | ::DataMigrate::SchemaMigration.pending_schema_migrations 174 | end 175 | 176 | def past_migrations(sort = nil) 177 | data_versions = DataMigrate::RailsHelper.data_schema_migration.table_exists? ? DataMigrate::RailsHelper.data_schema_migration.normalized_versions : [] 178 | schema_versions = DataMigrate::RailsHelper.schema_migration.normalized_versions 179 | migrations = data_versions.map { |v| { version: v.to_i, kind: :data } } + schema_versions.map { |v| { version: v.to_i, kind: :schema } } 180 | 181 | sort&.downcase == "asc" ? sort_migrations(migrations) : sort_migrations(migrations).reverse 182 | end 183 | 184 | def self.migrate_with_data 185 | DataMigrate::DataMigrator.create_data_schema_table 186 | 187 | ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true 188 | 189 | # 7.2 removes the param for db_configs_with_versions in https://github.com/rails/rails/commit/9572fcb4a0bd5396436689a6a42613886871cd81 190 | # 7.1 stable backported the change in https://github.com/rails/rails/commit/c53ec4b60980036b43528829d4b0b7457f759224 191 | schema_mapped_versions = if Gem::Dependency.new("railties", ">= 7.1.4").match?("railties", Gem.loaded_specs["railties"].version, true) 192 | ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions 193 | else 194 | db_configs = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env) 195 | 196 | ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions(db_configs) 197 | end 198 | 199 | data_mapped_versions = DataMigrate::DatabaseTasks.db_configs_with_versions 200 | 201 | mapped_versions = schema_mapped_versions.merge(data_mapped_versions) do |_key, schema_db_configs, data_db_configs| 202 | schema_db_configs + data_db_configs 203 | end 204 | 205 | mapped_versions.sort.each do |version, db_configs| 206 | db_configs.each do |db_config| 207 | if is_data_migration = db_config.is_a?(DataMigrate::DatabaseConfigurationWrapper) 208 | db_config = db_config.db_config 209 | end 210 | 211 | DataMigrate::DatabaseTasks.with_temporary_connection(db_config) do 212 | if is_data_migration 213 | DataMigrate::DataMigrator.run(:up, DataMigrate::DatabaseTasks.data_migrations_path, version) 214 | else 215 | ActiveRecord::Tasks::DatabaseTasks.migrate(version) 216 | end 217 | end 218 | end 219 | end 220 | end 221 | 222 | def self.prepare_all_with_data 223 | seed = false 224 | 225 | each_current_configuration(env) do |db_config| 226 | next unless primary?(db_config) 227 | 228 | with_temporary_pool(db_config) do |pool| 229 | connection = pool.respond_to?(:lease_connection) ? pool.lease_connection : pool.connection 230 | unless database_exists?(connection) 231 | create(db_config) 232 | if File.exist?(schema_dump_path(db_config)) 233 | load_schema(db_config, schema_format, nil) 234 | load_schema_current( 235 | :ruby, 236 | ENV["DATA_SCHEMA"] 237 | ) 238 | end 239 | 240 | seed = true 241 | end 242 | 243 | migrate_with_data 244 | if dump_schema_after_migration? 245 | dump_schema(db_config) 246 | DataMigrate::Tasks::DataMigrateTasks.dump 247 | end 248 | end 249 | end 250 | 251 | load_seed if seed 252 | end 253 | 254 | private 255 | 256 | def database_exists?(connection) 257 | if connection.respond_to?(:database_exists?) # Rails 7.1+ 258 | connection.database_exists? 259 | else 260 | connection.table_exists?(ActiveRecord::SchemaMigration.table_name) 261 | end 262 | rescue ActiveRecord::NoDatabaseError 263 | false 264 | end 265 | 266 | def primary?(db_config) 267 | if db_config.respond_to?(:primary?) # Rails 7.0+ 268 | db_config.primary? 269 | else 270 | db_config.name == "primary" 271 | end 272 | end 273 | 274 | def dump_schema_after_migration? 275 | if ActiveRecord.respond_to?(:dump_schema_after_migration) 276 | ActiveRecord.dump_schema_after_migration 277 | else 278 | ActiveRecord::Base.dump_schema_after_migration 279 | end 280 | end 281 | 282 | def schema_format 283 | if ActiveRecord.respond_to?(:schema_format) 284 | ActiveRecord.schema_format 285 | else 286 | ActiveRecord::Base.schema_format 287 | end 288 | end 289 | end 290 | end 291 | -------------------------------------------------------------------------------- /lib/data_migrate/migration_context.rb: -------------------------------------------------------------------------------- 1 | module DataMigrate 2 | class MigrationContext < ActiveRecord::MigrationContext 3 | def initialize(migrations_paths = "db/data") 4 | @migrations_paths = migrations_paths || "db/data" 5 | end 6 | 7 | def up(target_version = nil) 8 | selected_migrations = if block_given? 9 | migrations.select { |m| yield m } 10 | else 11 | migrations 12 | end 13 | 14 | data_migrator = DataMigrate::RailsHelper.data_migrator(:up, selected_migrations, DataMigrate::RailsHelper.schema_migration, DataMigrate::RailsHelper.internal_metadata, target_version) 15 | data_migrator.migrate 16 | end 17 | 18 | def down(target_version = nil) 19 | selected_migrations = 20 | if block_given? 21 | migrations.select { |m| yield m } 22 | else 23 | migrations 24 | end 25 | 26 | data_migrator = DataMigrate::RailsHelper.data_migrator(:down, selected_migrations, DataMigrate::RailsHelper.schema_migration, DataMigrate::RailsHelper.internal_metadata, target_version) 27 | data_migrator.migrate 28 | end 29 | 30 | def run(direction, target_version) 31 | data_migrator = DataMigrate::RailsHelper.data_migrator(direction, migrations, DataMigrate::RailsHelper.schema_migration, DataMigrate::RailsHelper.internal_metadata, target_version) 32 | data_migrator.run 33 | end 34 | 35 | def current_version 36 | get_all_versions.max || 0 37 | rescue ActiveRecord::NoDatabaseError 38 | end 39 | 40 | def migration_files 41 | paths = Array(migrations_paths) 42 | Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }] 43 | end 44 | 45 | def migrations_status 46 | db_list = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 47 | 48 | file_list = migration_files.map do |file| 49 | version, name, scope = parse_migration_filename(file) 50 | raise ActiveRecord::IllegalMigrationNameError.new(file) unless version 51 | version = DataMigrate::RailsHelper.schema_migration.normalize_migration_number(version) 52 | status = db_list.delete(version) ? "up" : "down" 53 | [status, version, (name + scope).humanize] 54 | end.compact 55 | 56 | db_list.map! do |version| 57 | ["up", version, "********** NO FILE **********"] 58 | end 59 | 60 | (db_list + file_list).sort_by { |_, version, _| version } 61 | end 62 | 63 | private 64 | 65 | def get_all_versions 66 | if DataMigrate::RailsHelper.data_schema_migration.table_exists? 67 | DataMigrate::RailsHelper.data_schema_migration.normalized_versions.map(&:to_i) 68 | else 69 | [] 70 | end 71 | end 72 | 73 | def move(direction, steps) 74 | migrator = DataMigrate::RailsHelper.data_migrator(direction, migrations) 75 | 76 | if current_version != 0 && !migrator.current_migration 77 | raise ActiveRecord::UnknownMigrationVersionError.new(current_version) 78 | end 79 | 80 | start_index = 81 | if current_version.zero? 82 | 0 83 | else 84 | migrator.migrations.index(migrator.current_migration) 85 | end 86 | 87 | finish = migrator.migrations[start_index + steps] 88 | version = finish ? finish.version : 0 89 | send(direction, version) 90 | end 91 | 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /lib/data_migrate/rails_helper.rb: -------------------------------------------------------------------------------- 1 | module DataMigrate 2 | class RailsHelper 3 | class << self 4 | def rails_version_equal_to_or_higher_than_7_2 5 | return @equal_to_or_higher_than_7_2 if defined?(@equal_to_or_higher_than_7_2) 6 | 7 | @equal_to_or_higher_than_7_2 = Gem::Dependency.new("railties", ">= 7.2.0.alpha").match?("railties", Gem.loaded_specs["railties"].version, true) 8 | end 9 | 10 | def rails_version_equal_to_or_higher_than_7_1 11 | return @equal_to_or_higher_than_7_1 if defined?(@equal_to_or_higher_than_7_1) 12 | 13 | @equal_to_or_higher_than_7_1 = Gem::Dependency.new("railties", ">= 7.1.0.alpha").match?("railties", Gem.loaded_specs["railties"].version, true) 14 | end 15 | 16 | def rails_version_equal_to_or_higher_than_7_0 17 | return @rails_version_equal_to_or_higher_than_7_0 if defined?(@rails_version_equal_to_or_higher_than_7_0) 18 | 19 | @rails_version_equal_to_or_higher_than_7_0 = Gem::Dependency.new("railties", ">= 7.0").match?("railties", Gem.loaded_specs["railties"].version, true) 20 | end 21 | 22 | def internal_metadata 23 | if rails_version_equal_to_or_higher_than_7_2 24 | ActiveRecord::Base.connection_pool.internal_metadata 25 | elsif rails_version_equal_to_or_higher_than_7_1 26 | ActiveRecord::Base.connection.internal_metadata 27 | else 28 | ActiveRecord::InternalMetadata 29 | end 30 | end 31 | 32 | def schema_migration 33 | if rails_version_equal_to_or_higher_than_7_2 34 | ActiveRecord::Base.connection_pool.schema_migration 35 | elsif rails_version_equal_to_or_higher_than_7_1 36 | ActiveRecord::Base.connection.schema_migration 37 | else 38 | ActiveRecord::SchemaMigration 39 | end 40 | end 41 | 42 | def schema_migration_versions 43 | if rails_version_equal_to_or_higher_than_7_1 44 | schema_migration.versions 45 | else 46 | schema_migration.all.pluck(:version) 47 | end 48 | end 49 | 50 | def schema_create_version(version) 51 | if rails_version_equal_to_or_higher_than_7_1 52 | schema_migration.create_version(version) 53 | else 54 | schema_migration.create(version: version) 55 | end 56 | end 57 | 58 | def data_schema_delete_version(version) 59 | if rails_version_equal_to_or_higher_than_7_1 60 | data_schema_migration.delete_version(version) 61 | else 62 | data_schema_migration.where(version: version.to_s).delete_all 63 | end 64 | end 65 | 66 | def data_schema_migration 67 | if rails_version_equal_to_or_higher_than_7_2 68 | DataMigrate::DataSchemaMigration.new(ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool) 69 | elsif rails_version_equal_to_or_higher_than_7_1 70 | DataMigrate::DataSchemaMigration.new(ActiveRecord::Tasks::DatabaseTasks.migration_connection) 71 | else 72 | DataMigrate::DataSchemaMigration 73 | end 74 | end 75 | 76 | def data_migrator( 77 | direction, 78 | migrations, 79 | schema_migration = DataMigrate::RailsHelper.schema_migration, 80 | internal_metadata = DataMigrate::RailsHelper.internal_metadata, 81 | target_version = nil 82 | ) 83 | if rails_version_equal_to_or_higher_than_7_1 84 | DataMigrate::DataMigrator.new(direction, migrations, schema_migration, internal_metadata, target_version) 85 | else 86 | DataMigrate::DataMigrator.new(direction, migrations, schema_migration, target_version) 87 | end 88 | end 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /lib/data_migrate/railtie.rb: -------------------------------------------------------------------------------- 1 | module DataMigrate 2 | class Railtie < ::Rails::Railtie 3 | generators = config.respond_to?(:app_generators) ? config.app_generators : config.generators 4 | 5 | rake_tasks do 6 | load File.join(File.dirname(__FILE__), '..', '..', 'tasks/databases.rake') 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/data_migrate/schema_dumper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DataMigrate 4 | ## 5 | # Provides the capability to write the current data schema version to 6 | # the data_schema file Based on ActiveRecord::SchemaDumper 7 | class SchemaDumper 8 | private_class_method :new 9 | 10 | class << self 11 | def dump(connection = ActiveRecord::Base.connection, stream = $stdout) 12 | new(connection).dump(stream) 13 | stream 14 | end 15 | end 16 | 17 | def dump(stream) 18 | define_params = @version ? "version: #{formatted_version}" : "" 19 | 20 | stream.puts "DataMigrate::Data.define(#{define_params})" 21 | 22 | stream 23 | end 24 | 25 | private 26 | 27 | def initialize(connection) 28 | @connection = connection 29 | all_versions = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 30 | 31 | @version = begin 32 | all_versions.max 33 | rescue StandardError 34 | 0 35 | end 36 | end 37 | 38 | # turns 20170404131909 into "2017_04_04_131909" 39 | def formatted_version 40 | stringified = @version.to_s 41 | return stringified unless stringified.length == 14 42 | stringified.insert(4, "_").insert(7, "_").insert(10, "_") 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/data_migrate/schema_migration.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DataMigrate 4 | # Helper class to getting access to db schema 5 | # to allow data/schema combiation tasks 6 | class SchemaMigration 7 | def self.pending_schema_migrations 8 | all_migrations = DataMigrate::MigrationContext.new(migrations_paths).migrations 9 | sort_migrations( 10 | ActiveRecord::Migrator.new(:up, all_migrations, DataMigrate::RailsHelper.schema_migration, DataMigrate::RailsHelper.internal_metadata). 11 | pending_migrations. 12 | map {|m| { version: m.version, kind: :schema }} 13 | ) 14 | end 15 | 16 | def self.run(direction, migration_paths, version) 17 | ActiveRecord::MigrationContext.new(migration_paths, DataMigrate::RailsHelper.schema_migration).run(direction, version) 18 | end 19 | 20 | def self.sort_migrations(set1, set2 = nil) 21 | migrations = set1 + (set2 || []) 22 | migrations.sort {|a, b| sort_string(a) <=> sort_string(b)} 23 | end 24 | 25 | def self.migrations_paths 26 | spec_name = DataMigrate.config.spec_name 27 | # The positional argument true is to include pre-release versions, such as 7.1.0.alpha 28 | if spec_name && Gem::Dependency.new("railties", ">= 7.0").match?("railties", Gem.loaded_specs["railties"].version, true) 29 | ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: spec_name).migrations_paths 30 | elsif spec_name && Gem::Dependency.new("railties", "~> 6.1").match?("railties", Gem.loaded_specs["railties"].version) 31 | ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name).migrations_paths 32 | else 33 | Rails.application.config.paths["db/migrate"].to_a 34 | end 35 | end 36 | 37 | def self.sort_string(migration) 38 | "#{migration[:version]}_#{migration[:kind] == :data ? 1 : 0}" 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/data_migrate/status_service.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DataMigrate 4 | class StatusService 5 | class << self 6 | def dump(connection = ActiveRecord::Base.connection, stream = $stdout) 7 | new(connection).dump(stream) 8 | stream 9 | end 10 | end 11 | 12 | def initialize(connection) 13 | @connection = connection 14 | end 15 | 16 | def root_folder 17 | Rails.root 18 | end 19 | 20 | def dump(stream) 21 | output(stream) 22 | end 23 | 24 | private 25 | 26 | def table_name 27 | DataMigrate::RailsHelper.data_schema_migration.table_name 28 | end 29 | 30 | def output(stream) 31 | unless DataMigrate::RailsHelper.data_schema_migration.table_exists? 32 | stream.puts "Data migrations table does not exist yet." 33 | return 34 | end 35 | 36 | # output 37 | stream.puts "\ndatabase: #{database_name}\n\n" 38 | stream.puts "#{"Status".center(8)} #{"Migration ID".ljust(14)} Migration Name" 39 | stream.puts "-" * 50 40 | db_list.each do |status, version, name| 41 | stream.puts "#{status.center(8)} #{version.ljust(14)} #{name}" 42 | end 43 | stream.puts 44 | end 45 | 46 | def database_name 47 | if Gem::Dependency.new("railties", "~> 7.0").match?("railties", Gem.loaded_specs["railties"].version) 48 | ActiveRecord::Base.connection_db_config.configuration_hash[:database] 49 | elsif Gem::Dependency.new("railties", "~> 6.1").match?("railties", Gem.loaded_specs["railties"].version) 50 | ActiveRecord::Base.connection_config[:database] 51 | end 52 | end 53 | 54 | def db_list 55 | DataMigrate::DataMigrator.migrations_status 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/data_migrate/tasks/data_migrate_tasks.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DataMigrate 4 | module Tasks 5 | module DataMigrateTasks 6 | extend self 7 | 8 | def migrations_paths 9 | @migrations_paths ||= Array.wrap(DataMigrate.config.data_migrations_path) 10 | end 11 | 12 | def dump 13 | if dump_schema_after_migration? 14 | filename = DataMigrate::DatabaseTasks.schema_file 15 | ActiveRecord::Base.establish_connection(DataMigrate.config.db_configuration) if DataMigrate.config.db_configuration 16 | File.open(filename, "w:utf-8") do |file| 17 | DataMigrate::SchemaDumper.dump(ActiveRecord::Base.connection, file) 18 | end 19 | end 20 | end 21 | 22 | def migrate 23 | target_version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil 24 | 25 | DataMigrate::DataMigrator.create_data_schema_table 26 | DataMigrate::MigrationContext.new(migrations_paths).migrate(target_version) 27 | end 28 | 29 | def abort_if_pending_migrations(migrations, message) 30 | if migrations.any? 31 | puts "You have #{migrations.size} pending #{'migration'.pluralize(migrations.size)}:" 32 | migrations.each do |pending_migration| 33 | puts " %4d %s" % [pending_migration[:version], pending_migration[:name]] 34 | end 35 | abort message 36 | end 37 | end 38 | 39 | def dump_schema_after_migration? 40 | if ActiveRecord.respond_to?(:dump_schema_after_migration) 41 | ActiveRecord.dump_schema_after_migration 42 | else 43 | ActiveRecord::Base.dump_schema_after_migration 44 | end 45 | end 46 | 47 | def status 48 | DataMigrate::StatusService.dump 49 | end 50 | 51 | def status_with_schema 52 | db_list_data = ActiveRecord::Base.connection.select_values( 53 | "SELECT version FROM #{DataMigrate::RailsHelper.data_schema_migration.table_name}" 54 | ) 55 | db_list_schema = DataMigrate::RailsHelper.schema_migration_versions 56 | file_list = [] 57 | 58 | migrations_paths.each do |path| 59 | Dir.foreach(File.join(Rails.root, path)) do |file| 60 | # only files matching "20091231235959_some_name.rb" pattern 61 | if match_data = /(\d{14})_(.+)\.rb/.match(file) 62 | status = db_list_data.delete(match_data[1]) ? 'up' : 'down' 63 | file_list << [status, match_data[1], match_data[2], 'data'] 64 | end 65 | end 66 | end 67 | 68 | DataMigrate::SchemaMigration.migrations_paths.map do |path| 69 | Dir.children(path) if Dir.exist?(path) 70 | end.flatten.compact.each do |file| 71 | # only files matching "20091231235959_some_name.rb" pattern 72 | if match_data = /(\d{14})_(.+)\.rb/.match(file) 73 | status = db_list_schema.delete(match_data[1]) ? 'up' : 'down' 74 | file_list << [status, match_data[1], match_data[2], 'schema'] 75 | end 76 | end 77 | 78 | file_list.sort!{|a,b| "#{a[1]}_#{a[3] == 'data' ? 1 : 0}" <=> "#{b[1]}_#{b[3] == 'data' ? 1 : 0}" } 79 | 80 | # output 81 | puts "\ndatabase: #{database_name}\n\n" 82 | puts "#{"Status".center(8)} #{"Type".center(8)} #{"Migration ID".ljust(14)} Migration Name" 83 | puts "-" * 60 84 | file_list.each do |file| 85 | puts "#{file[0].center(8)} #{file[3].center(8)} #{file[1].ljust(14)} #{file[2].humanize}" 86 | end 87 | db_list_schema.each do |version| 88 | puts "#{'up'.center(8)} #{version.ljust(14)} *** NO SCHEMA FILE ***" 89 | end 90 | db_list_data.each do |version| 91 | puts "#{'up'.center(8)} #{version.ljust(14)} *** NO DATA FILE ***" 92 | end 93 | puts 94 | end 95 | 96 | private 97 | 98 | def database_name 99 | if Gem::Dependency.new("railties", "~> 7.0").match?("railties", Gem.loaded_specs["railties"].version) 100 | ActiveRecord::Base.connection_db_config.database 101 | elsif Gem::Dependency.new("railties", "~> 6.1").match?("railties", Gem.loaded_specs["railties"].version) 102 | ActiveRecord::Base.connection_config[:database] 103 | end 104 | end 105 | end 106 | end 107 | end 108 | -------------------------------------------------------------------------------- /lib/data_migrate/version.rb: -------------------------------------------------------------------------------- 1 | module DataMigrate 2 | VERSION = "11.3.0".freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/generators/data_migrate.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators/named_base' 2 | 3 | module DataMigrate 4 | module Generators 5 | class DataMigrationGenerator < Rails::Generators::NamedBase #:nodoc: 6 | class << self 7 | def source_root 8 | build_data_migrate_source_root 9 | end 10 | 11 | private 12 | 13 | def build_data_migrate_source_root 14 | if DataMigrate.config.data_template_path == DataMigrate::Config::DEFAULT_DATA_TEMPLATE_PATH 15 | File.expand_path(File.join(File.dirname(__FILE__), generator_name, 'templates')) 16 | else 17 | File.expand_path(File.dirname(DataMigrate.config.data_template_path)) 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/generators/data_migration/data_migration_generator.rb: -------------------------------------------------------------------------------- 1 | require "generators/data_migrate" 2 | require "rails/generators" 3 | require "rails/generators/active_record/migration" 4 | require "rails/generators/migration" 5 | require "data_migrate/config" 6 | 7 | module DataMigrate 8 | module Generators 9 | class DataMigrationGenerator < Rails::Generators::NamedBase 10 | namespace "data_migration" 11 | include ActiveRecord::Generators::Migration 12 | 13 | argument :attributes, type: :array, default: [], banner: "field:type field:type" 14 | 15 | def create_data_migration 16 | set_local_assigns! 17 | migration_template template_path, data_migrations_file_path 18 | end 19 | 20 | protected 21 | 22 | def set_local_assigns! 23 | if file_name =~ /^(add|remove)_.*_(?:to|from)_(.*)/ 24 | @migration_action = $1 25 | @table_name = $2.pluralize 26 | end 27 | end 28 | 29 | def template_path 30 | DataMigrate.config.data_template_path 31 | end 32 | 33 | def migration_base_class_name 34 | "ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]" 35 | end 36 | 37 | def data_migrations_file_path 38 | File.join(data_migrations_path, "#{file_name}.rb") 39 | end 40 | 41 | # Use the first path in the data_migrations_path as the target directory 42 | def data_migrations_path 43 | Array.wrap(DataMigrate.config.data_migrations_path).first 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/generators/data_migration/templates/data_migration.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class <%= migration_class_name %> < <%= migration_base_class_name %> 4 | def up 5 | end 6 | 7 | def down 8 | raise ActiveRecord::IrreversibleMigration 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/generators/data_migration/templates/migration.rb: -------------------------------------------------------------------------------- 1 | class <%= migration_class_name %> < ActiveRecord::Migration 2 | def self.up 3 | <% attributes.each do |attribute| -%> 4 | <%- if migration_action -%> 5 | <%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end %> 6 | <%- end -%> 7 | <%- end -%> 8 | end 9 | 10 | def self.down 11 | <% attributes.reverse.each do |attribute| -%> 12 | <%- if migration_action -%> 13 | <%= migration_action == 'add' ? 'remove' : 'add' %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'remove' %>, :<%= attribute.type %><% end %> 14 | <%- end -%> 15 | <%- end -%> 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilyakatz/data-migrate/d4cebfad06b13a1fd30050986320436cae965352/screenshot.png -------------------------------------------------------------------------------- /spec/data_migrate/config_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe DataMigrate::Config do 6 | it "sets default data_migrations_path path", :no_override do 7 | expect(DataMigrate.config.data_migrations_path).to eq "db/data/" 8 | end 9 | 10 | it "sets default data_template_path path", :no_override do 11 | expect(DataMigrate.config.data_template_path).to eq DataMigrate::Config::DEFAULT_DATA_TEMPLATE_PATH 12 | end 13 | 14 | describe "data migration path configured" do 15 | subject { DataMigrate.config.data_migrations_path } 16 | let(:data_migrations_path) { "db/awesome/" } 17 | 18 | before do 19 | @original_data_migrations_path = DataMigrate.config.data_migrations_path 20 | 21 | DataMigrate.configure do |config| 22 | config.data_migrations_path = data_migrations_path 23 | end 24 | end 25 | 26 | after do 27 | DataMigrate.configure do |config| 28 | config.data_migrations_path = @original_data_migrations_path 29 | end 30 | end 31 | 32 | it "equals the custom data migration path" do 33 | is_expected.to eq(data_migrations_path) 34 | end 35 | end 36 | 37 | describe "data template path configured" do 38 | subject { DataMigrate.config.data_template_path } 39 | let(:data_template_path) { File.join(DataMigrate.root, "generators", "data_migration", "templates", "data_migration.rb") } 40 | 41 | before do 42 | @original_data_migrations_path = DataMigrate.config.data_template_path 43 | 44 | DataMigrate.configure do |config| 45 | config.data_template_path = data_template_path 46 | end 47 | end 48 | 49 | after do 50 | DataMigrate.configure do |config| 51 | config.data_template_path = @original_data_migrations_path 52 | end 53 | end 54 | 55 | it "equals the custom data template path" do 56 | is_expected.to eq data_template_path 57 | end 58 | 59 | context "when path does not exist" do 60 | subject { DataMigrate.config.data_template_path = invalid_path } 61 | 62 | let(:invalid_path) { "lib/awesome/templates/data_migration.rb" } 63 | 64 | it "checks that file exists on setting config var" do 65 | expect { subject }.to raise_error { ArgumentError.new("File not found: '#{data_template_path}'") } 66 | end 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/data_migrate/data_migrator_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe DataMigrate::DataMigrator do 6 | let(:described_class) { DataMigrate::DataMigrator } 7 | 8 | let(:db_config) do 9 | { 10 | adapter: "sqlite3", 11 | database: "spec/db/test.db" 12 | } 13 | end 14 | 15 | before do 16 | ActiveRecord::Base.establish_connection(db_config) 17 | DataMigrate::RailsHelper.schema_migration.create_table 18 | DataMigrate::RailsHelper.data_schema_migration.create_table 19 | end 20 | 21 | after do 22 | ActiveRecord::Migration.drop_table("data_migrations") rescue nil 23 | ActiveRecord::Migration.drop_table("schema_migrations") rescue nil 24 | end 25 | 26 | describe ".load_migrated" do 27 | let(:migrator) { DataMigrate::RailsHelper.data_migrator(:up, []) } 28 | 29 | it "loads migrated versions" do 30 | DataMigrate::RailsHelper.data_schema_migration.create_version(20090000000000) 31 | DataMigrate::RailsHelper.schema_create_version(20100000000000) 32 | DataMigrate::RailsHelper.data_schema_migration.create_version(20110000000000) 33 | DataMigrate::RailsHelper.schema_create_version(20120000000000) 34 | migrated = migrator.load_migrated 35 | expect(migrated.count).to eq 2 36 | expect(migrated).to include 20090000000000 37 | expect(migrated).to include 20110000000000 38 | end 39 | end 40 | 41 | describe :create_data_schema_table do 42 | it "creates the data_migrations table" do 43 | ActiveRecord::Migration.drop_table("data_migrations") rescue nil 44 | described_class.create_data_schema_table 45 | expect( 46 | ActiveRecord::Base.connection.table_exists?("data_migrations") 47 | ).to eq true 48 | end 49 | end 50 | 51 | describe "#migrations_status" do 52 | it "returns all migrations statuses" do 53 | status = described_class.migrations_status 54 | expect(status.length).to eq 3 55 | expect(status.first).to eq ["down", "20091231235959", "Some name"] 56 | expect(status.second).to eq ["down", "20171231235959", "Super update"] 57 | expect(status.third).to eq ["down", "20241231235959", "Data two update"] 58 | end 59 | end 60 | 61 | describe :match do 62 | context "when the file does not match" do 63 | it "returns nil" do 64 | expect(described_class.match("not_a_data_migration_file")).to be_nil 65 | end 66 | end 67 | 68 | context "when the file doesn't end in .rb" do 69 | it "returns nil" do 70 | expect(described_class.match("20091231235959_some_name.rb.un~")).to be_nil 71 | end 72 | end 73 | 74 | context "when the file matches" do 75 | it "returns a valid MatchData object" do 76 | match_data = described_class.match("20091231235959_some_name.rb") 77 | 78 | expect(match_data[0]).to eq "20091231235959_some_name.rb" 79 | expect(match_data[1]).to eq "20091231235959" 80 | expect(match_data[2]).to eq "some_name" 81 | end 82 | end 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /spec/data_migrate/data_schema_migration_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DataMigrate::DataSchemaMigration do 4 | if DataMigrate::RailsHelper.rails_version_equal_to_or_higher_than_7_1 5 | let(:connection) { double(:connection) } 6 | let(:subject) { DataMigrate::DataSchemaMigration.new(connection) } 7 | 8 | describe :table_name do 9 | it "returns correct table name" do 10 | expect(subject.table_name).to eq("data_migrations") 11 | end 12 | 13 | describe "when data migrations table name configured" do 14 | let(:data_migrations_table_name) { "my_app_data_template_migrations"} 15 | 16 | before do 17 | @before = DataMigrate.config.data_migrations_table_name 18 | DataMigrate.configure do |config| 19 | config.data_migrations_table_name = data_migrations_table_name 20 | end 21 | end 22 | 23 | after do 24 | DataMigrate.configure do |config| 25 | config.data_migrations_table_name = @before 26 | end 27 | end 28 | 29 | it "returns correct table name" do 30 | expect(subject.table_name).to eq(data_migrations_table_name) 31 | end 32 | end 33 | end 34 | 35 | describe :index_name do 36 | it "returns correct primary key name" do 37 | expect(subject.primary_key).to eq("version") 38 | end 39 | end 40 | else 41 | let(:subject) { DataMigrate::DataSchemaMigration } 42 | describe :table_name do 43 | it "returns correct table name" do 44 | expect(subject.table_name).to eq("data_migrations") 45 | end 46 | 47 | describe "when data migrations table name configured" do 48 | let(:data_migrations_table_name) { "my_app_data_template_migrations"} 49 | 50 | before do 51 | @before = DataMigrate.config.data_migrations_table_name 52 | DataMigrate.configure do |config| 53 | config.data_migrations_table_name = data_migrations_table_name 54 | end 55 | end 56 | 57 | after do 58 | DataMigrate.configure do |config| 59 | config.data_migrations_table_name = @before 60 | end 61 | end 62 | 63 | it "returns correct table name" do 64 | expect(subject.table_name).to eq(data_migrations_table_name) 65 | end 66 | end 67 | end 68 | 69 | describe :index_name do 70 | it "returns correct primary key name" do 71 | expect(subject.primary_key).to eq("version") 72 | end 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /spec/data_migrate/data_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe DataMigrate::Data do 6 | let(:subject) { DataMigrate::Data } 7 | let(:fixture_file_timestamps) do 8 | %w[20091231235959 20101231235959 20111231235959] 9 | end 10 | 11 | around do |example| 12 | Dir.mktmpdir do |temp_dir| 13 | @temp_dir = temp_dir 14 | 15 | # create the fake data migration files 16 | fixture_file_timestamps.each do |timestamp| 17 | FileUtils.touch File.join(temp_dir, "#{timestamp}_data_migration.rb") 18 | end 19 | 20 | example.run 21 | end 22 | end 23 | 24 | describe :define do 25 | after do 26 | ActiveRecord::Migration.drop_table("data_migrations") 27 | end 28 | 29 | context "when no version is supplied" do 30 | it "returns nil" do 31 | expect(subject.define(version: nil)).to be_nil 32 | end 33 | end 34 | 35 | context "when a version is supplied" do 36 | before do 37 | allow(DataMigrate::DataMigrator). 38 | to receive(:full_migrations_path).and_return(@temp_dir) 39 | end 40 | 41 | it "sets the current version to the supplied version" do 42 | version = fixture_file_timestamps[1] 43 | 44 | expect(DataMigrate::DataMigrator.current_version).not_to eq version.to_i 45 | subject.define(version: version) 46 | expect(DataMigrate::DataMigrator.current_version).to eq version.to_i 47 | end 48 | 49 | it "creates entries for migration versions that come " \ 50 | "before the supplied version" do 51 | 52 | version = fixture_file_timestamps[1] 53 | 54 | subject.define(version: version) 55 | 56 | sql_select = <<-SQL 57 | SELECT version 58 | FROM #{DataMigrate::RailsHelper.data_schema_migration.table_name} 59 | SQL 60 | 61 | db_list_data = ActiveRecord::Base.connection. 62 | select_values(sql_select).map(&:to_i) 63 | expect(db_list_data).to match_array( 64 | [fixture_file_timestamps[0], fixture_file_timestamps[1]].map(&:to_i) 65 | ) 66 | 67 | # The last remaining migration (fixture_file_timestamps[2]) was 68 | # not included as part of the supplied version and so should not 69 | # appear in the data_migrations table. 70 | expect(db_list_data).not_to include(fixture_file_timestamps[2]) 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /spec/data_migrate/database_tasks_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe DataMigrate::DatabaseTasks do 6 | let(:subject) { DataMigrate::DatabaseTasks } 7 | let(:migration_path) { "spec/db/migrate" } 8 | let(:data_migrations_path) { DataMigrate.config.data_migrations_path } 9 | 10 | before do 11 | # In a normal Rails installation, db_dir would defer to 12 | # Rails.application.config.paths["db"].first 13 | # @see https://github.com/rails/rails/blob/a7d49ef78c36df2d1ca876451f30915ada1079a5/activerecord/lib/active_record/tasks/database_tasks.rb#L54 14 | allow(subject).to receive(:db_dir).and_return("db") 15 | allow(ActiveRecord::Tasks::DatabaseTasks).to receive(:db_dir).and_return("db") 16 | end 17 | 18 | before do 19 | allow(DataMigrate::Tasks::DataMigrateTasks).to receive(:migrations_paths) do 20 | data_migrations_path 21 | end 22 | ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: "spec/db/test.db") 23 | hash_config = ActiveRecord::DatabaseConfigurations::HashConfig.new( 24 | 'test', 'test', adapter: "sqlite3", database: "spec/db/test.db" 25 | ) 26 | config_obj = ActiveRecord::DatabaseConfigurations.new([hash_config]) 27 | allow(ActiveRecord::Base).to receive(:configurations).and_return(config_obj) 28 | end 29 | 30 | context "migrations" do 31 | after do 32 | ActiveRecord::Migration.drop_table("data_migrations") rescue nil 33 | ActiveRecord::Migration.drop_table("schema_migrations") rescue nil 34 | end 35 | 36 | before do 37 | DataMigrate::RailsHelper.schema_migration.create_table 38 | 39 | allow(DataMigrate::SchemaMigration).to receive(:migrations_paths) { migration_path } 40 | allow(DataMigrate::DatabaseTasks).to receive(:data_migrations_path) do 41 | data_migrations_path 42 | end.at_least(:once) 43 | end 44 | 45 | describe :past_migrations do 46 | it "returns past migration records" do 47 | subject.forward 48 | migrations = subject.past_migrations 49 | expect(migrations.count).to eq 1 50 | expect(migrations.first[:version]).to eq 20091231235959 51 | end 52 | 53 | it "shows nothing without any migrations" do 54 | migrations = subject.past_migrations 55 | expect(migrations.count).to eq 0 56 | end 57 | end 58 | 59 | describe :forward do 60 | it "run forward default amount of times" do 61 | subject.forward 62 | versions = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 63 | expect(versions.count).to eq(1) 64 | end 65 | 66 | it "run forward defined number of times" do 67 | subject.forward(2) 68 | versions = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 69 | expect(versions.count).to eq(1) 70 | expect(versions.first).to eq "20091231235959" 71 | versions = DataMigrate::RailsHelper.schema_migration.normalized_versions 72 | expect(versions.count).to eq(1) 73 | expect(versions.first).to eq "20131111111111" 74 | end 75 | end 76 | 77 | if DataMigrate::RailsHelper.rails_version_equal_to_or_higher_than_7_0 78 | describe :schema_dump_path do 79 | before do 80 | allow(ActiveRecord::Base).to receive(:configurations) 81 | .and_return(ActiveRecord::DatabaseConfigurations.new([db_config])) 82 | end 83 | 84 | context "for primary database" do 85 | let(:db_config) do 86 | ActiveRecord::DatabaseConfigurations::HashConfig.new("development", "primary", {}) 87 | end 88 | 89 | context "for :ruby db format" do 90 | it 'returns the data schema path' do 91 | allow(ActiveRecord).to receive(:schema_format).and_return(:ruby) 92 | expect(subject.schema_dump_path(db_config)).to eq("db/data_schema.rb") 93 | end 94 | end 95 | 96 | context "for :sql db format" do 97 | it 'returns the data schema path' do 98 | allow(ActiveRecord).to receive(:schema_format).and_return(:sql) 99 | expect(subject.schema_dump_path(db_config, :sql)).to eq("db/data_schema.rb") 100 | end 101 | end 102 | end 103 | end 104 | end 105 | 106 | describe :prepare_all_with_data do 107 | let(:db_config) do 108 | ActiveRecord::DatabaseConfigurations::HashConfig.new( 109 | 'test', 110 | 'primary', 111 | adapter: "sqlite3", 112 | database: "spec/db/test.db" 113 | ) 114 | end 115 | 116 | let(:pool) { double("ConnectionPool") } 117 | let(:connection) { double("Connection") } 118 | 119 | before do 120 | allow(subject).to receive(:each_current_configuration).and_yield(db_config) 121 | allow(subject).to receive(:with_temporary_pool).with(db_config).and_yield(pool) 122 | allow(pool).to receive(:lease_connection).and_return(connection) 123 | allow(subject).to receive(:schema_dump_path).and_return("db/data_schema.rb") 124 | allow(File).to receive(:exist?).and_return(true) 125 | allow(subject).to receive(:load_schema) 126 | allow(subject).to receive(:load_schema_current) 127 | allow(subject).to receive(:migrate_with_data) 128 | allow(subject).to receive(:dump_schema) 129 | allow(DataMigrate::Tasks::DataMigrateTasks).to receive(:dump) 130 | allow(subject).to receive(:load_seed) 131 | 132 | configurations = ActiveRecord::DatabaseConfigurations.new([db_config]) 133 | allow(ActiveRecord::Base).to receive(:configurations).and_return(configurations) 134 | end 135 | 136 | context "when the database does not exist" do 137 | before do 138 | allow(subject).to receive(:database_exists?).with(connection).and_return(false) 139 | allow_any_instance_of(ActiveRecord::Tasks::DatabaseTasks).to receive(:create) 140 | .and_return(true) 141 | end 142 | 143 | it "creates the database" do 144 | expect_any_instance_of(ActiveRecord::Tasks::DatabaseTasks).to receive(:create) 145 | .with(db_config) 146 | subject.prepare_all_with_data 147 | end 148 | 149 | it "loads the schema" do 150 | expect(subject).to receive(:load_schema).with( 151 | db_config, 152 | subject.send(:schema_format), 153 | nil 154 | ) 155 | subject.prepare_all_with_data 156 | end 157 | 158 | it "loads the current data schema" do 159 | expect(subject).to receive(:load_schema_current).with(:ruby, ENV["DATA_SCHEMA"]) 160 | subject.prepare_all_with_data 161 | end 162 | 163 | it "runs migrations with data" do 164 | expect(subject).to receive(:migrate_with_data) 165 | subject.prepare_all_with_data 166 | end 167 | 168 | it "dumps the schema after migration" do 169 | expect(subject).to receive(:dump_schema).with(db_config) 170 | expect(DataMigrate::Tasks::DataMigrateTasks).to receive(:dump) 171 | subject.prepare_all_with_data 172 | end 173 | 174 | it "loads seed data" do 175 | expect(subject).to receive(:load_seed) 176 | subject.prepare_all_with_data 177 | end 178 | end 179 | 180 | context "when the database exists" do 181 | before do 182 | allow(subject).to receive(:database_exists?).with(connection).and_return(true) 183 | end 184 | 185 | it "does not create the database" do 186 | expect(ActiveRecord::Tasks::DatabaseTasks).not_to receive(:create) 187 | subject.prepare_all_with_data 188 | end 189 | 190 | it "does not load the schema" do 191 | expect(subject).not_to receive(:load_schema) 192 | expect(subject).not_to receive(:load_schema_current) 193 | subject.prepare_all_with_data 194 | end 195 | 196 | it "runs migrations with data" do 197 | expect(subject).to receive(:migrate_with_data) 198 | subject.prepare_all_with_data 199 | end 200 | 201 | it "dumps the schema after migration" do 202 | expect(subject).to receive(:dump_schema).with(db_config) 203 | expect(DataMigrate::Tasks::DataMigrateTasks).to receive(:dump) 204 | subject.prepare_all_with_data 205 | end 206 | 207 | it "does not load seed data" do 208 | expect(subject).not_to receive(:load_seed) 209 | subject.prepare_all_with_data 210 | end 211 | end 212 | end 213 | end 214 | end 215 | -------------------------------------------------------------------------------- /spec/data_migrate/migration.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe DataMigrate::Migration do 6 | describe ".table_name" do 7 | it "returns correct table name" do 8 | expect(subject.table_name).to eq("data_migrations") 9 | end 10 | end 11 | 12 | describe ".index_name" do 13 | it "returns correct primary key name" do 14 | expect(subject.primary_key).to eq("version") 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/data_migrate/migration_context_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe DataMigrate::DataMigrator do 6 | let(:context) { DataMigrate::MigrationContext.new("spec/db/data") } 7 | let(:schema_context) { ActiveRecord::MigrationContext.new("spec/db/migrate", ar_schema_migration) } 8 | let(:db_config) do 9 | { 10 | adapter: "sqlite3", 11 | database: "spec/db/test.db" 12 | } 13 | end 14 | 15 | before do 16 | ActiveRecord::Base.establish_connection(db_config) 17 | DataMigrate::RailsHelper.schema_migration.create_table 18 | DataMigrate::RailsHelper.data_schema_migration.create_table 19 | end 20 | 21 | after do 22 | ActiveRecord::Migration.drop_table("data_migrations") rescue nil 23 | ActiveRecord::Migration.drop_table("schema_migrations") rescue nil 24 | end 25 | 26 | describe "migrate" do 27 | it "migrates existing file" do 28 | context.migrate(nil) 29 | context.migrations_status 30 | versions = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 31 | expect(versions.count).to eq(2) 32 | expect(versions).to include("20091231235959") 33 | expect(versions).to include("20171231235959") 34 | end 35 | 36 | it "undo migration" do 37 | context.migrate(nil) 38 | context.run(:down, 20171231235959) 39 | versions = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 40 | expect(versions.count).to eq(1) 41 | expect(versions).to include("20091231235959") 42 | end 43 | 44 | it "does not do anything if migration is undone twice" do 45 | context.migrate(nil) 46 | expect { 47 | context.run(:down, 20171231235959) 48 | }.to output(/Undoing SuperUpdate/).to_stdout 49 | expect { 50 | context.run(:down, 20171231235959) 51 | }.not_to output(/Undoing SuperUpdate/).to_stdout 52 | end 53 | 54 | it "runs a specific migration" do 55 | context.run(:up, 20171231235959) 56 | versions = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 57 | expect(versions.count).to eq(1) 58 | expect(versions).to include("20171231235959") 59 | end 60 | 61 | it "does not do anything if migration is ran twice" do 62 | expect { 63 | context.run(:up, 20171231235959) 64 | }.to output(/Doing SuperUpdate/).to_stdout 65 | expect { 66 | context.run(:down, 20171231235959) 67 | }.not_to output(/Doing SuperUpdate/).to_stdout 68 | end 69 | 70 | it "alerts for an invalid specific migration" do 71 | expect { 72 | context.run(:up, 201712312) 73 | }.to raise_error( 74 | ActiveRecord::UnknownMigrationVersionError, 75 | /No migration with version number 201712312/ 76 | ) 77 | end 78 | 79 | it "rolls back latest migration" do 80 | context.migrate(nil) 81 | expect { 82 | context.rollback 83 | }.to output(/Undoing SuperUpdate/).to_stdout 84 | versions = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 85 | expect(versions.count).to eq(1) 86 | expect(versions).to include("20091231235959") 87 | end 88 | 89 | it "rolls back 2 migrations" do 90 | context.migrate(nil) 91 | schema_context.migrate(nil) 92 | expect { 93 | context.rollback(2) 94 | }.to output(/Undoing SomeName/).to_stdout 95 | versions = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 96 | expect(versions.count).to eq(0) 97 | end 98 | 99 | it "rolls back 2 migrations" do 100 | context.migrate(nil) 101 | expect { 102 | context.rollback(2) 103 | }.to output(/Undoing SomeName/).to_stdout 104 | versions = DataMigrate::RailsHelper.data_schema_migration.normalized_versions 105 | expect(versions.count).to eq(0) 106 | end 107 | end 108 | 109 | # schema migration changed in Rails 7.2, from the connection to the pool object. 110 | def ar_schema_migration 111 | if ActiveRecord::Base.connection_pool.respond_to?(:schema_migration) 112 | ActiveRecord::Base.connection_pool.schema_migration 113 | else 114 | ActiveRecord::Base.connection.schema_migration 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /spec/data_migrate/schema_dumper_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe DataMigrate::SchemaDumper do 6 | let(:subject) { DataMigrate::SchemaDumper } 7 | let(:fixture_file_timestamps) do 8 | %w[20091231235959 20101231235959 20111231235959] 9 | end 10 | 11 | before do 12 | DataMigrate::RailsHelper.schema_migration.create_table 13 | DataMigrate::RailsHelper.data_schema_migration.create_table 14 | 15 | fixture_file_timestamps.map do |t| 16 | DataMigrate::RailsHelper.data_schema_migration.create_version(t) 17 | end 18 | end 19 | 20 | after do 21 | ActiveRecord::Migration.drop_table("data_migrations") rescue nil 22 | ActiveRecord::Migration.drop_table("schema_migrations") rescue nil 23 | end 24 | 25 | describe ".dump" do 26 | it "writes the define method with the version key to the stream" do 27 | stream = StringIO.new 28 | DataMigrate::SchemaDumper.dump(ActiveRecord::Base.connection, stream) 29 | stream.rewind 30 | 31 | last_version = fixture_file_timestamps.last.dup.insert(4, "_").insert(7, "_").insert(10, "_") 32 | expected = "DataMigrate::Data.define(version: #{last_version})" 33 | expect(stream.read).to include expected 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/data_migrate/schema_migration_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe DataMigrate::SchemaMigration do 6 | let(:subject) { DataMigrate::SchemaMigration } 7 | let(:migration_path) { "spec/db/migrate" } 8 | let(:fixture_file_timestamps) do 9 | %w[20091231235959 20101231235959 20111231235959] 10 | end 11 | let(:db_config) do 12 | { 13 | adapter: "sqlite3", 14 | database: "spec/db/test.db" 15 | } 16 | end 17 | 18 | before do 19 | ActiveRecord::Base.establish_connection(db_config) 20 | DataMigrate::RailsHelper.schema_migration.create_table 21 | DataMigrate::RailsHelper.data_schema_migration.create_table 22 | end 23 | 24 | after do 25 | ActiveRecord::Migration.drop_table("data_migrations") rescue nil 26 | ActiveRecord::Migration.drop_table("schema_migrations") rescue nil 27 | end 28 | 29 | describe :pending_schema_migrations do 30 | it "list sorted schema migrations" do 31 | expect(subject).to receive(:migrations_paths) { 32 | migration_path 33 | } 34 | 35 | migrations = subject.pending_schema_migrations 36 | 37 | expect(migrations.count).to eq 2 38 | expect(migrations[0][:version]).to eq(20131111111111) 39 | expect(migrations[1][:version]).to eq(20202020202011) 40 | end 41 | end 42 | 43 | describe :run do 44 | it "can run up task" do 45 | expect { 46 | subject.run(:up, migration_path, 20202020202011) 47 | }.to output(/20202020202011 DbMigration: migrating/).to_stdout 48 | versions = DataMigrate::RailsHelper.schema_migration.normalized_versions 49 | expect(versions.first).to eq("20202020202011") 50 | end 51 | 52 | it "can run down task" do 53 | subject.run(:up, migration_path, 20202020202011) 54 | 55 | expect { 56 | subject.run(:down, migration_path, 20202020202011) 57 | }.to output(/Undoing DbMigration/).to_stdout 58 | 59 | versions = DataMigrate::RailsHelper.schema_migration.normalized_versions 60 | 61 | expect(versions.count).to eq(0) 62 | end 63 | end 64 | 65 | describe :migrations_paths do 66 | context 'when a db_name is configured' do 67 | let(:config) { double(:config) } 68 | let(:paths) { ['spec/db/migrate', 'spec/db/migrate/other'] } 69 | let(:specification_name) { "primary" } 70 | let(:config_options) do 71 | if Gem::Dependency.new("railties", "~> 6.1").match?("railties", Gem.loaded_specs["railties"].version) 72 | { env_name: Rails.env, spec_name: specification_name } 73 | else 74 | { env_name: Rails.env, name: specification_name } 75 | end 76 | end 77 | 78 | before do 79 | @original_config_spec_name = DataMigrate.config.spec_name 80 | 81 | DataMigrate.configure do |config| 82 | config.spec_name = specification_name 83 | end 84 | 85 | allow(ActiveRecord::Base.configurations) 86 | .to receive(:configs_for) 87 | .with(config_options) 88 | .and_return(config) 89 | allow(config).to receive(:migrations_paths).and_return(paths) 90 | end 91 | 92 | after do 93 | DataMigrate.configure do |config| 94 | config.spec_name = @original_config_spec_name 95 | end 96 | end 97 | 98 | it 'lists schema migration paths' do 99 | expect(subject.migrations_paths.size).to eq(paths.count) 100 | expect(subject.migrations_paths).to eq(paths) 101 | end 102 | end 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /spec/data_migrate/status_service_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe DataMigrate::StatusService do 6 | let(:subject) { DataMigrate::StatusService } 7 | let(:stream) { StringIO.new } 8 | let(:stream_data) { stream.read } 9 | let(:connection_db_config) do 10 | if Gem::Dependency.new("railties", ">= 6.1").match?("railties", Gem.loaded_specs["railties"].version) 11 | ActiveRecord::Base.connection_db_config 12 | else 13 | ActiveRecord::Base.configurations.configs_for.first 14 | end 15 | end 16 | 17 | context "table does not exists" do 18 | before do 19 | allow_any_instance_of(subject).to receive(:table_name) { "bogus"} 20 | 21 | subject.dump(connection_db_config, stream) 22 | stream.rewind 23 | end 24 | 25 | it "show error message" do 26 | expect(stream_data).to include("Data migrations table does not exist") 27 | end 28 | end 29 | 30 | context "table exists" do 31 | let(:fixture_file_timestamps) do 32 | %w[20091231235959 20101231235959 20111231235959] 33 | end 34 | 35 | before do 36 | DataMigrate::RailsHelper.schema_migration.create_table 37 | DataMigrate::RailsHelper.data_schema_migration.create_table 38 | 39 | fixture_file_timestamps.map do |t| 40 | DataMigrate::RailsHelper.data_schema_migration.create_version(t) 41 | end 42 | 43 | subject.dump(connection_db_config, stream) 44 | stream.rewind 45 | end 46 | 47 | after do 48 | ActiveRecord::Migration.drop_table("data_migrations") rescue nil 49 | ActiveRecord::Migration.drop_table("schema_migrations") rescue nil 50 | end 51 | 52 | it "shows successfully executed migration" do 53 | expected = " up 20091231235959 Some name" 54 | expect(stream_data).to include expected 55 | end 56 | 57 | it "excludes files without .rb extension" do 58 | expected = "20181128000207 Excluded file" 59 | expect(stream_data).to_not include expected 60 | end 61 | 62 | it "shows missing file migration" do 63 | expected = " up 20101231235959 ********** NO FILE **********" 64 | expect(stream_data).to include expected 65 | end 66 | 67 | it "shows migration that has not run yet" do 68 | expected = " down 20171231235959 Super update" 69 | expect(stream_data).to include expected 70 | end 71 | 72 | it "outputs migrations in chronological order" do 73 | expect(stream_data.index("20091231235959")).to be < stream_data.index("20111231235959") 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/data_migrate/tasks/data_migrate_tasks_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe DataMigrate::Tasks::DataMigrateTasks do 6 | let(:db_config) do 7 | { 8 | adapter: "sqlite3", 9 | database: "spec/db/test.db" 10 | } 11 | end 12 | 13 | before do 14 | ActiveRecord::Base.establish_connection(db_config) 15 | DataMigrate::RailsHelper.schema_migration.create_table 16 | DataMigrate::RailsHelper.data_schema_migration.create_table 17 | end 18 | 19 | after do 20 | ActiveRecord::Migration.drop_table("data_migrations") rescue nil 21 | ActiveRecord::Migration.drop_table("schema_migrations") rescue nil 22 | end 23 | 24 | describe :dump do 25 | before do 26 | allow(DataMigrate::DatabaseTasks).to receive(:db_dir).and_return("spec/db") 27 | DataMigrate::Tasks::DataMigrateTasks.migrate 28 | end 29 | 30 | context 'when not given a separate db config' do 31 | it 'does not override the default connection' do 32 | expect(ActiveRecord::Base).not_to receive(:establish_connection) 33 | expect(DataMigrate::SchemaDumper).to receive(:dump) 34 | 35 | DataMigrate::Tasks::DataMigrateTasks.dump 36 | end 37 | end 38 | 39 | context 'when given a separate db config' do 40 | let(:override_config) do 41 | { 42 | 'host' => '127.0.0.1', 43 | 'database' => 'other_test', 44 | 'adapter' => 'sqlite3', 45 | 'username' => 'root', 46 | 'password' => nil, 47 | } 48 | end 49 | let(:paths) { ["spec/db/migrate"] } 50 | 51 | before do 52 | DataMigrate.configure do |config| 53 | config.db_configuration = override_config 54 | end 55 | end 56 | 57 | it 'overrides the default connection' do 58 | expect(ActiveRecord::Base).to receive(:establish_connection).with(override_config) 59 | DataMigrate::Tasks::DataMigrateTasks.dump 60 | end 61 | end 62 | end 63 | 64 | describe :migrate do 65 | it "first run should run the first pending migration" do 66 | expect { DataMigrate::Tasks::DataMigrateTasks.migrate }.to output(/20091231235959 SomeName: migrating/).to_stdout 67 | end 68 | 69 | it "second run should run the second pending migration" do 70 | expect { DataMigrate::Tasks::DataMigrateTasks.migrate }.to output(/20171231235959 SuperUpdate: migrating/).to_stdout 71 | end 72 | end 73 | 74 | describe :abort_if_pending_migrations do 75 | subject { DataMigrate::Tasks::DataMigrateTasks.abort_if_pending_migrations(migrations, message) } 76 | 77 | let(:message) { "ABORT_MESSAGE" } 78 | 79 | context "when there are no pending migrations" do 80 | let(:migrations) { [] } 81 | 82 | it "shouldn't do anything" do 83 | expect { subject }.to_not raise_error 84 | end 85 | end 86 | 87 | context "when there are pending migrations" do 88 | let(:migrations) do 89 | [{ 90 | name: "A", 91 | version: 1 92 | }, { 93 | name: 'B', 94 | version: 2 95 | }] 96 | end 97 | 98 | it "should abort with given message and print names and versions of pending migrations" do 99 | expect { subject } 100 | .to raise_error(SystemExit, message) 101 | .and output(match(/You have #{migrations.count} pending migrations:/) 102 | .and match(Regexp.new(migrations.map { |m| m.slice(:version, :name) 103 | .values.join("\\W+") }.join("\\W+")))).to_stdout 104 | end 105 | end 106 | end 107 | 108 | describe ".status" do 109 | before do 110 | allow(Rails).to receive(:root) { "." } 111 | allow(Rails).to receive(:application) { OpenStruct.new(config: OpenStruct.new(paths: { "db/migrate" => ["spec/db/migrate"] })) } 112 | 113 | DataMigrate::Tasks::DataMigrateTasks.migrate 114 | end 115 | 116 | it "should display data migration status" do 117 | expect { 118 | DataMigrate::Tasks::DataMigrateTasks.status 119 | }.to output(/up 20091231235959 Some name/).to_stdout 120 | end 121 | 122 | it "should display schema and data migration status" do 123 | expect { 124 | DataMigrate::Tasks::DataMigrateTasks.status_with_schema 125 | }.to output(match(/up data 20091231235959 Some name/) 126 | .and match(/down schema 20131111111111 Late migration/)).to_stdout 127 | end 128 | end 129 | end 130 | -------------------------------------------------------------------------------- /spec/db/data/20091231235959_some_name.rb: -------------------------------------------------------------------------------- 1 | class SomeName < ActiveRecord::Migration[6.1] 2 | def up 3 | puts "Doing data migration" 4 | end 5 | 6 | def down 7 | puts "Undoing SomeName" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/db/data/20171231235959_super_update.rb: -------------------------------------------------------------------------------- 1 | class SuperUpdate < ActiveRecord::Migration[6.1] 2 | def up 3 | puts "Doing SuperUpdate" 4 | end 5 | 6 | def down 7 | puts "Undoing SuperUpdate" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/db/data/20181128000207_excluded_file.rb.other_ext: -------------------------------------------------------------------------------- 1 | # This file should be excluded 2 | -------------------------------------------------------------------------------- /spec/db/data/partial_schema/data_schema.rb: -------------------------------------------------------------------------------- 1 | DataMigrate::Data.define(version: 20091231235959) 2 | -------------------------------------------------------------------------------- /spec/db/data/partial_schema/test_data_schema.rb: -------------------------------------------------------------------------------- 1 | DataMigrate::Data.define(version: 20091231235959) 2 | -------------------------------------------------------------------------------- /spec/db/data/schema/data_schema.rb: -------------------------------------------------------------------------------- 1 | DataMigrate::Data.define(version: 20171231235959) 2 | -------------------------------------------------------------------------------- /spec/db/data/schema/test_data_schema.rb: -------------------------------------------------------------------------------- 1 | DataMigrate::Data.define(version: 20171231235959) 2 | -------------------------------------------------------------------------------- /spec/db/data_two/20241231235959_data_two_update.rb: -------------------------------------------------------------------------------- 1 | class DataTwoUpdate < ActiveRecord::Migration[6.1] 2 | def up 3 | puts "Doing DataTwoUpdate" 4 | end 5 | 6 | def down 7 | puts "Undoing DataTwoUpdate" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/db/migrate/20131111111111_late_migration.rb: -------------------------------------------------------------------------------- 1 | class LateMigration < ActiveRecord::Migration[6.1] 2 | def up 3 | puts "Doing schema LateMigration" 4 | end 5 | 6 | def down 7 | puts "Undoing LateMigration" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/db/migrate/20202020202011_db_migration.rb: -------------------------------------------------------------------------------- 1 | class DbMigration < ActiveRecord::Migration[6.1] 2 | def up 3 | puts "Doing schema migration" 4 | end 5 | 6 | def down 7 | puts "Undoing DbMigration" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/generators/data_migration/data_migration_generator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'rails/generators' 3 | require 'rails/generators/migration' 4 | require 'generators/data_migration/data_migration_generator' 5 | 6 | describe DataMigrate::Generators::DataMigrationGenerator do 7 | subject { DataMigrate::Generators::DataMigrationGenerator } 8 | 9 | describe :next_migration_number do 10 | it "next migration" do 11 | Timecop.freeze("2016-12-03 22:15:26 -0800") do 12 | if ActiveRecord.version >= Gem::Version.new('7.0') 13 | expect(ActiveRecord).to receive(:timestamped_migrations) { true } 14 | else 15 | expect(ActiveRecord::Base).to receive(:timestamped_migrations) { true } 16 | end 17 | expect(subject.next_migration_number(1).to_s).to eq("20161204061526") 18 | end 19 | end 20 | end 21 | 22 | describe :migration_base_class_name do 23 | subject { generator.send(:migration_base_class_name) } 24 | 25 | let(:generator) { DataMigrate::Generators::DataMigrationGenerator.new(['my_migration']) } 26 | 27 | it "returns the correct base class name" do 28 | is_expected.to eq("ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]") 29 | end 30 | end 31 | 32 | describe :create_data_migration do 33 | subject { DataMigrate::Generators::DataMigrationGenerator.new(['my_migration']) } 34 | 35 | let(:data_migrations_file_path) { 'abc/my_migration.rb' } 36 | 37 | context 'when custom data migrations path has a trailing slash' do 38 | before do 39 | DataMigrate.config.data_migrations_path = 'abc/' 40 | end 41 | 42 | it 'returns correct file path' do 43 | is_expected.to receive(:migration_template).with( 44 | 'data_migration.rb', data_migrations_file_path 45 | ) 46 | 47 | subject.create_data_migration 48 | end 49 | end 50 | 51 | context 'when custom data migrations path does not have a trailing slash' do 52 | before do 53 | DataMigrate.config.data_migrations_path = 'abc' 54 | end 55 | 56 | it 'returns correct file path' do 57 | is_expected.to receive(:migration_template).with( 58 | 'data_migration.rb', data_migrations_file_path 59 | ) 60 | 61 | subject.create_data_migration 62 | end 63 | end 64 | end 65 | 66 | describe ".source_root" do 67 | subject { described_class.source_root } 68 | 69 | let(:default_source_root) do 70 | File.expand_path( 71 | File.dirname(File.join(DataMigrate.root, "generators", "data_migration", "templates", "data_migration.rb")) 72 | ) 73 | end 74 | 75 | it { is_expected.to eq default_source_root } 76 | 77 | context "when DateMigrate.config.data_template_path is set" do 78 | before do 79 | @before = DataMigrate.config.data_template_path 80 | DataMigrate.configure do |config| 81 | config.data_template_path = data_template_path 82 | end 83 | end 84 | 85 | let(:data_template_path) do 86 | File.join(DataMigrate.root, "generators", "data_migration", "templates", "data_migration.rb") 87 | end 88 | let(:expected_source_root) { File.dirname(data_template_path) } 89 | 90 | after do 91 | DataMigrate.configure do |config| 92 | config.data_template_path = @before 93 | end 94 | end 95 | 96 | it "reads directory from config data template path" do 97 | is_expected.to eq expected_source_root 98 | end 99 | end 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rspec' 2 | require 'rails' 3 | require 'sqlite3' 4 | require 'data_migrate' 5 | require 'pry' 6 | require 'timecop' 7 | 8 | RSpec.configure do |config| 9 | config.mock_with :rspec do |mocks| 10 | mocks.verify_partial_doubles = true 11 | end 12 | 13 | config.after(:each) do 14 | DataMigrate.configure do |config| 15 | config.data_migrations_path = @prev_data_migrations_path 16 | end 17 | end 18 | 19 | config.before(:each) do |example| 20 | if example.metadata[:no_override] 21 | else 22 | @prev_data_migrations_path = DataMigrate.config.data_migrations_path 23 | DataMigrate.configure do |config| 24 | config.data_migrations_path = ["spec/db/data", "spec/db/data_two"] 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilyakatz/data-migrate/d4cebfad06b13a1fd30050986320436cae965352/tasks/.gitkeep -------------------------------------------------------------------------------- /tasks/databases.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'data_migrate/tasks/data_migrate_tasks' 4 | 5 | namespace :db do 6 | namespace :migrate do 7 | desc "Migrate the database data and schema (options: VERSION=x, VERBOSE=false)." 8 | task :with_data => :load_config do 9 | DataMigrate::DatabaseTasks.migrate_with_data 10 | Rake::Task["db:_dump"].invoke 11 | Rake::Task["data:dump"].invoke 12 | end 13 | 14 | namespace :redo do 15 | desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).' 16 | task :with_data => :environment do 17 | DataMigrate::DataMigrator.create_data_schema_table 18 | if ENV["VERSION"] 19 | Rake::Task["db:migrate:down:with_data"].invoke 20 | Rake::Task["db:migrate:up:with_data"].invoke 21 | else 22 | Rake::Task["db:rollback:with_data"].invoke 23 | Rake::Task["db:migrate:with_data"].invoke 24 | end 25 | end 26 | end 27 | 28 | namespace :up do 29 | desc 'Runs the "up" for a given migration VERSION. (options both=false)' 30 | task :with_data => :environment do 31 | version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil 32 | raise "VERSION is required" unless version 33 | DataMigrate::DataMigrator.create_data_schema_table 34 | run_both = ENV["BOTH"] == "true" 35 | migrations = DataMigrate::DatabaseTasks.pending_migrations.keep_if{|m| m[:version] == version} 36 | 37 | unless run_both || migrations.size < 2 38 | migrations = migrations.slice(0,1) 39 | end 40 | 41 | migrations.each do |migration| 42 | DataMigrate::DatabaseTasks.run_migration(migration, :up) 43 | end 44 | 45 | Rake::Task["db:_dump"].invoke 46 | Rake::Task["data:dump"].invoke 47 | end 48 | end 49 | 50 | namespace :down do 51 | desc 'Runs the "down" for a given migration VERSION. (option BOTH=false)' 52 | task :with_data => :environment do 53 | version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil 54 | raise "VERSION is required" unless version 55 | DataMigrate::DataMigrator.create_data_schema_table 56 | run_both = ENV["BOTH"] == "true" 57 | migrations = DataMigrate::DatabaseTasks.past_migrations.keep_if{|m| m[:version] == version} 58 | 59 | unless run_both || migrations.size < 2 60 | migrations = migrations.slice(0,1) 61 | end 62 | 63 | migrations.each do |migration| 64 | DataMigrate::DatabaseTasks.run_migration(migration, :down) 65 | end 66 | 67 | Rake::Task["db:_dump"].invoke 68 | Rake::Task["data:dump"].invoke 69 | end 70 | end 71 | 72 | namespace :status do 73 | desc "Display status of data and schema migrations" 74 | task :with_data => :environment do 75 | DataMigrate::Tasks::DataMigrateTasks.status_with_schema 76 | end 77 | end 78 | end # END OF MIGRATE NAME SPACE 79 | 80 | namespace :rollback do 81 | desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).' 82 | task :with_data => :environment do 83 | step = ENV['STEP'] ? ENV['STEP'].to_i : 1 84 | DataMigrate::DataMigrator.create_data_schema_table 85 | DataMigrate::DatabaseTasks.past_migrations[0..(step - 1)].each do | past_migration | 86 | DataMigrate::DatabaseTasks.run_migration(past_migration, :down) 87 | end 88 | 89 | Rake::Task["db:_dump"].invoke 90 | Rake::Task["data:dump"].invoke 91 | end 92 | end 93 | 94 | namespace :forward do 95 | desc 'Pushes the schema to the next version (specify steps w/ STEP=n).' 96 | task :with_data => :environment do 97 | DataMigrate::DataMigrator.create_data_schema_table 98 | step = ENV['STEP'] ? ENV['STEP'].to_i : 1 99 | DataMigrate::DatabaseTasks.forward(step) 100 | Rake::Task["db:_dump"].invoke 101 | Rake::Task["data:dump"].invoke 102 | end 103 | end 104 | 105 | namespace :version do 106 | desc "Retrieves the current schema version numbers for data and schema migrations" 107 | task :with_data => :environment do 108 | DataMigrate::DataMigrator.create_data_schema_table 109 | puts "Current Schema version: #{ActiveRecord::Migrator.current_version}" 110 | puts "Current Data version: #{DataMigrate::DataMigrator.current_version}" 111 | end 112 | end 113 | 114 | namespace :abort_if_pending_migrations do 115 | desc "Raises an error if there are pending migrations or data migrations" 116 | task with_data: :environment do 117 | message = %{Run `rake db:migrate:with_data` to update your database then try again.} 118 | DataMigrate::Tasks::DataMigrateTasks.abort_if_pending_migrations(DataMigrate::DatabaseTasks.pending_migrations, message) 119 | end 120 | end 121 | 122 | namespace :schema do 123 | namespace :load do 124 | desc "Load both schema.rb and data_schema.rb file into the database" 125 | task with_data: :environment do 126 | Rake::Task["db:schema:load"].invoke 127 | 128 | DataMigrate::DatabaseTasks.load_schema_current( 129 | :ruby, 130 | ENV["DATA_SCHEMA"] 131 | ) 132 | end 133 | end 134 | end 135 | 136 | namespace :structure do 137 | namespace :load do 138 | desc "Load both structure.sql and data_schema.rb file into the database" 139 | task with_data: :environment do 140 | Rake::Task["db:structure:load"].invoke 141 | 142 | DataMigrate::DatabaseTasks.load_schema_current( 143 | :ruby, 144 | ENV["DATA_SCHEMA"] 145 | ) 146 | end 147 | end 148 | end 149 | 150 | namespace :prepare do 151 | desc "Runs setup if database does not exist, or runs data and schema migrations if it does" 152 | task with_data: :environment do 153 | DataMigrate::DatabaseTasks.prepare_all_with_data 154 | end 155 | end 156 | end 157 | 158 | namespace :data do 159 | desc 'Migrate data migrations (options: VERSION=x, VERBOSE=false)' 160 | task :migrate => :environment do 161 | DataMigrate::Tasks::DataMigrateTasks.migrate 162 | Rake::Task["data:dump"].invoke 163 | end 164 | 165 | namespace :migrate do 166 | desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).' 167 | task :redo => :environment do 168 | DataMigrate::DataMigrator.create_data_schema_table 169 | if ENV["VERSION"] 170 | Rake::Task["data:migrate:down"].invoke 171 | Rake::Task["data:migrate:up"].invoke 172 | else 173 | Rake::Task["data:rollback"].invoke 174 | Rake::Task["data:migrate"].invoke 175 | end 176 | end 177 | 178 | desc 'Runs the "up" for a given migration VERSION.' 179 | task :up => :environment do 180 | DataMigrate::DataMigrator.create_data_schema_table 181 | version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil 182 | raise "VERSION is required" unless version 183 | DataMigrate::DataMigrator.run(:up, DataMigrate::DatabaseTasks.data_migrations_path, version) 184 | Rake::Task["data:dump"].invoke 185 | end 186 | 187 | desc 'Runs the "down" for a given migration VERSION.' 188 | task :down => :environment do 189 | version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil 190 | raise "VERSION is required" unless version 191 | DataMigrate::DataMigrator.create_data_schema_table 192 | DataMigrate::DataMigrator.run(:down, DataMigrate::DatabaseTasks.data_migrations_path, version) 193 | Rake::Task["data:dump"].invoke 194 | end 195 | 196 | desc "Display status of data migrations" 197 | task :status => :environment do 198 | DataMigrate::Tasks::DataMigrateTasks.status 199 | end 200 | end 201 | 202 | desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).' 203 | task :rollback => :environment do 204 | DataMigrate::DataMigrator.create_data_schema_table 205 | step = ENV['STEP'] ? ENV['STEP'].to_i : 1 206 | DataMigrate::DataMigrator.rollback(DataMigrate::DatabaseTasks.data_migrations_path, step) 207 | Rake::Task["data:dump"].invoke 208 | end 209 | 210 | desc 'Pushes the schema to the next version (specify steps w/ STEP=n).' 211 | task :forward => :environment do 212 | DataMigrate::DataMigrator.create_data_schema_table 213 | step = ENV['STEP'] ? ENV['STEP'].to_i : 1 214 | # TODO: No worky for .forward 215 | # DataMigrate::DataMigrator.forward('db/data/', step) 216 | migrations = DataMigrate::DatabaseTasks.pending_data_migrations.reverse.pop(step).reverse 217 | migrations.each do | pending_migration | 218 | DataMigrate::DataMigrator.run(:up, DataMigrate::DatabaseTasks.data_migrations_path, pending_migration[:version]) 219 | end 220 | Rake::Task["data:dump"].invoke 221 | end 222 | 223 | desc "Retrieves the current schema version number for data migrations" 224 | task :version => :environment do 225 | DataMigrate::DataMigrator.create_data_schema_table 226 | puts "Current data version: #{DataMigrate::DataMigrator.current_version}" 227 | end 228 | 229 | desc "Raises an error if there are pending data migrations" 230 | task abort_if_pending_migrations: :environment do 231 | message = %{Run `rake data:migrate` to update your database then try again.} 232 | DataMigrate::Tasks::DataMigrateTasks.abort_if_pending_migrations(DataMigrate::DatabaseTasks.pending_data_migrations, message) 233 | end 234 | 235 | desc "Create a db/data_schema.rb file that stores the current data version" 236 | task dump: :environment do 237 | DataMigrate::Tasks::DataMigrateTasks.dump 238 | 239 | # Allow this task to be called as many times as required. An example 240 | # is the migrate:redo task, which calls other two internally 241 | # that depend on this one. 242 | Rake::Task["data:dump"].reenable 243 | end 244 | 245 | namespace :schema do 246 | desc "Load data_schema.rb file into the database" 247 | task load: :environment do 248 | DataMigrate::DatabaseTasks.load_schema_current( 249 | :ruby, 250 | ENV["DATA_SCHEMA"] 251 | ) 252 | end 253 | end 254 | end 255 | --------------------------------------------------------------------------------