<commit_before># Guidelines for implementing Enterprise Edition features

- **Write the code and the tests.**: As with any code, EE features should have
  good test coverage to prevent regressions.
- **Write documentation.**: Add documentation to the `doc/` directory. Describe
  the feature and include screenshots, if applicable.
- **Submit a MR to the `www-gitlab-com` project.**: Add the new feature to the
  [EE features list][ee-features-list].

## Act as CE when unlicensed

Since the implementation of [GitLab CE features to work with unlicensed EE instance][ee-as-ce]
GitLab Enterprise Edition should work like GitLab Community Edition
when no license is active. So EE features always should be guarded by
`project.feature_available?` or `group.feature_available?` (or
`License.feature_available?` if it is a system-wide feature).

CE specs should remain untouched as much as possible and extra specs
should be added for EE. Licensed features can be stubbed using the
spec helper `stub_licensed_features` in `EE::LicenseHelpers`.

[ee-as-ce]: https://gitlab.com/gitlab-org/gitlab-ee/issues/2500

## Separation of EE code

We want a [single code base][] eventually, but before we reach the goal,
we still need to merge changes from GitLab CE to EE. To help us get there,
we should make sure that we no longer edit CE files in place in order to
implement EE features.

Instead, all EE code should be put inside the `ee/` top-level directory. The
rest of the code should be as close to the CE files as possible.

[single code base]: https://gitlab.com/gitlab-org/gitlab-ee/issues/2952#note_41016454

### EE-only features

If the feature being developed is not present in any form in CE, we don't
need to put the codes under `EE` namespace. For example, an EE model could
go into: `ee/app/models/awesome.rb` using `Awesome` as the class name. This
is applied not only to models. Here's a list of other examples:

- `ee/app/controllers/foos_controller.rb`
- `ee/app/finders/foos_finder.rb`
- `ee/app/helpers/foos_helper.rb`
- `ee/app/mailers/foos_mailer.rb`
- `ee/app/models/foo.rb`
- `ee/app/policies/foo_policy.rb`
- `ee/app/serializers/foo_entity.rb`
- `ee/app/serializers/foo_serializer.rb`
- `ee/app/services/foo/create_service.rb`
- `ee/app/validators/foo_attr_validator.rb`
- `ee/app/workers/foo_worker.rb`

### EE features based on CE features

For features that build on existing CE features, write a module in the
`EE` namespace and `prepend` it in the CE class. This makes conflicts<commit_msg>Document the ee-files-location-check CI job<commit_after># Guidelines for implementing Enterprise Edition features

- **Write the code and the tests.**: As with any code, EE features should have
  good test coverage to prevent regressions.
- **Write documentation.**: Add documentation to the `doc/` directory. Describe
  the feature and include screenshots, if applicable.
- **Submit a MR to the `www-gitlab-com` project.**: Add the new feature to the
  [EE features list][ee-features-list].

## Act as CE when unlicensed

Since the implementation of [GitLab CE features to work with unlicensed EE instance][ee-as-ce]
GitLab Enterprise Edition should work like GitLab Community Edition
when no license is active. So EE features always should be guarded by
`project.feature_available?` or `group.feature_available?` (or
`License.feature_available?` if it is a system-wide feature).

CE specs should remain untouched as much as possible and extra specs
should be added for EE. Licensed features can be stubbed using the
spec helper `stub_licensed_features` in `EE::LicenseHelpers`.

[ee-as-ce]: https://gitlab.com/gitlab-org/gitlab-ee/issues/2500

## Separation of EE code

We want a [single code base][] eventually, but before we reach the goal,
we still need to merge changes from GitLab CE to EE. To help us get there,
we should make sure that we no longer edit CE files in place in order to
implement EE features.

Instead, all EE code should be put inside the `ee/` top-level directory. The
rest of the code should be as close to the CE files as possible.

[single code base]: https://gitlab.com/gitlab-org/gitlab-ee/issues/2952#note_41016454

### Detection of EE-only files

For each commit (except on `master`), the `ee-files-location-check` CI job tries
to detect if there are any new files that are EE-only. If any file is detected,
the job fails with an explanation of why and what to do to make it pass.

Basically, the fix is simple: `git mv <file> ee/<file>`.

#### How to name your branches?

For any EE branch, the job will try to detect its CE counterpart by removing any
`ee-` prefix or `-ee` suffix from the EE branch name, and matching the last
branch that contains it.

For instance, from the EE branch `new-shiny-feature-ee` (or
`ee-new-shiny-feature`), the job would find the corresponding CE branches:

- `new-shiny-feature`
- `ce-new-shiny-feature`
- `new-shiny-feature-ce`
- `my-super-new-shiny-feature-in-ce`

#### Whitelist some EE-only files that cannot be moved to `ee/`

The `ee-files-location-check` CI job provides a whitelist of files or folders
that cannot or should not be moved to `ee/`. Feel free to open an issue to
discuss adding a new file/folder to this whitelist.

For instance, it was decided that moving EE-only files from `qa/` to `ee/qa/`
would make it difficult to build the `gitLab-{ce,ee}-qa` Docker images and it
was [not worth the complexity].

[not worth the complexity]: https://gitlab.com/gitlab-org/gitlab-ee/issues/4997#note_59764702

### EE-only features

If the feature being developed is not present in any form in CE, we don't
need to put the codes under `EE` namespace. For example, an EE model could
go into: `ee/app/models/awesome.rb` using `Awesome` as the class name. This
is applied not only to models. Here's a list of other examples:

- `ee/app/controllers/foos_controller.rb`
- `ee/app/finders/foos_finder.rb`
- `ee/app/helpers/foos_helper.rb`
- `ee/app/mailers/foos_mailer.rb`
- `ee/app/models/foo.rb`
- `ee/app/policies/foo_policy.rb`
- `ee/app/serializers/foo_entity.rb`
- `ee/app/serializers/foo_serializer.rb`
- `ee/app/services/foo/create_service.rb`
- `ee/app/validators/foo_attr_validator.rb`
- `ee/app/workers/foo_worker.rb`

This works because for every path that are present in CE's eager-load/auto-load
paths, we add the same `ee/`-prepended path in [`config/application.rb`].

[`config/application.rb`]: https://gitlab.com/gitlab-org/gitlab-ee/blob/d278b76d6600a0e27d8019a0be27971ba23ab640/config/application.rb#L41-51

### EE features based on CE features

For features that build on existing CE features, write a module in the
`EE` namespace and `prepend` it in the CE class. This makes conflicts
{'fraction_non_alphanumeric': 0.09629186602870814, 'fraction_numerical': 0.011214114832535885, 'mean_word_length': 4.246274509803921, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '642237', 'n_tokens_mistral': 2150, 'n_tokens_neox': 2040, 'n_words': 862}