Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new Rails/ReversibleMigrationMethodDefinition cop #457

Merged
merged 1 commit into from
Apr 16, 2021

Conversation

hey-leon
Copy link
Contributor

@hey-leon hey-leon commented Apr 7, 2021

This cop attempts to automate part of the review process of rails migrations. Two example cases this cop helps prevent are:

  1. a typo in a change method e.g. chance instead of change
  2. a migration that only has one direction implemented.

These can both be a bad time when not caught before merging to production.

Case 1 can lead to the deployment of code that relies on a column that has not been added yet.
Case 2 can lead to hard to revert faulty deployments.

Rails/ReversibleMigrationMethodDefinition cop

   # bad
   class SomeMigration < ActiveRecord::Migration[6.0]
     def up
       # up migration
     end

     # <----- missing down method
   end

   class SomeMigration < ActiveRecord::Migration[6.0]
     # <----- missing up method

      def down
        # down migration
      end
    end
 
    # good
    class SomeMigration < ActiveRecord::Migration[6.0]
      def change
        # reversible migration
      end
    end
 
    class SomeMigration < ActiveRecord::Migration[6.0]
      def up
        # up migration
      end
 
      def down
        # down migration
      end
    end

Before submitting the PR make sure the following are checked:

  • Wrote good commit messages.
  • Commit message starts with [Fix #issue-number] (if the related issue exists).
  • Feature branch is up-to-date with master (if not - rebase it).
  • Squashed related commits together.
  • Added tests.
  • Added an entry to the Changelog if the new code introduces user-observable changes. See changelog entry format.
  • The PR relates to only one subject with a clear title
    and description in grammatically correct, complete sentences.
  • Run bundle exec rake default. It executes all tests and RuboCop for itself, and generates the documentation.
  • If this is a new cop, consider making a corresponding update to the Rails Style Guide.

@hey-leon hey-leon force-pushed the feature/implemented-migration-cop branch 2 times, most recently from 78cbc83 to 83225a6 Compare April 7, 2021 20:37
@hey-leon hey-leon changed the title Add new Rails/ImplementedMigration cop Add new Rails/ImplementedMigration cop Apr 7, 2021
@andyw8
Copy link
Contributor

andyw8 commented Apr 8, 2021

I haven't tried it, but would https://github.com/ankane/strong_migrations help prevent any of these issues?

@hey-leon
Copy link
Contributor Author

hey-leon commented Apr 8, 2021

I haven't tried it, but would https://github.com/ankane/strong_migrations help prevent any of these issues?

Good thought. I don't believe it can be configured to catch these cases (we use it at our company and have these issues).

From what I understand strong migrations uses instrumentation to enforce best practices. I don't think it's possible to catch these types of issues with instrumentation as it cannot catch issues on methods not called?

@hey-leon hey-leon force-pushed the feature/implemented-migration-cop branch from 83225a6 to 08dc1a4 Compare April 13, 2021 19:06
CHANGELOG.md Outdated
@@ -4,6 +4,7 @@

### New features

* [#457](https://github.com/rubocop/rubocop-rails/pull/457): New cop `Rails/ImplementedMigration` checks for migrations that have a typo in a method name or are half implemented. ([@leonp1991][])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* [#457](https://github.com/rubocop/rubocop-rails/pull/457): New cop `Rails/ImplementedMigration` checks for migrations that have a typo in a method name or are half implemented. ([@leonp1991][])
* [#457](https://github.com/rubocop/rubocop-rails/pull/457): Add new `Rails/ReversibleMigrationMethodDefinition` cop. ([@leonp1991][])

@@ -362,6 +362,11 @@ Rails/IgnoredSkipActionFilterOption:
Include:
- app/controllers/**/*.rb

Rails/ImplementedMigration:
Description: 'Checks for migrations that have a typo in a method name or are half implemented.'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the description?

Suggested change
Description: 'Checks for migrations that have a typo in a method name or are half implemented.'
Description: 'Checks whether the migration implements either a `change` method or both an `up` and a `down` method.

Rails/ImplementedMigration:
Description: 'Checks for migrations that have a typo in a method name or are half implemented.'
Enabled: false
VersionAdded: '2.10'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add Include path?

Suggested change
VersionAdded: '2.10'
VersionAdded: '2.10'
Include:
- db/migrate/*.rb

def chance # <----- typo
# migration
end
end
Copy link
Member

@koic koic Apr 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think typos are not the main focus of the cop, so can you remove this example?

# good
class SomeMigration < ActiveRecord::Migration[6.0]
def change
# migration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# migration
# reversible migration

# # down migration
# end
# end
class ImplementedMigration < Base
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name ImplementedMigration looks abstract in purpose. How about the name ReversibleMigrationMethodDefinition?

Suggested change
class ImplementedMigration < Base
class ReversibleMigrationMethodDefinition < Base

Comment on lines 52 to 53
MSG = 'Migrations must contain either a change method, or ' \
'both an up and a down method.'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you enclose method names in backticks?

Suggested change
MSG = 'Migrations must contain either a change method, or ' \
'both an up and a down method.'
MSG = 'Migrations must contain either a `change` method, or ' \
'both an `up` and a `down` method.'

Comment on lines 74 to 75
return if change_method?(node)
return if up_and_down_methods?(node)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you refactor it?

Suggested change
return if change_method?(node)
return if up_and_down_methods?(node)
return if change_method?(node) || up_and_down_methods?(node)

RUBY
end

it 'registers an offense with a typo\'d change method' do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it 'registers an offense with a typo\'d change method' do
it "registers an offense with a typo'd change method" do

Comment on lines 16 to 19
class SomeMigration < ActiveRecord::Migration[6.0]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migrations must contain either a change method, or both an up and a down method.

def up
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove the redundant blank line in this PR' test examples?

Suggested change
class SomeMigration < ActiveRecord::Migration[6.0]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migrations must contain either a change method, or both an up and a down method.
def up
class SomeMigration < ActiveRecord::Migration[6.0]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migrations must contain either a change method, or both an up and a down method.
def up

Comment on lines 81 to 99
expect_offense(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[5.1]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migrations must contain either a change method, or both an up and a down method.

def chance
add_column :users, :email, :text, null: false
end
end
RUBY

expect_offense(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[7.1]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migrations must contain either a change method, or both an up and a down method.

def chance
add_column :users, :email, :text, null: false
end
end
RUBY
Copy link
Member

@koic koic Apr 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove the redundant test case and leave only one of them?

Suggested change
expect_offense(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[5.1]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migrations must contain either a change method, or both an up and a down method.
def chance
add_column :users, :email, :text, null: false
end
end
RUBY
expect_offense(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[7.1]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migrations must contain either a change method, or both an up and a down method.
def chance
add_column :users, :email, :text, null: false
end
end
RUBY
expect_offense(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[5.2]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migrations must contain either a change method, or both an up and a down method.
def chance
add_column :users, :email, :text, null: false
end
end
RUBY

Comment on lines 103 to 117
expect_no_offenses(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[5.2]
def change
add_column :users, :email, :text, null: false
end
end
RUBY

expect_no_offenses(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[7.1]
def change
add_column :users, :email, :text, null: false
end
end
RUBY
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto :-)

Suggested change
expect_no_offenses(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[5.2]
def change
add_column :users, :email, :text, null: false
end
end
RUBY
expect_no_offenses(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[7.1]
def change
add_column :users, :email, :text, null: false
end
end
RUBY
expect_no_offenses(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[5.2]
def change
add_column :users, :email, :text, null: false
end
end
RUBY


it 'registers offenses correctly with any migration class' do
expect_offense(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[5.1]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rails has not officially maintained Rails 5.1 series.
https://guides.rubyonrails.org/maintenance_policy.html

RuboCop Rails also has negative support, so please specify it to 5.2 or higher for the example.

RUBY

expect_offense(<<~RUBY)
class SomeMigration < ActiveRecord::Migration[7.1]
Copy link
Member

@koic koic Apr 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's just my two cents. Rails 7.1 is a world no one has seen yet 😅 Can you update to 6.1?

Suggested change
class SomeMigration < ActiveRecord::Migration[7.1]
class SomeMigration < ActiveRecord::Migration[6.1]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol this is true it is not in the world yet and may not ever be a specific version (however likely). Was just trying to make sure it wont break on a future release 🤠.

@hey-leon hey-leon force-pushed the feature/implemented-migration-cop branch from 9213485 to c615bd4 Compare April 14, 2021 15:51
@hey-leon
Copy link
Contributor Author

hey-leon commented Apr 14, 2021

@koic I appreciate all the feedback. I think the new name has made the cop's intention much clearer. The latest version should address all comments and anywhere else that made sense after.

@hey-leon hey-leon changed the title Add new Rails/ImplementedMigration cop Add new Rails/ReversibleMigrationMethodDefinition cop Apr 14, 2021
@koic koic merged commit 8e56365 into rubocop:master Apr 16, 2021
@koic
Copy link
Member

koic commented Apr 16, 2021

Thanks!

@hey-leon hey-leon deleted the feature/implemented-migration-cop branch April 19, 2021 14:32
Description: 'Checks whether the migration implements either a `change` method or both an `up` and a `down` method.'
Enabled: false
VersionAdded: '2.10'
include:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include typo.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, without it it flags all Ruby files :=)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😅 My bad thanks @rhymes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants