Class: Group

Constant Summary collapse

ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT =
10
UpdateSharedRunnersError =
Class.new(StandardError)

Constants included from WithUploads

WithUploads::FILE_UPLOADERS

Constants included from Avatarable

Avatarable::ALLOWED_IMAGE_SCALER_WIDTHS

Constants inherited from Namespace

Namespace::NUMBER_OF_ANCESTORS_ALLOWED

Constants included from Gitlab::SQL::Pattern

Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING, Gitlab::SQL::Pattern::REGEX_QUOTED_WORD

Constants included from Gitlab::VisibilityLevel

Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PRIVATE, Gitlab::VisibilityLevel::PUBLIC

Constants included from CacheMarkdownField

CacheMarkdownField::INVALIDATED_BY

Class Method Summary collapse

Instance Method Summary collapse

Methods included from GroupAPICompatibility

#project_creation_level_str, #project_creation_level_str=, #subgroup_creation_level_str, #subgroup_creation_level_str=

Methods included from Gitlab::Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Methods included from WithUploads

#retrieve_upload

Methods included from FastDestroyAll::Helpers

#perform_fast_destroy

Methods included from AfterCommitQueue

#run_after_commit, #run_after_commit_or_now

Methods included from GroupDescendant

build_hierarchy, #hierarchy

Methods included from LoadedInGroupList

#children_count, #member_count, #project_count, #subgroup_count

Methods included from Referable

#referable_inspect, #reference_link_text, #to_reference_base

Methods included from Avatarable

#avatar_path, #avatar_type, #uncached_avatar_path, #upload_paths

Methods included from AccessRequestable

#request_access

Methods included from Gitlab::ConfigHelper

#gitlab_config, #gitlab_config_features

Methods inherited from Namespace

#actual_limits, #actual_plan, #actual_plan_name, #aggregation_scheduled?, #all_pipelines, #all_projects, #ancestors, #ancestors_upto, #any_project_has_container_registry_tags?, #any_project_with_pages_deployed?, #any_project_with_shared_runners_enabled?, #auto_devops_enabled?, by_path, clean_name, clean_path, #closest_setting, #default_branch_protection, #descendants, #emails_disabled?, #feature_available?, find_by_pages_host, find_by_path_or_name, #find_fork_of, #first_auto_devops_config, #first_project_with_container_registry_tags, #full_path_before_last_save, #group?, #has_parent?, #kind, #multiple_issue_boards_available?, #pages_virtual_domain, #root_ancestor, search, #self_and_ancestors, #self_and_descendants, #self_and_hierarchy, #send_update_instructions, #subgroup?, #to_param, #user?, #visibility_level_field

Methods included from FeatureGate

#flipper_id

Methods included from Storage::LegacyNamespace

#move_dir, #prepare_for_destroy

Methods included from Gitlab::ShellAdapter

#gitlab_shell

Methods included from Routable

#build_full_path, #full_name, #full_path, #full_path_components

Methods included from Gitlab::VisibilityLevel

allowed_for?, allowed_level?, allowed_levels, closest_allowed_level, #internal?, level_name, level_value, levels_for_user, non_restricted_level?, options, #private?, #public?, public_visibility_restricted?, restricted_level?, string_level, string_options, string_values, valid_level?, #visibility, #visibility=, #visibility_attribute_present?, #visibility_level_attributes, #visibility_level_decreased?, #visibility_level_previous_changes, #visibility_level_value

Methods included from CacheMarkdownField

#attribute_invalidated?, #banzai_render_context, #cached_html_for, #cached_html_up_to_date?, #can_cache_field?, #invalidated_markdown_cache?, #latest_cached_markdown_version, #local_version, #parent_user, #refresh_markdown_cache, #refresh_markdown_cache!, #rendered_field_content, #skip_project_check?, #updated_cached_html_for

Methods inherited from ApplicationRecord

at_most, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, underscore, without_order

Class Method Details

.public_or_visible_to_user(user) ⇒ Object

WARNING: This method should never be used on its own please do make sure the number of rows you are filtering is small enough for this query


123
124
125
126
127
128
129
130
131
# File 'app/models/group.rb', line 123

