Add Duo Code Review depth cascading setting columns

What does this MR do and why?

Deep reviews by GitLab Duo Code Review Flow are usage-billed, so groups need a way to turn them off, and organizations need a way to choose the default review depth. Both settings cascade from the instance to groups, subgroups and projects. Like the other cascading GitLab Duo settings, an instance or group can enforce a value so the levels below cannot change it.

This MR only adds the columns. The models, settings pages, REST API and docs follow in separate MRs. Nothing reads or writes the new columns yet.

  • duo_code_review_depth_allowed: depths beyond Standard are allowed. Today that means Deep. The name is not specific to Deep so it still fits if a third depth is added. Defaults to true on the instance.
  • duo_code_review_default_depth: the default depth, stored as a smallint enum (0 = Standard, 1 = Deep). Defaults to Standard on the instance.
  • lock_* columns on the instance and namespace tables enforce each value. Projects have no lock columns because they have nothing below them.

The columns follow the recommended pattern for new cascading settings, the same as duo_auto_mode_enabled:

  • namespace_settings: nullable with no default. A change at instance or group level is written to descendants by the existing cascade workers, which come in a later MR.
  • project_settings: NOT NULL with the same defaults as the instance. New projects copy the value inherited from their group at creation time, which also comes in a later MR.

There is one migration for each column and table. project_settings is a high-traffic table, so its two columns are added in transactional migrations, which use lock retries by default. The cascading helper needs a non-transactional migration, so the application_settings and namespace_settings columns are in separate migrations.

References

Screenshots or screen recordings

Not applicable. This MR has no UI changes.

How to set up and validate locally

  1. Check out this branch and run the migrations:

    bundle exec rails db:migrate
  2. Check that the new columns exist on each table:

    gdk psql -c "SELECT table_name, column_name, data_type, column_default, is_nullable FROM information_schema.columns WHERE column_name LIKE '%duo_code_review_de%' ORDER BY table_name, column_name;"
    • application_settings and namespace_settings each have four columns: the two settings and their lock_ columns.
    • project_settings has the two settings only.
    • On application_settings, duo_code_review_depth_allowed defaults to true and duo_code_review_default_depth defaults to 0 (Standard). Both are NOT NULL.
    • In namespace_settings, the two settings are nullable with no default.
    • In project_settings, duo_code_review_depth_allowed defaults to true and duo_code_review_default_depth defaults to 0. Both are NOT NULL.
  3. Roll back the four migrations and check that the columns are removed:

    for v in 20261028132631 20261028132630 20261028132629 20261028132628; do
      bundle exec rails db:migrate:down:main VERSION=$v
    done
Migration output (main)
== 20261028132631 AddDuoCodeReviewDefaultDepthToProjectSettings: reverting ====
-- remove_column(:project_settings, :duo_code_review_default_depth, :smallint, {default: 0, null: false})
== 20261028132631 AddDuoCodeReviewDefaultDepthToProjectSettings: reverted (0.0509s)
== 20261028132630 AddDuoCodeReviewDepthAllowedToProjectSettings: reverting ====
-- remove_column(:project_settings, :duo_code_review_depth_allowed, :boolean, {default: true, null: false})
== 20261028132630 AddDuoCodeReviewDepthAllowedToProjectSettings: reverted (0.0438s)
== 20261028132629 AddDuoCodeReviewDefaultDepthCascadingSetting: reverting =====
-- column_exists?(:namespace_settings, :duo_code_review_default_depth)
-- remove_column(:namespace_settings, :duo_code_review_default_depth)
-- column_exists?(:namespace_settings, :lock_duo_code_review_default_depth)
-- remove_column(:namespace_settings, :lock_duo_code_review_default_depth)
-- column_exists?(:application_settings, :duo_code_review_default_depth)
-- remove_column(:application_settings, :duo_code_review_default_depth)
-- column_exists?(:application_settings, :lock_duo_code_review_default_depth)
-- remove_column(:application_settings, :lock_duo_code_review_default_depth)
== 20261028132629 AddDuoCodeReviewDefaultDepthCascadingSetting: reverted (0.4323s)
== 20261028132628 AddDuoCodeReviewDepthAllowedCascadingSetting: reverting =====
-- column_exists?(:namespace_settings, :duo_code_review_depth_allowed)
-- remove_column(:namespace_settings, :duo_code_review_depth_allowed)
-- column_exists?(:namespace_settings, :lock_duo_code_review_depth_allowed)
-- remove_column(:namespace_settings, :lock_duo_code_review_depth_allowed)
-- column_exists?(:application_settings, :duo_code_review_depth_allowed)
-- remove_column(:application_settings, :duo_code_review_depth_allowed)
-- column_exists?(:application_settings, :lock_duo_code_review_depth_allowed)
-- remove_column(:application_settings, :lock_duo_code_review_depth_allowed)
== 20261028132628 AddDuoCodeReviewDepthAllowedCascadingSetting: reverted (0.4292s)
== 20261028132628 AddDuoCodeReviewDepthAllowedCascadingSetting: migrating =====
-- column_exists?(:namespace_settings, :duo_code_review_depth_allowed)
-- column_exists?(:namespace_settings, :lock_duo_code_review_depth_allowed)
-- column_exists?(:application_settings, :duo_code_review_depth_allowed)
-- column_exists?(:application_settings, :lock_duo_code_review_depth_allowed)
-- add_column(:namespace_settings, :duo_code_review_depth_allowed, :boolean, {default: nil, null: true})
-- add_column(:namespace_settings, :lock_duo_code_review_depth_allowed, :boolean, {default: false, null: false})
-- add_column(:application_settings, :duo_code_review_depth_allowed, :boolean, {default: true, null: false})
-- add_column(:application_settings, :lock_duo_code_review_depth_allowed, :boolean, {default: false, null: false})
== 20261028132628 AddDuoCodeReviewDepthAllowedCascadingSetting: migrated (0.4503s)
== 20261028132629 AddDuoCodeReviewDefaultDepthCascadingSetting: migrating =====
-- column_exists?(:namespace_settings, :duo_code_review_default_depth)
-- column_exists?(:namespace_settings, :lock_duo_code_review_default_depth)
-- column_exists?(:application_settings, :duo_code_review_default_depth)
-- column_exists?(:application_settings, :lock_duo_code_review_default_depth)
-- add_column(:namespace_settings, :duo_code_review_default_depth, :smallint, {default: nil, null: true})
-- add_column(:namespace_settings, :lock_duo_code_review_default_depth, :boolean, {default: false, null: false})
-- add_column(:application_settings, :duo_code_review_default_depth, :smallint, {default: 0, null: false})
-- add_column(:application_settings, :lock_duo_code_review_default_depth, :boolean, {default: false, null: false})
== 20261028132629 AddDuoCodeReviewDefaultDepthCascadingSetting: migrated (0.4488s)
== 20261028132630 AddDuoCodeReviewDepthAllowedToProjectSettings: migrating ====
-- add_column(:project_settings, :duo_code_review_depth_allowed, :boolean, {default: true, null: false})
== 20261028132630 AddDuoCodeReviewDepthAllowedToProjectSettings: migrated (0.0530s)
== 20261028132631 AddDuoCodeReviewDefaultDepthToProjectSettings: migrating ====
-- add_column(:project_settings, :duo_code_review_default_depth, :smallint, {default: 0, null: false})
== 20261028132631 AddDuoCodeReviewDefaultDepthToProjectSettings: migrated (0.0631s)

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Wanderson Policarpo

Merge request reports

Loading
Loading