Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
gitlab-ce
Commits
65650bc0
Commit
65650bc0
authored
Mar 07, 2018
by
Lin Jen-Shin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Document a few strategies to extract EE APIs
parent
be60d106
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
249 additions
and
0 deletions
+249
-0
doc/development/ee_features.md
doc/development/ee_features.md
+249
-0
No files found.
doc/development/ee_features.md
View file @
65650bc0
...
...
@@ -350,6 +350,255 @@ 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
`ee/lib/ee/gitlab/ldap`
.
### Code in `lib/api/`
It could be very tricky to extend EE features by a single line of
`prepend`
,
and for each different
[
Grape
](
https://github.com/ruby-grape/grape
)
features,
we might need different strategies to extend it. To apply different strategies
easily, we would use
`extend ActiveSupport::Concern`
in the EE module.
Put the EE module files following the same rule with other EE modules.
#### EE API routes
For EE API routes, we could just put them in
`prepended`
block like:
```
ruby
module
EE
module
API
module
MergeRequests
extend
ActiveSupport
::
Concern
prepended
do
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a project'
end
resource
:projects
,
requirements:
::
API
::
API
::
PROJECT_ENDPOINT_REQUIREMENTS
do
# ...
end
end
end
end
end
```
Note that due to namespace difference, we need to use full qualifier for some
constants. If this is annoying, we could also consider include some namespace
so that we could use shorter name. This is especially true for Grape
data type like:
`Grape::API::Boolean`
.
#### EE params
We could define
`params`
and use
`use`
in another params to include EE defined
params. However we need to define the "interface" first in CE in order for
EE to override it. We don't have to do this in other places due to
`prepend`
,
but Grape is complex internally and we couldn't easily do that, so we'll just
follow regular object-oriented practice that we define interface first here.
For example, suppose we have a few more optional params for EE, given this CE
API code:
```
ruby
module
API
class
MergeRequests
<
Grape
::
API
# EE::API::MergeRequests would override the following helpers
helpers
do
params
:optional_params_ee
do
end
end
prepend
EE
::
API
::
MergeRequests
params
:optional_params
do
# CE specific params go here...
use
:optional_params_ee
end
end
end
```
And then we could override it in EE module:
```
ruby
module
EE
module
API
module
MergeRequests
extend
ActiveSupport
::
Concern
prepended
do
helpers
do
params
:optional_params_ee
do
# EE specific params go here...
end
end
end
end
end
end
```
This way, the only difference in CE and EE for that API file, would be:
`prepend EE::API::MergeRequests`
and everything else should be the same.
#### EE helpers
To make it easy for EE module to override the CE helpers, we need to define
those helpers we want to extend first. Try to do that just after class
definition to make it easy and clear:
```
ruby
module
API
class
JobArtifacts
<
Grape
::
API
# EE::API::JobArtifacts would override the following helpers
helpers
do
def
authorize_download_artifacts!
authorize_read_builds!
end
end
prepend
EE
::
API
::
JobArtifacts
end
end
```
And then we could just follow regular object-oriented practice to override it:
```
ruby
module
EE
module
API
module
JobArtifacts
extend
ActiveSupport
::
Concern
prepended
do
helpers
do
def
authorize_download_artifacts!
super
check_cross_project_pipelines_feature!
end
end
end
end
end
end
```
#### EE specific behaviour
Sometimes we need EE specific behaviour in some of the APIs. Normally we could
use EE methods to override CE methods, however API routes are not methods
therefore we can't simply override them. We would need to extract them into a
standalone method, or just introduce some "hooks" where we could inject
behaviour in CE route. Something like:
```
ruby
module
API
class
MergeRequests
<
Grape
::
API
helpers
do
# EE::API::MergeRequests would override the following helpers
def
update_merge_request_ee
(
merge_request
)
end
end
prepend
EE
::
API
::
MergeRequests
put
':id/merge_requests/:merge_request_iid/merge'
do
merge_request
=
find_project_merge_request
(
params
[
:merge_request_iid
])
# ...
update_merge_request_ee
(
merge_request
)
# ...
end
end
end
```
See that above
`update_merge_request_ee`
doesn't do anything in CE, but
then we could override it in EE:
```
ruby
module
EE
module
API
module
MergeRequests
extend
ActiveSupport
::
Concern
prepended
do
helpers
do
def
update_merge_request_ee
(
merge_request
)
# ...
end
end
end
end
end
end
```
#### EE route_setting
It's very hard to extend this by the EE module, and this is simply storing
some meta-data for a particular route. Given that, we could simply leave the
EE
`route_setting`
in CE as it won't hurt and we are just not going to use
those meta-data in CE.
We could revisit this policy when we're using
`route_setting`
more and if
we might really need to extend it from EE. For now we're not using it so much.
#### Utilizing class methods for setting up EE specific data
Sometimes we need to use different arguments for a particular API route, and
we can't easily extend it with EE module because Grape has different context
in different blocks. In order to overcome this, we could just use class
methods from the API class.
For example, in one place we need to pass an extra argument to
`at_least_one_of`
so that the API could consider an EE only argument as the
least argument. This is not quite beautiful but it's working:
```
ruby
module
API
class
MergeRequests
<
Grape
::
API
def
self
.
update_params_at_least_one_of
%i[
assignee_id
description
]
end
prepend
EE
::
API
::
MergeRequests
params
do
at_least_one_of
(
*::
API
::
MergeRequests
.
update_params_at_least_one_of
)
end
end
end
```
And then we could easily extend that arguments in EE class method:
```
ruby
module
EE
module
API
module
MergeRequests
extend
ActiveSupport
::
Concern
class_methods
do
def
update_params_at_least_one_of
super
.
push
(
*
%i[
squash
]
)
end
end
end
end
end
```
It could be annoying if we need this for a lot of routes, but it might be the
simplest solution right now.
### Code in `spec/`
When you're testing EE-only features, avoid adding examples to the
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment