Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a8b96c3072
commit
cfc8827f6b
|
|
@ -88,7 +88,7 @@ export const billingPlanNames = {
|
|||
[billingPlans.ULTIMATE]: s__('BillingPlans|Ultimate'),
|
||||
};
|
||||
|
||||
const INTEGRATION_TYPE_SLACK = 'slack';
|
||||
export const INTEGRATION_TYPE_SLACK = 'slack';
|
||||
const INTEGRATION_TYPE_SLACK_APPLICATION = 'gitlab_slack_application';
|
||||
const INTEGRATION_TYPE_MATTERMOST = 'mattermost';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
<script>
|
||||
import { GlIcon, GlLink, GlTable, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { INTEGRATION_TYPE_SLACK } from '~/integrations/constants';
|
||||
import { sprintf, s__, __ } from '~/locale';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -13,6 +15,7 @@ export default {
|
|||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
integrations: {
|
||||
type: Array,
|
||||
|
|
@ -55,6 +58,15 @@ export default {
|
|||
},
|
||||
];
|
||||
},
|
||||
filteredIntegrations() {
|
||||
if (this.glFeatures.integrationSlackAppNotifications) {
|
||||
return this.integrations.filter(
|
||||
(integration) =>
|
||||
!(integration.name === INTEGRATION_TYPE_SLACK && integration.active === false),
|
||||
);
|
||||
}
|
||||
return this.integrations;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getStatusTooltipTitle(integration) {
|
||||
|
|
@ -67,7 +79,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<gl-table :items="integrations" :fields="fields" :empty-text="emptyText" show-empty fixed>
|
||||
<gl-table :items="filteredIntegrations" :fields="fields" :empty-text="emptyText" show-empty fixed>
|
||||
<template #cell(active)="{ item }">
|
||||
<gl-icon
|
||||
v-if="item.active"
|
||||
|
|
|
|||
|
|
@ -50,6 +50,14 @@ export const timelineEventTagsI18n = Object.freeze({
|
|||
endTime: __('End time'),
|
||||
});
|
||||
|
||||
export const timelineEventTagsPopover = Object.freeze({
|
||||
title: s__('Incident|Event tag'),
|
||||
message: s__(
|
||||
'Incident|Adding an event tag associates the timeline comment with specific incident metrics.',
|
||||
),
|
||||
link: __('Learn more'),
|
||||
});
|
||||
|
||||
export const MAX_TEXT_LENGTH = 280;
|
||||
|
||||
export const TIMELINE_EVENT_TAGS = Object.values(timelineEventTagsI18n).map((item) => ({
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { GlDatepicker, GlFormInput, GlFormGroup, GlButton, GlCollapsibleListbox
|
|||
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import TimelineEventsTagsPopover from './timeline_events_tags_popover.vue';
|
||||
import { MAX_TEXT_LENGTH, TIMELINE_EVENT_TAGS, timelineFormI18n } from './constants';
|
||||
import { getUtcShiftedDate, getPreviousEventTags } from './utils';
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ export default {
|
|||
],
|
||||
components: {
|
||||
MarkdownField,
|
||||
TimelineEventsTagsPopover,
|
||||
GlDatepicker,
|
||||
GlFormInput,
|
||||
GlFormGroup,
|
||||
|
|
@ -197,8 +199,13 @@ export default {
|
|||
<p class="gl-ml-3 gl-align-self-end gl-line-height-32">{{ __('UTC') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<gl-form-group v-if="glFeatures.incidentEventTags" :label="$options.i18n.tagsLabel">
|
||||
<gl-form-group v-if="glFeatures.incidentEventTags">
|
||||
<label class="gl-display-flex gl-align-items-center gl-gap-3" for="timeline-input-tags">
|
||||
{{ $options.i18n.tagsLabel }}
|
||||
<timeline-events-tags-popover />
|
||||
</label>
|
||||
<gl-collapsible-listbox
|
||||
id="timeline-input-tags"
|
||||
:selected="selectedTags"
|
||||
:toggle-text="listboxText"
|
||||
:items="tags"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<script>
|
||||
import { GlIcon, GlPopover, GlLink } from '@gitlab/ui';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { timelineEventTagsPopover } from './constants';
|
||||
|
||||
export default {
|
||||
name: 'TimelineEventsTagsPopover',
|
||||
components: {
|
||||
GlIcon,
|
||||
GlPopover,
|
||||
GlLink,
|
||||
},
|
||||
i18n: timelineEventTagsPopover,
|
||||
learnMoreLink: helpPagePath('ee/operations/incident_management/incident_timeline_events', {
|
||||
anchor: 'incident-tags',
|
||||
}),
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span>
|
||||
<gl-icon id="timeline-events-tag-question" name="question-o" class="gl-text-blue-600" />
|
||||
|
||||
<gl-popover
|
||||
target="timeline-events-tag-question"
|
||||
triggers="hover focus"
|
||||
placement="top"
|
||||
container="viewport"
|
||||
:title="$options.i18n.title"
|
||||
>
|
||||
<div>
|
||||
<p class="gl-mb-0">
|
||||
{{ $options.i18n.message }}
|
||||
</p>
|
||||
<gl-link target="_blank" class="gl-font-sm" :href="$options.learnMoreLink">{{
|
||||
$options.i18n.link
|
||||
}}</gl-link
|
||||
>.
|
||||
</div>
|
||||
</gl-popover>
|
||||
</span>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<script>
|
||||
import { GlDisclosureDropdown, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
components: {
|
||||
GlDisclosureDropdown,
|
||||
},
|
||||
i18n: {
|
||||
createNew: __('Create new...'),
|
||||
},
|
||||
props: {
|
||||
groups: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-disclosure-dropdown
|
||||
v-gl-tooltip:super-sidebar.bottom="$options.i18n.createNew"
|
||||
category="tertiary"
|
||||
icon="plus"
|
||||
:items="groups"
|
||||
no-caret
|
||||
text-sr-only
|
||||
:toggle-text="$options.i18n.createNew"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -31,6 +31,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<aside
|
||||
id="super-sidebar"
|
||||
class="super-sidebar gl-fixed gl-bottom-0 gl-left-0 gl-display-flex gl-flex-direction-column gl-bg-gray-10 gl-border-r gl-border-gray-a-08 gl-z-index-9999"
|
||||
data-testid="super-sidebar"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { __ } from '~/locale';
|
|||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
|
||||
import logo from '../../../../views/shared/_logo.svg';
|
||||
import CreateMenu from './create_menu.vue';
|
||||
import Counter from './counter.vue';
|
||||
|
||||
export default {
|
||||
|
|
@ -12,10 +13,12 @@ export default {
|
|||
GlAvatar,
|
||||
GlDropdown,
|
||||
GlIcon,
|
||||
CreateMenu,
|
||||
NewNavToggle,
|
||||
Counter,
|
||||
},
|
||||
i18n: {
|
||||
createNew: __('Create new...'),
|
||||
issues: __('Issues'),
|
||||
mergeRequests: __('Merge requests'),
|
||||
todoList: __('To-Do list'),
|
||||
|
|
@ -39,11 +42,7 @@ export default {
|
|||
<div class="gl-flex-grow-1">
|
||||
<a v-safe-html="$options.logo" :href="rootPath"></a>
|
||||
</div>
|
||||
<gl-dropdown variant="link" no-caret>
|
||||
<template #button-content>
|
||||
<gl-icon name="plus" class="gl-vertical-align-middle gl-text-black-normal" />
|
||||
</template>
|
||||
</gl-dropdown>
|
||||
<create-menu :groups="sidebarData.create_new_menu_groups" />
|
||||
<button class="gl-border-none">
|
||||
<gl-icon name="search" class="gl-vertical-align-middle" />
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ module Types
|
|||
# Life-cycle timestamps:
|
||||
field :created_at, Types::TimeType, null: false,
|
||||
description: "When the job was created."
|
||||
field :erased_at, Types::TimeType, null: true,
|
||||
description: "When the job was erased."
|
||||
field :finished_at, Types::TimeType, null: true,
|
||||
description: 'When a job has finished running.'
|
||||
field :queued_at, Types::TimeType, null: true,
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def support_url
|
||||
Gitlab::CurrentSettings.current_application_settings.help_page_support_url.presence || "#{promo_url}/getting-help/"
|
||||
Gitlab::CurrentSettings.current_application_settings.help_page_support_url.presence || "#{promo_url}/get-help/"
|
||||
end
|
||||
|
||||
def instance_review_permitted?
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ module Nav
|
|||
end
|
||||
|
||||
{
|
||||
title: _('This group'),
|
||||
title: _('In this group'),
|
||||
menu_items: menu_items.compact
|
||||
}
|
||||
end
|
||||
|
|
@ -110,7 +110,7 @@ module Nav
|
|||
end
|
||||
|
||||
{
|
||||
title: _('This project'),
|
||||
title: _('In this project'),
|
||||
menu_items: menu_items
|
||||
}
|
||||
end
|
||||
|
|
@ -152,7 +152,7 @@ module Nav
|
|||
end
|
||||
|
||||
{
|
||||
title: _('GitLab'),
|
||||
title: _('In GitLab'),
|
||||
menu_items: menu_items
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module SidebarsHelper
|
||||
include Nav::NewDropdownHelper
|
||||
|
||||
def sidebar_tracking_attributes_by_object(object)
|
||||
sidebar_attributes_for_object(object).fetch(:tracking_attrs, {})
|
||||
end
|
||||
|
|
@ -31,7 +33,7 @@ module SidebarsHelper
|
|||
Sidebars::Groups::Context.new(**context_data)
|
||||
end
|
||||
|
||||
def super_sidebar_context(user)
|
||||
def super_sidebar_context(user, group:, project:)
|
||||
{
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
|
|
@ -39,12 +41,29 @@ module SidebarsHelper
|
|||
assigned_open_issues_count: user.assigned_open_issues_count,
|
||||
assigned_open_merge_requests_count: user.assigned_open_merge_requests_count,
|
||||
todos_pending_count: user.todos_pending_count,
|
||||
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username)
|
||||
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username),
|
||||
create_new_menu_groups: create_new_menu_groups(group: group, project: project)
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_new_menu_groups(group:, project:)
|
||||
new_dropdown_sections = new_dropdown_view_model(group: group, project: project)[:menu_sections]
|
||||
show_headers = new_dropdown_sections.length > 1
|
||||
new_dropdown_sections.map do |section|
|
||||
{
|
||||
name: show_headers ? section[:title] : '',
|
||||
items: section[:menu_items].map do |item|
|
||||
{
|
||||
text: item[:title],
|
||||
href: item[:href]
|
||||
}
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def sidebar_attributes_for_object(object)
|
||||
case object
|
||||
when Project
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
= f.gitlab_ui_checkbox_component :help_page_hide_commercial_content, _('Hide marketing-related entries from the Help page')
|
||||
.form-group
|
||||
= f.label :help_page_support_url, _('Support page URL'), class: 'label-bold'
|
||||
= f.text_field :help_page_support_url, class: 'form-control gl-form-input', placeholder: 'https://company.example.com/getting-help', :'aria-describedby' => 'support_help_block'
|
||||
= f.text_field :help_page_support_url, class: 'form-control gl-form-input', placeholder: 'https://company.example.com/get-help', :'aria-describedby' => 'support_help_block'
|
||||
%span.form-text.text-muted#support_help_block= _('Alternate support URL for Help page and Help dropdown.')
|
||||
|
||||
.form-group
|
||||
|
|
|
|||
|
|
@ -12,14 +12,17 @@
|
|||
= gl_badge_tag migration.status_name.to_s.humanize, { size: :sm, variant: batched_migration_status_badge_variant(migration) }
|
||||
%td{ role: 'cell', data: { label: _('Action') } }
|
||||
- if migration.active?
|
||||
= button_to pause_admin_background_migration_path(migration, database: params[:database]),
|
||||
class: 'gl-button btn btn-icon has-tooltip', title: _('Pause'), 'aria-label' => _('Pause') do
|
||||
= sprite_icon('pause', css_class: 'gl-button-icon gl-icon')
|
||||
= render Pajamas::ButtonComponent.new(icon: 'pause',
|
||||
method: :post,
|
||||
href: pause_admin_background_migration_path(migration, database: params[:database]),
|
||||
button_options: { class: 'has-tooltip', title: _('Pause'), 'aria-label' => _('Pause') })
|
||||
- elsif migration.paused?
|
||||
= button_to resume_admin_background_migration_path(migration, database: params[:database]),
|
||||
class: 'gl-button btn btn-icon has-tooltip', title: _('Resume'), 'aria-label' => _('Resume') do
|
||||
= sprite_icon('play', css_class: 'gl-button-icon gl-icon')
|
||||
= render Pajamas::ButtonComponent.new(icon: 'play',
|
||||
method: :post,
|
||||
href: resume_admin_background_migration_path(migration, database: params[:database]),
|
||||
button_options: { class: 'has-tooltip', title: _('Resume'), 'aria-label' => _('Resume') })
|
||||
- elsif migration.failed?
|
||||
= button_to retry_admin_background_migration_path(migration, database: params[:database]),
|
||||
class: 'gl-button btn btn-icon has-tooltip', title: _('Retry'), 'aria-label' => _('Retry') do
|
||||
= sprite_icon('retry', css_class: 'gl-button-icon gl-icon')
|
||||
= render Pajamas::ButtonComponent.new(icon: 'retry',
|
||||
method: :post,
|
||||
href: retry_admin_background_migration_path(migration, database: params[:database]),
|
||||
button_options: { class: 'has-tooltip', title: _('Retry'), 'aria-label' => _('Retry') })
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
- @left_sidebar = true
|
||||
.layout-page.hide-when-top-nav-responsive-open{ class: page_with_sidebar_class }
|
||||
- if show_super_sidebar?
|
||||
- sidebar_data = super_sidebar_context(current_user).to_json
|
||||
- sidebar_data = super_sidebar_context(current_user, group: @group, project: @project).to_json
|
||||
%aside.js-super-sidebar.nav-sidebar{ data: { root_path: root_path, sidebar: sidebar_data, toggle_new_nav_endpoint: profile_preferences_url } }
|
||||
- elsif defined?(nav) && nav
|
||||
= render "layouts/nav/sidebar/#{nav}"
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ When creating Geo-Based record sets, GCP applies a nearest match for the source
|
|||
1. Select **Network Services** > **Cloud DNS**.
|
||||
1. Select the Zone configured for your domain.
|
||||
1. Select **Add Record Set**.
|
||||
1. Enter the DNS Name for your Location-aware public URL e.g. `gitlab.example.com`.
|
||||
1. Enter the DNS Name for your Location-aware public URL, for example, `gitlab.example.com`.
|
||||
1. Select the **Routing Policy**: **Geo-Based**.
|
||||
1. Select **Add Managed RRData**.
|
||||
1. Select **Source Region**: **us-central1**.
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ jq --raw-output '[.route, .ua] | @tsv' api_json.log | sort | uniq -c | sort -n
|
|||
1234 /api/:version/internal/allowed GitLab-Shell
|
||||
```
|
||||
|
||||
This sample response seems normal. A custom tool or script might be causing a high load
|
||||
This sample response seems typical. A custom tool or script might be causing a high load
|
||||
if the output contains many:
|
||||
|
||||
- Third party libraries like `python-requests` or `curl`.
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ sudo -u git -H bundle exec rails runner -e production /path/to/script.rb
|
|||
|
||||
Rails Runner does not produce the same output as the console.
|
||||
|
||||
If you set a variable on the console, the console will generate useful debug output
|
||||
If you set a variable on the console, the console generates useful debug output
|
||||
such as the variable contents or properties of referenced entity:
|
||||
|
||||
```ruby
|
||||
|
|
@ -176,7 +176,7 @@ root
|
|||
1
|
||||
```
|
||||
|
||||
Some basic knowledge of Ruby will be very useful. Try
|
||||
Some basic knowledge of Ruby is very useful. Try
|
||||
[this 30-minute tutorial](https://try.ruby-lang.org/) for a quick introduction.
|
||||
Rails experience is helpful but not essential.
|
||||
|
||||
|
|
@ -425,7 +425,7 @@ D, [2020-03-05T17:18:30.406047 #910] DEBUG -- : User Load (2.6ms) SELECT "use
|
|||
```
|
||||
|
||||
For more on different ways to retrieve data from the database using Active
|
||||
Record, please see the [Active Record Query Interface documentation](https://guides.rubyonrails.org/active_record_querying.html).
|
||||
Record, see the [Active Record Query Interface documentation](https://guides.rubyonrails.org/active_record_querying.html).
|
||||
|
||||
## Query the database using an Active Record model
|
||||
|
||||
|
|
@ -547,7 +547,7 @@ be the fastest way to get to the root of the problem.
|
|||
|
||||
### Interacting with Active Record objects
|
||||
|
||||
At the end of the day, Active Record objects are just normal Ruby objects. As
|
||||
At the end of the day, Active Record objects are just standard Ruby objects. As
|
||||
such, we can define methods on them which perform arbitrary actions.
|
||||
|
||||
For example, GitLab developers have added some methods which help with
|
||||
|
|
|
|||
|
|
@ -1136,7 +1136,7 @@ To enable the read-only mode:
|
|||
1. Next, trigger one of the garbage collect commands:
|
||||
|
||||
WARNING:
|
||||
You must use `/opt/gitlab/embedded/bin/registry` to recycle unused tags. If you use `gitlab-ctl registry-garbage-collect`, you **will bring the container registry down**.
|
||||
You must use `/opt/gitlab/embedded/bin/registry` to recycle unused tags. If you use `gitlab-ctl registry-garbage-collect`, **the container registry goes down**.
|
||||
|
||||
```shell
|
||||
# Recycling unused tags
|
||||
|
|
@ -1706,7 +1706,7 @@ case, since we know that since the login succeeded, we probably need to look
|
|||
at the communication between the client and the Registry.
|
||||
|
||||
The REST API between the Docker client and Registry is described
|
||||
[in the Docker documentation](https://docs.docker.com/registry/spec/api/). Normally, one would just
|
||||
[in the Docker documentation](https://docs.docker.com/registry/spec/api/). Usually, one would just
|
||||
use Wireshark or tcpdump to capture the traffic and see where things went
|
||||
wrong. However, since all communications between Docker clients and servers
|
||||
are done over HTTPS, it's a bit difficult to decrypt the traffic quickly even
|
||||
|
|
|
|||
|
|
@ -719,7 +719,10 @@ To set the maximum size of GitLab Pages site in a project, overriding the inheri
|
|||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
1. Enter a value under **Maximum size of pages** in MB.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../../user/project/pages/index.md#menu-position-test).
|
||||
1. In **Maximum size of pages**, enter the size in MB.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Set maximum number of GitLab Pages custom domains for a project
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
Sometimes it is necessary to move your databases from one PostgreSQL instance to
|
||||
another. For example, if you are using AWS Aurora and are preparing to
|
||||
enable Database Load Balancing, you will need to move your databases to
|
||||
enable Database Load Balancing, you need to move your databases to
|
||||
RDS for PostgreSQL.
|
||||
|
||||
To move databases from one instance to another:
|
||||
|
|
@ -36,7 +36,7 @@ To move databases from one instance to another:
|
|||
/opt/gitlab/embedded/bin/pg_dump -h $SRC_PGHOST -U $SRC_PGUSER -c -C -f praefect_production.sql praefect_production
|
||||
```
|
||||
|
||||
1. Restore the databases to the destination (this will overwrite any existing databases with the same names):
|
||||
1. Restore the databases to the destination (this overwrites any existing databases with the same names):
|
||||
|
||||
```shell
|
||||
/opt/gitlab/embedded/bin/psql -h $DST_PGHOST -U $DST_PGUSER -f praefect_production.sql postgres
|
||||
|
|
|
|||
|
|
@ -11233,6 +11233,7 @@ CI/CD variables for a GitLab instance.
|
|||
| <a id="cijobdetailedstatus"></a>`detailedStatus` | [`DetailedStatus`](#detailedstatus) | Detailed status of the job. |
|
||||
| <a id="cijobdownstreampipeline"></a>`downstreamPipeline` | [`Pipeline`](#pipeline) | Downstream pipeline for a bridge. |
|
||||
| <a id="cijobduration"></a>`duration` | [`Int`](#int) | Duration of the job in seconds. |
|
||||
| <a id="cijoberasedat"></a>`erasedAt` | [`Time`](#time) | When the job was erased. |
|
||||
| <a id="cijobfinishedat"></a>`finishedAt` | [`Time`](#time) | When a job has finished running. |
|
||||
| <a id="cijobid"></a>`id` | [`JobID`](#jobid) | ID of the job. |
|
||||
| <a id="cijobkind"></a>`kind` | [`CiJobKind!`](#cijobkind) | Indicates the type of job. |
|
||||
|
|
|
|||
|
|
@ -1201,8 +1201,7 @@ GET /groups?search=foobar
|
|||
|
||||
> Introduced in GitLab 14.8.
|
||||
|
||||
Get a list of users provisioned by a given group. Does not include subgroups.
|
||||
Users in this list are considered [enterprise users](../user/enterprise_user/index.md).
|
||||
Get a list of users provisioned by a given group. Does not include users provisioned by subgroups.
|
||||
|
||||
Requires at least the Maintainer role on the group.
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ Example of response
|
|||
"created_at": "2015-12-24T15:51:21.802Z",
|
||||
"started_at": "2015-12-24T17:54:27.722Z",
|
||||
"finished_at": "2015-12-24T17:54:27.895Z",
|
||||
"erased_at": null,
|
||||
"duration": 0.173,
|
||||
"queued_duration": 0.010,
|
||||
"artifacts_file": {
|
||||
|
|
@ -112,6 +113,7 @@ Example of response
|
|||
"created_at": "2015-12-24T15:51:21.727Z",
|
||||
"started_at": "2015-12-24T17:54:24.729Z",
|
||||
"finished_at": "2015-12-24T17:54:24.921Z",
|
||||
"erased_at": null,
|
||||
"duration": 0.192,
|
||||
"queued_duration": 0.023,
|
||||
"artifacts_expire_at": "2016-01-23T17:54:24.921Z",
|
||||
|
|
@ -199,6 +201,7 @@ Example of response
|
|||
"created_at": "2015-12-24T15:51:21.727Z",
|
||||
"started_at": "2015-12-24T17:54:24.729Z",
|
||||
"finished_at": "2015-12-24T17:54:24.921Z",
|
||||
"erased_at": null,
|
||||
"duration": 0.192,
|
||||
"queued_duration": 0.023,
|
||||
"artifacts_expire_at": "2016-01-23T17:54:24.921Z",
|
||||
|
|
@ -258,6 +261,7 @@ Example of response
|
|||
"created_at": "2015-12-24T15:51:21.802Z",
|
||||
"started_at": "2015-12-24T17:54:27.722Z",
|
||||
"finished_at": "2015-12-24T17:54:27.895Z",
|
||||
"erased_at": null,
|
||||
"duration": 0.173,
|
||||
"queued_duration": 0.023,
|
||||
"artifacts_file": {
|
||||
|
|
@ -361,6 +365,7 @@ Example of response
|
|||
"created_at": "2015-12-24T15:51:21.802Z",
|
||||
"started_at": "2015-12-24T17:54:27.722Z",
|
||||
"finished_at": "2015-12-24T17:58:27.895Z",
|
||||
"erased_at": null,
|
||||
"duration": 240,
|
||||
"queued_duration": 0.123,
|
||||
"id": 7,
|
||||
|
|
@ -449,6 +454,7 @@ Example of response
|
|||
"created_at": "2015-12-24T15:51:21.880Z",
|
||||
"started_at": "2015-12-24T17:54:30.733Z",
|
||||
"finished_at": "2015-12-24T17:54:31.198Z",
|
||||
"erased_at": null,
|
||||
"duration": 0.465,
|
||||
"queued_duration": 0.123,
|
||||
"artifacts_expire_at": "2016-01-23T17:54:31.198Z",
|
||||
|
|
@ -600,6 +606,7 @@ Example of response
|
|||
"created_at": "2015-12-24T15:51:21.880Z",
|
||||
"started_at": "2015-12-24T17:54:30.733Z",
|
||||
"finished_at": "2015-12-24T17:54:31.198Z",
|
||||
"erased_at": null,
|
||||
"duration": 0.465,
|
||||
"queued_duration": 0.010,
|
||||
"artifacts_expire_at": "2016-01-23T17:54:31.198Z",
|
||||
|
|
@ -704,6 +711,7 @@ Example of response
|
|||
"created_at": "2016-01-11T10:13:33.506Z",
|
||||
"started_at": "2016-01-11T10:14:09.526Z",
|
||||
"finished_at": null,
|
||||
"erased_at": null,
|
||||
"duration": 8,
|
||||
"queued_duration": 0.010,
|
||||
"id": 1,
|
||||
|
|
@ -757,6 +765,7 @@ Example of response
|
|||
"created_at": "2016-01-11T10:13:33.506Z",
|
||||
"started_at": null,
|
||||
"finished_at": null,
|
||||
"erased_at": null,
|
||||
"duration": null,
|
||||
"queued_duration": 0.010,
|
||||
"id": 1,
|
||||
|
|
@ -821,6 +830,7 @@ Example of response
|
|||
"created_at": "2016-01-11T10:13:33.506Z",
|
||||
"started_at": "2016-01-11T10:13:33.506Z",
|
||||
"finished_at": "2016-01-11T10:15:10.506Z",
|
||||
"erased_at": "2016-01-11T11:30:19.914Z",
|
||||
"duration": 97.0,
|
||||
"queued_duration": 0.010,
|
||||
"status": "failed",
|
||||
|
|
@ -894,6 +904,7 @@ Example response:
|
|||
"created_at": "2016-01-11T10:13:33.506Z",
|
||||
"started_at": null,
|
||||
"finished_at": null,
|
||||
"erased_at": null,
|
||||
"duration": null,
|
||||
"queued_duration": 0.010,
|
||||
"id": 1,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ In GitLab 14.8 and earlier, projects in personal namespaces have an `access_leve
|
|||
|
||||
The `group_saml_identity` attribute is only visible to a group owner for [SSO enabled groups](../user/group/saml_sso/index.md).
|
||||
|
||||
The `email` attribute is only visible to group Owners for any [enterprise user](../user/enterprise_user/index.md).
|
||||
The `email` attribute is only visible to group owners when the user was provisioned by the group.
|
||||
Users are provisioned by the group when the account was created via [SCIM](../user/group/saml_sso/scim_setup.md) or by first sign-in with [SAML SSO for GitLab.com groups](../user/group/saml_sso/index.md).
|
||||
|
||||
## List all members of a group or project
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ It has a pipeline that looks like the following:
|
|||
Using a DAG, you can relate the `_a` jobs to each other separately from the `_b` jobs,
|
||||
and even if service `a` takes a very long time to build, service `b` doesn't
|
||||
wait for it and finishes as quickly as it can. In this very same pipeline, `_c` and
|
||||
`_d` can be left alone and run together in staged sequence just like any normal
|
||||
`_d` can be left alone and run together in staged sequence just like any standard
|
||||
GitLab pipeline.
|
||||
|
||||
## Use cases
|
||||
|
|
@ -68,7 +68,7 @@ as quickly as possible.
|
|||
|
||||
Relationships are defined between jobs using the [`needs` keyword](../yaml/index.md#needs).
|
||||
|
||||
Note that `needs` also works with the [parallel](../yaml/index.md#parallel) keyword,
|
||||
The `needs` keyword also works with the [parallel](../yaml/index.md#parallel) keyword,
|
||||
giving you powerful options for parallelization within your pipeline.
|
||||
|
||||
## Limitations
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ and [view your pipeline status](https://marketplace.visualstudio.com/items?itemN
|
|||
|
||||
Pipelines can be manually executed, with predefined or manually-specified [variables](../variables/index.md).
|
||||
|
||||
You might do this if the results of a pipeline (for example, a code build) are required outside the normal
|
||||
You might do this if the results of a pipeline (for example, a code build) are required outside the standard
|
||||
operation of the pipeline.
|
||||
|
||||
To execute a pipeline manually:
|
||||
|
|
@ -425,7 +425,7 @@ You can group the jobs by:
|
|||
you visualize the entire pipeline, including all cross-project inter-dependencies.
|
||||
|
||||
If a stage contains more than 100 jobs, only the first 100 jobs are listed in the
|
||||
pipeline graph. The remaining jobs still run as normal. To see the jobs:
|
||||
pipeline graph. The remaining jobs still run as usual. To see the jobs:
|
||||
|
||||
- Select the pipeline, and the jobs are listed on the right side of the pipeline details page.
|
||||
- On the left sidebar, select **CI/CD > Jobs**.
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ If you are working on a feature or enhancement, use the
|
|||
If you are not a GitLab team member, or do not have the Developer role for the GitLab repository, to update GitLab documentation:
|
||||
|
||||
1. Select an [issue](https://about.gitlab.com/handbook/product/ux/technical-writing/#community-contribution-opportunities) you'd like to work on.
|
||||
- You don't need an issue to open a merge request.
|
||||
- For a Hackathon, mention `@docs-hackathon` in a comment and ask for the issue to be assigned to you.
|
||||
To be fair to other contributors, if you see someone has already asked to work on the issue, choose another issue.
|
||||
- If you're not taking part in a Hackathon, you don't need an issue to open a merge request.
|
||||
If you are looking for issues to work on and don't see any that suit you, you can always fix [Vale](testing.md#vale) issues.
|
||||
1. Go to the [GitLab repository](https://gitlab.com/gitlab-org/gitlab).
|
||||
1. In the top right, select **Fork**. Forking makes a copy of the repository on GitLab.com.
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ when trying to clone via HTTPS.
|
|||
When using Kerberos ticket-based authentication in an Active Directory domain,
|
||||
it may be necessary to increase the maximum header size allowed by NGINX,
|
||||
as extensions to the Kerberos protocol may result in HTTP authentication headers
|
||||
larger than the default size of 8kB. Configure `large_client_header_buffers`
|
||||
larger than the default size of 8 kB. Configure `large_client_header_buffers`
|
||||
to a larger value in [the NGINX configuration](https://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers).
|
||||
|
||||
## Troubleshooting
|
||||
|
|
|
|||
|
|
@ -1,92 +1,11 @@
|
|||
---
|
||||
stage: Create
|
||||
group: Source Code
|
||||
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
|
||||
comments: false
|
||||
redirect_to: '../../tutorials/make_your_first_git_commit.md'
|
||||
remove_date: '2023-04-23'
|
||||
---
|
||||
|
||||
# Getting started **(FREE)**
|
||||
This document was moved to [another location](../../tutorials/make_your_first_git_commit.md).
|
||||
|
||||
## Instantiating Repositories
|
||||
|
||||
- Create a new repository by instantiating it through:
|
||||
|
||||
```shell
|
||||
git init
|
||||
```
|
||||
|
||||
- Copy an existing project by cloning the repository through:
|
||||
|
||||
```shell
|
||||
git clone <url>
|
||||
```
|
||||
|
||||
NOTE:
|
||||
You can also clone GitLab projects with the
|
||||
[GitLab Workflow VS Code extension](../../user/project/repository/vscode.md).
|
||||
To learn more, read about the extension's
|
||||
[`Git: Clone` command](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#clone-gitlab-projects).
|
||||
|
||||
## Central Repositories
|
||||
|
||||
- To instantiate a central repository a `--bare` flag is required.
|
||||
- Bare repositories don't allow file editing or committing changes.
|
||||
- Create a bare repository with:
|
||||
|
||||
```shell
|
||||
git init --bare project-name.git
|
||||
```
|
||||
|
||||
## Instantiate workflow with clone
|
||||
|
||||
1. Create a project in your user namespace.
|
||||
- Choose to import from **Any Repository by URL** and use <https://gitlab.com/gitlab-org/training-examples.git>.
|
||||
1. Create a '`Workspace`' directory in your home directory.
|
||||
1. Clone the '`training-examples`' project.
|
||||
|
||||
```shell
|
||||
mkdir ~/workspace
|
||||
cd ~/workspace
|
||||
|
||||
git clone git@gitlab.example.com:<username>/training-examples.git
|
||||
cd training-examples
|
||||
```
|
||||
|
||||
## Git concepts
|
||||
|
||||
**Untracked files**
|
||||
|
||||
New files that Git has not been told to track previously.
|
||||
|
||||
**Working area**
|
||||
|
||||
Files that have been modified but are not committed.
|
||||
|
||||
**Staging area**
|
||||
|
||||
Modified files that have been marked to go in the next commit.
|
||||
|
||||
## Committing Workflow
|
||||
|
||||
1. Edit '`edit_this_file.rb`' in '`training-examples`'
|
||||
1. See it listed as a changed file (working area)
|
||||
1. View the differences
|
||||
1. Stage the file
|
||||
1. Commit
|
||||
1. Push the commit to the remote
|
||||
1. View the Git log
|
||||
|
||||
```shell
|
||||
# Edit `edit_this_file.rb`
|
||||
git status
|
||||
git diff
|
||||
git add <file>
|
||||
git commit -m 'My change'
|
||||
git push origin master
|
||||
git log
|
||||
```
|
||||
|
||||
## Note
|
||||
|
||||
- `git fetch` vs `git pull`
|
||||
- Pull is `git fetch` + `git merge`
|
||||
<!-- This redirect file can be deleted after <2023-04-23>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ of the page to activate it in the GitLab instance.
|
|||
|
||||
## System header and footer messages
|
||||
|
||||
> **Enable header and footer in emails** checkbox [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/344819) in GitLab 15.9.
|
||||
|
||||
You can add a small header message, a small footer message, or both, to the interface
|
||||
of your GitLab instance. These messages appear on all projects and pages of the
|
||||
instance, including the sign in / sign up page. The default color is white text on
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Authentication and Authorization
|
||||
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
|
||||
type: reference
|
||||
---
|
||||
|
||||
# Enterprise users **(PREMIUM SAAS)**
|
||||
|
||||
Enterprise users have user accounts that are administered by an organization that
|
||||
has purchased a [GitLab subscription](../../subscriptions/index.md).
|
||||
|
||||
Enterprise users are identified by the [**Enterprise** badge](../project/badges.md)
|
||||
next to their names on the [Members list](../group/manage.md#filter-and-sort-members-in-a-group).
|
||||
|
||||
## Provision an enterprise user
|
||||
|
||||
A user account is considered an enterprise account when:
|
||||
|
||||
- A user without an existing GitLab user account uses the group's
|
||||
[SAML SSO](../group/saml_sso/index.md) to sign in for the first time.
|
||||
- [SCIM](../group/saml_sso/scim_setup.md) creates the user account on behalf of
|
||||
the group.
|
||||
|
||||
A user can also [manually connect an identity provider (IdP) to a GitLab account whose email address matches the subscribing organization's domain](../group/saml_sso/index.md#linking-saml-to-your-existing-gitlabcom-account).
|
||||
By selecting **Authorize** when connecting these two accounts, the user account
|
||||
with the matching email address is classified as an enterprise user. However, this
|
||||
user account does not have an **Enterprise** badge in GitLab.
|
||||
|
||||
Although a user can be a member of more than one group, each user account can be
|
||||
provisioned by only one group. As a result, a user is considered an enterprise
|
||||
user under one top-level group only.
|
||||
|
||||
## Manage enterprise users in a namespace
|
||||
|
||||
A top-level Owner of a namespace on a paid plan can retrieve information about and
|
||||
manage enterprise user accounts in that namespace.
|
||||
|
||||
These enterprise user-specific actions are in addition to the standard
|
||||
[group member permissions](../permissions.md#group-members-permissions).
|
||||
|
||||
### Disable two-factor authentication
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/9484) in GitLab 15.8.
|
||||
|
||||
Top-level group Owners can disable two-factor authentication (2FA) for enterprise users.
|
||||
|
||||
To disable 2FA:
|
||||
|
||||
1. On the top bar, select **Main menu > Groups** and find your group.
|
||||
1. On the left sidebar, select **Group information > Members**.
|
||||
1. Find a user with the **Enterprise** and **2FA** badges.
|
||||
1. Select **More actions** (**{ellipsis_v}**) and select **Disable two-factor authentication**.
|
||||
|
||||
### Prevent users from creating groups and projects outside the corporate group
|
||||
|
||||
A SAML IdP administrator or a top-level group Owner can use a SAML response to set:
|
||||
|
||||
- Whether users can create groups.
|
||||
- The maximum number of personal projects users can create.
|
||||
|
||||
For more information, see the [supported user attributes for SAML responses](../group/saml_sso/index.md#supported-user-attributes).
|
||||
|
||||
### Bypass email confirmation for provisioned users
|
||||
|
||||
A top-level group Owner can [set up verified domains to bypass confirmation emails](../group/saml_sso/index.md#bypass-user-email-confirmation-with-verified-domains).
|
||||
|
||||
### Get users' email addresses through the API
|
||||
|
||||
A top-level group Owner can use the [group and project members API](../../api/members.md)
|
||||
to access users' information, including email addresses.
|
||||
|
|
@ -131,7 +131,7 @@ Filter a group to find members. By default, all members in the group and subgrou
|
|||
In lists of group members, entries can display the following badges:
|
||||
|
||||
- **SAML**, to indicate the member has a [SAML account](saml_sso/index.md) connected to them.
|
||||
- **Enterprise**, to indicate that the member is an [enterprise user](../enterprise_user/index.md).
|
||||
- **Enterprise**, to indicate that [SCIM created the account](saml_sso/scim_setup.md).
|
||||
|
||||
1. On the top bar, select **Main menu > Groups** and find your group.
|
||||
1. Above the list of members, in the **Filter members** box, enter filter criteria.
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ To migrate users to a new email domain, users must:
|
|||
## User access and management
|
||||
|
||||
> - SAML user provisioning [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/268142) in GitLab 13.7.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325712) in GitLab 14.0, GitLab users created by [SAML SSO](index.md#user-access-and-management) or SCIM provisioning are displayed with an ][**Enterprise**](../../enterprise_user/index.md) badge in the **Members** view.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325712) in GitLab 14.0, GitLab users created by [SAML SSO](index.md#user-access-and-management) or SCIM provisioning are displayed with an **Enterprise** badge in the **Members** view.
|
||||
|
||||
After group SSO is configured and enabled, users can access the GitLab.com group through the identity provider's dashboard.
|
||||
If [SCIM](scim_setup.md) is configured, see [user access](scim_setup.md#user-access) on the SCIM page.
|
||||
|
|
@ -431,7 +431,7 @@ convert the information to XML. An example SAML response is shown here.
|
|||
|
||||
By default, users provisioned with SAML or SCIM are sent a verification email to verify their identity. Instead, you can
|
||||
[configure GitLab with a custom domain](../../project/pages/custom_domains_ssl_tls_certification/index.md) and GitLab
|
||||
automatically confirms user accounts. Users still receive an [enterprise user](../../enterprise_user/index.md) welcome email. Confirmation is bypassed for
|
||||
automatically confirms user accounts. Users still receive an enterprise user welcome email. Confirmation is bypassed for
|
||||
users:
|
||||
|
||||
- That are provisioned with SAML or SCIM.
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ encounter issues.
|
|||
|
||||
## User access
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325712) in GitLab 14.0, GitLab users created by [SAML SSO](index.md#user-access-and-management) or SCIM provisioning are displayed with an [**Enterprise**](../../enterprise_user/index.md) badge in the **Members** view.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325712) in GitLab 14.0, GitLab users created by [SAML SSO](index.md#user-access-and-management) or SCIM provisioning are displayed with an **Enterprise** badge in the **Members** view.
|
||||
|
||||
During the synchronization process, all new users:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Create
|
||||
group: Source Code
|
||||
stage: Manage
|
||||
group: Organization
|
||||
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
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -34,18 +34,25 @@ For example:
|
|||
| Code Owner approval rule | Frontend: Code Style | `*.css` files | A frontend engineer reviews CSS file changes for adherence to project style standards. |
|
||||
| Code Owner approval rule | Backend: Code Review | `*.rb` files | A backend engineer reviews the logic and code style of Ruby files. |
|
||||
|
||||
## Code Owners file
|
||||
|
||||
A `CODEOWNERS` file (with no extension) can specify users or [shared groups](members/share_project_with_groups.md)
|
||||
that are responsible for specific files and directories in a repository. Each repository
|
||||
can have a single `CODEOWNERS` file, and it must be found one of these three locations:
|
||||
|
||||
- In the root directory of the repository.
|
||||
- In the `.gitlab/` directory.
|
||||
- In the `docs/` directory.
|
||||
|
||||
A CODEOWNERS file in any other location is ignored.
|
||||
|
||||
## Set up Code Owners
|
||||
|
||||
Create a `CODEOWNERS` file to specify users or [shared groups](members/share_project_with_groups.md)
|
||||
that are responsible for specific files and directories in a repository. Each repository
|
||||
can have a single `CODEOWNERS` file. To create it:
|
||||
1. Create a file named `CODEOWNERS` (with no extension) in one of these locations:
|
||||
|
||||
1. Choose the location where you want to specify Code Owners:
|
||||
- In the root directory of the repository
|
||||
- In the `.gitlab/` directory
|
||||
- In the `docs/` directory
|
||||
|
||||
1. In that location, create a file named `CODEOWNERS`.
|
||||
- In the root directory of the repository
|
||||
- In the `.gitlab/` directory
|
||||
- In the `docs/` directory
|
||||
|
||||
1. In the file, enter text that follows one of these patterns:
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ disqus_identifier: 'https://docs.gitlab.com/ee/user/project/merge_requests/appro
|
|||
|
||||
# Merge request approvals **(FREE)**
|
||||
|
||||
> Redesign [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1979) in GitLab 11.8 and [feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/10685) in 12.0.
|
||||
|
||||
You can configure your merge requests so that they must be approved before
|
||||
they can be merged. While [GitLab Free](https://about.gitlab.com/pricing/) allows
|
||||
all users with Developer or greater [permissions](../../../permissions.md) to
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ To add your custom domain to GitLab Pages:
|
|||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
1. In the top right, select **New Domain**.
|
||||
1. In **Domain**, enter your domain.
|
||||
1. In the top-right corner, select **New Domain**.
|
||||
1. In **Domain**, enter the domain name.
|
||||
1. Optional. In **Certificate**, turn off the **Automatic certificate management using Let's Encrypt** toggle to add an [SSL/TLS certificate](#adding-an-ssltls-certificate-to-pages). You can also add the certificate and key later.
|
||||
1. Select **Create New Domain**.
|
||||
|
||||
|
|
@ -168,10 +168,13 @@ If you're using Cloudflare, check
|
|||
|
||||
Once you have added all the DNS records:
|
||||
|
||||
1. Go back at your project's **Settings > Pages** (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test)).
|
||||
1. Locate your domain name and select **Details**.
|
||||
1. Select the **Retry verification** button to activate your new domain.
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
1. Next to the domain name, select **Edit**.
|
||||
1. In **Verification status**, select **Retry verification** (**{retry}**).
|
||||
|
||||

|
||||
|
||||
|
|
@ -290,12 +293,28 @@ meet these requirements.
|
|||
|
||||
#### Steps
|
||||
|
||||
- To add the certificate at the time you add a new domain, go to your
|
||||
project's **Settings > Pages > New Domain** (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test)), add the domain name and the
|
||||
certificate.
|
||||
- To add the certificate to a domain previously added, go to your
|
||||
project's **Settings > Pages**, locate your domain name, select **Details** and **Edit** to add the certificate.
|
||||
- To add the certificate at the time you add a new domain:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
1. In the top-right corner, select **New Domain**.
|
||||
1. In **Domain**, enter the domain name.
|
||||
1. In **Certificate**, turn off the **Automatic certificate management using Let's Encrypt** toggle to add an [SSL/TLS certificate](#adding-an-ssltls-certificate-to-pages).
|
||||
1. Select **Create New Domain**.
|
||||
|
||||
- To add the certificate to a domain previously added:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
1. Next to the domain name, select **Edit**.
|
||||
1. In **Certificate**, turn off the **Automatic certificate management using Let's Encrypt** toggle to add an [SSL/TLS certificate](#adding-an-ssltls-certificate-to-pages).
|
||||
1. Select **Save changes**.
|
||||
|
||||
NOTE:
|
||||
The Pages menu entry may also be located at **Deployments > Pages**, [more information](../index.md#menu-position-test)
|
||||
|
|
@ -322,9 +341,13 @@ domain (as long as you've set a valid certificate for it).
|
|||
|
||||
To enable this setting:
|
||||
|
||||
1. Navigate to your project's **Settings > Pages** (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test)).
|
||||
1. Tick the checkbox **Force HTTPS (requires valid certificates)**.
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
1. Select the **Force HTTPS (requires valid certificates)** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
If you use Cloudflare CDN in front of GitLab Pages, make sure to set the SSL connection setting to
|
||||
`full` instead of `flexible`. For more details, see the [Cloudflare CDN directions](https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef).
|
||||
|
|
|
|||
|
|
@ -42,11 +42,13 @@ For **self-managed** GitLab instances, make sure your administrator has
|
|||
|
||||
Once you've met the requirements, enable Let's Encrypt integration:
|
||||
|
||||
1. Navigate to your project's **Settings > Pages** (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test)).
|
||||
1. Find your domain and select **Details**.
|
||||
1. Select **Edit** in the top-right corner.
|
||||
1. Enable Let's Encrypt integration by switching **Automatic certificate management using Let's Encrypt**:
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
1. Next to the domain name, select **Edit**.
|
||||
1. Turn on the **Automatic certificate management using Let's Encrypt** toggle.
|
||||
|
||||

|
||||
|
||||
|
|
@ -70,31 +72,37 @@ associated Pages domain. GitLab also renews it automatically.
|
|||
|
||||
If you get an error **Something went wrong while obtaining the Let's Encrypt certificate**, first, make sure that your pages site is set to "Everyone" in your project's **Settings > General > Visibility**. This allows the Let's Encrypt Servers reach your pages site. Once this is confirmed, you can try obtaining the certificate again by following these steps:
|
||||
|
||||
1. Go to your project's **Settings > Pages** (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test)).
|
||||
1. Select **Edit** on your domain.
|
||||
1. Select **Retry**.
|
||||
1. If you're still seeing the same error:
|
||||
1. Make sure you have properly set only one `CNAME` or `A` DNS record for your domain.
|
||||
1. Make sure your domain **doesn't have** an `AAAA` DNS record.
|
||||
1. If you have a `CAA` DNS record for your domain or any higher level domains, make sure [it includes `letsencrypt.org`](https://letsencrypt.org/docs/caa/).
|
||||
1. Make sure [your domain is verified](index.md#1-add-a-custom-domain).
|
||||
1. Go to step 1.
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
1. Next to the domain name, select **Edit**.
|
||||
1. In **Verification status**, select **Retry verification** (**{retry}**).
|
||||
1. If you're still getting the same error:
|
||||
1. Make sure you have properly set only one `CNAME` or `A` DNS record for your domain.
|
||||
1. Make sure your domain **doesn't have** an `AAAA` DNS record.
|
||||
1. If you have a `CAA` DNS record for your domain or any higher level domains, make sure [it includes `letsencrypt.org`](https://letsencrypt.org/docs/caa/).
|
||||
1. Make sure [your domain is verified](index.md#1-add-a-custom-domain).
|
||||
1. Go to step 1.
|
||||
|
||||
### Message "GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later." hangs for more than an hour
|
||||
|
||||
If you've enabled Let's Encrypt integration, but a certificate is absent after an hour and you see the message, "GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later.", try to remove and add the domain for GitLab Pages again by following these steps:
|
||||
|
||||
1. Go to your project's **Settings > Pages** (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test)).
|
||||
1. Select **Remove** on your domain.
|
||||
1. [Add the domain again and verify it](index.md#1-add-a-custom-domain).
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
1. Next to the domain name, select **Remove**.
|
||||
1. [Add the domain again, and verify it](index.md#1-add-a-custom-domain).
|
||||
1. [Enable Let's Encrypt integration for your domain](#enabling-lets-encrypt-integration-for-your-custom-domain).
|
||||
1. If you still see the same message after some time:
|
||||
1. Make sure you have properly set only one `CNAME` or `A` DNS record for your domain.
|
||||
1. Make sure your domain **doesn't have** an `AAAA` DNS record.
|
||||
1. If you have a `CAA` DNS record for your domain or any higher level domains, make sure [it includes `letsencrypt.org`](https://letsencrypt.org/docs/caa/).
|
||||
1. Go to step 1.
|
||||
1. If you're still getting the same error:
|
||||
1. Make sure you have properly set only one `CNAME` or `A` DNS record for your domain.
|
||||
1. Make sure your domain **doesn't have** an `AAAA` DNS record.
|
||||
1. If you have a `CAA` DNS record for your domain or any higher level domains, make sure [it includes `letsencrypt.org`](https://letsencrypt.org/docs/caa/).
|
||||
1. Go to step 1.
|
||||
|
||||
<!-- Include any troubleshooting steps that you can foresee. If you know beforehand what issues
|
||||
one might have when setting this up, or when something is changed, or on upgrading, it's
|
||||
|
|
|
|||
|
|
@ -27,9 +27,11 @@ these steps, you may have to do additional configuration for the Pages site to g
|
|||
If everything is configured correctly, the site can take approximately 30 minutes to deploy.
|
||||
|
||||
To view the pipeline, go to **CI/CD > Pipelines**.
|
||||
|
||||
When the pipeline is finished, go to **Settings > Pages** to find the link to
|
||||
your Pages website. (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test))
|
||||
your Pages website.
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
|
||||
For every change pushed to your repository, GitLab CI/CD runs a new pipeline
|
||||
that immediately publishes your changes to the Pages site.
|
||||
|
|
|
|||
|
|
@ -24,9 +24,10 @@ To fork a sample project and create a Pages website:
|
|||
GitLab CI/CD builds and deploys your site.
|
||||
|
||||
The site can take approximately 30 minutes to deploy.
|
||||
When the pipeline is finished, go to **Settings > Pages** to find the link
|
||||
to your website from your project. (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test))
|
||||
When the pipeline is finished, go to **Settings > Pages** to find the link to
|
||||
your Pages website.
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
|
||||
For every change pushed to your repository, GitLab CI/CD runs a new pipeline
|
||||
that immediately publishes your changes to the Pages site.
|
||||
|
|
|
|||
|
|
@ -175,10 +175,11 @@ deploy your website:
|
|||
|
||||
1. Save and commit the `.gitlab-ci.yml` file.
|
||||
1. Go to **CI/CD > Pipelines** to watch the pipeline.
|
||||
1. When the pipeline succeeds, go to **Settings > Pages**
|
||||
to view the URL where your site is now available. (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test))
|
||||
1. When the pipeline is finished, go to **Settings > Pages** to find the link to
|
||||
your Pages website.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
When this `pages` job completes successfully, a special `pages:deploy` job
|
||||
appears in the pipeline view. It prepares the content of the website for the
|
||||
GitLab Pages daemon. GitLab runs it in the background and doesn't use a runner.
|
||||
|
|
|
|||
|
|
@ -24,8 +24,9 @@ configured to generate a Pages site.
|
|||
site.
|
||||
|
||||
When the pipeline is finished, go to **Settings > Pages** to find the link to
|
||||
your Pages website. (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test))
|
||||
your Pages website.
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
|
||||
For every change pushed to your repository, GitLab CI/CD runs a new pipeline
|
||||
that immediately publishes your changes to the Pages site.
|
||||
|
|
|
|||
|
|
@ -34,8 +34,10 @@ a pipeline deploys your Pages website.
|
|||
To complete the setup and generate a GitLab Pages deployment:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages** (Note: this may also be
|
||||
located at **Deployments > Pages**, [more information](../index.md#menu-position-test)).
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](../index.md#menu-position-test).
|
||||
A **Get Started with Pages** form appears. If this form is not available,
|
||||
see [Troubleshooting](#if-the-get-started-with-pages-form-is-not-available).
|
||||
1. For **Step 1**, enter an image name and verify that your files are in a `public` folder.
|
||||
|
|
@ -61,10 +63,10 @@ and on the right side, select **Download artifacts**.
|
|||
|
||||
### If the `Get Started with Pages` form is not available
|
||||
|
||||
When you go to **Settings > Pages**, the form is not available if you:
|
||||
The `Get Started with Pages` form is not available if you:
|
||||
|
||||
- Deployed a GitLab Pages site before.
|
||||
- Committed a `.gitlab-ci.yml` through the forms at least one time.
|
||||
- Committed `.gitlab-ci.yml` through the forms at least one time.
|
||||
|
||||
To fix this issue:
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ To remove your pages:
|
|||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > Pages**.
|
||||
|
||||
If this path is not visible, select **Deployments > Pages**.
|
||||
[This location is part of an experiment](index.md#menu-position-test).
|
||||
1. Select **Remove pages**.
|
||||
|
||||
## Subdomains of subdomains
|
||||
|
|
|
|||
|
|
@ -180,6 +180,47 @@ you can sign individual commits manually, or configure Git to default to signed
|
|||
git config --global commit.gpgsign true
|
||||
```
|
||||
|
||||
#### Set signing key conditionally
|
||||
|
||||
If you maintain signing keys for separate purposes, such as work and personal
|
||||
use, use an `IncludeIf` statement in your `.gitconfig` file to set which key
|
||||
you sign commits with.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Requires Git version 2.13 or later.
|
||||
|
||||
1. In the same directory as your main `~/.gitconfig` file, create a second file,
|
||||
such as `.gitconfig-gitlab`.
|
||||
1. In your main `~/.gitconfig` file, add your Git settings for work in non-GitLab projects.
|
||||
1. Append this information to the end of your main `~/.gitconfig` file:
|
||||
|
||||
```ini
|
||||
# The contents of this file are included only for GitLab.com URLs
|
||||
[includeIf "hasconfig:remote.*.url:https://gitlab.com/**"]
|
||||
|
||||
# Edit this line to point to your alternate configuration file
|
||||
path = ~/.gitconfig-gitlab
|
||||
```
|
||||
|
||||
1. In your alternate `.gitconfig-gitlab` file, add the configuration overrides to
|
||||
use when you're committing to a GitLab repository. All settings from your
|
||||
main `~/.gitconfig` file are retained unless you explicitly override them.
|
||||
In this example,
|
||||
|
||||
```ini
|
||||
# Alternate ~/.gitconfig-gitlab file
|
||||
# These values are used for repositories matching the string 'gitlab.com',
|
||||
# and override their corresponding values in ~/.gitconfig
|
||||
|
||||
[user]
|
||||
email = you@example.com
|
||||
signingkey = <KEY ID>
|
||||
|
||||
[commit]
|
||||
gpgsign = true
|
||||
```
|
||||
|
||||
## Verify commits
|
||||
|
||||
You can review commits for a merge request, or for an entire project:
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Web Editor **(FREE)**
|
||||
|
||||
You can use the Web Editor to make changes directly from the GitLab UI instead of
|
||||
cloning a project and using the command line.
|
||||
You can use the Web Editor to make changes to a single file directly from the
|
||||
GitLab UI. To make changes to multiple files, see [Web IDE](../web_ide/index.md).
|
||||
|
||||
From the project dashboard or repository, you can:
|
||||
In the Web Editor, you can:
|
||||
|
||||
- [Create a file](#create-a-file).
|
||||
- [Edit a file](#edit-a-file).
|
||||
|
|
@ -18,8 +18,8 @@ From the project dashboard or repository, you can:
|
|||
- [Create a branch](#create-a-branch).
|
||||
- [Create a tag](#create-a-tag).
|
||||
|
||||
Your [primary email address](../../../user/profile/index.md#change-the-email-displayed-on-your-commits)
|
||||
is used by default for any change you commit through the Web Editor.
|
||||
Your [primary email address is used by default](../../../user/profile/index.md#change-the-email-displayed-on-your-commits)
|
||||
for any change you commit through the Web Editor.
|
||||
|
||||
## Create a file
|
||||
|
||||
|
|
@ -28,18 +28,22 @@ To create a text file in the Web Editor:
|
|||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. From the project dashboard or repository, next to the branch name, select the plus icon (**{plus}**).
|
||||
1. From the dropdown list, select **New file**.
|
||||
1. Complete the fields.
|
||||
- From the **Select a template type** dropdown list, you can apply a template to the new file.
|
||||
- To create a merge request with the new file, ensure the **Start a new merge request with these changes** checkbox is selected.
|
||||
1. Complete the fields. To create a merge request with the new file, ensure the **Start a new merge request with these changes** checkbox is selected.
|
||||
1. Select **Commit changes**.
|
||||
|
||||
## Edit a file
|
||||
|
||||
To edit a file in the Web Editor:
|
||||
To edit a text file in the Web Editor:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. Go to your file.
|
||||
1. Next to the display buttons, select **Edit**.
|
||||
1. In the upper-right corner of the file, select **Edit**.
|
||||
|
||||
If **Edit** is not visible:
|
||||
|
||||
1. Next to **Open in Web IDE** or **Open in Gitpod**, select the down arrow (**{chevron-lg-down}**).
|
||||
1. From the dropdown list, select **Edit** as your default setting.
|
||||
1. Select **Edit**.
|
||||
|
||||
### Keyboard shortcuts
|
||||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ With Service Desk, you can use templates for:
|
|||
|
||||
#### Email header and footer **(FREE SELF)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/344819) in GitLab 15.9.
|
||||
|
||||
Instance administrators can add a small header or footer to the GitLab instance and make them
|
||||
visible in the email template. For more information, see
|
||||
[System header and footer messages](../admin_area/appearance.md#system-header-and-footer-messages).
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Web IDE **(FREE)**
|
||||
|
||||
The Web Integrated Development Environment (IDE) editor streamlines the process
|
||||
to contribute changes to your projects, by providing an advanced editor with
|
||||
commit staging.
|
||||
The Web IDE is an advanced editor with commit staging.
|
||||
You can use the Web IDE to make changes to multiple files directly from the
|
||||
GitLab UI. For a more basic implementation, see [Web Editor](../repository/web_editor.md).
|
||||
|
||||
NOTE:
|
||||
The Web IDE is being updated to use VS Code. For details,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ module API
|
|||
expose :created_at, documentation: { type: 'dateTime', example: '2015-12-24T15:51:21.880Z' }
|
||||
expose :started_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:30.733Z' }
|
||||
expose :finished_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
|
||||
expose :erased_at, documentation: { type: 'dateTime', example: '2015-12-24T18:00:29.728Z' }
|
||||
expose :duration,
|
||||
documentation: { type: 'number', format: 'float', desc: 'Time spent running', example: 0.465 }
|
||||
expose :queued_duration,
|
||||
|
|
|
|||
|
|
@ -21378,6 +21378,9 @@ msgstr ""
|
|||
msgid "Improve quality with test cases"
|
||||
msgstr ""
|
||||
|
||||
msgid "In GitLab"
|
||||
msgstr ""
|
||||
|
||||
msgid "In case of pull mirroring, your user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21390,9 +21393,15 @@ msgstr ""
|
|||
msgid "In the background, we're attempting to connect you again."
|
||||
msgstr ""
|
||||
|
||||
msgid "In this group"
|
||||
msgstr ""
|
||||
|
||||
msgid "In this page you will find information about the settings that are used in your current instance."
|
||||
msgstr ""
|
||||
|
||||
msgid "In this project"
|
||||
msgstr ""
|
||||
|
||||
msgid "In use"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -22143,6 +22152,9 @@ msgstr ""
|
|||
msgid "Incident|Add new timeline event"
|
||||
msgstr ""
|
||||
|
||||
msgid "Incident|Adding an event tag associates the timeline comment with specific incident metrics."
|
||||
msgstr ""
|
||||
|
||||
msgid "Incident|Alert details"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -22176,6 +22188,9 @@ msgstr ""
|
|||
msgid "Incident|Error updating incident timeline event: %{error}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Incident|Event tag"
|
||||
msgstr ""
|
||||
|
||||
msgid "Incident|Incident"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -43370,9 +43385,6 @@ msgstr ""
|
|||
msgid "This process deletes the project repository and all related resources."
|
||||
msgstr ""
|
||||
|
||||
msgid "This project"
|
||||
msgstr ""
|
||||
|
||||
msgid "This project can be restored until %{date}."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@
|
|||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/fonts": "^1.1.0",
|
||||
"@gitlab/svgs": "3.16.0",
|
||||
"@gitlab/ui": "52.11.0",
|
||||
"@gitlab/svgs": "3.17.0",
|
||||
"@gitlab/ui": "52.13.1",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "0.0.1-dev-20230120231236",
|
||||
"@rails/actioncable": "6.1.4-7",
|
||||
|
|
|
|||
|
|
@ -8,18 +8,25 @@ module QA
|
|||
QA::EE::Resource::Settings::Elasticsearch.fabricate_via_api! unless advanced_search_on
|
||||
end
|
||||
|
||||
after do
|
||||
Runtime::Search.disable_elasticsearch(api_client) if !advanced_search_on && !api_client.nil?
|
||||
end
|
||||
# TODO: convert check_advanced_search_status method to use the API instead of the UI once the functionality exists
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/382849 and then we can resume turning off advanced search after the
|
||||
# tests as in the `after` block here. For now the advanced search tests will have the side effect of turning on
|
||||
# advanced search if it wasn't enabled before the tests run.
|
||||
|
||||
# after do
|
||||
# Runtime::Search.disable_elasticsearch(api_client) if !advanced_search_on && !api_client.nil?
|
||||
# end
|
||||
|
||||
# TODO: convert this method to use the API instead of the UI once the functionality exists
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/382849
|
||||
def check_advanced_search_status
|
||||
Flow::Login.sign_in
|
||||
QA::Page::Main::Menu.perform do |menu|
|
||||
menu.search_for('lorem ipsum')
|
||||
QA::Support::Retrier.retry_on_exception(
|
||||
max_attempts: Runtime::Search::RETRY_MAX_ITERATION,
|
||||
sleep_interval: Runtime::Search::RETRY_SLEEP_INTERVAL) do
|
||||
QA::Page::Main::Menu.perform do |menu|
|
||||
menu.search_for('lorem ipsum')
|
||||
end
|
||||
page.has_text?('Advanced search is enabled')
|
||||
end
|
||||
page.has_text?('Advanced search is enabled')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -92,11 +92,11 @@ RSpec.describe "Admin > Admin sees background migrations", feature_category: :da
|
|||
expect(page).not_to have_content('Paused')
|
||||
expect(page).to have_content('Active')
|
||||
|
||||
click_button('Pause')
|
||||
click_on('Pause')
|
||||
expect(page).not_to have_content('Active')
|
||||
expect(page).to have_content('Paused')
|
||||
|
||||
click_button('Resume')
|
||||
click_on('Resume')
|
||||
expect(page).not_to have_content('Paused')
|
||||
expect(page).to have_content('Active')
|
||||
end
|
||||
|
|
@ -123,7 +123,7 @@ RSpec.describe "Admin > Admin sees background migrations", feature_category: :da
|
|||
tab = find_link 'Failed'
|
||||
tab.click
|
||||
|
||||
expect(page).to have_selector("[method='post'][action='/admin/background_migrations/#{failed_migration.id}/retry?database=main']")
|
||||
expect(page).to have_selector("[data-method='post'][href='/admin/background_migrations/#{failed_migration.id}/retry?database=main']")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ RSpec.describe "Admin > Admin sees background migrations", feature_category: :da
|
|||
expect(page).to have_content('0.00%')
|
||||
expect(page).to have_content(failed_migration.status_name.to_s)
|
||||
|
||||
click_button('Retry')
|
||||
click_on('Retry')
|
||||
expect(page).not_to have_content(failed_migration.job_class_name)
|
||||
expect(page).not_to have_content(failed_migration.table_name)
|
||||
expect(page).not_to have_content('0.00%')
|
||||
|
|
|
|||
|
|
@ -861,7 +861,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do
|
|||
|
||||
context 'Nav bar' do
|
||||
it 'shows default help links in nav' do
|
||||
default_support_url = "https://#{ApplicationHelper.promo_host}/getting-help/"
|
||||
default_support_url = "https://#{ApplicationHelper.promo_host}/get-help/"
|
||||
|
||||
visit root_dashboard_path
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ RSpec.describe 'User activates Slack notifications', :js, feature_category: :int
|
|||
|
||||
context 'when integration is not configured yet' do
|
||||
before do
|
||||
stub_feature_flags(integration_slack_app_notifications: false)
|
||||
visit_project_integration('Slack notifications')
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
"created_at",
|
||||
"started_at",
|
||||
"finished_at",
|
||||
"erased_at",
|
||||
"duration",
|
||||
"queued_duration",
|
||||
"user",
|
||||
|
|
@ -35,6 +36,7 @@
|
|||
"created_at": { "type": "string" },
|
||||
"started_at": { "type": ["null", "string"] },
|
||||
"finished_at": { "type": ["null", "string"] },
|
||||
"erased_at": { "type": ["null", "string"] },
|
||||
"duration": { "type": ["null", "number"] },
|
||||
"queued_duration": { "type": ["null", "number"] },
|
||||
"user": { "$ref": "user/basic.json" },
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import waitForPromises from 'helpers/wait_for_promises';
|
|||
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { redirectTo } from '~/lib/utils/url_utility';
|
||||
import BroadcastMessagesBase from '~/admin/broadcast_messages/components/base.vue';
|
||||
import MessagesTable from '~/admin/broadcast_messages/components/messages_table.vue';
|
||||
|
|
@ -86,7 +87,7 @@ describe('BroadcastMessagesBase', () => {
|
|||
it('removes a deleted message from visibleMessages on success', async () => {
|
||||
createComponent();
|
||||
const { id, delete_path } = MOCK_MESSAGES[0];
|
||||
axiosMock.onDelete(delete_path).replyOnce(200);
|
||||
axiosMock.onDelete(delete_path).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
findTable().vm.$emit('delete-message', id);
|
||||
await waitForPromises();
|
||||
|
|
@ -102,7 +103,7 @@ describe('BroadcastMessagesBase', () => {
|
|||
const { id, delete_path } = messages[0];
|
||||
createComponent({ messages, messagesCount: messages.length });
|
||||
|
||||
axiosMock.onDelete(delete_path).replyOnce(200);
|
||||
axiosMock.onDelete(delete_path).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
findTable().vm.$emit('delete-message', id);
|
||||
await waitForPromises();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import * as types from '~/feature_flags/store/edit/mutation_types';
|
|||
import state from '~/feature_flags/store/edit/state';
|
||||
import { mapStrategiesToRails } from '~/feature_flags/store/helpers';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
jest.mock('~/lib/utils/url_utility');
|
||||
|
||||
|
|
@ -55,7 +56,9 @@ describe('Feature flags Edit Module actions', () => {
|
|||
},
|
||||
],
|
||||
};
|
||||
mock.onPut(mockedState.endpoint, mapStrategiesToRails(featureFlag)).replyOnce(200);
|
||||
mock
|
||||
.onPut(mockedState.endpoint, mapStrategiesToRails(featureFlag))
|
||||
.replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
return testAction(
|
||||
updateFeatureFlag,
|
||||
|
|
@ -155,7 +158,7 @@ describe('Feature flags Edit Module actions', () => {
|
|||
|
||||
describe('success', () => {
|
||||
it('dispatches requestFeatureFlag and receiveFeatureFlagSuccess', () => {
|
||||
mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, { id: 1 });
|
||||
mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(HTTP_STATUS_OK, { id: 1 });
|
||||
|
||||
return testAction(
|
||||
fetchFeatureFlag,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
import * as types from '~/feature_flags/store/new/mutation_types';
|
||||
import state from '~/feature_flags/store/new/state';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
jest.mock('~/lib/utils/url_utility');
|
||||
|
||||
|
|
@ -48,7 +49,9 @@ describe('Feature flags New Module Actions', () => {
|
|||
},
|
||||
],
|
||||
};
|
||||
mock.onPost(mockedState.endpoint, mapStrategiesToRails(actionParams)).replyOnce(200);
|
||||
mock
|
||||
.onPost(mockedState.endpoint, mapStrategiesToRails(actionParams))
|
||||
.replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
return testAction(
|
||||
createFeatureFlag,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
|||
import { TEST_HOST } from 'spec/test_constants';
|
||||
import GpgBadges from '~/gpg_badges';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
describe('GpgBadges', () => {
|
||||
let mock;
|
||||
|
|
@ -63,7 +64,7 @@ describe('GpgBadges', () => {
|
|||
});
|
||||
|
||||
it('fetches commit signatures', async () => {
|
||||
mock.onGet(dummyUrl).replyOnce(200);
|
||||
mock.onGet(dummyUrl).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
await GpgBadges.fetch();
|
||||
|
||||
|
|
@ -75,7 +76,7 @@ describe('GpgBadges', () => {
|
|||
});
|
||||
|
||||
it('fetches commit signatures with search parameters with spaces', async () => {
|
||||
mock.onGet(dummyUrl).replyOnce(200);
|
||||
mock.onGet(dummyUrl).replyOnce(HTTP_STATUS_OK);
|
||||
setForm({ search: 'my search' });
|
||||
|
||||
await GpgBadges.fetch();
|
||||
|
|
@ -88,7 +89,7 @@ describe('GpgBadges', () => {
|
|||
});
|
||||
|
||||
it('fetches commit signatures with search parameters with plus symbols', async () => {
|
||||
mock.onGet(dummyUrl).replyOnce(200);
|
||||
mock.onGet(dummyUrl).replyOnce(HTTP_STATUS_OK);
|
||||
setForm({ search: 'my+search' });
|
||||
|
||||
await GpgBadges.fetch();
|
||||
|
|
@ -101,7 +102,7 @@ describe('GpgBadges', () => {
|
|||
});
|
||||
|
||||
it('displays a loading spinner', async () => {
|
||||
mock.onGet(dummyUrl).replyOnce(200);
|
||||
mock.onGet(dummyUrl).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
await GpgBadges.fetch();
|
||||
expect(document.querySelector('.js-loading-gpg-badge:empty')).toBe(null);
|
||||
|
|
@ -111,7 +112,7 @@ describe('GpgBadges', () => {
|
|||
});
|
||||
|
||||
it('replaces the loading spinner', async () => {
|
||||
mock.onGet(dummyUrl).replyOnce(200, dummyResponse);
|
||||
mock.onGet(dummyUrl).replyOnce(HTTP_STATUS_OK, dummyResponse);
|
||||
|
||||
await GpgBadges.fetch();
|
||||
expect(document.querySelector('.js-loading-gpg-badge')).toBe(null);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
|
|||
import InviteMembersBanner from '~/groups/components/invite_members_banner.vue';
|
||||
import eventHub from '~/invite_members/event_hub';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
jest.mock('~/lib/utils/common_utils');
|
||||
|
||||
|
|
@ -89,7 +90,7 @@ describe('InviteMembersBanner', () => {
|
|||
|
||||
it('sends the dismissEvent when the banner is dismissed', () => {
|
||||
mockTrackingOnWrapper();
|
||||
mockAxios.onPost(provide.calloutsPath).replyOnce(200);
|
||||
mockAxios.onPost(provide.calloutsPath).replyOnce(HTTP_STATUS_OK);
|
||||
const dismissEvent = 'invite_members_banner_dismissed';
|
||||
|
||||
wrapper.findComponent(GlBanner).vm.$emit('close');
|
||||
|
|
@ -136,7 +137,7 @@ describe('InviteMembersBanner', () => {
|
|||
});
|
||||
|
||||
it('should close the banner when dismiss is clicked', async () => {
|
||||
mockAxios.onPost(provide.calloutsPath).replyOnce(200);
|
||||
mockAxios.onPost(provide.calloutsPath).replyOnce(HTTP_STATUS_OK);
|
||||
expect(wrapper.findComponent(GlBanner).exists()).toBe(true);
|
||||
wrapper.findComponent(GlBanner).vm.$emit('close');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { GlTable, GlIcon } from '@gitlab/ui';
|
||||
import { GlTable, GlIcon, GlLink } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { INTEGRATION_TYPE_SLACK } from '~/integrations/constants';
|
||||
import IntegrationsTable from '~/integrations/index/components/integrations_table.vue';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
|
||||
|
|
@ -10,12 +11,17 @@ describe('IntegrationsTable', () => {
|
|||
|
||||
const findTable = () => wrapper.findComponent(GlTable);
|
||||
|
||||
const createComponent = (propsData = {}) => {
|
||||
const createComponent = (propsData = {}, flagIsOn = false) => {
|
||||
wrapper = mount(IntegrationsTable, {
|
||||
propsData: {
|
||||
integrations: mockActiveIntegrations,
|
||||
...propsData,
|
||||
},
|
||||
provide: {
|
||||
glFeatures: {
|
||||
integrationSlackAppNotifications: flagIsOn,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -50,4 +56,51 @@ describe('IntegrationsTable', () => {
|
|||
expect(findTable().findComponent(GlIcon).exists()).toBe(shouldRenderActiveIcon);
|
||||
});
|
||||
});
|
||||
|
||||
describe('integrations filtering', () => {
|
||||
const slackActive = {
|
||||
...mockActiveIntegrations[0],
|
||||
name: INTEGRATION_TYPE_SLACK,
|
||||
title: 'Slack',
|
||||
};
|
||||
const slackInactive = {
|
||||
...mockInactiveIntegrations[0],
|
||||
name: INTEGRATION_TYPE_SLACK,
|
||||
title: 'Slack',
|
||||
};
|
||||
|
||||
describe.each`
|
||||
desc | flagIsOn | integrations | expectedIntegrations
|
||||
${'only active'} | ${false} | ${mockActiveIntegrations} | ${mockActiveIntegrations}
|
||||
${'only active'} | ${true} | ${mockActiveIntegrations} | ${mockActiveIntegrations}
|
||||
${'only inactive'} | ${true} | ${mockInactiveIntegrations} | ${mockInactiveIntegrations}
|
||||
${'only inactive'} | ${false} | ${mockInactiveIntegrations} | ${mockInactiveIntegrations}
|
||||
${'active and inactive'} | ${true} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]}
|
||||
${'active and inactive'} | ${false} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]}
|
||||
${'Slack active with active'} | ${false} | ${[slackActive, ...mockActiveIntegrations]} | ${[slackActive, ...mockActiveIntegrations]}
|
||||
${'Slack active with active'} | ${true} | ${[slackActive, ...mockActiveIntegrations]} | ${[slackActive, ...mockActiveIntegrations]}
|
||||
${'Slack active with inactive'} | ${false} | ${[slackActive, ...mockInactiveIntegrations]} | ${[slackActive, ...mockInactiveIntegrations]}
|
||||
${'Slack active with inactive'} | ${true} | ${[slackActive, ...mockInactiveIntegrations]} | ${[slackActive, ...mockInactiveIntegrations]}
|
||||
${'Slack inactive with active'} | ${false} | ${[slackInactive, ...mockActiveIntegrations]} | ${[slackInactive, ...mockActiveIntegrations]}
|
||||
${'Slack inactive with active'} | ${true} | ${[slackInactive, ...mockActiveIntegrations]} | ${mockActiveIntegrations}
|
||||
${'Slack inactive with inactive'} | ${false} | ${[slackInactive, ...mockInactiveIntegrations]} | ${[slackInactive, ...mockInactiveIntegrations]}
|
||||
${'Slack inactive with inactive'} | ${true} | ${[slackInactive, ...mockInactiveIntegrations]} | ${mockInactiveIntegrations}
|
||||
${'Slack active with active and inactive'} | ${true} | ${[slackActive, ...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[slackActive, ...mockActiveIntegrations, ...mockInactiveIntegrations]}
|
||||
${'Slack active with active and inactive'} | ${false} | ${[slackActive, ...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[slackActive, ...mockActiveIntegrations, ...mockInactiveIntegrations]}
|
||||
${'Slack inactive with active and inactive'} | ${true} | ${[slackInactive, ...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[...mockActiveIntegrations, ...mockInactiveIntegrations]}
|
||||
${'Slack inactive with active and inactive'} | ${false} | ${[slackInactive, ...mockActiveIntegrations, ...mockInactiveIntegrations]} | ${[slackInactive, ...mockActiveIntegrations, ...mockInactiveIntegrations]}
|
||||
`('when $desc and flag "$flagIsOn"', ({ flagIsOn, integrations, expectedIntegrations }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({ integrations }, flagIsOn);
|
||||
});
|
||||
|
||||
it('renders correctly', () => {
|
||||
const links = wrapper.findAllComponents(GlLink);
|
||||
expect(links).toHaveLength(expectedIntegrations.length);
|
||||
expectedIntegrations.forEach((integration, index) => {
|
||||
expect(links.at(index).text()).toBe(integration.title);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
import { nextTick } from 'vue';
|
||||
import { GlIcon, GlPopover, GlLink } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import TimelineEventsTagsPopover from '~/issues/show/components/incidents/timeline_events_tags_popover.vue';
|
||||
|
||||
describe('TimelineEventsTagsPopover component', () => {
|
||||
let wrapper;
|
||||
|
||||
const mountComponent = () => {
|
||||
wrapper = shallowMount(TimelineEventsTagsPopover, {
|
||||
stubs: {
|
||||
GlPopover,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
const findQuestionIcon = () => wrapper.findComponent(GlIcon);
|
||||
const findPopover = () => wrapper.findComponent(GlPopover);
|
||||
const findDocumentationLink = () => findPopover().findComponent(GlLink);
|
||||
|
||||
describe('question icon', () => {
|
||||
it('should open a popover with a link when hovered', async () => {
|
||||
findQuestionIcon().vm.$emit('hover');
|
||||
await nextTick();
|
||||
|
||||
expect(findPopover().exists()).toBe(true);
|
||||
expect(findDocumentationLink().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('documentation link', () => {
|
||||
it('redirects to a correct documentation page', async () => {
|
||||
findQuestionIcon().vm.$emit('hover');
|
||||
await nextTick();
|
||||
|
||||
expect(findDocumentationLink().attributes('href')).toBe(
|
||||
helpPagePath('/ee/operations/incident_management/incident_timeline_events', {
|
||||
anchor: 'incident-tags',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { ApolloLink, Observable } from '@apollo/client/core';
|
||||
import { StartupJSLink } from '~/lib/utils/apollo_startup_js_link';
|
||||
import { HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
|
||||
import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
describe('StartupJSLink', () => {
|
||||
const FORWARDED_RESPONSE = { data: 'FORWARDED_RESPONSE' };
|
||||
|
|
@ -38,7 +38,7 @@ describe('StartupJSLink', () => {
|
|||
let startupLink;
|
||||
let link;
|
||||
|
||||
function mockFetchCall(status = 200, response = STARTUP_JS_RESPONSE) {
|
||||
function mockFetchCall(status = HTTP_STATUS_OK, response = STARTUP_JS_RESPONSE) {
|
||||
const p = {
|
||||
ok: status >= 200 && status < 300,
|
||||
status,
|
||||
|
|
@ -210,7 +210,7 @@ describe('StartupJSLink', () => {
|
|||
window.gl = {
|
||||
startup_graphql_calls: [
|
||||
{
|
||||
fetchCall: mockFetchCall(200, ERROR_RESPONSE),
|
||||
fetchCall: mockFetchCall(HTTP_STATUS_OK, ERROR_RESPONSE),
|
||||
query: STARTUP_JS_QUERY,
|
||||
variables: { id: 3 },
|
||||
},
|
||||
|
|
@ -227,7 +227,7 @@ describe('StartupJSLink', () => {
|
|||
window.gl = {
|
||||
startup_graphql_calls: [
|
||||
{
|
||||
fetchCall: mockFetchCall(200, { 'no-data': 'yay' }),
|
||||
fetchCall: mockFetchCall(HTTP_STATUS_OK, { 'no-data': 'yay' }),
|
||||
query: STARTUP_JS_QUERY,
|
||||
variables: { id: 3 },
|
||||
},
|
||||
|
|
@ -340,7 +340,7 @@ describe('StartupJSLink', () => {
|
|||
variables: { id: 3 },
|
||||
},
|
||||
{
|
||||
fetchCall: mockFetchCall(200, STARTUP_JS_RESPONSE_TWO),
|
||||
fetchCall: mockFetchCall(HTTP_STATUS_OK, STARTUP_JS_RESPONSE_TWO),
|
||||
query: STARTUP_JS_QUERY_TWO,
|
||||
variables: { id: 3 },
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import setupAxiosStartupCalls from '~/lib/utils/axios_startup_calls';
|
||||
import { HTTP_STATUS_BAD_REQUEST } from '~/lib/utils/http_status';
|
||||
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
describe('setupAxiosStartupCalls', () => {
|
||||
const AXIOS_RESPONSE = { text: 'AXIOS_RESPONSE' };
|
||||
|
|
@ -32,9 +32,9 @@ describe('setupAxiosStartupCalls', () => {
|
|||
beforeEach(() => {
|
||||
window.gl = {};
|
||||
mock = new MockAdapter(axios);
|
||||
mock.onGet('/non-startup').reply(200, AXIOS_RESPONSE);
|
||||
mock.onGet('/startup').reply(200, AXIOS_RESPONSE);
|
||||
mock.onGet('/startup-failing').reply(200, AXIOS_RESPONSE);
|
||||
mock.onGet('/non-startup').reply(HTTP_STATUS_OK, AXIOS_RESPONSE);
|
||||
mock.onGet('/startup').reply(HTTP_STATUS_OK, AXIOS_RESPONSE);
|
||||
mock.onGet('/startup-failing').reply(HTTP_STATUS_OK, AXIOS_RESPONSE);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
@ -53,7 +53,7 @@ describe('setupAxiosStartupCalls', () => {
|
|||
beforeEach(() => {
|
||||
window.gl.startup_calls = {
|
||||
'/startup': {
|
||||
fetchCall: mockFetchCall(200),
|
||||
fetchCall: mockFetchCall(HTTP_STATUS_OK),
|
||||
},
|
||||
'/startup-failing': {
|
||||
fetchCall: mockFetchCall(HTTP_STATUS_BAD_REQUEST),
|
||||
|
|
@ -81,7 +81,7 @@ describe('setupAxiosStartupCalls', () => {
|
|||
const { headers, data, status, statusText } = await axios.get('/startup');
|
||||
|
||||
expect(headers).toEqual({ 'content-type': 'application/json' });
|
||||
expect(status).toBe(200);
|
||||
expect(status).toBe(HTTP_STATUS_OK);
|
||||
expect(statusText).toBe('MOCK-FETCH 200');
|
||||
expect(data).toEqual(STARTUP_JS_RESPONSE);
|
||||
expect(data).not.toEqual(AXIOS_RESPONSE);
|
||||
|
|
@ -127,7 +127,7 @@ describe('setupAxiosStartupCalls', () => {
|
|||
it('removes GitLab Base URL from startup call', async () => {
|
||||
window.gl.startup_calls = {
|
||||
'/startup': {
|
||||
fetchCall: mockFetchCall(200),
|
||||
fetchCall: mockFetchCall(HTTP_STATUS_OK),
|
||||
},
|
||||
};
|
||||
setupAxiosStartupCalls(axios);
|
||||
|
|
@ -140,7 +140,7 @@ describe('setupAxiosStartupCalls', () => {
|
|||
it('sorts the params in the requested API url', async () => {
|
||||
window.gl.startup_calls = {
|
||||
'/startup?alpha=true&bravo=true': {
|
||||
fetchCall: mockFetchCall(200),
|
||||
fetchCall: mockFetchCall(HTTP_STATUS_OK),
|
||||
},
|
||||
};
|
||||
setupAxiosStartupCalls(axios);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ describe('axios_utils', () => {
|
|||
|
||||
return axios.waitForAll().finally(() => {
|
||||
expect(handler).toHaveBeenCalledTimes(2);
|
||||
expect(handler.mock.calls[0][0].status).toBe(200);
|
||||
expect(handler.mock.calls[1][0].response.status).toBe(500);
|
||||
expect(handler.mock.calls[0][0].status).toBe(HTTP_STATUS_OK);
|
||||
expect(handler.mock.calls[1][0].response.status).toBe(HTTP_STATUS_INTERNAL_SERVER_ERROR);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ exports[`EmptyState shows gettingStarted state 1`] = `
|
|||
<!---->
|
||||
|
||||
<gl-empty-state-stub
|
||||
contentclass=""
|
||||
description="Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments."
|
||||
invertindarkmode="true"
|
||||
primarybuttonlink="/clustersPath"
|
||||
|
|
@ -22,6 +23,7 @@ exports[`EmptyState shows noData state 1`] = `
|
|||
<!---->
|
||||
|
||||
<gl-empty-state-stub
|
||||
contentclass=""
|
||||
description="You are connected to the Prometheus server, but there is currently no data to display."
|
||||
invertindarkmode="true"
|
||||
primarybuttonlink="/settingsPath"
|
||||
|
|
@ -39,6 +41,7 @@ exports[`EmptyState shows unableToConnect state 1`] = `
|
|||
<!---->
|
||||
|
||||
<gl-empty-state-stub
|
||||
contentclass=""
|
||||
description="Ensure connectivity is available from the GitLab server to the Prometheus server"
|
||||
invertindarkmode="true"
|
||||
primarybuttonlink="/documentationPath"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
exports[`GroupEmptyState given state BAD_QUERY passes the expected props to GlEmptyState 1`] = `
|
||||
Object {
|
||||
"compact": true,
|
||||
"contentClass": Array [],
|
||||
"description": null,
|
||||
"invertInDarkMode": true,
|
||||
"primaryButtonLink": "/path/to/settings",
|
||||
|
|
@ -31,6 +32,7 @@ exports[`GroupEmptyState given state BAD_QUERY renders the slotted content 1`] =
|
|||
exports[`GroupEmptyState given state CONNECTION_FAILED passes the expected props to GlEmptyState 1`] = `
|
||||
Object {
|
||||
"compact": true,
|
||||
"contentClass": Array [],
|
||||
"description": "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating.",
|
||||
"invertInDarkMode": true,
|
||||
"primaryButtonLink": "/path/to/settings",
|
||||
|
|
@ -48,6 +50,7 @@ exports[`GroupEmptyState given state CONNECTION_FAILED renders the slotted conte
|
|||
exports[`GroupEmptyState given state FOO STATE passes the expected props to GlEmptyState 1`] = `
|
||||
Object {
|
||||
"compact": true,
|
||||
"contentClass": Array [],
|
||||
"description": "An error occurred while loading the data. Please try again.",
|
||||
"invertInDarkMode": true,
|
||||
"primaryButtonLink": null,
|
||||
|
|
@ -65,6 +68,7 @@ exports[`GroupEmptyState given state FOO STATE renders the slotted content 1`] =
|
|||
exports[`GroupEmptyState given state LOADING passes the expected props to GlEmptyState 1`] = `
|
||||
Object {
|
||||
"compact": true,
|
||||
"contentClass": Array [],
|
||||
"description": "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available.",
|
||||
"invertInDarkMode": true,
|
||||
"primaryButtonLink": null,
|
||||
|
|
@ -82,6 +86,7 @@ exports[`GroupEmptyState given state LOADING renders the slotted content 1`] = `
|
|||
exports[`GroupEmptyState given state NO_DATA passes the expected props to GlEmptyState 1`] = `
|
||||
Object {
|
||||
"compact": true,
|
||||
"contentClass": Array [],
|
||||
"description": null,
|
||||
"invertInDarkMode": true,
|
||||
"primaryButtonLink": null,
|
||||
|
|
@ -110,6 +115,7 @@ exports[`GroupEmptyState given state NO_DATA renders the slotted content 1`] = `
|
|||
exports[`GroupEmptyState given state TIMEOUT passes the expected props to GlEmptyState 1`] = `
|
||||
Object {
|
||||
"compact": true,
|
||||
"contentClass": Array [],
|
||||
"description": null,
|
||||
"invertInDarkMode": true,
|
||||
"primaryButtonLink": null,
|
||||
|
|
@ -138,6 +144,7 @@ exports[`GroupEmptyState given state TIMEOUT renders the slotted content 1`] = `
|
|||
exports[`GroupEmptyState given state UNKNOWN_ERROR passes the expected props to GlEmptyState 1`] = `
|
||||
Object {
|
||||
"compact": true,
|
||||
"contentClass": Array [],
|
||||
"description": "An error occurred while loading the data. Please try again.",
|
||||
"invertInDarkMode": true,
|
||||
"primaryButtonLink": null,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { EVENT_ISSUABLE_VUE_APP_CHANGE } from '~/issuable/constants';
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import {
|
||||
HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||
HTTP_STATUS_OK,
|
||||
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
||||
} from '~/lib/utils/http_status';
|
||||
import * as notesConstants from '~/notes/constants';
|
||||
|
|
@ -179,7 +180,7 @@ describe('Actions Notes Store', () => {
|
|||
|
||||
describe('async methods', () => {
|
||||
beforeEach(() => {
|
||||
axiosMock.onAny().reply(200, {});
|
||||
axiosMock.onAny().reply(HTTP_STATUS_OK, {});
|
||||
});
|
||||
|
||||
describe('closeMergeRequest', () => {
|
||||
|
|
@ -253,7 +254,7 @@ describe('Actions Notes Store', () => {
|
|||
const pollResponse = { notes: [], last_fetched_at: '123456' };
|
||||
const pollHeaders = { 'poll-interval': `${pollInterval}` };
|
||||
const successMock = () =>
|
||||
axiosMock.onGet(notesDataMock.notesPath).reply(200, pollResponse, pollHeaders);
|
||||
axiosMock.onGet(notesDataMock.notesPath).reply(HTTP_STATUS_OK, pollResponse, pollHeaders);
|
||||
const failureMock = () =>
|
||||
axiosMock.onGet(notesDataMock.notesPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
|
||||
const advanceAndRAF = async (time) => {
|
||||
|
|
@ -350,7 +351,7 @@ describe('Actions Notes Store', () => {
|
|||
.onGet(notesDataMock.notesPath)
|
||||
.replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR) // cause one error
|
||||
.onGet(notesDataMock.notesPath)
|
||||
.replyOnce(200, pollResponse, pollHeaders) // then a success
|
||||
.replyOnce(HTTP_STATUS_OK, pollResponse, pollHeaders) // then a success
|
||||
.onGet(notesDataMock.notesPath)
|
||||
.reply(HTTP_STATUS_INTERNAL_SERVER_ERROR); // and then more errors
|
||||
|
||||
|
|
@ -403,7 +404,7 @@ describe('Actions Notes Store', () => {
|
|||
const endpoint = `${TEST_HOST}/note`;
|
||||
|
||||
beforeEach(() => {
|
||||
axiosMock.onDelete(endpoint).replyOnce(200, {});
|
||||
axiosMock.onDelete(endpoint).replyOnce(HTTP_STATUS_OK, {});
|
||||
|
||||
document.body.dataset.page = '';
|
||||
});
|
||||
|
|
@ -472,7 +473,7 @@ describe('Actions Notes Store', () => {
|
|||
const endpoint = `${TEST_HOST}/note`;
|
||||
|
||||
beforeEach(() => {
|
||||
axiosMock.onDelete(endpoint).replyOnce(200, {});
|
||||
axiosMock.onDelete(endpoint).replyOnce(HTTP_STATUS_OK, {});
|
||||
|
||||
document.body.dataset.page = '';
|
||||
});
|
||||
|
|
@ -512,7 +513,7 @@ describe('Actions Notes Store', () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
axiosMock.onAny().reply(200, res);
|
||||
axiosMock.onAny().reply(HTTP_STATUS_OK, res);
|
||||
});
|
||||
|
||||
it('commits ADD_NEW_NOTE and dispatches updateMergeRequestWidget', () => {
|
||||
|
|
@ -547,7 +548,7 @@ describe('Actions Notes Store', () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
axiosMock.onAny().replyOnce(200, res);
|
||||
axiosMock.onAny().replyOnce(HTTP_STATUS_OK, res);
|
||||
});
|
||||
|
||||
it('does not commit ADD_NEW_NOTE or dispatch updateMergeRequestWidget', () => {
|
||||
|
|
@ -568,7 +569,7 @@ describe('Actions Notes Store', () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
axiosMock.onAny().reply(200, res);
|
||||
axiosMock.onAny().reply(HTTP_STATUS_OK, res);
|
||||
});
|
||||
|
||||
describe('as note', () => {
|
||||
|
|
@ -759,7 +760,7 @@ describe('Actions Notes Store', () => {
|
|||
|
||||
it('updates discussion if response contains disussion', () => {
|
||||
const discussion = { notes: [] };
|
||||
axiosMock.onAny().reply(200, { discussion });
|
||||
axiosMock.onAny().reply(HTTP_STATUS_OK, { discussion });
|
||||
|
||||
return testAction(
|
||||
actions.replyToDiscussion,
|
||||
|
|
@ -778,7 +779,7 @@ describe('Actions Notes Store', () => {
|
|||
|
||||
it('adds a reply to a discussion', () => {
|
||||
const res = {};
|
||||
axiosMock.onAny().reply(200, res);
|
||||
axiosMock.onAny().reply(HTTP_STATUS_OK, res);
|
||||
|
||||
return testAction(
|
||||
actions.replyToDiscussion,
|
||||
|
|
@ -1191,7 +1192,7 @@ describe('Actions Notes Store', () => {
|
|||
|
||||
describe('if response contains no errors', () => {
|
||||
it('dispatches requestDeleteDescriptionVersion', () => {
|
||||
axiosMock.onDelete(endpoint).replyOnce(200);
|
||||
axiosMock.onDelete(endpoint).replyOnce(HTTP_STATUS_OK);
|
||||
return testAction(
|
||||
actions.softDeleteDescriptionVersion,
|
||||
payload,
|
||||
|
|
@ -1443,7 +1444,7 @@ describe('Actions Notes Store', () => {
|
|||
});
|
||||
|
||||
it('updates the discussions and dispatches `updateResolvableDiscussionsCounts`', () => {
|
||||
axiosMock.onAny().reply(200, { discussion });
|
||||
axiosMock.onAny().reply(HTTP_STATUS_OK, { discussion });
|
||||
return testAction(
|
||||
actions.fetchDiscussions,
|
||||
{},
|
||||
|
|
@ -1509,7 +1510,7 @@ describe('Actions Notes Store', () => {
|
|||
const actionPayload = { config, path: 'test-path', perPage: 20 };
|
||||
|
||||
it('updates the discussions and dispatches `updateResolvableDiscussionsCounts if there are no headers', () => {
|
||||
axiosMock.onAny().reply(200, { discussion }, {});
|
||||
axiosMock.onAny().reply(HTTP_STATUS_OK, { discussion }, {});
|
||||
return testAction(
|
||||
actions.fetchDiscussionsBatch,
|
||||
actionPayload,
|
||||
|
|
@ -1524,7 +1525,7 @@ describe('Actions Notes Store', () => {
|
|||
});
|
||||
|
||||
it('dispatches itself if there is `x-next-page-cursor` header', () => {
|
||||
axiosMock.onAny().reply(200, { discussion }, { 'x-next-page-cursor': 1 });
|
||||
axiosMock.onAny().reply(HTTP_STATUS_OK, { discussion }, { 'x-next-page-cursor': 1 });
|
||||
return testAction(
|
||||
actions.fetchDiscussionsBatch,
|
||||
actionPayload,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ exports[`packages_list_app renders 1`] = `
|
|||
|
||||
<div
|
||||
class="gl-max-w-full gl-m-auto"
|
||||
data-testid="gl-empty-state-content"
|
||||
>
|
||||
<div
|
||||
class="gl-mx-auto gl-my-0 gl-p-5"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import MockAdapter from 'axios-mock-adapter';
|
|||
import testAction from 'helpers/vuex_action_helper';
|
||||
import Api from '~/api';
|
||||
import { createAlert } from '~/flash';
|
||||
import { HTTP_STATUS_BAD_REQUEST } from '~/lib/utils/http_status';
|
||||
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { MISSING_DELETE_PATH_ERROR } from '~/packages_and_registries/infrastructure_registry/list/constants';
|
||||
import * as actions from '~/packages_and_registries/infrastructure_registry/list/stores/actions';
|
||||
import * as types from '~/packages_and_registries/infrastructure_registry/list/stores/mutation_types';
|
||||
|
|
@ -183,7 +183,7 @@ describe('Actions Package list store', () => {
|
|||
},
|
||||
};
|
||||
it('should perform a delete operation on _links.delete_api_path', () => {
|
||||
mock.onDelete(payload._links.delete_api_path).replyOnce(200);
|
||||
mock.onDelete(payload._links.delete_api_path).replyOnce(HTTP_STATUS_OK);
|
||||
Api.projectPackages = jest.fn().mockResolvedValue({ data: 'foo' });
|
||||
|
||||
return testAction(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
|
|||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import PersistentUserCallout from '~/persistent_user_callout';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
|
@ -88,7 +89,7 @@ describe('PersistentUserCallout', () => {
|
|||
${'primary'}
|
||||
${'secondary'}
|
||||
`('POSTs endpoint and removes container when clicking $button close', async ({ button }) => {
|
||||
mockAxios.onPost(dismissEndpoint).replyOnce(200);
|
||||
mockAxios.onPost(dismissEndpoint).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
buttons[button].click();
|
||||
|
||||
|
|
@ -140,7 +141,7 @@ describe('PersistentUserCallout', () => {
|
|||
|
||||
it('defers loading of a link until callout is dismissed', async () => {
|
||||
const { href, target } = deferredLink;
|
||||
mockAxios.onPost(dismissEndpoint).replyOnce(200);
|
||||
mockAxios.onPost(dismissEndpoint).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
deferredLink.click();
|
||||
|
||||
|
|
@ -161,7 +162,7 @@ describe('PersistentUserCallout', () => {
|
|||
});
|
||||
|
||||
it('does not follow link when notification is closed', async () => {
|
||||
mockAxios.onPost(dismissEndpoint).replyOnce(200);
|
||||
mockAxios.onPost(dismissEndpoint).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
button.click();
|
||||
|
||||
|
|
@ -195,7 +196,7 @@ describe('PersistentUserCallout', () => {
|
|||
|
||||
it('uses a link to trigger callout and defers following until callout is finished', async () => {
|
||||
const { href } = link;
|
||||
mockAxios.onPost(dismissEndpoint).replyOnce(200);
|
||||
mockAxios.onPost(dismissEndpoint).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
link.click();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import * as urlUtility from '~/lib/utils/url_utility';
|
||||
import SidebarService from '~/sidebar/services/sidebar_service';
|
||||
import SidebarMediator from '~/sidebar/sidebar_mediator';
|
||||
|
|
@ -36,10 +37,10 @@ describe('Sidebar mediator', () => {
|
|||
});
|
||||
|
||||
it('saves assignees', () => {
|
||||
mock.onPut(mediatorMockData.endpoint).reply(200, {});
|
||||
mock.onPut(mediatorMockData.endpoint).reply(HTTP_STATUS_OK, {});
|
||||
|
||||
return mediator.saveAssignees('issue[assignee_ids]').then((resp) => {
|
||||
expect(resp.status).toEqual(200);
|
||||
expect(resp.status).toEqual(HTTP_STATUS_OK);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -91,7 +92,7 @@ describe('Sidebar mediator', () => {
|
|||
|
||||
it('fetches the data', async () => {
|
||||
const mockData = Mock.responseMap.GET[mediatorMockData.endpoint];
|
||||
mock.onGet(mediatorMockData.endpoint).reply(200, mockData);
|
||||
mock.onGet(mediatorMockData.endpoint).reply(HTTP_STATUS_OK, mockData);
|
||||
const spy = jest.spyOn(mediator, 'processFetchedData').mockReturnValue(Promise.resolve());
|
||||
await mediator.fetch();
|
||||
|
||||
|
|
@ -120,7 +121,7 @@ describe('Sidebar mediator', () => {
|
|||
|
||||
it('fetches autocomplete projects', () => {
|
||||
const searchTerm = 'foo';
|
||||
mock.onGet(mediatorMockData.projectsAutocompleteEndpoint).reply(200, {});
|
||||
mock.onGet(mediatorMockData.projectsAutocompleteEndpoint).reply(HTTP_STATUS_OK, {});
|
||||
const getterSpy = jest
|
||||
.spyOn(mediator.service, 'getProjectsAutocomplete')
|
||||
.mockReturnValue(Promise.resolve({ data: {} }));
|
||||
|
|
@ -137,7 +138,7 @@ describe('Sidebar mediator', () => {
|
|||
it('moves issue', () => {
|
||||
const mockData = Mock.responseMap.POST[mediatorMockData.moveIssueEndpoint];
|
||||
const moveToProjectId = 7;
|
||||
mock.onPost(mediatorMockData.moveIssueEndpoint).reply(200, mockData);
|
||||
mock.onPost(mediatorMockData.moveIssueEndpoint).reply(HTTP_STATUS_OK, mockData);
|
||||
mediator.store.setMoveToProjectId(moveToProjectId);
|
||||
const moveIssueSpy = jest
|
||||
.spyOn(mediator.service, 'moveIssue')
|
||||
|
|
|
|||
|
|
@ -13,10 +13,6 @@ describe('Counter component', () => {
|
|||
label: __('Issues'),
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
const findButton = () => wrapper.find('button');
|
||||
const findIcon = () => wrapper.getComponent(GlIcon);
|
||||
const findLink = () => wrapper.find('a');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import { GlDisclosureDropdown } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { __ } from '~/locale';
|
||||
import CreateMenu from '~/super_sidebar/components/create_menu.vue';
|
||||
import { createNewMenuGroups } from '../mock_data';
|
||||
|
||||
describe('CreateMenu component', () => {
|
||||
let wrapper;
|
||||
|
||||
const findGlDisclosureDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
|
||||
|
||||
const createWrapper = () => {
|
||||
wrapper = shallowMountExtended(CreateMenu, {
|
||||
propsData: {
|
||||
groups: createNewMenuGroups,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
describe('default', () => {
|
||||
beforeEach(() => {
|
||||
createWrapper();
|
||||
});
|
||||
|
||||
it("sets the toggle's label", () => {
|
||||
expect(findGlDisclosureDropdown().props('toggleText')).toBe(__('Create new...'));
|
||||
});
|
||||
|
||||
it('passes the groups to the disclosure dropdown', () => {
|
||||
expect(findGlDisclosureDropdown().props('items')).toBe(createNewMenuGroups);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -8,10 +8,6 @@ describe('SuperSidebar component', () => {
|
|||
|
||||
const findUserBar = () => wrapper.findComponent(UserBar);
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
const createWrapper = (props = {}) => {
|
||||
wrapper = shallowMountExtended(SuperSidebar, {
|
||||
propsData: {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { __ } from '~/locale';
|
||||
import CreateMenu from '~/super_sidebar/components/create_menu.vue';
|
||||
import Counter from '~/super_sidebar/components/counter.vue';
|
||||
import UserBar from '~/super_sidebar/components/user_bar.vue';
|
||||
import { sidebarData } from '../mock_data';
|
||||
|
|
@ -7,12 +8,9 @@ import { sidebarData } from '../mock_data';
|
|||
describe('UserBar component', () => {
|
||||
let wrapper;
|
||||
|
||||
const findCreateMenu = () => wrapper.findComponent(CreateMenu);
|
||||
const findCounter = (at) => wrapper.findAllComponents(Counter).at(at);
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
const createWrapper = (props = {}) => {
|
||||
wrapper = shallowMountExtended(UserBar, {
|
||||
propsData: {
|
||||
|
|
@ -31,6 +29,10 @@ describe('UserBar component', () => {
|
|||
createWrapper();
|
||||
});
|
||||
|
||||
it('passes the "Create new..." menu groups to the create-menu component', () => {
|
||||
expect(findCreateMenu().props('groups')).toBe(sidebarData.create_new_menu_groups);
|
||||
});
|
||||
|
||||
it('renders issues counter', () => {
|
||||
expect(findCounter(0).props('count')).toBe(sidebarData.assigned_open_issues_count);
|
||||
expect(findCounter(0).props('href')).toBe(sidebarData.issues_dashboard_path);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,44 @@
|
|||
export const createNewMenuGroups = [
|
||||
{
|
||||
name: 'This group',
|
||||
items: [
|
||||
{
|
||||
text: 'New project/repository',
|
||||
href: '/projects/new?namespace_id=22',
|
||||
},
|
||||
{
|
||||
text: 'New subgroup',
|
||||
href: '/groups/new?parent_id=22#create-group-pane',
|
||||
},
|
||||
{
|
||||
text: 'New epic',
|
||||
href: '/groups/gitlab-org/-/epics/new',
|
||||
},
|
||||
{
|
||||
text: 'Invite members',
|
||||
href: '/groups/gitlab-org/-/group_members',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'GitLab',
|
||||
items: [
|
||||
{
|
||||
text: 'New project/repository',
|
||||
href: '/projects/new',
|
||||
},
|
||||
{
|
||||
text: 'New group',
|
||||
href: '/groups/new',
|
||||
},
|
||||
{
|
||||
text: 'New snippet',
|
||||
href: '/-/snippets/new',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const sidebarData = {
|
||||
name: 'Administrator',
|
||||
username: 'root',
|
||||
|
|
@ -6,4 +47,5 @@ export const sidebarData = {
|
|||
assigned_open_merge_requests_count: 2,
|
||||
todos_pending_count: 3,
|
||||
issues_dashboard_path: 'path/to/issues',
|
||||
create_new_menu_groups: createNewMenuGroups,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import dismissibleContainer from '~/vue_shared/components/dismissible_container.vue';
|
||||
|
||||
describe('DismissibleContainer', () => {
|
||||
|
|
@ -28,7 +29,7 @@ describe('DismissibleContainer', () => {
|
|||
});
|
||||
|
||||
it('successfully dismisses', () => {
|
||||
mockAxios.onPost(propsData.path).replyOnce(200);
|
||||
mockAxios.onPost(propsData.path).replyOnce(HTTP_STATUS_OK);
|
||||
const button = findBtn();
|
||||
|
||||
button.trigger('click');
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ RSpec.describe Types::Ci::JobType do
|
|||
detailedStatus
|
||||
duration
|
||||
downstreamPipeline
|
||||
erasedAt
|
||||
finished_at
|
||||
id
|
||||
kind
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ RSpec.describe ApplicationHelper do
|
|||
|
||||
describe '#support_url' do
|
||||
context 'when alternate support url is specified' do
|
||||
let(:alternate_url) { 'http://company.example.com/getting-help' }
|
||||
let(:alternate_url) { 'http://company.example.com/get-help' }
|
||||
|
||||
it 'returns the alternate support url' do
|
||||
stub_application_setting(help_page_support_url: alternate_url)
|
||||
|
|
@ -222,7 +222,7 @@ RSpec.describe ApplicationHelper do
|
|||
|
||||
context 'when alternate support url is not specified' do
|
||||
it 'builds the support url from the promo_url' do
|
||||
expect(helper.support_url).to eq(helper.promo_url + '/getting-help/')
|
||||
expect(helper.support_url).to eq(helper.promo_url + '/get-help/')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
it 'has project menu item' do
|
||||
expect(subject[:menu_sections]).to eq(
|
||||
expected_menu_section(
|
||||
title: _('GitLab'),
|
||||
title: _('In GitLab'),
|
||||
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
|
||||
id: 'general_new_project',
|
||||
title: 'New project/repository',
|
||||
|
|
@ -95,7 +95,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
it 'has group menu item' do
|
||||
expect(subject[:menu_sections]).to eq(
|
||||
expected_menu_section(
|
||||
title: _('GitLab'),
|
||||
title: _('In GitLab'),
|
||||
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
|
||||
id: 'general_new_group',
|
||||
title: 'New group',
|
||||
|
|
@ -113,7 +113,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
it 'has new snippet menu item' do
|
||||
expect(subject[:menu_sections]).to eq(
|
||||
expected_menu_section(
|
||||
title: _('GitLab'),
|
||||
title: _('In GitLab'),
|
||||
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
|
||||
id: 'general_new_snippet',
|
||||
title: 'New snippet',
|
||||
|
|
@ -151,7 +151,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
it 'has new project menu item' do
|
||||
expect(subject[:menu_sections]).to eq(
|
||||
expected_menu_section(
|
||||
title: 'This group',
|
||||
title: 'In this group',
|
||||
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
|
||||
id: 'new_project',
|
||||
title: 'New project/repository',
|
||||
|
|
@ -169,7 +169,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
it 'has new subgroup menu item' do
|
||||
expect(subject[:menu_sections]).to eq(
|
||||
expected_menu_section(
|
||||
title: 'This group',
|
||||
title: 'In this group',
|
||||
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
|
||||
id: 'new_subgroup',
|
||||
title: 'New subgroup',
|
||||
|
|
@ -184,7 +184,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
context 'when can invite members' do
|
||||
let(:with_can_admin_in_group) { true }
|
||||
let(:with_invite_members_experiment) { true }
|
||||
let(:expected_title) { 'This group' }
|
||||
let(:expected_title) { 'In this group' }
|
||||
let(:expected_href) { "/groups/#{group.full_path}/-/group_members" }
|
||||
|
||||
it_behaves_like 'invite member link shared example'
|
||||
|
|
@ -218,7 +218,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
it 'shows new issue menu item' do
|
||||
expect(subject[:menu_sections]).to eq(
|
||||
expected_menu_section(
|
||||
title: 'This project',
|
||||
title: 'In this project',
|
||||
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
|
||||
id: 'new_issue',
|
||||
title: 'New issue',
|
||||
|
|
@ -236,7 +236,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
it 'shows merge project' do
|
||||
expect(subject[:menu_sections]).to eq(
|
||||
expected_menu_section(
|
||||
title: 'This project',
|
||||
title: 'In this project',
|
||||
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
|
||||
id: 'new_mr',
|
||||
title: 'New merge request',
|
||||
|
|
@ -254,7 +254,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
it 'shows new snippet' do
|
||||
expect(subject[:menu_sections]).to eq(
|
||||
expected_menu_section(
|
||||
title: 'This project',
|
||||
title: 'In this project',
|
||||
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
|
||||
id: 'new_snippet',
|
||||
title: 'New snippet',
|
||||
|
|
@ -269,7 +269,7 @@ RSpec.describe Nav::NewDropdownHelper do
|
|||
context 'when invite members experiment' do
|
||||
let(:with_invite_members_experiment) { true }
|
||||
let(:with_can_admin_project_member) { true }
|
||||
let(:expected_title) { 'This project' }
|
||||
let(:expected_title) { 'In this project' }
|
||||
let(:expected_href) { "/#{project.path_with_namespace}/-/project_members" }
|
||||
|
||||
it_behaves_like 'invite member link shared example'
|
||||
|
|
|
|||
|
|
@ -47,15 +47,19 @@ RSpec.describe SidebarsHelper do
|
|||
|
||||
describe '#super_sidebar_context' do
|
||||
let(:user) { build(:user) }
|
||||
let(:group) { build(:group) }
|
||||
|
||||
subject { helper.super_sidebar_context(user) }
|
||||
subject { helper.super_sidebar_context(user, group: group, project: nil) }
|
||||
|
||||
it 'returns sidebar values from user', :use_clean_rails_memory_store_caching do
|
||||
before do
|
||||
allow(helper).to receive(:current_user) { user }
|
||||
Rails.cache.write(['users', user.id, 'assigned_open_issues_count'], 1)
|
||||
Rails.cache.write(['users', user.id, 'assigned_open_merge_requests_count'], 2)
|
||||
Rails.cache.write(['users', user.id, 'todos_pending_count'], 3)
|
||||
end
|
||||
|
||||
expect(subject).to eq({
|
||||
it 'returns sidebar values from user', :use_clean_rails_memory_store_caching do
|
||||
expect(subject).to include({
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
avatar_url: user.avatar_url,
|
||||
|
|
@ -65,5 +69,42 @@ RSpec.describe SidebarsHelper do
|
|||
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username)
|
||||
})
|
||||
end
|
||||
|
||||
it 'returns "Create new" menu groups without headers', :use_clean_rails_memory_store_caching do
|
||||
expect(subject[:create_new_menu_groups]).to eq([
|
||||
{
|
||||
name: "",
|
||||
items: [
|
||||
{ href: "/projects/new", text: "New project/repository" },
|
||||
{ href: "/groups/new", text: "New group" },
|
||||
{ href: "/-/snippets/new", text: "New snippet" }
|
||||
]
|
||||
}
|
||||
])
|
||||
end
|
||||
|
||||
it 'returns "Create new" menu groups with headers', :use_clean_rails_memory_store_caching do
|
||||
allow(group).to receive(:persisted?).and_return(true)
|
||||
allow(helper).to receive(:can?).and_return(true)
|
||||
|
||||
expect(subject[:create_new_menu_groups]).to contain_exactly(
|
||||
a_hash_including(
|
||||
name: "In this group",
|
||||
items: array_including(
|
||||
{ href: "/projects/new", text: "New project/repository" },
|
||||
{ href: "/groups/new#create-group-pane", text: "New subgroup" },
|
||||
{ href: "/groups/#{group.full_path}/-/group_members", text: "Invite members" }
|
||||
)
|
||||
),
|
||||
a_hash_including(
|
||||
name: "In GitLab",
|
||||
items: array_including(
|
||||
{ href: "/projects/new", text: "New project/repository" },
|
||||
{ href: "/groups/new", text: "New group" },
|
||||
{ href: "/-/snippets/new", text: "New snippet" }
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ RSpec.describe API::Ci::Jobs, feature_category: :continuous_integration do
|
|||
|
||||
it 'returns specific job data' do
|
||||
expect(json_response['finished_at']).to be_nil
|
||||
expect(json_response['erased_at']).to be_nil
|
||||
end
|
||||
|
||||
it 'avoids N+1 queries', :skip_before_request do
|
||||
|
|
@ -651,6 +652,18 @@ RSpec.describe API::Ci::Jobs, feature_category: :continuous_integration do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when job is erased' do
|
||||
let(:job) do
|
||||
create(:ci_build, pipeline: pipeline, erased_at: Time.now)
|
||||
end
|
||||
|
||||
it 'returns specific job data' do
|
||||
get api("/projects/#{project.id}/jobs/#{job.id}", api_user)
|
||||
|
||||
expect(Time.parse(json_response['erased_at'])).to be_like_time(job.erased_at)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when trace artifact record exists with no stored file', :skip_before_request do
|
||||
before do
|
||||
create(:ci_job_artifact, :unarchived_trace_artifact, job: job, project: job.project)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ RSpec.shared_examples 'integration settings form' do
|
|||
it 'displays all the integrations' do
|
||||
aggregate_failures do
|
||||
integrations.each do |integration|
|
||||
stub_feature_flags(integration_slack_app_notifications: false)
|
||||
navigate_to_integration(integration)
|
||||
|
||||
page.within('form.integration-settings-form') do
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
require 'rake'
|
||||
|
||||
RSpec.describe 'gitlab:db namespace rake task', :silence_stdout do
|
||||
RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_category: :database do
|
||||
before :all do
|
||||
Rake.application.rake_require 'active_record/railties/databases'
|
||||
Rake.application.rake_require 'tasks/seed_fu'
|
||||
|
|
@ -352,6 +352,94 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'dictionary generate' do
|
||||
let(:db_config) { instance_double(ActiveRecord::DatabaseConfigurations::HashConfig, name: 'fake_db') }
|
||||
|
||||
let(:model) { ActiveRecord::Base }
|
||||
let(:connection) { model.connection }
|
||||
|
||||
let(:base_models) { { 'fake_db' => model }.with_indifferent_access }
|
||||
|
||||
let(:tables) { %w[table1] }
|
||||
let(:views) { %w[view1] }
|
||||
|
||||
let(:table_file_path) { 'db/docs/table1.yml' }
|
||||
let(:view_file_path) { 'db/docs/views/view1.yml' }
|
||||
|
||||
before do
|
||||
allow(Gitlab::Database).to receive(:db_config_for_connection).and_return(db_config)
|
||||
allow(Gitlab::Database).to receive(:database_base_models).and_return(base_models)
|
||||
|
||||
allow(connection).to receive(:tables).and_return(tables)
|
||||
allow(connection).to receive(:views).and_return(views)
|
||||
end
|
||||
|
||||
after do
|
||||
File.delete(table_file_path)
|
||||
File.delete(view_file_path)
|
||||
end
|
||||
|
||||
context 'when the dictionary files do not exist' do
|
||||
it 'generate the dictionary files' do
|
||||
run_rake_task('gitlab:db:dictionary:generate')
|
||||
|
||||
expect(File).to exist(File.join(table_file_path))
|
||||
expect(File).to exist(File.join(view_file_path))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the dictionary files already exist' do
|
||||
let(:table_class) do
|
||||
Class.new(ApplicationRecord) do
|
||||
self.table_name = 'table1'
|
||||
end
|
||||
end
|
||||
|
||||
let(:view_class) do
|
||||
Class.new(ApplicationRecord) do
|
||||
self.table_name = 'view1'
|
||||
end
|
||||
end
|
||||
|
||||
table_metadata = {
|
||||
'table_name' => 'table1',
|
||||
'classes' => [],
|
||||
'feature_categories' => [],
|
||||
'description' => nil,
|
||||
'introduced_by_url' => nil,
|
||||
'milestone' => 14.3
|
||||
}
|
||||
view_metadata = {
|
||||
'view_name' => 'view1',
|
||||
'classes' => [],
|
||||
'feature_categories' => [],
|
||||
'description' => nil,
|
||||
'introduced_by_url' => nil,
|
||||
'milestone' => 14.3
|
||||
}
|
||||
|
||||
before do
|
||||
stub_const('TableClass', table_class)
|
||||
stub_const('ViewClass', view_class)
|
||||
|
||||
File.write(table_file_path, table_metadata.to_yaml)
|
||||
File.write(view_file_path, view_metadata.to_yaml)
|
||||
|
||||
allow(model).to receive(:descendants).and_return([table_class, view_class])
|
||||
end
|
||||
|
||||
it 'update the dictionary content' do
|
||||
run_rake_task('gitlab:db:dictionary:generate')
|
||||
|
||||
table_metadata = YAML.safe_load(File.read(table_file_path))
|
||||
expect(table_metadata['classes']).to match_array(['TableClass'])
|
||||
|
||||
view_metadata = YAML.safe_load(File.read(view_file_path))
|
||||
expect(view_metadata['classes']).to match_array(['ViewClass'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unattended' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
|
|
|
|||
16
yarn.lock
16
yarn.lock
|
|
@ -1140,15 +1140,15 @@
|
|||
stylelint-declaration-strict-value "1.8.0"
|
||||
stylelint-scss "4.2.0"
|
||||
|
||||
"@gitlab/svgs@3.16.0":
|
||||
version "3.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.16.0.tgz#ba7f566c160bd408f3fce63b92bbf9d66a0e6a4d"
|
||||
integrity sha512-sL2D6yNxq4eT5go6d9k9QBbYyvlqWbxWUFB+Ty0/xxxx1ZaWlBs/PpGERgebPZ9uk5v4FIW1mI+Ra8ZVFBOjww==
|
||||
"@gitlab/svgs@3.17.0":
|
||||
version "3.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.17.0.tgz#beeda4bd2b97ec2637bebe1760dbe283d6a599ef"
|
||||
integrity sha512-+5wsh/FG7SSkUQjehROl+0nRgrg/XRNUa9h3LkxpksP0AXy4j6xuYuq+7xucDGJDdXo43tUftLc9w7u/SCmgQA==
|
||||
|
||||
"@gitlab/ui@52.11.0":
|
||||
version "52.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-52.11.0.tgz#a81f5e4901531fca3d2340cc17f1282d2370665c"
|
||||
integrity sha512-6ocP2GhIpaq4+Zf05n1nBoTckyHEYGf9KRs0CNyOyNoCe28fSTRX91KTdC4hcvam9IdQZY049X+tcG6bRxooCg==
|
||||
"@gitlab/ui@52.13.1":
|
||||
version "52.13.1"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-52.13.1.tgz#178854d01de1637240e60d06572ff01fc927bc5a"
|
||||
integrity sha512-TSS5ghAto0ZPGeVmucrrYgvfBBhesvvKm4wPz29MkQRv3yCUbTJ+emBgXLDECDvUZvZPfwomN6QqsyQzVezz5g==
|
||||
dependencies:
|
||||
"@popperjs/core" "^2.11.2"
|
||||
bootstrap-vue "2.20.1"
|
||||
|
|
|
|||
Loading…
Reference in New Issue