def public_or_visible_to_user(user)
  return public_to_user unless user

  public_for_user = public_to_user_arel(user)
  visible_for_user = visible_to_user_arel(user)
  public_or_visible = public_for_user.or(visible_for_user)

  where(public_or_visible)
end

.reference_patternObject


116
117
118
# File 'app/models/group.rb', line 116

def reference_pattern
  User.reference_pattern
end

.reference_prefixObject


112
113
114
# File 'app/models/group.rb', line 112

def reference_prefix
  User.reference_prefix
end

.select_for_project_authorizationObject


133
134
135
136
137
138
139
140
141
# File 'app/models/group.rb', line 133

def select_for_project_authorization
  if current_scope.joins_values.include?(:shared_projects)
    joins('INNER JOIN namespaces project_namespace ON project_namespace.id = projects.namespace_id')
      .where('project_namespace.share_with_group_lock = ?', false)
      .select("projects.id AS project_id, LEAST(project_group_links.group_access, members.access_level) AS access_level")
  else
    super
  end
end

.sort_by_attribute(method) ⇒ Object


102
103
104
105
106
107
108
109
110
# File 'app/models/group.rb', line 102

def sort_by_attribute(method)
  if method == 'storage_size_desc'
    # storage_size is a virtual column so we need to
    # pass a string to avoid AR adding the table name
    reorder('storage_size DESC, namespaces.id DESC')
  else
    order_by(method)
  end
end

Instance Method Details

#access_request_approvers_to_be_notifiedObject


489
490
491
# File 'app/models/group.rb', line 489

def access_request_approvers_to_be_notified
  members.owners..limit(ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT)
end

#add_developer(user, current_user = nil) ⇒ Object


262
263
264
# File 'app/models/group.rb', line 262

def add_developer(user, current_user = nil)
  add_user(user, :developer, current_user: current_user)
end

#add_guest(user, current_user = nil) ⇒ Object


254
255
256
# File 'app/models/group.rb', line 254

def add_guest(user, current_user = nil)
  add_user(user, :guest, current_user: current_user)
end

#add_maintainer(user, current_user = nil) ⇒ Object


266
267
268
# File 'app/models/group.rb', line 266

def add_maintainer(user, current_user = nil)
  add_user(user, :maintainer, current_user: current_user)
end

#add_owner(user, current_user = nil) ⇒ Object


270
271
272
# File 'app/models/group.rb', line 270

def add_owner(user, current_user = nil)
  add_user(user, :owner, current_user: current_user)
end

#add_reporter(user, current_user = nil) ⇒ Object


258
259
260
# File 'app/models/group.rb', line 258

def add_reporter(user, current_user = nil)
  add_user(user, :reporter, current_user: current_user)
end

#add_user(user, access_level, current_user: nil, expires_at: nil, ldap: false) ⇒ Object


243
244
245
246
247
248
249
250
251
252
# File 'app/models/group.rb', line 243

def add_user(user, access_level, current_user: nil, expires_at: nil, ldap: false)
  GroupMember.add_user(
    self,
    user,
    access_level,
    current_user: current_user,
    expires_at: expires_at,
    ldap: ldap
  )
end

#add_users(users, access_level, current_user: nil, expires_at: nil) ⇒ Object


233
234
235
236
237
238
239
240
241
# File 'app/models/group.rb', line 233

def add_users(users, access_level, current_user: nil, expires_at: nil)
  GroupMember.add_users(
    self,
    users,
    access_level,
    current_user: current_user,
    expires_at: expires_at
  )
end

#adjourned_deletion?Boolean

Returns:

  • (Boolean)

505
506
507
# File 'app/models/group.rb', line 505

def adjourned_deletion?
  false
end

#allow_descendants_override_disabled_shared_runners!Object


555
556
557
558
559
560
# File 'app/models/group.rb', line 555

def allow_descendants_override_disabled_shared_runners!
  raise UpdateSharedRunnersError, 'Shared Runners enabled' if shared_runners_enabled?
  raise UpdateSharedRunnersError, 'Group level shared Runners not allowed' unless parent_allows_shared_runners?

  update_column(:allow_descendants_override_disabled_shared_runners, true)
end

#ci_variables_for(ref, project) ⇒ Object


436
437
438
439
440
441
442
443
444
445
446
# File 'app/models/group.rb', line 436

def ci_variables_for(ref, project)
  cache_key = "ci_variables_for:group:#{self&.id}:project:#{project&.id}:ref:#{ref}"

  ::Gitlab::SafeRequestStore.fetch(cache_key) do
    list_of_ids = [self] + ancestors
    variables = Ci::GroupVariable.where(group: list_of_ids)
    variables = variables.unprotected unless project.protected_for?(ref)
    variables = variables.group_by(&:group_id)
    list_of_ids.reverse.flat_map { |group| variables[group.id] }.compact
  end
end

#default_ownerObject


573
574
575
# File 'app/models/group.rb', line 573

def default_owner
  owners.first || parent&.default_owner || owner
end

#direct_and_indirect_membersObject

Returns all members that are part of the group, it's subgroups, and ancestor groups


369
370
371
372
373
# File 'app/models/group.rb', line 369

def direct_and_indirect_members
  GroupMember
    .active_without_invites_and_requests
    .where(source_id: self_and_hierarchy.reorder(nil).select(:id))
end

#direct_and_indirect_usersObject

Returns all users that are members of the group because:

  1. They belong to the group

  2. They belong to a project that belongs to the group

  3. They belong to a sub-group or project in such sub-group

  4. They belong to an ancestor group


392
393
394
395
396
397
398
399
# File 'app/models/group.rb', line 392

def direct_and_indirect_users
  User.from_union([
    User
      .where(id: direct_and_indirect_members.select(:user_id))
      .reorder(nil),
    project_users_with_descendants
  ])
end

#disable_shared_runners!Object


546
547
548
549
550
551
552
553
# File 'app/models/group.rb', line 546

def disable_shared_runners!
  group_ids = self_and_descendants
  return if group_ids.empty?

  Group.by_id(group_ids).update_all(shared_runners_enabled: false)

  all_projects.update_all(shared_runners_enabled: false)
end

#disallow_descendants_override_disabled_shared_runners!Object


562
563
564
565
566
567
568
569
570
571
# File 'app/models/group.rb', line 562

def disallow_descendants_override_disabled_shared_runners!
  raise UpdateSharedRunnersError, 'Shared Runners enabled' if shared_runners_enabled?

  group_ids = self_and_descendants
  return if group_ids.empty?

  Group.by_id(group_ids).update_all(allow_descendants_override_disabled_shared_runners: false)

  all_projects.update_all(shared_runners_enabled: false)
end

#enable_shared_runners!Object


540
541
542
543
544
# File 'app/models/group.rb', line 540

def enable_shared_runners!
  raise UpdateSharedRunnersError, 'Shared Runners disabled for the parent group' unless parent_enabled_shared_runners?

  update_column(:shared_runners_enabled, true)
end

#execute_hooks(data, hooks_scope) ⇒ Object


509
510
511
512
# File 'app/models/group.rb', line 509

def execute_hooks(data, hooks_scope)
  # NOOP
  # TODO: group hooks https://gitlab.com/gitlab-org/gitlab/-/issues/216904
end

#execute_services(data, hooks_scope) ⇒ Object


514
515
516
517
# File 'app/models/group.rb', line 514

def execute_services(data, hooks_scope)
  # NOOP
  # TODO: group hooks https://gitlab.com/gitlab-org/gitlab/-/issues/216904
end

#export_fileObject


501
502
503
# File 'app/models/group.rb', line 501

def export_file
  import_export_upload&.export_file
end

#export_file_exists?Boolean

Returns:

  • (Boolean)

497
498
499
# File 'app/models/group.rb', line 497

def export_file_exists?
  export_file&.file
end

#group_member(user) ⇒ Object


448
449
450
451
452
453
454
# File 'app/models/group.rb', line 448

def group_member(user)
  if group_members.loaded?
    group_members.find { |gm| gm.user_id == user.id }
  else
    group_members.find_by(user_id: user)
  end
end

#has_container_repository_including_subgroups?Boolean

Returns:

  • (Boolean)

292
293
294
# File 'app/models/group.rb', line 292

def has_container_repository_including_subgroups?
  ::ContainerRepository.for_group_and_its_subgroups(self).exists?
