diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/api/README.md | 1 | ||||
-rw-r--r-- | doc/api/groups.md | 32 | ||||
-rw-r--r-- | doc/api/pages_domains.md | 170 | ||||
-rw-r--r-- | doc/api/services.md | 4 | ||||
-rw-r--r-- | doc/development/ee_features.md | 382 | ||||
-rw-r--r-- | doc/integration/saml.md | 11 | ||||
-rw-r--r-- | doc/user/project/merge_requests/index.md | 1 |
7 files changed, 594 insertions, 7 deletions
diff --git a/doc/api/README.md b/doc/api/README.md index 8f2a14e825e..89ffe9d7868 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -37,6 +37,7 @@ following locations: - [Notes](notes.md) (comments) - [Notification settings](notification_settings.md) - [Open source license templates](templates/licenses.md) +- [Pages Domains](pages_domains.md) - [Pipelines](pipelines.md) - [Pipeline Triggers](pipeline_triggers.md) - [Pipeline Schedules](pipeline_schedules.md) diff --git a/doc/api/groups.md b/doc/api/groups.md index c2daa8bc029..99d200c9c93 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -40,6 +40,38 @@ GET /groups ] ``` +When adding the parameter `statistics=true` and the authenticated user is an admin, additional group statistics are returned. + +``` +GET /groups?statistics=true +``` + +```json +[ + { + "id": 1, + "name": "Foobar Group", + "path": "foo-bar", + "description": "An interesting group", + "visibility": "public", + "lfs_enabled": true, + "avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg", + "web_url": "http://localhost:3000/groups/foo-bar", + "request_access_enabled": false, + "full_name": "Foobar Group", + "full_path": "foo-bar", + "parent_id": null, + "statistics": { + "storage_size" : 212, + "repository_size" : 33, + "lfs_objects_size" : 123, + "job_artifacts_size" : 57 + + } + } +] +``` + You can search for groups by name or path, see below. ## List a group's projects diff --git a/doc/api/pages_domains.md b/doc/api/pages_domains.md new file mode 100644 index 00000000000..51962595e33 --- /dev/null +++ b/doc/api/pages_domains.md @@ -0,0 +1,170 @@ +# Pages domains API + +Endpoints for connecting custom domain(s) and TLS certificates in [GitLab Pages](https://about.gitlab.com/features/pages/). + +The GitLab Pages feature must be enabled to use these endpoints. Find out more about [administering](../administration/pages/index.md) and [using](../user/project/pages/index.md) the feature. + +## List pages domains + +Get a list of project pages domains. The user must have permissions to view pages domains. + +```http +GET /projects/:id/pages/domains +``` + +| Attribute | Type | Required | Description | +| --------- | -------------- | -------- | ---------------------------------------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/pages/domains +``` + +```json +[ + { + "domain": "www.domain.example", + "url": "http://www.domain.example" + }, + { + "domain": "ssl.domain.example", + "url": "https://ssl.domain.example", + "certificate": { + "subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate", + "expired": false, + "certificate": "-----BEGIN CERTIFICATE-----\n … \n-----END CERTIFICATE-----", + "certificate_text": "Certificate:\n … \n" + } + } +] +``` + +## Single pages domain + +Get a single project pages domain. The user must have permissions to view pages domains. + +```http +GET /projects/:id/pages/domains/:domain +``` + +| Attribute | Type | Required | Description | +| --------- | -------------- | -------- | ---------------------------------------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `domain` | string | yes | The domain | + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/pages/domains/www.domain.example +``` + +```json +{ + "domain": "www.domain.example", + "url": "http://www.domain.example" +} +``` + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example +``` + +```json +{ + "domain": "ssl.domain.example", + "url": "https://ssl.domain.example", + "certificate": { + "subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate", + "expired": false, + "certificate": "-----BEGIN CERTIFICATE-----\n … \n-----END CERTIFICATE-----", + "certificate_text": "Certificate:\n … \n" + } +} +``` + +## Create new pages domain + +Creates a new pages domain. The user must have permissions to create new pages domains. + +```http +POST /projects/:id/pages/domains +``` + +| Attribute | Type | Required | Description | +| ------------- | -------------- | -------- | ---------------------------------------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `domain` | string | yes | The domain | +| `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.| +| `key` | file/string | no | The certificate key in PEM format. | + +```bash +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form="domain=ssl.domain.example" --form="certificate=@/path/to/cert.pem" --form="key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains +``` + +```bash +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form="domain=ssl.domain.example" --form="certificate=$CERT_PEM" --form="key=$KEY_PEM" https://gitlab.example.com/api/v4/projects/5/pages/domains +``` + +```json +{ + "domain": "ssl.domain.example", + "url": "https://ssl.domain.example", + "certificate": { + "subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate", + "expired": false, + "certificate": "-----BEGIN CERTIFICATE-----\n … \n-----END CERTIFICATE-----", + "certificate_text": "Certificate:\n … \n" + } +} +``` + +## Update pages domain + +Updates an existing project pages domain. The user must have permissions to change an existing pages domains. + +```http +PUT /projects/:id/pages/domains/:domain +``` + +| Attribute | Type | Required | Description | +| ------------- | -------------- | -------- | ---------------------------------------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `domain` | string | yes | The domain | +| `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.| +| `key` | file/string | no | The certificate key in PEM format. | + +```bash +curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form="certificate=@/path/to/cert.pem" --form="key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example +``` + +```bash +curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form="certificate=$CERT_PEM" --form="key=$KEY_PEM" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example +``` + +```json +{ + "domain": "ssl.domain.example", + "url": "https://ssl.domain.example", + "certificate": { + "subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate", + "expired": false, + "certificate": "-----BEGIN CERTIFICATE-----\n … \n-----END CERTIFICATE-----", + "certificate_text": "Certificate:\n … \n" + } +} +``` + +## Delete pages domain + +Deletes an existing project pages domain. + +```http +DELETE /projects/:id/pages/domains/:domain +``` + +| Attribute | Type | Required | Description | +| --------- | -------------- | -------- | ---------------------------------------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `domain` | string | yes | The domain | + +```bash +curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example +``` diff --git a/doc/api/services.md b/doc/api/services.md index 49b87a4228c..6c8f196fd5c 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -478,8 +478,8 @@ PUT /projects/:id/services/jira | --------- | ---- | -------- | ----------- | | `url` | string | yes | The URL to the JIRA project which is being linked to this GitLab project, e.g., `https://jira.example.com`. | | `project_key` | string | yes | The short identifier for your JIRA project, all uppercase, e.g., `PROJ`. | -| `username` | string | no | The username of the user created to be used with GitLab/JIRA. | -| `password` | string | no | The password of the user created to be used with GitLab/JIRA. | +| `username` | string | yes | The username of the user created to be used with GitLab/JIRA. | +| `password` | string | yes | The password of the user created to be used with GitLab/JIRA. | | `jira_issue_transition_id` | integer | no | The ID of a transition that moves issues to a closed state. You can find this number under the JIRA workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot][trans]). By default, this ID is set to `2`. | ### Delete JIRA service diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md new file mode 100644 index 00000000000..932a44f65e4 --- /dev/null +++ b/doc/development/ee_features.md @@ -0,0 +1,382 @@ +# Guidelines for implementing Enterprise Edition feature + +- **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 codes should be put inside the `ee/` top-level directory, and +tests should be put inside `spec/ee/`. We don't use `ee/spec` for now due to +technical limitation. The rest of codes should be as close as to the CE files. + +[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 +less likely to happen during CE to EE merges because only one line is +added to the CE class - the `prepend` line. + +Since the module would require an `EE` namespace, the file should also be +put in an `ee/` sub-directory. For example, we want to extend the user model +in EE, so we have a module called `::EE::User` put inside +`ee/app/models/ee/user.rb`. + +This is also not just applied to models. Here's a list of other examples: + +- `ee/app/controllers/ee/foos_controller.rb` +- `ee/app/finders/ee/foos_finder.rb` +- `ee/app/helpers/ee/foos_helper.rb` +- `ee/app/mailers/ee/foos_mailer.rb` +- `ee/app/models/ee/foo.rb` +- `ee/app/policies/ee/foo_policy.rb` +- `ee/app/serializers/ee/foo_entity.rb` +- `ee/app/serializers/ee/foo_serializer.rb` +- `ee/app/services/ee/foo/create_service.rb` +- `ee/app/validators/ee/foo_attr_validator.rb` +- `ee/app/workers/ee/foo_worker.rb` + +#### Overriding CE methods + +To override a method present in the CE codebase, use `prepend`. It +lets you override a method in a class with a method from a module, while +still having access the class's implementation with `super`. + +There are a few gotchas with it: + +- you should always add a `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. +- when the "overrider" would add a line in the middle of the CE + implementation, you should refactor the CE method and split it in + smaller methods. Or create a "hook" method that is empty in CE, + and with the EE-specific implementation in EE. +- when the original implementation contains a guard clause (e.g. + `return unless condition`), we cannot easily extend the behaviour by + overriding the method, because we can't know when the overridden method + (i.e. calling `super` in the overriding method) would want to stop early. + In this case, we shouldn't just override it, but update the original method + to make it call the other method we want to extend, like a [template method + pattern](https://en.wikipedia.org/wiki/Template_method_pattern). + For example, given this base: + ``` ruby + class Base + def execute + return unless enabled? + + # ... + # ... + end + end + ``` + Instead of just overriding `Base#execute`, we should update it and extract + the behaviour into another method: + ``` ruby + class Base + def execute + return unless enabled? + + do_something + end + + private + + def do_something + # ... + # ... + end + end + ``` + Then we're free to override that `do_something` without worrying about the + guards: + ``` ruby + module EE::Base + def do_something + # Follow the above pattern to call super and extend it + end + end + ``` + This would require updating CE first, or make sure this is back ported to CE. + +When prepending, place them in the `ee/` specific sub-directory, and +wrap class or module in `module EE` to avoid naming conflicts. + +For example to override the CE implementation of +`ApplicationController#after_sign_out_path_for`: + +```ruby +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 add `prepend` to +the existing file: + +```ruby +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 +``` + +And create a new file in the `ee/` sub-directory with the altered +implementation: + +```ruby +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 +``` + +#### Use self-descriptive wrapper methods + +When it's not possible/logical to modify the implementation of a +method. Wrap it in a self-descriptive method and use that method. + +For example, in CE only an `admin` is allowed to access all private +projects/groups, but in EE also an `auditor` has full private +access. It would be incorrect to override the implementation of +`User#admin?`, so instead add a method `full_private_access?` to +`app/models/users.rb`. The implementation in CE will be: + +```ruby +def full_private_access? + admin? +end +``` + +In EE, the implementation `ee/app/models/ee/users.rb` would be: + +```ruby +def full_private_access? + raise NotImplementedError unless defined?(super) + super || auditor? +end +``` + +In `lib/gitlab/visibility_level.rb` this method is used to return the +allowed visibilty levels: + +```ruby +def levels_for_user(user = nil) + if user.full_private_access? + [PRIVATE, INTERNAL, PUBLIC] + elsif # ... +end +``` + +See [CE MR][ce-mr-full-private] and [EE MR][ee-mr-full-private] for +full implementation details. + +[ce-mr-full-private]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12373 +[ee-mr-full-private]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2199 + +### Code in `app/controllers/` + +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 `params.require` / `params.permit` calls. + +**Mitigations** + +Separate CE and EE actions/keywords. For instance for `params.require` in +`ProjectsController`: + +```ruby +def project_params + params.require(:project).permit(project_params_attributes) +end + +# Always returns an array of symbols, created however best fits the use case. +# It _should_ be sorted alphabetically. +def project_params_attributes + %i[ + description + name + path + ] +end + +``` + +In the `EE::ProjectsController` module: + +```ruby +def project_params_attributes + super + project_params_attributes_ee +end + +def project_params_attributes_ee + %i[ + approvals_before_merge + approver_group_ids + approver_ids + ... + ] +end +``` + +### Code in `app/models/` + +EE-specific models should `extend EE::Model`. + +For example, if EE has a specific `Tanuki` model, you would +place it in `ee/app/models/ee/tanuki.rb`. + +### Code in `app/views/` + +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. + +**Mitigations** + +Blocks of code that are EE-specific should be moved to partials. This +avoids conflicts with big chunks of HAML code that that are not fun to +resolve when you add the indentation to the equation. + +EE-specific views should be placed in `ee/app/views/ee/`, using extra +sub-directories if appropriate. + +### Code in `lib/` + +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 `ee/lib/ee/gitlab/ldap`. + +### Code in `spec/` + +When you're testing EE-only features, avoid adding examples to the +existing CE specs. Also do no change existing CE examples, since they +should remain working as-is when EE is running without a license. + +Instead place EE specs in the `spec/ee/spec` folder. + +## JavaScript code in `assets/javascripts/` + +To separate EE-specific JS-files we can also move the files into an `ee` folder. + +For example there can be an +`app/assets/javascripts/protected_branches/protected_branches_bundle.js` and an +EE counterpart +`ee/app/assets/javascripts/protected_branches/protected_branches_bundle.js`. + +That way we can create a separate webpack bundle in `webpack.config.js`: + +```javascript + protected_branches: '~/protected_branches', + ee_protected_branches: 'ee/protected_branches/protected_branches_bundle.js', +``` + +With the separate bundle in place, we can decide which bundle to load inside the +view, using the `page_specific_javascript_bundle_tag` helper. + +```haml +- content_for :page_specific_javascripts do + = page_specific_javascript_bundle_tag('protected_branches') +``` + +## SCSS code in `assets/stylesheets` + +To separate EE-specific styles in SCSS files, if a component you're adding styles for +is limited to only EE, it is better to have a separate SCSS file in appropriate directory +within `app/assets/stylesheets`. + +In some cases, this is not entirely possible or creating dedicated SCSS file is an overkill, +e.g. a text style of some component is different for EE. In such cases, +styles are usually kept in stylesheet that is common for both CE and EE, and it is wise +to isolate such ruleset from rest of CE rules (along with adding comment describing the same) +to avoid conflicts during CE to EE merge. + +#### Bad +```scss +.section-body { + .section-title { + background: $gl-header-color; + } + + &.ee-section-body { + .section-title { + background: $gl-header-color-cyan; + } + } +} +``` + +#### Good +```scss +.section-body { + .section-title { + background: $gl-header-color; + } +} + +/* EE-specific styles */ +.section-body.ee-section-body { + .section-title { + background: $gl-header-color-cyan; + } +} +``` diff --git a/doc/integration/saml.md b/doc/integration/saml.md index b5b245c626f..3ae98adc465 100644 --- a/doc/integration/saml.md +++ b/doc/integration/saml.md @@ -132,14 +132,17 @@ On the sign in page there should now be a SAML button below the regular sign in Click the icon to begin the authentication process. If everything goes well the user will be returned to GitLab and will be signed in. -## External Groups +## Marking Users as External based on SAML Groups >**Note:** This setting is only available on GitLab 8.7 and above. -SAML login includes support for external groups. You can define in the SAML -settings which groups, to which your users belong in your IdP, you wish to be -marked as [external](../user/permissions.md). +SAML login includes support for automatically identifying whether a user should +be considered an [external](../user/permissions.md) user based on the user's group +membership in the SAML identity provider. This feature **does not** allow you to +automatically add users to GitLab [Groups](../user/group/index.md), it simply +allows you to mark users as External if they are members of certain groups in the +Identity Provider. ### Requirements diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 6289fcf3c2b..4b2e042251b 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -34,7 +34,6 @@ With **[GitLab Enterprise Edition][ee]**, you can also: - View the deployment process across projects with [Multi-Project Pipeline Graphs](https://docs.gitlab.com/ee/ci/multi_project_pipeline_graphs.html#multi-project-pipeline-graphs) (available only in GitLab Enterprise Edition Premium) - Request [approvals](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html) from your managers (available in GitLab Enterprise Edition Starter) - [Squash and merge](https://docs.gitlab.com/ee/user/project/merge_requests/squash_and_merge.html) for a cleaner commit history (available in GitLab Enterprise Edition Starter) -- Enable [semi-linear history merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/index.html#semi-linear-history-merge-requests) as another security layer to guarantee the pipeline is passing in the target branch (available in GitLab Enterprise Edition Starter) - Analise the impact of your changes with [Code Quality reports](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality_diff.html) (available in GitLab Enterprise Edition Starter) ## Use cases |