doc/directory. Describe the feature and include screenshots, if applicable.
www-gitlab-comproject.: Add the new feature to the EE features list.
Merging changes from GitLab CE to EE can result in numerous conflicts. To reduce conflicts, EE code should be separated in to the
EE module as much as possible.
Place EE-specific controllers, finders, helpers, mailers, models, policies, serializers/entities, services, validators and workers in the top-level
EE module namespace, and in a specific
If you modify an existing part of a CE controller, model, service, worker etc. one simple solution is to use the
prepend strategy (presented below).
For example to override the CE implementation of
def after_sign_out_path_for(resource) current_application_settings.after_sign_out_path.presence || new_user_session_path end
Instead of modifying the method in place, you should do the following:
class ApplicationController < ActionController::Base prepend EE::ApplicationController [...] def after_sign_out_path_for(resource) current_application_settings.after_sign_out_path.presence || new_user_session_path end [...] end module EE class ApplicationController def after_sign_out_path_for(resource) raise NotImplementedError unless defined?(super) if Gitlab::Geo.secondary? Gitlab::Geo.primary_node.oauth_logout_url(@geo_logout_state) else super end end end end
In controllers, the most common type of conflict is with
before_action that has a list of actions in CE but EE adds some actions to that list.
The same problem often occurs for
Separate CE and EE actions/keywords. For instance for
def project_params params.require(:project).permit(project_params_ce) # On EE, this is always: # params.require(:project).permit(project_params_ce << project_params_ee) end # Always returns an array of symbols, created however best fits the use case. # It _should_ be sorted alphabetically. def project_params_ce %i[ description name path ] end # (On EE) def project_params_ee %i[ approvals_before_merge approver_group_ids approver_ids ... ] end
EE-specific models should
For example, if EE has a specific
Tanuki model, you would place it in
It's a very frequent problem that EE is adding some specific view code in a CE view. For instance the approval code in the project's settings page.
Blocks of code that are EE-specific should be moved to partials as much as possible to avoid conflicts with big chunks of HAML code that that are not fun to resolve when you add the indentation to the equation.
Place EE-specific logic in the top-level
EE module namespace. Namespace the class beneath the
EE module just as you would normally.
For example, if CE has LDAP classes in
lib/gitlab/ldap/ then you would place EE-specific LDAP classes in
If the feature being developed is not present in any form in CE, separation is easier - build the class entirely in the
EE namespace. For features that build on existing CE features, write a module in the
EE namespace and include it in the CE class. This makes conflicts less likely during CE to EE merges because only one line is added to the CE class - the
There are two ways for overriding a method that's defined in CE:
prependwhich lets you override a method in a class with a method from a module, and still access the class's implementation with
prepend method should always be preferred but there are a few gotchas with it:
raise NotImplementedError unless defined?(super)guard clause in the "overrider" method to ensure that if the method gets renamed in CE, the EE override won't be silently forgotten.
return unless condition), it doesn't return from the overriden method (it's actually the same behavior as with method overridding via inheritance). In this case, it's usually better to create a "hook" method that is empty in CE, and with the EE-specific implementation in EE