Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4a69e105ab
commit
9450a63064
|
|
@ -97,7 +97,7 @@ export default {
|
|||
|
||||
<div
|
||||
v-else-if="podStats && !error"
|
||||
class="gl-display-flex gl-flex-wrap-wrap gl-sm-flex-nowrap gl-mx-n3 gl-mt-n3"
|
||||
class="gl-display-flex gl-flex-wrap gl-sm-flex-nowrap gl-mx-n3 gl-mt-n3"
|
||||
>
|
||||
<gl-single-stat
|
||||
v-for="(stat, index) in podStats"
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ export default {
|
|||
<!-- If there is no room beside the path, meta attributes are put ABOVE it (flex-wrap-reverse). -->
|
||||
<!-- See design: https://gitlab-org.gitlab.io/gitlab-design/hosted/pedro/%2383-issue-mr-rows-cards-spec-previews/#artboard16 -->
|
||||
<div
|
||||
class="item-meta gl-display-flex gl-md-justify-content-space-between gl-gap-3 gl-flex-wrap-wrap-reverse"
|
||||
class="item-meta gl-display-flex gl-md-justify-content-space-between gl-gap-3 gl-flex-wrap-reverse"
|
||||
>
|
||||
<!-- Path area: status icon (<XL), path, issue # -->
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export default {
|
|||
<template>
|
||||
<gl-tab :title="$options.i18n.title">
|
||||
<activity-calendar />
|
||||
<div class="gl-mx-n3 gl-display-flex gl-flex-wrap-wrap">
|
||||
<div class="gl-mx-n3 gl-display-flex gl-flex-wrap">
|
||||
<div class="gl-px-3 gl-w-full gl-lg-w-half"></div>
|
||||
<div class="gl-px-3 gl-w-full gl-lg-w-half" data-testid="personal-projects-section">
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -99,6 +99,6 @@ export default {
|
|||
{{ $options.i18n.emptyHint }}
|
||||
</div>
|
||||
</gl-collapse>
|
||||
<hr class="gl-my-2 gl-mx-4" />
|
||||
<hr aria-hidden="true" class="gl-my-2 gl-mx-4" />
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ export default {
|
|||
<ul class="gl-p-0 gl-m-0">
|
||||
<nav-item v-for="item in staticItems" :key="item.id" :item="item" is-static />
|
||||
</ul>
|
||||
<hr class="gl-my-2 gl-mx-4" />
|
||||
<hr aria-hidden="true" class="gl-my-2 gl-mx-4" />
|
||||
</section>
|
||||
|
||||
<pinned-section
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import { createAlert } from '~/alert';
|
|||
import { STATUS_CLOSED, STATUS_MERGED } from '~/issues/constants';
|
||||
import notify from '~/lib/utils/notify';
|
||||
import { sprintf, s__, __ } from '~/locale';
|
||||
import Project from '~/pages/projects/project';
|
||||
import SmartInterval from '~/smart_interval';
|
||||
import { TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constants';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
|
|
@ -479,7 +478,6 @@ export default {
|
|||
el.innerHTML = res.data;
|
||||
document.body.appendChild(el);
|
||||
document.dispatchEvent(new CustomEvent('merged:UpdateActions'));
|
||||
Project.initRefSwitcher();
|
||||
}
|
||||
})
|
||||
.catch(() =>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ module Clusters
|
|||
has_many :ci_access_project_authorizations, class_name: 'Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization'
|
||||
has_many :ci_access_authorized_projects, class_name: '::Project', through: :ci_access_project_authorizations, source: :project
|
||||
|
||||
has_many :user_access_group_authorizations, class_name: 'Clusters::Agents::Authorizations::UserAccess::GroupAuthorization'
|
||||
has_many :user_access_authorized_groups, class_name: '::Group', through: :user_access_group_authorizations, source: :group
|
||||
|
||||
has_many :user_access_project_authorizations, class_name: 'Clusters::Agents::Authorizations::UserAccess::ProjectAuthorization'
|
||||
has_many :user_access_authorized_projects, class_name: '::Project', through: :user_access_project_authorizations, source: :project
|
||||
|
||||
has_many :activity_events, -> { in_timeline_order }, class_name: 'Clusters::Agents::ActivityEvent', inverse_of: :agent
|
||||
|
||||
scope :ordered_by_name, -> { order(:name) }
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@ module Clusters
|
|||
def config_project
|
||||
agent.project
|
||||
end
|
||||
|
||||
class << self
|
||||
def upsert_configs(configs)
|
||||
upsert_all(configs, unique_by: [:agent_id, :group_id])
|
||||
end
|
||||
|
||||
def delete_unlisted(group_ids)
|
||||
where.not(group_id: group_ids).delete_all
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@ module Clusters
|
|||
def config_project
|
||||
agent.project
|
||||
end
|
||||
|
||||
class << self
|
||||
def upsert_configs(configs)
|
||||
upsert_all(configs, unique_by: [:agent_id, :project_id])
|
||||
end
|
||||
|
||||
def delete_unlisted(project_ids)
|
||||
where.not(project_id: project_ids).delete_all
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Clusters
|
||||
module Agents
|
||||
module Authorizations
|
||||
module UserAccess
|
||||
class RefreshService
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
AUTHORIZED_ENTITY_LIMIT = 100
|
||||
|
||||
delegate :project, to: :agent, private: true
|
||||
delegate :root_ancestor, to: :project, private: true
|
||||
|
||||
def initialize(agent, config:)
|
||||
@agent = agent
|
||||
@config = config
|
||||
end
|
||||
|
||||
def execute
|
||||
refresh_projects!
|
||||
refresh_groups!
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :agent, :config
|
||||
|
||||
def refresh_projects!
|
||||
if allowed_project_configurations.present?
|
||||
project_ids = allowed_project_configurations.map { |config| config.fetch(:project_id) }
|
||||
|
||||
agent.with_lock do
|
||||
agent.user_access_project_authorizations.upsert_configs(allowed_project_configurations)
|
||||
agent.user_access_project_authorizations.delete_unlisted(project_ids)
|
||||
end
|
||||
else
|
||||
agent.user_access_project_authorizations.delete_all(:delete_all)
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_groups!
|
||||
if allowed_group_configurations.present?
|
||||
group_ids = allowed_group_configurations.map { |config| config.fetch(:group_id) }
|
||||
|
||||
agent.with_lock do
|
||||
agent.user_access_group_authorizations.upsert_configs(allowed_group_configurations)
|
||||
agent.user_access_group_authorizations.delete_unlisted(group_ids)
|
||||
end
|
||||
else
|
||||
agent.user_access_group_authorizations.delete_all(:delete_all)
|
||||
end
|
||||
end
|
||||
|
||||
def allowed_project_configurations
|
||||
project_entries = extract_config_entries(entity: 'projects')
|
||||
|
||||
return unless project_entries
|
||||
|
||||
allowed_projects.where_full_path_in(project_entries.keys).map do |project|
|
||||
{ project_id: project.id, config: user_access_as }
|
||||
end
|
||||
end
|
||||
strong_memoize_attr :allowed_project_configurations
|
||||
|
||||
def allowed_group_configurations
|
||||
group_entries = extract_config_entries(entity: 'groups')
|
||||
|
||||
return unless group_entries
|
||||
|
||||
allowed_groups.where_full_path_in(group_entries.keys).map do |group|
|
||||
{ group_id: group.id, config: user_access_as }
|
||||
end
|
||||
end
|
||||
strong_memoize_attr :allowed_group_configurations
|
||||
|
||||
def extract_config_entries(entity:)
|
||||
config.dig('user_access', entity)
|
||||
&.first(AUTHORIZED_ENTITY_LIMIT)
|
||||
&.index_by { |config| config.delete('id').downcase }
|
||||
end
|
||||
|
||||
def allowed_projects
|
||||
root_ancestor.all_projects
|
||||
end
|
||||
|
||||
def allowed_groups
|
||||
if group_root_ancestor?
|
||||
root_ancestor.self_and_descendants
|
||||
else
|
||||
::Group.none
|
||||
end
|
||||
end
|
||||
|
||||
def group_root_ancestor?
|
||||
root_ancestor.group_namespace?
|
||||
end
|
||||
|
||||
def user_access_as
|
||||
@user_access_as ||= config['user_access']&.slice('access_as') || {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -113,15 +113,19 @@ To make sure your configuration is correct:
|
|||
redis.info
|
||||
```
|
||||
|
||||
Keep this screen open and try to simulate a failover below.
|
||||
Keep this screen open, and proceed to trigger a failover as described below.
|
||||
|
||||
1. To simulate a failover on primary Redis, SSH into the Redis server and run:
|
||||
1. To trigger a failover on the primary Redis, SSH into the Redis server and run:
|
||||
|
||||
```shell
|
||||
# port must match your primary redis port, and the sleep time must be a few seconds bigger than defined one
|
||||
redis-cli -h localhost -p 6379 DEBUG sleep 20
|
||||
```
|
||||
|
||||
WARNING:
|
||||
This action affects services, and takes the instance down for up to 20 seconds. If successful,
|
||||
it should recover after that.
|
||||
|
||||
1. Then back in the Rails console from the first step, run:
|
||||
|
||||
```ruby
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ group: Import
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Group migration by direct transfer API **(FREE)**
|
||||
# Group and project migration by direct transfer API **(FREE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64335) in GitLab 14.1.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64335) in GitLab 14.1.
|
||||
> - Project migration [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/390515) in GitLab 15.11.
|
||||
|
||||
With the group migration by direct transfer API, you can start and view the progress of migrations initiated with
|
||||
[group migration by direct transfer](../user/group/import/index.md#migrate-groups-by-direct-transfer-recommended).
|
||||
|
|
@ -16,11 +17,16 @@ With the group migration by direct transfer API, you can start and view the prog
|
|||
For information on prerequisites for group migration by direct transfer API, see
|
||||
prerequisites for [migrating groups by direct transfer](../user/group/import/index.md#prerequisites).
|
||||
|
||||
## Start a new group migration
|
||||
## Start a new group or project migration
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66353) in GitLab 14.2.
|
||||
> - `project_entity` source type [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/390515) in GitLab 15.11.
|
||||
|
||||
Use this endpoint to start a new group or project migration. Specify:
|
||||
|
||||
- `entities[group_entity]` to migrate a group.
|
||||
- `entities[project_entity]` to migrate a project.
|
||||
|
||||
```plaintext
|
||||
POST /bulk_imports
|
||||
```
|
||||
|
|
@ -60,7 +66,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
|
|||
{ "id": 1, "status": "created", "source_type": "gitlab", "created_at": "2021-06-18T09:45:55.358Z", "updated_at": "2021-06-18T09:46:27.003Z" }
|
||||
```
|
||||
|
||||
## List all group migrations
|
||||
## List all group or project migrations
|
||||
|
||||
```plaintext
|
||||
GET /bulk_imports
|
||||
|
|
@ -103,7 +109,7 @@ curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
|
|||
]
|
||||
```
|
||||
|
||||
## List all group migrations' entities
|
||||
## List all group or project migrations' entities
|
||||
|
||||
```plaintext
|
||||
GET /bulk_imports/entities
|
||||
|
|
@ -171,7 +177,7 @@ curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
|
|||
]
|
||||
```
|
||||
|
||||
## Get group migration details
|
||||
## Get group or project migration details
|
||||
|
||||
```plaintext
|
||||
GET /bulk_imports/:id
|
||||
|
|
@ -191,7 +197,7 @@ curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
|
|||
}
|
||||
```
|
||||
|
||||
## List group migration entities
|
||||
## List group or project migration entities
|
||||
|
||||
```plaintext
|
||||
GET /bulk_imports/:id/entities
|
||||
|
|
@ -227,7 +233,7 @@ curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
|
|||
]
|
||||
```
|
||||
|
||||
## Get group migration entity details
|
||||
## Get group or project migration entity details
|
||||
|
||||
```plaintext
|
||||
GET /bulk_imports/:id/entities/:entity_id
|
||||
|
|
|
|||
|
|
@ -17,5 +17,5 @@ When implementing new features, please refer to these existing features to avoid
|
|||
- [Route Maps](../ci/review_apps/index.md#route-maps): `.gitlab/route-map.yml`.
|
||||
- [Customize Auto DevOps Helm Values](../topics/autodevops/customize.md#customize-helm-chart-values): `.gitlab/auto-deploy-values.yaml`.
|
||||
- [Insights](../user/project/insights/index.md#configure-project-insights): `.gitlab/insights.yml`.
|
||||
- [Service Desk Templates](../user/project/service_desk.md#using-customized-email-templates): `.gitlab/service_desk_templates/`.
|
||||
- [Service Desk Templates](../user/project/service_desk.md#create-customized-email-templates): `.gitlab/service_desk_templates/`.
|
||||
- [Web IDE](../user/project/web_ide/index.md#web-ide-configuration-file): `.gitlab/.gitlab-webide.yml`.
|
||||
|
|
|
|||
|
|
@ -472,6 +472,10 @@ You can use `if: Gitlab.ee?` or `unless: Gitlab.ee?` on context/spec blocks to e
|
|||
|
||||
Example: [SchemaValidator reads a different path depending on the license](https://gitlab.com/gitlab-org/gitlab/-/blob/7cdcf9819cfa02c701d6fa9f18c1e7a8972884ed/spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb#L571)
|
||||
|
||||
### Tests depending on SaaS
|
||||
|
||||
You can use the `:saas` RSpec metadata tag helper on context/spec blocks to test code that only runs on GitLab.com. This helper sets `Gitlab.config.gitlab['url']` to `Gitlab::Saas.com_url`.
|
||||
|
||||
### Coverage
|
||||
|
||||
[`simplecov`](https://github.com/colszowka/simplecov) is used to generate code test coverage reports.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@ This integration method supports [Smart Commits](dvcs/index.md#smart-commits).
|
|||
For an overview, see
|
||||
[Configure the GitLab for Jira Cloud app from the Atlassian Marketplace](https://youtu.be/SwR-g1s1zTo).
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have at least the Maintainer role for the GitLab namespace.
|
||||
- You must have administrator access to the Jira instance.
|
||||
|
||||
To install the GitLab for Jira Cloud app:
|
||||
|
||||
1. In Jira, go to **Jira Settings > Apps > Find new apps**, then search for GitLab.
|
||||
|
|
@ -47,8 +52,6 @@ To install the GitLab for Jira Cloud app:
|
|||
1. To open the list of available namespaces, select **Add namespace**.
|
||||
|
||||
1. Identify the namespace you want to link, and select **Link**.
|
||||
- You must have at least the Maintainer role for the namespace.
|
||||
- Only Jira site administrators can add or remove namespaces for an installation.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ entities.where(status: [-1]).pluck(:destination_name, :destination_namespace, :s
|
|||
```
|
||||
|
||||
You can also see all migrated entities with any failures related to them using an
|
||||
[API endpoint](../../../api/bulk_imports.md#list-all-group-migrations-entities).
|
||||
[API endpoint](../../../api/bulk_imports.md#list-all-group-or-project-migrations-entities).
|
||||
|
||||
#### Stale imports
|
||||
|
||||
|
|
|
|||
|
|
@ -477,6 +477,10 @@ You can export a list of members in a group or subgroup as a CSV.
|
|||
1. Select **Export as CSV**.
|
||||
1. After the CSV file has been generated, it is emailed as an attachment to the user that requested it.
|
||||
|
||||
The output lists direct members and members inherited from the ancestor groups.
|
||||
For members with `Minimal Access` in the selected group, their `Max Role` and `Source` are derived from their membership in subgroups.
|
||||
[Issue 390358](https://gitlab.com/gitlab-org/gitlab/-/issues/390358) tracks the discussion about the group members CSV export list not matching the UI members list.
|
||||
|
||||
## User cap for groups
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/330027) in GitLab 14.7.
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ You might want to use these templates:
|
|||
|
||||
- For different stages of your workflow, for example, feature proposal, feature improvement, or a bug report.
|
||||
- For every issue or merge request for a specific project, so the layout is consistent.
|
||||
- For a [Service Desk email template](service_desk.md#new-service-desk-issues).
|
||||
- For a [Service Desk email template](service_desk.md#use-a-custom-template-for-service-desk-issues).
|
||||
|
||||
For description templates to work, they must be:
|
||||
|
||||
|
|
|
|||
|
|
@ -41,44 +41,45 @@ Meanwhile:
|
|||
- Your team saves time by not having to leave GitLab (or set up integrations) to follow up with
|
||||
your customer.
|
||||
|
||||
## Configuring Service Desk
|
||||
## Configure Service Desk
|
||||
|
||||
Users with Maintainer and higher access in a project can configure Service Desk.
|
||||
To start using Service Desk for a project, you must first turn it on.
|
||||
By default, Service Desk is turned off.
|
||||
|
||||
Service Desk issues are [confidential](issues/confidential_issues.md), so they are
|
||||
only visible to project members.
|
||||
Prerequisites:
|
||||
|
||||
If you have [templates](description_templates.md) in your repository, you can optionally select
|
||||
one from the selector menu to append it to all Service Desk issues.
|
||||
- You must have at least the Maintainer role for the project.
|
||||
- On GitLab self-managed, you must [set up incoming email](../../administration/incoming_email.md#set-it-up)
|
||||
for the GitLab instance. You should use
|
||||
[email sub-addressing](../../administration/incoming_email.md#email-sub-addressing),
|
||||
but you can also use [catch-all mailboxes](../../administration/incoming_email.md#catch-all-mailbox).
|
||||
To do this, you must have administrator access.
|
||||
|
||||
To enable Service Desk in your project:
|
||||
|
||||
1. (GitLab self-managed only) [Set up incoming email](../../administration/incoming_email.md#set-it-up) for the GitLab instance.
|
||||
You should use [email sub-addressing](../../administration/incoming_email.md#email-sub-addressing),
|
||||
but you can also use [catch-all mailboxes](../../administration/incoming_email.md#catch-all-mailbox).
|
||||
1. In a project, in the left sidebar, go to **Settings > General** and expand the **Service Desk** section.
|
||||
1. Enable the **Activate Service Desk** toggle. This reveals a unique email address to email issues
|
||||
to the project.
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Expand **Service Desk**.
|
||||
1. Turn on the **Activate Service Desk** toggle.
|
||||
1. Optional. Complete the fields.
|
||||
- [Add a suffix](#configuring-a-custom-email-address-suffix) to your Service Desk email address.
|
||||
- If the list below **Template to append to all Service Desk issues** is empty, create a
|
||||
[description template](description_templates.md) in your repository.
|
||||
1. Select **Save changes**.
|
||||
|
||||
Service Desk is now enabled for this project! To access it in a project, in the left sidebar, select
|
||||
**Issues > Service Desk**.
|
||||
Service Desk is now enabled for this project.
|
||||
If anyone sends an email to the address available below **Email address to use for Support Desk**,
|
||||
GitLab creates a confidential issue with the email's content.
|
||||
|
||||
WARNING:
|
||||
Anyone in your project can use the Service Desk email address to create an issue in this project, **regardless
|
||||
of their access level** to your GitLab instance.
|
||||
### Improve your project's security
|
||||
|
||||
To improve your project's security, you should:
|
||||
To improve your Service Desk project's security, you should:
|
||||
|
||||
- Put the Service Desk email address behind an alias on your email system so you can change it later.
|
||||
- [Enable Akismet](../../integration/akismet.md) on your GitLab instance to add spam checking to this service.
|
||||
Unblocked email spam can result in many spam issues being created.
|
||||
|
||||
The unique internal email address is visible to project members at least
|
||||
the Reporter role in your GitLab instance.
|
||||
An external user (issue creator) cannot see the internal email address
|
||||
displayed in the information note.
|
||||
|
||||
### Using customized email templates
|
||||
### Create customized email templates
|
||||
|
||||
> - Moved from GitLab Premium to GitLab Free in 13.2.
|
||||
> - `UNSUBSCRIBE_URL`, `SYSTEM_HEADER`, `SYSTEM_FOOTER`, and `ADDITIONAL_TEXT` placeholders [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/285512) in GitLab 15.9.
|
||||
|
|
@ -89,14 +90,6 @@ An email is sent to the author when:
|
|||
- A new note is created on a Service Desk issue.
|
||||
|
||||
You can customize the body of these email messages with templates.
|
||||
Save your templates in the `.gitlab/service_desk_templates/`
|
||||
directory in your repository.
|
||||
|
||||
With Service Desk, you can use templates for:
|
||||
|
||||
- [Thank you emails](#thank-you-email)
|
||||
- [New note emails](#new-note-email)
|
||||
- [New Service Desk issues](#new-service-desk-issues)
|
||||
|
||||
#### Email header and footer **(FREE SELF)**
|
||||
|
||||
|
|
@ -109,7 +102,9 @@ visible in the email template. For more information, see
|
|||
#### Thank you email
|
||||
|
||||
When a user submits an issue through Service Desk, GitLab sends a **thank you email**.
|
||||
You must name the template file `thank_you.md`.
|
||||
|
||||
To create a custom email template, in the `.gitlab/service_desk_templates/`
|
||||
directory in your repository, create a file named `thank_you.md`.
|
||||
|
||||
You can use these placeholders to be automatically replaced in each email:
|
||||
|
||||
|
|
@ -126,7 +121,9 @@ the response email does not contain the issue link.
|
|||
#### New note email
|
||||
|
||||
When a user-submitted issue receives a new comment, GitLab sends a **new note email**.
|
||||
You must name the template file `new_note.md`.
|
||||
|
||||
To create a custom email template, in the `.gitlab/service_desk_templates/`
|
||||
directory in your repository, create a file named `new_note.md`.
|
||||
|
||||
You can use these placeholders to be automatically replaced in each email:
|
||||
|
||||
|
|
@ -138,7 +135,7 @@ You can use these placeholders to be automatically replaced in each email:
|
|||
- `%{SYSTEM_FOOTER}`: [system footer message](../admin_area/appearance.md#system-header-and-footer-messages)
|
||||
- `%{ADDITIONAL_TEXT}`: [custom additional text](../admin_area/settings/email.md#custom-additional-text)
|
||||
|
||||
#### New Service Desk issues
|
||||
### Use a custom template for Service Desk issues
|
||||
|
||||
You can select one [description template](description_templates.md#create-an-issue-template)
|
||||
**per project** to be appended to every new Service Desk issue's description.
|
||||
|
|
@ -151,24 +148,35 @@ You can set description templates at various levels:
|
|||
|
||||
The templates are inherited. For example, in a project, you can also access templates set for the instance, or the project's parent groups.
|
||||
|
||||
Prerequisite:
|
||||
|
||||
- You must have [created a description template](description_templates.md#create-an-issue-template).
|
||||
|
||||
To use a custom description template with Service Desk:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. [Create a description template](description_templates.md#create-an-issue-template).
|
||||
1. On the left sidebar, select **Settings > General > Service Desk**.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Expand **Service Desk**.
|
||||
1. From the dropdown list **Template to append to all Service Desk issues**, search or select your template.
|
||||
|
||||
### Using a custom email display name
|
||||
### Support Bot user
|
||||
|
||||
You can customize the email display name. Emails sent from Service Desk have
|
||||
Behind the scenes, Service Desk works by the special Support Bot user creating issues.
|
||||
This user isn't a [billable user](../../subscriptions/self_managed/index.md#billable-users),
|
||||
so it does not count toward the license limit count.
|
||||
|
||||
#### Change the Support Bot's display name
|
||||
|
||||
You can change the display name of the Support Bot user. Emails sent from Service Desk have
|
||||
this name in the `From` header. The default display name is `GitLab Support Bot`.
|
||||
|
||||
To edit the custom email display name:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > General > Service Desk**.
|
||||
1. Enter a new name in **Email display name**.
|
||||
1. Select **Save Changes**.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Expand **Service Desk**.
|
||||
1. Below **Email display name**, enter a new name.
|
||||
1. Select **Save changes**.
|
||||
|
||||
### Using a custom email address **(FREE SELF)**
|
||||
|
||||
|
|
@ -255,7 +263,7 @@ The configuration options are the same as for configuring
|
|||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108279) in GitLab 15.9.
|
||||
|
||||
Instead of having the Service Desk email credentials stored in plaintext in the configuration files, you can optionally
|
||||
use an encrypted file for the Incoming email credentials.
|
||||
use an encrypted file for the incoming email credentials.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
|
|
@ -439,7 +447,7 @@ The [incoming email](../../administration/incoming_email.md) address still works
|
|||
|
||||
If you don't configure the custom suffix, the default project identification is used for identifying the project. You can see that email address in the project settings.
|
||||
|
||||
## Using Service Desk
|
||||
## Use Service Desk
|
||||
|
||||
You can use Service Desk to [create an issue](#as-an-end-user-issue-creator) or [respond to one](#as-a-responder-to-the-issue).
|
||||
In these issues, you can also see our friendly neighborhood [Support Bot](#support-bot-user).
|
||||
|
|
@ -483,7 +491,32 @@ You can read and write comments as you usually do in GitLab:
|
|||
- The project's visibility (private, internal, public) does not affect Service Desk.
|
||||
- The path to the project, including its group or namespace, is shown in emails.
|
||||
|
||||
#### Receiving files attached to comments as email attachments
|
||||
#### View Service Desk issues
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have at least the Reporter role for the project.
|
||||
|
||||
To view Service Desk issues:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Issues > Service Desk**.
|
||||
|
||||
### Email contents and formatting
|
||||
|
||||
#### Special HTML formatting in HTML emails
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109811) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `service_desk_html_to_text_email_handler`. Disabled by default.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116809) in GitLab 15.11. Feature flag `service_desk_html_to_text_email_handler` removed.
|
||||
|
||||
HTML emails show HTML formatting, such as:
|
||||
|
||||
- Tables
|
||||
- Blockquotes
|
||||
- Images
|
||||
- Collapsible sections
|
||||
|
||||
#### Files attached to comments
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11733) in GitLab 15.8 [with a flag](../../administration/feature_flags.md) named `service_desk_new_note_email_native_attachments`. Disabled by default.
|
||||
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/386860) in GitLab 15.10.
|
||||
|
|
@ -497,23 +530,12 @@ attachments are sent as part of the email. In other cases, the email contains li
|
|||
|
||||
In GitLab 15.9 and earlier, uploads to a comment are sent as links in the email.
|
||||
|
||||
#### Special HTML formatting in HTML emails
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109811) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `service_desk_html_to_text_email_handler`. Disabled by default.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116809) in GitLab 15.11. Feature flag `service_desk_html_to_text_email_handler` removed.
|
||||
|
||||
HTML emails show special HTML formatting such as:
|
||||
|
||||
- Tables
|
||||
- Blockquotes
|
||||
- Images
|
||||
- Collapsible sections
|
||||
|
||||
#### Privacy considerations
|
||||
## Privacy considerations
|
||||
|
||||
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108901) the minimum required role to view the creator's and participant's email in GitLab 15.9.
|
||||
|
||||
Service Desk issues are confidential, but the project owner can
|
||||
Service Desk issues are [confidential](issues/confidential_issues.md), so they are
|
||||
only visible to project members. The project owner can
|
||||
[make an issue public](issues/confidential_issues.md#modify-issue-confidentiality).
|
||||
When a Service Desk issue becomes public, the issue creator's and participants' email addresses are
|
||||
visible to signed-in users with at least the Reporter role for the project.
|
||||
|
|
@ -521,17 +543,18 @@ visible to signed-in users with at least the Reporter role for the project.
|
|||
In GitLab 15.8 and earlier, when a Service Desk issue becomes public, the issue creator's email
|
||||
address is disclosed to everyone who can view the project.
|
||||
|
||||
### Support Bot user
|
||||
Anyone in your project can use the Service Desk email address to create an issue in this project, **regardless
|
||||
of their role** in the project.
|
||||
|
||||
Behind the scenes, Service Desk works by the special Support Bot user creating issues. This user
|
||||
does not count toward the license limit count.
|
||||
The unique internal email address is visible to project members at least
|
||||
the Reporter role in your GitLab instance.
|
||||
An external user (issue creator) cannot see the internal email address
|
||||
displayed in the information note.
|
||||
|
||||
### Moving a Service Desk issue
|
||||
|
||||
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/372246) in GitLab 15.7: customers continue receiving notifications when a Service Desk issue is moved.
|
||||
|
||||
Service Desk issues can be moved like any other issue in GitLab.
|
||||
|
||||
You can move a Service Desk issue the same way you
|
||||
[move a regular issue](issues/managing_issues.md#move-an-issue) in GitLab.
|
||||
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ module API
|
|||
agent = ::Clusters::Agent.find(params[:agent_id])
|
||||
|
||||
::Clusters::Agents::Authorizations::CiAccess::RefreshService.new(agent, config: params[:agent_config]).execute
|
||||
::Clusters::Agents::Authorizations::UserAccess::RefreshService.new(agent, config: params[:agent_config]).execute
|
||||
|
||||
no_content!
|
||||
end
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ module QA
|
|||
|
||||
# Used for stablility, due to feature_caching of vscode_web_ide
|
||||
def wait_until_ide_loads
|
||||
Support::Waiter.wait_until(sleep_interval: 2, max_duration: 60, reload_page: page,
|
||||
Support::Waiter.wait_until(sleep_interval: 2, max_duration: 120, reload_page: page,
|
||||
retry_on_exception: true) do
|
||||
has_element?(:commit_mode_tab)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -147,6 +147,14 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
|
|||
projects: [
|
||||
{ id: project.full_path, default_namespace: 'staging' }
|
||||
]
|
||||
},
|
||||
user_access: {
|
||||
groups: [
|
||||
{ id: group.full_path }
|
||||
],
|
||||
projects: [
|
||||
{ id: project.full_path }
|
||||
]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
@ -160,6 +168,8 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
|
|||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
expect(agent.ci_access_authorized_groups).to contain_exactly(group)
|
||||
expect(agent.ci_access_authorized_projects).to contain_exactly(project)
|
||||
expect(agent.user_access_authorized_groups).to contain_exactly(group)
|
||||
expect(agent.user_access_authorized_projects).to contain_exactly(project)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,181 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Clusters::Agents::Authorizations::UserAccess::RefreshService, feature_category: :kubernetes_management do
|
||||
describe '#execute' do
|
||||
let_it_be(:root_ancestor) { create(:group) }
|
||||
let_it_be(:agent_management_project) { create(:project, namespace: root_ancestor) }
|
||||
let_it_be(:group_1) { create(:group, path: 'group-path-with-UPPERCASE', parent: root_ancestor) }
|
||||
let_it_be(:group_2) { create(:group, parent: root_ancestor) }
|
||||
let_it_be(:project_1) { create(:project, path: 'project-path-with-UPPERCASE', namespace: root_ancestor) }
|
||||
let_it_be(:project_2) { create(:project, namespace: root_ancestor) }
|
||||
|
||||
let(:agent) { create(:cluster_agent, project: agent_management_project) }
|
||||
|
||||
let(:config) do
|
||||
{
|
||||
user_access: {
|
||||
groups: [
|
||||
{ id: group_2.full_path }
|
||||
],
|
||||
projects: [
|
||||
{ id: project_2.full_path }
|
||||
]
|
||||
}
|
||||
}.deep_merge(extra_config).deep_stringify_keys
|
||||
end
|
||||
|
||||
let(:extra_config) { {} }
|
||||
|
||||
subject { described_class.new(agent, config: config).execute }
|
||||
|
||||
before do
|
||||
agent.user_access_group_authorizations.create!(group: group_1, config: {})
|
||||
agent.user_access_project_authorizations.create!(project: project_1, config: {})
|
||||
end
|
||||
|
||||
shared_examples 'removing authorization' do
|
||||
context 'when config contains no groups or projects' do
|
||||
let(:config) { {} }
|
||||
|
||||
it 'removes all authorizations' do
|
||||
expect(subject).to be_truthy
|
||||
expect(authorizations).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when config contains groups or projects outside of the configuration project hierarchy' do
|
||||
let_it_be(:agent_management_project) { create(:project, namespace: create(:group)) }
|
||||
|
||||
it 'removes all authorizations' do
|
||||
expect(subject).to be_truthy
|
||||
expect(authorizations).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when configuration project does not belong to a group' do
|
||||
let_it_be(:agent_management_project) { create(:project) }
|
||||
|
||||
it 'removes all authorizations' do
|
||||
expect(subject).to be_truthy
|
||||
expect(authorizations).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'group authorization' do
|
||||
it 'refreshes authorizations for the agent' do
|
||||
expect(subject).to be_truthy
|
||||
expect(agent.user_access_authorized_groups).to contain_exactly(group_2)
|
||||
|
||||
added_authorization = agent.user_access_group_authorizations.find_by(group: group_2)
|
||||
expect(added_authorization.config).to eq({})
|
||||
end
|
||||
|
||||
context 'when config contains "access_as" keyword' do
|
||||
let(:extra_config) do
|
||||
{
|
||||
user_access: {
|
||||
access_as: {
|
||||
agent: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'refreshes authorizations for the agent' do
|
||||
expect(subject).to be_truthy
|
||||
expect(agent.user_access_authorized_groups).to contain_exactly(group_2)
|
||||
|
||||
added_authorization = agent.user_access_group_authorizations.find_by(group: group_2)
|
||||
expect(added_authorization.config).to eq({ 'access_as' => { 'agent' => {} } })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when config contains too many groups' do
|
||||
before do
|
||||
stub_const("#{described_class}::AUTHORIZED_ENTITY_LIMIT", 0)
|
||||
end
|
||||
|
||||
it 'authorizes groups up to the limit' do
|
||||
expect(subject).to be_truthy
|
||||
expect(agent.user_access_authorized_groups).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'removing authorization' do
|
||||
let(:authorizations) { agent.user_access_authorized_groups }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'project authorization' do
|
||||
it 'refreshes authorizations for the agent' do
|
||||
expect(subject).to be_truthy
|
||||
expect(agent.user_access_authorized_projects).to contain_exactly(project_2)
|
||||
|
||||
added_authorization = agent.user_access_project_authorizations.find_by(project: project_2)
|
||||
expect(added_authorization.config).to eq({})
|
||||
end
|
||||
|
||||
context 'when config contains "access_as" keyword' do
|
||||
let(:extra_config) do
|
||||
{
|
||||
user_access: {
|
||||
access_as: {
|
||||
agent: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'refreshes authorizations for the agent' do
|
||||
expect(subject).to be_truthy
|
||||
expect(agent.user_access_authorized_projects).to contain_exactly(project_2)
|
||||
|
||||
added_authorization = agent.user_access_project_authorizations.find_by(project: project_2)
|
||||
expect(added_authorization.config).to eq({ 'access_as' => { 'agent' => {} } })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project belongs to a user namespace, and is in the same namespace as the agent' do
|
||||
let_it_be(:root_ancestor) { create(:namespace) }
|
||||
let_it_be(:agent_management_project) { create(:project, namespace: root_ancestor) }
|
||||
let_it_be(:project_1) { create(:project, path: 'project-path-with-UPPERCASE', namespace: root_ancestor) }
|
||||
let_it_be(:project_2) { create(:project, namespace: root_ancestor) }
|
||||
|
||||
it 'creates an authorization record for the project' do
|
||||
expect(subject).to be_truthy
|
||||
expect(agent.user_access_authorized_projects).to contain_exactly(project_2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project belongs to a user namespace, and is authorizing itself' do
|
||||
let_it_be(:root_ancestor) { create(:namespace) }
|
||||
let_it_be(:agent_management_project) { create(:project, namespace: root_ancestor) }
|
||||
let_it_be(:project_1) { create(:project, path: 'project-path-with-UPPERCASE', namespace: root_ancestor) }
|
||||
let_it_be(:project_2) { agent_management_project }
|
||||
|
||||
it 'creates an authorization record for the project' do
|
||||
expect(subject).to be_truthy
|
||||
expect(agent.user_access_authorized_projects).to contain_exactly(project_2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when config contains too many projects' do
|
||||
before do
|
||||
stub_const("#{described_class}::AUTHORIZED_ENTITY_LIMIT", 0)
|
||||
end
|
||||
|
||||
it 'authorizes projects up to the limit' do
|
||||
expect(subject).to be_truthy
|
||||
expect(agent.user_access_authorized_projects).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'removing authorization' do
|
||||
let(:authorizations) { agent.user_access_authorized_projects }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -31,71 +31,73 @@ RSpec.describe 'devise/sessions/new' do
|
|||
|
||||
flag_values = [true, false]
|
||||
flag_values.each do |val|
|
||||
before do
|
||||
stub_feature_flags(restyle_login_page: val)
|
||||
end
|
||||
|
||||
describe 'ldap' do
|
||||
include LdapHelpers
|
||||
|
||||
let(:server) { { provider_name: 'ldapmain', label: 'LDAP' }.with_indifferent_access }
|
||||
|
||||
context "with #{val}" do
|
||||
before do
|
||||
enable_ldap
|
||||
stub_devise
|
||||
disable_captcha
|
||||
disable_sign_up
|
||||
disable_other_signin_methods
|
||||
|
||||
allow(view).to receive(:experiment_enabled?).and_return(false)
|
||||
stub_feature_flags(restyle_login_page: val)
|
||||
end
|
||||
|
||||
it 'is shown when enabled' do
|
||||
render
|
||||
describe 'ldap' do
|
||||
include LdapHelpers
|
||||
|
||||
expect(rendered).to have_selector('.new-session-tabs')
|
||||
expect(rendered).to have_selector('[data-testid="ldap-tab"]')
|
||||
expect(rendered).to have_field('LDAP Username')
|
||||
end
|
||||
let(:server) { { provider_name: 'ldapmain', label: 'LDAP' }.with_indifferent_access }
|
||||
|
||||
it 'is not shown when LDAP sign in is disabled' do
|
||||
disable_ldap_sign_in
|
||||
|
||||
render
|
||||
|
||||
expect(rendered).to have_content('No authentication methods configured')
|
||||
expect(rendered).not_to have_selector('[data-testid="ldap-tab"]')
|
||||
expect(rendered).not_to have_field('LDAP Username')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Google Tag Manager' do
|
||||
let!(:gtm_id) { 'GTM-WWKMTWS' }
|
||||
|
||||
subject { rendered }
|
||||
|
||||
before do
|
||||
stub_devise
|
||||
disable_captcha
|
||||
stub_config(extra: { google_tag_manager_id: gtm_id, google_tag_manager_nonce_id: gtm_id })
|
||||
end
|
||||
|
||||
describe 'when Google Tag Manager is enabled' do
|
||||
before do
|
||||
enable_gtm
|
||||
render
|
||||
enable_ldap
|
||||
stub_devise
|
||||
disable_captcha
|
||||
disable_sign_up
|
||||
disable_other_signin_methods
|
||||
|
||||
allow(view).to receive(:experiment_enabled?).and_return(false)
|
||||
end
|
||||
|
||||
it { is_expected.to match /www.googletagmanager.com/ }
|
||||
end
|
||||
|
||||
describe 'when Google Tag Manager is disabled' do
|
||||
before do
|
||||
disable_gtm
|
||||
it 'is shown when enabled' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_selector('.new-session-tabs')
|
||||
expect(rendered).to have_selector('[data-testid="ldap-tab"]')
|
||||
expect(rendered).to have_field('LDAP Username')
|
||||
end
|
||||
|
||||
it { is_expected.not_to match /www.googletagmanager.com/ }
|
||||
it 'is not shown when LDAP sign in is disabled' do
|
||||
disable_ldap_sign_in
|
||||
|
||||
render
|
||||
|
||||
expect(rendered).to have_content('No authentication methods configured')
|
||||
expect(rendered).not_to have_selector('[data-testid="ldap-tab"]')
|
||||
expect(rendered).not_to have_field('LDAP Username')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Google Tag Manager' do
|
||||
let!(:gtm_id) { 'GTM-WWKMTWS' }
|
||||
|
||||
subject { rendered }
|
||||
|
||||
before do
|
||||
stub_devise
|
||||
disable_captcha
|
||||
stub_config(extra: { google_tag_manager_id: gtm_id, google_tag_manager_nonce_id: gtm_id })
|
||||
end
|
||||
|
||||
describe 'when Google Tag Manager is enabled' do
|
||||
before do
|
||||
enable_gtm
|
||||
render
|
||||
end
|
||||
|
||||
it { is_expected.to match /www.googletagmanager.com/ }
|
||||
end
|
||||
|
||||
describe 'when Google Tag Manager is disabled' do
|
||||
before do
|
||||
disable_gtm
|
||||
render
|
||||
end
|
||||
|
||||
it { is_expected.not_to match /www.googletagmanager.com/ }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue