Skip to content

WIP: Enforce the Rails/InverseOf cop

Nick Thomas requested to merge 32747-enforce-inverse-of into master

What does this MR do?

Removes Rails/InverseOf from .rubocop_todo.yml and gets the test suite green again afterwards.

Screenshots

Failures seen at the start of the process:

app/models/project_feature.rb:76:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :project, -> { unscope(where: :pending_delete) }
  ^^^^^^^^^^
app/models/user.rb:90:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :keys, -> { regular_keys }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:91:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :deploy_keys, -> { where(type: 'DeployKey') }, dependent: :nullify # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:103:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :group_members, -> { where(requested_at: nil) }, source: 'GroupMember'
  ^^^^^^^^
app/models/user.rb:117:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :project_members, -> { where(requested_at: nil) }
  ^^^^^^^^
app/models/user.rb:119:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :created_projects,         foreign_key: :creator_id, class_name: 'Project'
  ^^^^^^^^
app/models/user.rb:128:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :snippets,                 dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:129:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :notes,                    dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:130:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :issues,                   dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:131:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :merge_requests,           dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:132:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :events,                   dependent: :delete_all, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:133:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :releases,                 dependent: :nullify, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:135:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:136:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_one  :abuse_report,             dependent: :destroy, foreign_key: :user_id # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^
app/models/user.rb:137:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :reported_abuse_reports,   dependent: :destroy, foreign_key: :reporter_id, class_name: "AbuseReport" # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:144:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :triggers,                 dependent: :destroy, class_name: 'Ci::Trigger', foreign_key: :owner_id # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/user.rb:148:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :assigned_merge_requests, dependent: :nullify, foreign_key: :assignee_id, class_name: "MergeRequest" # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/issue.rb:35:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :events, as: :target, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/board.rb:7:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :lists, -> { ordered }, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/board.rb:8:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :destroyable_lists, -> { destroyable.ordered }, class_name: "List"
  ^^^^^^^^
app/models/todo.rb:43:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :issue, -> { where("target_type = 'Issue'") }, foreign_key: :target_id
  ^^^^^^^^^^
app/models/issue_assignee.rb:5:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :assignee, class_name: "User", foreign_key: :user_id
  ^^^^^^^^^^
app/models/namespace.rb:33:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :children, class_name: "Namespace", foreign_key: :parent_id
  ^^^^^^^^
app/models/merge_request_diff.rb:26:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :merge_request_diff_commits, -> { order(:merge_request_diff_id, :relative_order) }
  ^^^^^^^^
app/models/snippet.rb:41:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :notes, as: :noteable, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/project.rb:140:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id'
  ^^^^^^^^^^
app/models/project.rb:145:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event'
  ^^^^^^^
app/models/project.rb:190:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :forked_to_members, class_name: 'ForkNetworkMember', foreign_key: 'forked_from_project_id'
  ^^^^^^^^
app/models/project.rb:202:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :source_of_merge_requests, foreign_key: 'source_project_id', class_name: 'MergeRequest'
  ^^^^^^^^
app/models/project.rb:213:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :repository_languages, -> { order "share DESC" }
  ^^^^^^^^
app/models/project.rb:217:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :project_members, -> { where(requested_at: nil) },
  ^^^^^^^^
app/models/project.rb:223:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :requesters, -> { where.not(requested_at: nil) },
  ^^^^^^^^
app/models/project.rb:225:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :members_and_requesters, as: :source, class_name: 'ProjectMember'
  ^^^^^^^^
app/models/project.rb:239:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :notification_settings, as: :source, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/project.rb:285:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :deployments, -> { success }
  ^^^^^^^^
app/models/audit_event.rb:8:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :user, foreign_key: :author_id
  ^^^^^^^^^^
app/models/merge_request_assignee.rb:5:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :assignee, class_name: "User", foreign_key: :user_id
  ^^^^^^^^^^
app/models/merge_request.rb:57:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :head_pipeline, foreign_key: "head_pipeline_id", class_name: "Ci::Pipeline"
  ^^^^^^^^^^
app/models/merge_request.rb:59:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :events, as: :target, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/merge_request.rb:66:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :pipelines_for_merge_request, foreign_key: 'merge_request_id', class_name: 'Ci::Pipeline'
  ^^^^^^^^
app/models/note.rb:79:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :events, as: :target, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/commit_status.rb:16:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id
  ^^^^^^^^^^
app/models/group.rb:20:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/group.rb:28:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/group.rb:29:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :members_and_requesters, as: :source, class_name: 'GroupMember'
  ^^^^^^^^
app/models/group.rb:37:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :notification_settings, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/milestone.rb:39:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :events, as: :target, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/environment.rb:9:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :deployments, -> { success }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/environment.rb:11:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_one :last_deployment, -> { success.order('deployments.id DESC') }, class_name: 'Deployment'
  ^^^^^^^
app/models/notification_setting.rb:10:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :project, foreign_key: 'source_id'
  ^^^^^^^^^^
app/models/members/project_member.rb:6:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :project, foreign_key: 'source_id'
  ^^^^^^^^^^
app/models/members/group_member.rb:8:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :group, foreign_key: 'source_id'
  ^^^^^^^^^^
app/models/concerns/routable.rb:12:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :redirect_routes, as: :source, autosave: true, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
    ^^^^^^^^
app/models/concerns/issuable.rb:63:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :todos, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
    ^^^^^^^^
