カスケード設定

GitLab 13.11で導入されました。

カスケード設定フレームワークにより、グループは基本的に祖先(グループ階層上の親グループ)やインスタンスレベルのアプリケーション設定から設定値を継承することができます。また、このフレームワークでは、設定値をより低い階層のグループに強制することもできます。

カスケード設定は現在、NamespaceSetting 内でのみ定義できますが、将来的には他のオブジェクトにも拡張される可能性があります。

新しいカスケード設定を追加

デフォルトでは、設定はカスケードされません。カスケード設定を定義するには、以下の手順を実行します:

  1. NamespaceSetting モデル内部で、cascading_attr ヘルパー・メソッドを使用して新しい属性を定義します。一行で複数の属性を定義するために配列を使うことができます。

    class NamespaceSetting
      include CascadingNamespaceSettingAttribute
       
      cascading_attr :delayed_project_removal
    end
    
  2. データベースのカラムを作ります。

    まったく新しい設定には、次のデータベースマイグレーションヘルパーを使うことができます。このヘルパーは4つのカラムを作成し、namespace_settingsapplication_settings にそれぞれ2つずつ作成します。

    class AddDelayedProjectRemovalCascadingSetting < Gitlab::Database::Migration[2.1]
      include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings
       
      enable_lock_retries!
       
      def up
        add_cascading_namespace_setting :delayed_project_removal, :boolean, default: false, null: false
      end
       
      def down
       remove_cascading_namespace_setting :delayed_project_removal
      end
    end
    

    カスケード設定に変換される既存の設定は、カラムを追加したり既存のカラムを変更したりするために個別のマイグレーションを必要とします。以下の仕様を使用して、必要に応じてマイグレーションを作成してください:

    1. namespace_settings テーブルのカラム:
      • delayed_project_removal:デフォルト値なし。ヌル値可。任意のカラム型を使用。
      • lock_delayed_project_removal:ブール型カラム。デフォルト値はfalse。Null値は不可。
    2. application_settings テーブルのカラム:
      • delayed_project_removal:namespace_settings で作成されたカラムのタイプ・マッチング。デフォルト値を任意に設定。Null 値は使用できません。
      • lock_delayed_project_removal:ブール型カラム。デフォルト値はfalse。Null値は不可。

便利なメソッド

cascading_attr メソッドを使って属性を定義すると、いくつかの便利なメソッドが自動的に定義されます。

定義

cascading_attr :delayed_project_removal

利用可能な便利メソッド

  • delayed_project_removal
  • delayed_project_removal=
  • delayed_project_removal_locked?
  • delayed_project_removal_locked_by_ancestor?
  • delayed_project_removal_locked_by_application_setting?
  • delayed_project_removal? (ブール属性のみ)
  • delayed_project_removal_locked_ancestor (ロックされたネームスペース設定オブジェクトを返します[namespace_id])

属性リーダーメソッド (delayed_project_removal)

属性リーダ・メソッド (delayed_project_removal) は、以下の基準で正しいカスケード値を返します:

  1. 属性が変更された場合、ダーティな値を返します。これにより、Railsの標準的なバリデータを属性に使用できるようになりますが、nil の値は許可する必要があります。
  2. ロックされた祖先の値を返します。
  3. ロックされたインスタンスレベルのアプリケーション設定値を返します。
  4. nil でない場合は、このネームスペースの属性を返します。
  5. 値が nil でない最も近い祖先の値を返します。
  6. インスタンスレベルのアプリケーション設定を返します。

_locked? メソッド

デフォルトでは、_locked? メソッド (delayed_project_removal_locked?) は、グループまたはアプリケーション設定の祖先が属性をロックしている場合、true を返します。属性をロックしたグループから呼び出された場合は、false を返します。

include_self: true が指定された場合、属性をロックしたグループから呼び出されるとtrue を返します。これは、例えば、属性がプロジェクトからロックされているかどうかをチェックする場合に関連します。

フロントエンドでのカスケード設定の表示

フロントエンドでカスケード設定を表示するために使えるRailsビューヘルパー、HAMLパーシャル、JavaScript関数がいくつかあります。

Railsビューヘルパー

cascading_namespace_setting_locked?

_locked? メソッド を呼び出して、設定がロックされているかどうかをチェックします。

引数説明種類必須(デフォルト値)
attribute設定の名前。例えば、:delayed_project_removal String またはSymbol true
group現在のグループGrouptrue
**args_locked? メソッドに渡す追加の引数。 false

HAMLパーシャル

_enforcement_checkbox.html.haml

強制チェックボックスをレンダリングします。

ローカル説明種類必須(デフォルト値)
attribute設定の名前。例えば、:delayed_project_removal String またはSymbol true
group現在のグループGrouptrue
form Rails FormBuilder オブジェクトActionView::Helpers::FormBuildertrue
setting_locked設定が祖先グループまたは管理者設定によってロックされている場合。cascading_namespace_setting_locked? で計算できます。Booleantrue
help_textチェックボックスの下に表示されるテキストString false (サブグループはこの設定を変更できません)。