end

#has_maintainer?(user) ⇒ Boolean

Returns:

  • (Boolean)

286
287
288
289
290
# File 'app/models/group.rb', line 286

def has_maintainer?(user)
  return false unless user

  members_with_parents.maintainers.exists?(user_id: user)
end

#has_owner?(user) ⇒ Boolean

Returns:

  • (Boolean)

280
281
282
283
284
# File 'app/models/group.rb', line 280

def has_owner?(user)
  return false unless user

  members_with_parents.owners.exists?(user_id: user)
end

#hashed_storage?(_feature) ⇒ Boolean

Returns:

  • (Boolean)

466
467
468
# File 'app/models/group.rb', line 466

def hashed_storage?(_feature)
  false
end

#highest_group_member(user) ⇒ Object


456
457
458
# File 'app/models/group.rb', line 456

def highest_group_member(user)
  GroupMember.where(source_id: self_and_ancestors_ids, user_id: user.id).order(:access_level).last
end

#human_nameObject


198
199
200
# File 'app/models/group.rb', line 198

def human_name
  full_name
end

#last_owner?(user) ⇒ Boolean

Check if user is a last owner of the group.

Returns:

  • (Boolean)

297
298
299
# File 'app/models/group.rb', line 297

def last_owner?(user)
  has_owner?(user) && members_with_parents.owners.size == 1
end

#ldap_synced?Boolean

Returns:

  • (Boolean)

301
302
303
# File 'app/models/group.rb', line 301

def ldap_synced?
  false
end

#lfs_enabled?Boolean

Returns:

  • (Boolean)

222
223
224
225
226
227
# File 'app/models/group.rb', line 222

def lfs_enabled?
  return false unless Gitlab.config.lfs.enabled
  return Gitlab.config.lfs.enabled if self[:lfs_enabled].nil?

  self[:lfs_enabled]
end

#mattermost_team_paramsObject


426
427
428
429
430
431
432
433
434
# File 'app/models/group.rb', line 426

def mattermost_team_params
  max_length = 59

  {
    name: path[0..max_length],
    display_name: name[0..max_length],
    type: public? ? 'O' : 'I' # Open vs Invite-only
  }
end

#max_member_access_for_user(user) ⇒ Object


413
414
415
416
417
418
419
420
421
422
423
424
# File 'app/models/group.rb', line 413

def max_member_access_for_user(user)
  return GroupMember::NO_ACCESS unless user

  return GroupMember::OWNER if user.admin?

  max_member_access = members_with_parents.where(user_id: user)
                                          .reorder(access_level: :desc)
                                          .first
                                          &.access_level

  max_member_access || GroupMember::NO_ACCESS
end

#member?(user, min_access_level = Gitlab::Access::GUEST) ⇒ Boolean

Returns:

  • (Boolean)

274
275
276
277
278
# File 'app/models/group.rb', line 274

def member?(user, min_access_level = Gitlab::Access::GUEST)
  return false unless user

  max_member_access_for_user(user) >= min_access_level
end

#members_from_self_and_ancestors_with_effective_access_levelObject


357
358
359
360
# File 'app/models/group.rb', line 357

def members_from_self_and_ancestors_with_effective_access_level
  members_with_parents.select([:user_id, 'MAX(access_level) AS access_level'])
                      .group(:user_id)
end

#members_with_descendantsObject


362
363
364
365
366
# File 'app/models/group.rb', line 362

def members_with_descendants
  GroupMember
    .active_without_invites_and_requests
    .where(source_id: self_and_descendants.reorder(nil).select(:id))
end

#members_with_parentsObject


341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'app/models/group.rb', line 341

def members_with_parents
  # Avoids an unnecessary SELECT when the group has no parents
  source_ids =
    if has_parent?
      self_and_ancestors.reorder(nil).select(:id)
    else
      id
    end

  group_hierarchy_members = GroupMember.active_without_invites_and_requests
                                       .where(source_id: source_ids)

  GroupMember.from_union([group_hierarchy_members,
                          members_from_self_and_ancestor_group_shares])
end

#notification_email_for(user) ⇒ Object


184
185
186
187
188
# File 'app/models/group.rb', line 184