app/models/concerns/spammable.rb:13:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_one :user_agent_detail, as: :subject, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
    ^^^^^^^
app/models/concerns/subscribable.rb:14:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :subscriptions, dependent: :destroy, as: :subscribable # rubocop:disable Cop/ActiveRecordDependent
    ^^^^^^^^
app/models/concerns/with_uploads.rb:29:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :uploads, as: :model
    ^^^^^^^^
app/models/concerns/with_uploads.rb:30:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :file_uploads, -> { where(uploader: FILE_UPLOADERS) },
    ^^^^^^^^
app/models/concerns/awardable.rb:7:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :award_emoji, -> { includes(:user).order(:id) }, as: :awardable, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
    ^^^^^^^^
app/models/project_services/slash_commands_service.rb:10:3: C: Rails/InverseOf: Specify an :inverse_of option.
  has_many :chat_names, foreign_key: :service_id, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
  ^^^^^^^^
app/models/merge_request/metrics.rb:5:3: C: Rails/InverseOf: Specify an :inverse_of option.
  belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :pipeline_id
  ^^^^^^^^^^
app/models/ci/runner.rb:46:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_one :last_build, ->() { order('id DESC') }, class_name: 'Ci::Build'
    ^^^^^^^
app/models/ci/build_trace_section_name.rb:8:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :trace_sections, class_name: 'Ci::BuildTraceSection', foreign_key: :section_name_id
    ^^^^^^^^
app/models/ci/runner_namespace.rb:9:5: C: Rails/InverseOf: Specify an :inverse_of option.
    belongs_to :group, class_name: '::Group', foreign_key: :namespace_id
    ^^^^^^^^^^
app/models/ci/trigger_request.rb:8:5: C: Rails/InverseOf: Specify an :inverse_of option.
    belongs_to :pipeline, foreign_key: :commit_id
    ^^^^^^^^^^
app/models/ci/build_trace_chunk.rb:9:5: C: Rails/InverseOf: Specify an :inverse_of option.
    belongs_to :build, class_name: "Ci::Build", foreign_key: :build_id
    ^^^^^^^^^^
app/models/ci/build.rb:39:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_one :deployment, as: :deployable, class_name: 'Deployment'
    ^^^^^^^
app/models/ci/build.rb:41:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :trace_chunks, class_name: 'Ci::BuildTraceChunk', foreign_key: :build_id
    ^^^^^^^^
app/models/ci/build.rb:45:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :job_variables, class_name: 'Ci::JobVariable', foreign_key: :job_id
    ^^^^^^^^
app/models/ci/pipeline_schedule.rb:11:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_one :last_pipeline, -> { order(id: :desc) }, class_name: 'Ci::Pipeline'
    ^^^^^^^
app/models/ci/stage.rb:15:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :statuses, class_name: 'CommitStatus', foreign_key: :stage_id
    ^^^^^^^^
app/models/ci/stage.rb:16:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :builds, foreign_key: :stage_id
    ^^^^^^^^
app/models/ci/stage.rb:17:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :bridges, foreign_key: :stage_id
    ^^^^^^^^
app/models/ci/pipeline.rb:37:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
    ^^^^^^^^
app/models/ci/pipeline.rb:44:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :merge_requests_as_head_pipeline, foreign_key: "head_pipeline_id", class_name: 'MergeRequest'
    ^^^^^^^^
app/models/ci/pipeline.rb:46:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build'
    ^^^^^^^^
app/models/ci/pipeline.rb:47:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :retryable_builds, -> { latest.failed_or_canceled.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
    ^^^^^^^^
app/models/ci/pipeline.rb:48:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus'
    ^^^^^^^^
app/models/ci/pipeline.rb:49:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
    ^^^^^^^^
app/models/ci/pipeline.rb:50:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :scheduled_actions, -> { latest.scheduled_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
    ^^^^^^^^
app/models/ci/pipeline.rb:51:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :artifacts, -> { latest.with_artifacts_not_expired.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
    ^^^^^^^^
app/models/ci/pipeline.rb:53:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id'
    ^^^^^^^^
app/models/ci/pipeline.rb:54:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id'
    ^^^^^^^^
app/models/ci/job_artifact.rb:55:5: C: Rails/InverseOf: Specify an :inverse_of option.
    belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id
    ^^^^^^^^^^
app/models/ci/job_variable.rb:8:5: C: Rails/InverseOf: Specify an :inverse_of option.
    belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id
    ^^^^^^^^^^
app/models/clusters/cluster.rb:30:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_one :cluster_project, -> { order(id: :desc) }, class_name: 'Clusters::Project'
    ^^^^^^^
app/models/clusters/concerns/application_core.rb:9:9: C: Rails/InverseOf: Specify an :inverse_of option.
        belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id
        ^^^^^^^^^^
app/models/clusters/applications/runner.rb:15:7: C: Rails/InverseOf: Specify an :inverse_of option.
      belongs_to :runner, class_name: 'Ci::Runner', foreign_key: :runner_id
      ^^^^^^^^^^
app/models/clusters/project.rb:10:5: C: Rails/InverseOf: Specify an :inverse_of option.
    has_many :kubernetes_namespaces, class_name: 'Clusters::KubernetesNamespace', foreign_key: :cluster_project_id
    ^^^^^^^^

Does this MR meet the acceptance criteria?

Conformity

Closes #32747

Merge request reports