_setting_label_checkbox.html.haml

チェックボックス設定のラベルをレンダリングします。

ローカル説明種類必須(デフォルト値)
attribute設定の名前。例えば、:delayed_project_removal String またはSymbol true
group現在のグループGrouptrue
form Rails FormBuilder オブジェクトActionView::Helpers::FormBuildertrue
setting_locked設定が祖先グループまたは管理者設定によってロックされている場合。cascading_namespace_setting_locked? で計算できます。Booleantrue
settings_path_helper先祖設定へのパスを生成するラムダ関数。例えばsettings_path_helper: -> (locked_ancestor) { edit_group_path(locked_ancestor, anchor: 'js-permissions-settings') } Lambdatrue
help_textチェックボックスの下に表示されるテキストString false (nil)

_setting_label_fieldset.html.haml

fieldset 設定のラベルをレンダリングします。

ローカル説明種類必須(デフォルト値)
attribute設定の名前。例えば、:delayed_project_removal String またはSymbol true
group現在のグループGrouptrue
setting_locked設定がロックされている場合。cascading_namespace_setting_locked?で計算できます。Booleantrue
settings_path_helper先祖設定へのパスを生成するラムダ関数。例えば-> (locked_ancestor) { edit_group_path(locked_ancestor, anchor: 'js-permissions-settings') } Lambdatrue
help_textチェックボックスの下に表示されるテキストString false (nil)

_lock_popovers.html.haml

ロックアイコンにカーソルを置いたときにポップオーバーを表示するJavaScriptを初期化するために必要なmount要素をレンダリングします。このパーシャルはページごとに一度だけ必要です。

ジャバスクリプト

initCascadingSettingsLockPopovers

ロックアイコン({lock})にカーソルを合わせたときにポップオーバーを表示するために必要なJavaScriptを初期化します。この関数はインポートし、ページ固有のJavaScriptで呼び出す必要があります。

すべてをまとめる

-# app/views/groups/edit.html.haml

= render 'shared/namespaces/cascading_settings/lock_popovers'

- delayed_project_removal_locked = cascading_namespace_setting_locked?(:delayed_project_removal, @group)
- merge_method_locked = cascading_namespace_setting_locked?(:merge_method, @group)

= form_for @group do |f|
  .form-group{ data: { testid: 'delayed-project-removal-form-group' } }
    .gl-form-checkbox.custom-control.custom-checkbox
      = f.check_box :delayed_project_removal, checked: @group.namespace_settings.delayed_project_removal?, disabled: delayed_project_removal_locked, class: 'custom-control-input'
      = render 'shared/namespaces/cascading_settings/setting_label_checkbox', attribute: :delayed_project_removal,
          group: @group,
          form: f,
          setting_locked: delayed_project_removal_locked,
          settings_path_helper: -> (locked_ancestor) { edit_group_path(locked_ancestor, anchor: 'js-permissions-settings') },
          help_text: s_('Settings|Projects will be permanently deleted after a 7-day delay. Inherited by subgroups.') do
        = s_('Settings|Enable delayed project deletion')
      = render 'shared/namespaces/cascading_settings/enforcement_checkbox',
          attribute: :delayed_project_removal,
          group: @group,
          form: f,
          setting_locked: delayed_project_removal_locked

  %fieldset.form-group
    = render 'shared/namespaces/cascading_settings/setting_label_fieldset', attribute: :merge_method,
        group: @group,
        setting_locked: merge_method_locked,
        settings_path_helper: -> (locked_ancestor) { edit_group_path(locked_ancestor, anchor: 'js-permissions-settings') },
        help_text: s_('Settings|Determine what happens to the commit history when you merge a merge request.') do
      = s_('Settings|Merge method')

    .gl-form-radio.custom-control.custom-radio
      = f.gitlab_ui_radio_component :merge_method, :merge, s_('Settings|Merge commit'), help_text: s_('Settings|Every merge creates a merge commit.'), radio_options: { disabled: merge_method_locked }

    .gl-form-radio.custom-control.custom-radio
      = f.gitlab_ui_radio_component :merge_method, :rebase_merge, s_('Settings|Merge commit with semi-linear history'), help_text: s_('Settings|Every merge creates a merge commit.'), radio_options: { disabled: merge_method_locked }

    .gl-form-radio.custom-control.custom-radio
      = f.gitlab_ui_radio_component :merge_method, :ff, s_('Settings|Fast-forward merge'), help_text: s_('Settings|No merge commits are created.'), radio_options: { disabled: merge_method_locked }

    = render 'shared/namespaces/cascading_settings/enforcement_checkbox',
      attribute: :merge_method,
      group: @group,
      form: f,
      setting_locked: merge_method_locked
// app/assets/javascripts/pages/groups/edit/index.js

import { initCascadingSettingsLockPopovers } from '~/namespaces/cascading_settings';

initCascadingSettingsLockPopovers();