def notification_email_for(user)
  # Finds the closest notification_setting with a `notification_email`
  notification_settings = notification_settings_for(user, hierarchy_order: :asc)
  notification_settings.find { |n| n.notification_email.present? }&.notification_email
end

#notification_settings(hierarchy_order: nil) ⇒ Object

Overrides notification_settings has_many association This allows to apply notification settings from parent groups to child groups and projects.


164
165
166
167
168
169
170
171
172
173
174
# File 'app/models/group.rb', line 164

def notification_settings(hierarchy_order: nil)
  source_type = self.class.base_class.name
  settings = NotificationSetting.where(source_type: source_type, source_id: self_and_ancestors_ids)

  return settings unless hierarchy_order && self_and_ancestors_ids.length > 1

  settings
    .joins("LEFT JOIN (#{self_and_ancestors(hierarchy_order: hierarchy_order).to_sql}) AS ordered_groups ON notification_settings.source_id = ordered_groups.id")
    .select('notification_settings.*, ordered_groups.depth AS depth')
    .order("ordered_groups.depth #{hierarchy_order}")
end

#notification_settings_for(user, hierarchy_order: nil) ⇒ Object


176
177
178
# File 'app/models/group.rb', line 176

def notification_settings_for(user, hierarchy_order: nil)
  notification_settings(hierarchy_order: hierarchy_order).where(user: user)
end

#owned_by?(user) ⇒ Boolean

Returns:

  • (Boolean)

229
230
231
# File 'app/models/group.rb', line 229

def owned_by?(user)
  owners.include?(user)
end

#packages_feature_enabled?Boolean

Returns:

  • (Boolean)

180
181
182
# File 'app/models/group.rb', line 180

def packages_feature_enabled?
  ::Gitlab.config.packages.enabled
end

#parent_allows_shared_runners?Boolean

Returns:

  • (Boolean)

528
529
530
531
532
# File 'app/models/group.rb', line 528

def parent_allows_shared_runners?
  return true unless has_parent?

  parent.shared_runners_allowed?
end

#parent_enabled_shared_runners?Boolean

Returns:

  • (Boolean)

534
535
536
537
538
# File 'app/models/group.rb', line 534

def parent_enabled_shared_runners?
  return true unless has_parent?

  parent.shared_runners_enabled?
end

#post_create_hookObject


305
306
307
308
309
# File 'app/models/group.rb', line 305

def post_create_hook
  Gitlab::AppLogger.info("Group \"#{name}\" was created")

  system_hook_service.execute_hooks_for(self, :create)
end

#post_destroy_hookObject


311
312
313
314
315
# File 'app/models/group.rb', line 311

def post_destroy_hook
  Gitlab::AppLogger.info("Group \"#{name}\" was removed")

  system_hook_service.execute_hooks_for(self, :destroy)
end

519
520
521
522
# File 'app/models/group.rb', line 519

def preload_shared_group_links
  preloader = ActiveRecord::Associations::Preloader.new
  preloader.preload(self, shared_with_group_links: [shared_with_group: :route])
end

#project_creation_levelObject


481
482
483
# File 'app/models/group.rb', line 481

def project_creation_level
  super || ::Gitlab::CurrentSettings.default_project_creation
end

#project_users_with_descendantsObject

Returns all users that are members of projects belonging to the current group or sub-groups


407
408
409
410
411
# File 'app/models/group.rb', line 407

def project_users_with_descendants
  User
    .joins(projects: :group)
    .where(namespaces: { id: self_and_descendants.select(:id) })
end

#refresh_members_authorized_projects(blocking: true, priority: UserProjectAccessChangedService::HIGH_PRIORITY) ⇒ Object

rubocop: disable CodeReuse/ServiceClass


324
325
326
327
328
# File 'app/models/group.rb', line 324

def refresh_members_authorized_projects(blocking: true, priority: UserProjectAccessChangedService::HIGH_PRIORITY)
  UserProjectAccessChangedService
    .new(user_ids_for_project_authorizations)
    .execute(blocking: blocking, priority: priority)
end

#refresh_project_authorizationsObject


470
471
472
# File 'app/models/group.rb', line 470

def refresh_project_authorizations
  refresh_members_authorized_projects(blocking: false)
end

460
461
462
463
464
# File 'app/models/group.rb', line 460

def related_group_ids
  [id,
   *ancestors.pluck(:id),
   *shared_with_group_links.pluck(:shared_with_group_id)]
end

#runners_tokenObject

each existing group needs to have a `runners_token`. we do this on read since migrating all existing groups is not a feasible solution.


477
478
479
# File 'app/models/group.rb', line 477

def runners_token
  ensure_runners_token!
end

#self_and_ancestors_idsObject


335
336
337
338
339
# File 'app/models/group.rb', line 335

def self_and_ancestors_ids
  strong_memoize(:self_and_ancestors_ids) do
    self_and_ancestors.pluck(:id)
  end
end

#shared_runners_allowed?Boolean

Returns:

  • (Boolean)

524
525
526
# File 'app/models/group.rb', line 524

def shared_runners_allowed?
  shared_runners_enabled? || allow_descendants_override_disabled_shared_runners?
end

#subgroup_creation_levelObject


485
486
487
# File 'app/models/group.rb', line 485

def subgroup_creation_level
  super || ::Gitlab::Access::OWNER_SUBGROUP_ACCESS
end

#supports_events?Boolean

Returns:

  • (Boolean)

493
494
495
# File 'app/models/group.rb', line 493

def supports_events?
  false
end

#system_hook_serviceObject

rubocop: disable CodeReuse/ServiceClass


318
319
320
# File 'app/models/group.rb', line 318

def system_hook_service
  SystemHooksService.new
end

#to_reference(_from = nil, target_project: nil, full: nil) ⇒ Object


190
191
192
# File 'app/models/group.rb', line 190

def to_reference(_from = nil, target_project: nil, full: nil)
  "#{self.class.reference_prefix}#{full_path}"
end

#user_ids_for_project_authorizationsObject

rubocop: enable CodeReuse/ServiceClass


331
332
333
# File 'app/models/group.rb', line 331

def user_ids_for_project_authorizations
  members_with_parents.pluck(:user_id)
end

#users_countObject


401
402
403
# File 'app/models/group.rb', line 401

def users_count
  members.count
end

#users_with_descendantsObject


381
382
383
384
385
# File 'app/models/group.rb', line 381

def users_with_descendants
  User
    .where(id: members_with_descendants.select(:user_id))
    .reorder(nil)
end

#users_with_parentsObject


375
376
377
378
379
# File 'app/models/group.rb', line 375

def users_with_parents
  User
    .where(id: members_with_parents.select(:user_id))
    .reorder(nil)
end

#visibility_level_allowed?(level = self.visibility_level) ⇒ Boolean

Returns:

  • (Boolean)

216
217
218
219
220
# File 'app/models/group.rb', line 216

def visibility_level_allowed?(level = self.visibility_level)
  visibility_level_allowed_by_parent?(level) &&
    visibility_level_allowed_by_projects?(level) &&
    visibility_level_allowed_by_sub_groups?(level)
end

#visibility_level_allowed_by_parent?(level = self.visibility_level) ⇒ Boolean

Returns:

  • (Boolean)

202
203
204
205
206
# File 'app/models/group.rb', line 202

def visibility_level_allowed_by_parent?(level = self.visibility_level)
  return true unless parent_id && parent_id.nonzero?

  level <= parent.visibility_level
end

#visibility_level_allowed_by_projects?(level = self.visibility_level) ⇒ Boolean

Returns:

  • (Boolean)

208
209
210
# File 'app/models/group.rb', line 208

def visibility_level_allowed_by_projects?(level = self.visibility_level)
  !projects.where('visibility_level > ?', level).exists?
end

#visibility_level_allowed_by_sub_groups?(level = self.visibility_level) ⇒ Boolean

Returns:

  • (Boolean)

212
213
214
# File 'app/models/group.rb', line 212

def visibility_level_allowed_by_sub_groups?(level = self.visibility_level)
  !children.where('visibility_level > ?', level).exists?
end

#web_url(only_path: nil) ⇒ Object


194
195
196
# File 'app/models/group.rb', line 194

def web_url(only_path: nil)
  Gitlab::UrlBuilder.build(self, only_path: only_path)
end