Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-08-16 18:10:51 +00:00
parent d872c89ce4
commit e684f438e6
60 changed files with 786 additions and 169 deletions

View file

@ -5,17 +5,17 @@ import { clamp } from '../services/utils';
export const tableContentType = 'table';
const MIN_ROWS = 3;
const MIN_COLS = 3;
const MAX_ROWS = 8;
const MAX_COLS = 8;
const MIN_ROWS = 5;
const MIN_COLS = 5;
const MAX_ROWS = 10;
const MAX_COLS = 10;
export default {
components: {
GlButton,
GlDropdown,
GlDropdownDivider,
GlDropdownForm,
GlButton,
},
inject: ['tiptapEditor'],
data() {
@ -62,22 +62,22 @@ export default {
};
</script>
<template>
<gl-dropdown size="small" category="tertiary" icon="table">
<gl-dropdown-form class="gl-px-3! gl-w-auto!">
<div class="gl-w-auto!">
<div v-for="r of list(maxRows)" :key="r" class="gl-display-flex">
<gl-button
v-for="c of list(maxCols)"
:key="c"
:data-testid="`table-${r}-${c}`"
:class="{ 'gl-bg-blue-50!': r <= rows && c <= cols }"
:aria-label="getButtonLabel(r, c)"
class="gl-display-inline! gl-px-0! gl-w-5! gl-h-5! gl-rounded-0!"
@mouseover="setRowsAndCols(r, c)"
@click="insertTable()"
/>
</div>
<gl-dropdown-divider />
<gl-dropdown size="small" category="tertiary" icon="table" class="table-dropdown">
<gl-dropdown-form class="gl-px-3!">
<div v-for="r of list(maxRows)" :key="r" class="gl-display-flex">
<gl-button
v-for="c of list(maxCols)"
:key="c"
:data-testid="`table-${r}-${c}`"
:class="{ 'active gl-bg-blue-50!': r <= rows && c <= cols }"
:aria-label="getButtonLabel(r, c)"
class="table-creator-grid-item gl-display-inline gl-rounded-0! gl-w-6! gl-h-6! gl-p-0!"
@mouseover="setRowsAndCols(r, c)"
@click="insertTable()"
/>
</div>
<gl-dropdown-divider class="gl-my-3! gl-mx-n3!" />
<div class="gl-px-1">
{{ getButtonLabel(rows, cols) }}
</div>
</gl-dropdown-form>

View file

@ -0,0 +1,10 @@
import axios from '~/lib/utils/axios_utils';
export const fetchOverrides = (overridesPath, { page, perPage }) => {
return axios.get(overridesPath, {
params: {
page,
per_page: perPage,
},
});
};

View file

@ -1,15 +1,127 @@
<script>
import { GlLink, GlLoadingIcon, GlPagination, GlTable } from '@gitlab/ui';
import { DEFAULT_PER_PAGE } from '~/api';
import createFlash from '~/flash';
import { fetchOverrides } from '~/integrations/overrides/api';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { truncateNamespace } from '~/lib/utils/text_utility';
import { __, s__ } from '~/locale';
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
export default {
name: 'IntegrationOverrides',
components: {
GlLink,
GlLoadingIcon,
GlPagination,
GlTable,
ProjectAvatar,
},
props: {
overridesPath: {
type: String,
required: true,
},
},
fields: [
{
key: 'name',
label: __('Project'),
},
],
data() {
return {
isLoading: true,
overrides: [],
page: 1,
totalItems: 0,
};
},
computed: {
showPagination() {
return this.totalItems > this.$options.DEFAULT_PER_PAGE && this.overrides.length > 0;
},
},
mounted() {
this.loadOverrides();
},
methods: {
loadOverrides(page = this.page) {
this.isLoading = true;
fetchOverrides(this.overridesPath, {
page,
perPage: this.$options.DEFAULT_PER_PAGE,
})
.then(({ data, headers }) => {
const { page: newPage, total } = parseIntPagination(normalizeHeaders(headers));
this.page = newPage;
this.totalItems = total;
this.overrides = data;
})
.catch((error) => {
createFlash({
message: this.$options.i18n.defaultErrorMessage,
error,
captureError: true,
});
})
.finally(() => {
this.isLoading = false;
});
},
truncateNamespace,
},
DEFAULT_PER_PAGE,
i18n: {
defaultErrorMessage: s__(
'Integrations|An error occurred while loading projects using custom settings.',
),
tableEmptyText: s__('Integrations|There are no projects using custom settings'),
},
};
</script>
<template>
<div></div>
<div>
<gl-table
:items="overrides"
:fields="$options.fields"
:busy="isLoading"
show-empty
:empty-text="$options.i18n.tableEmptyText"
>
<template #cell(name)="{ item }">
<gl-link
class="gl-display-inline-flex gl-align-items-center gl-hover-text-decoration-none gl-text-body!"
:href="item.full_path"
>
<project-avatar
class="gl-mr-3"
:project-avatar-url="item.avatar_url"
:project-name="item.name"
aria-hidden="true"
/>
{{ truncateNamespace(item.full_name) }} /&nbsp;
<strong>{{ item.name }}</strong>
</gl-link>
</template>
<template #table-busy>
<gl-loading-icon size="md" class="gl-my-2" />
</template>
</gl-table>
<div class="gl-display-flex gl-justify-content-center gl-mt-5">
<gl-pagination
v-if="showPagination"
:per-page="$options.DEFAULT_PER_PAGE"
:total-items="totalItems"
:value="page"
:disabled="isLoading"
@input="loadOverrides"
/>
</div>
</div>
</template>

View file

@ -2,10 +2,12 @@
import { GlLink, GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { isEmpty } from 'lodash';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
export default {
components: {
CiIcon,
clipboardButton,
GlDropdown,
GlDropdownItem,
GlLink,
@ -45,7 +47,7 @@ export default {
<template>
<div class="dropdown">
<div class="js-pipeline-info" data-testid="pipeline-info">
<ci-icon :status="pipeline.details.status" class="vertical-align-middle" />
<ci-icon :status="pipeline.details.status" />
<span class="font-weight-bold">{{ s__('Job|Pipeline') }}</span>
<gl-link
@ -85,7 +87,14 @@ export default {
</template>
<gl-link v-else :href="pipeline.ref.path" class="link-commit ref-name">{{
pipeline.ref.name
}}</gl-link>
}}</gl-link
><clipboard-button
:text="pipeline.ref.name"
:title="__('Copy reference')"
category="tertiary"
size="small"
data-testid="copy-source-ref-link"
/>
</template>
</div>

View file

@ -14,6 +14,11 @@ export default {
type: Object,
required: true,
},
noteIsConfidential: {
type: Boolean,
required: false,
default: false,
},
noteableType: {
type: String,
required: false,
@ -38,6 +43,9 @@ export default {
emailParticipants() {
return this.noteableData.issue_email_participants?.map(({ email }) => email) || [];
},
showEmailParticipantsWarning() {
return this.emailParticipants.length && !this.noteIsConfidential;
},
},
};
</script>
@ -61,7 +69,7 @@ export default {
/>
<slot></slot>
<email-participants-warning
v-if="emailParticipants.length"
v-if="showEmailParticipantsWarning"
class="gl-border-t-1 gl-border-t-solid gl-border-t-gray-100 gl-rounded-base gl-rounded-top-left-none! gl-rounded-top-right-none!"
:emails="emailParticipants"
/>

View file

@ -380,6 +380,7 @@ export default {
<comment-field-layout
:with-alert-container="true"
:noteable-data="getNoteableData"
:note-is-confidential="noteIsConfidential"
:noteable-type="noteableType"
>
<markdown-field

View file

@ -326,7 +326,10 @@ export default {
></div>
<div class="flash-container timeline-content"></div>
<form :data-line-code="lineCode" class="edit-note common-note-form js-quick-submit gfm-form">
<comment-field-layout :noteable-data="getNoteableData">
<comment-field-layout
:noteable-data="getNoteableData"
:note-is-confidential="discussion.confidential"
>
<markdown-field
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"

View file

@ -1,6 +1,6 @@
<script>
/* eslint-disable vue/no-v-html */
import { s__ } from '~/locale';
import { s__, n__ } from '~/locale';
export default {
name: 'MRWidgetRelatedLinks',
@ -24,7 +24,8 @@ export default {
if (this.state === 'closed') {
return s__('mrWidget|Did not close');
}
return s__('mrWidget|Closes');
return n__('mrWidget|Closes issue', 'mrWidget|Closes issues', this.relatedLinks.closingCount);
},
},
};
@ -33,7 +34,8 @@ export default {
<section class="mr-info-list gl-ml-7 gl-pb-5">
<p v-if="relatedLinks.closing">{{ closesText }} <span v-html="relatedLinks.closing"></span></p>
<p v-if="relatedLinks.mentioned">
{{ s__('mrWidget|Mentions') }} <span v-html="relatedLinks.mentioned"></span>
{{ n__('mrWidget|Mentions issue', 'mrWidget|Mentions issues', relatedLinks.mentionedCount) }}
<span v-html="relatedLinks.mentioned"></span>
</p>
<p v-if="relatedLinks.assignToMe"><span v-html="relatedLinks.assignToMe"></span></p>
</section>

View file

@ -72,7 +72,13 @@ export default class MergeRequestStore {
const assignToMe = links.assign_to_closing;
if (closing || mentioned || assignToMe) {
this.relatedLinks = { closing, mentioned, assignToMe };
this.relatedLinks = {
closing,
mentioned,
assignToMe,
closingCount: links.closing_count,
mentionedCount: links.mentioned_count,
};
}
}

View file

@ -35,3 +35,22 @@
}
}
}
.table-creator-grid-item {
box-shadow: inset 0 0 0 $gl-spacing-scale-2 $white,
inset $gl-spacing-scale-1 $gl-spacing-scale-1 0 #{$gl-spacing-scale-2 * 3 / 4} $gray-100,
inset #{-$gl-spacing-scale-1} #{-$gl-spacing-scale-1} 0 #{$gl-spacing-scale-2 * 3 / 4} $gray-100 !important;
&.active {
box-shadow: inset 0 0 0 $gl-spacing-scale-2 $white,
inset $gl-spacing-scale-1 $gl-spacing-scale-1 0 $gl-spacing-scale-2 $blue-500,
inset #{-$gl-spacing-scale-1} #{-$gl-spacing-scale-1} 0 $gl-spacing-scale-2 $blue-500 !important;
}
}
.table-dropdown .dropdown-menu {
@include gl-min-w-0;
@include gl-w-auto;
@include gl-white-space-nowrap;
}

View file

@ -26,8 +26,4 @@ class Admin::IntegrationsController < Admin::ApplicationController
def find_or_initialize_non_project_specific_integration(name)
Integration.find_or_initialize_non_project_specific_integration(name, instance: true)
end
def instance_level_integration_overrides?
Feature.enabled?(:instance_level_integration_overrides, default_enabled: :yaml)
end
end

View file

@ -24,7 +24,8 @@ module ClustersHelper
agent_docs_url: help_page_path('user/clusters/agent/index'),
install_docs_url: help_page_path('administration/clusters/kas'),
get_started_docs_url: help_page_path('user/clusters/agent/index', anchor: 'define-a-configuration-repository'),
integration_docs_url: help_page_path('user/clusters/agent/index', anchor: 'get-started-with-gitops-and-the-gitlab-agent')
integration_docs_url: help_page_path('user/clusters/agent/index', anchor: 'get-started-with-gitops-and-the-gitlab-agent'),
kas_address: Gitlab::Kas.external_url
}
end

View file

@ -125,6 +125,17 @@ module IntegrationsHelper
!Gitlab.com?
end
def integration_tabs(integration:)
[
{ key: 'edit', text: _('Settings'), href: scoped_edit_integration_path(integration) },
({ key: 'overrides', text: s_('Integrations|Projects using custom settings'), href: scoped_overrides_integration_path(integration) } if instance_level_integration_overrides?)
].compact
end
def instance_level_integration_overrides?
Feature.enabled?(:instance_level_integration_overrides, default_enabled: :yaml)
end
def jira_issue_breadcrumb_link(issue_reference)
link_to '', { class: 'gl-display-flex gl-align-items-center gl-white-space-nowrap' } do
icon = image_tag image_path('illustrations/logos/jira.svg'), width: 15, height: 15, class: 'gl-mr-2'

View file

@ -139,7 +139,6 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
def mentioned_issues_links
mentioned_issues = issues_mentioned_but_not_closing(current_user)
markdown(
issues_sentence(project, mentioned_issues),
pipeline: :gfm,
@ -239,6 +238,18 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
APPROVALS_WIDGET_BASE_TYPE
end
def closing_issues
strong_memoize(:closing_issues) do
visible_closing_issues_for(current_user)
end
end
def mentioned_issues
strong_memoize(:mentioned_issues) do
issues_mentioned_but_not_closing(current_user)
end
end
private
def cached_can_be_reverted?
@ -253,10 +264,6 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
# rubocop: enable CodeReuse/ServiceClass
end
def closing_issues
@closing_issues ||= visible_closing_issues_for(current_user)
end
def pipeline
@pipeline ||= actual_head_pipeline
end

View file

@ -110,9 +110,17 @@ class MergeRequestWidgetEntity < Grape::Entity
presenter(merge_request).closing_issues_links
end
expose :closing_count do |merge_request|
presenter(merge_request).closing_issues.size
end
expose :mentioned_but_not_closing do |merge_request|
presenter(merge_request).mentioned_issues_links
end
expose :mentioned_count do |merge_request|
presenter(merge_request).mentioned_issues.size
end
end
expose :codeclimate, if: -> (mr, _) { head_pipeline_downloadable_path_for_report_type(:codequality) } do

View file

@ -1,6 +1,3 @@
- if group_sidebar_link?(:wiki)
= render 'layouts/nav/sidebar/wiki_link', wiki_url: @group.wiki.web_url
- if group_sidebar_link?(:settings)
= nav_link(path: group_settings_nav_link_paths) do
= link_to edit_group_path(@group), class: 'has-sub-items' do

View file

@ -1,11 +0,0 @@
= nav_link(controller: :wikis) do
= link_to wiki_url, class: 'shortcuts-wiki', data: { qa_selector: 'wiki_link' } do
.nav-icon-container
= sprite_icon('book')
%span.nav-item-name
= _('Wiki')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :wikis, html_options: { class: "fly-out-top-item" } ) do
= link_to wiki_url do
%strong.fly-out-top-item-name
= _('Wiki')

View file

@ -1,7 +1,4 @@
- integration = local_assigns.fetch(:integration)
%h3.page-title
= integration.title
= form_for integration, as: :service, url: scoped_integration_path(integration), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'test-url' => scoped_test_integration_path(integration) } } do |form|
= render 'shared/service_settings', form: form, integration: integration

View file

@ -1,14 +1,18 @@
.tabs.gl-tabs
%div
%ul.nav.gl-tabs-nav{ role: 'tablist' }
%li.nav-item{ role: 'presentation' }
%a.nav-link.gl-tab-nav-item{ role: 'tab', href: scoped_edit_integration_path(integration) }
= _('Settings')
- active_tab = local_assigns.fetch(:active_tab, 'edit')
- active_classes = 'gl-tab-nav-item-active gl-tab-nav-item-active-indigo active'
- tabs = integration_tabs(integration: integration)
%li.nav-item{ role: 'presentation' }
%a.nav-link.gl-tab-nav-item.gl-tab-nav-item-active.gl-tab-nav-item-active-indigo.active{ role: 'tab', href: scoped_overrides_integration_path(integration) }
= s_('Integrations|Projects using custom settings')
- if tabs.length <= 1
= yield
- else
.tabs.gl-tabs
%div
%ul.nav.gl-tabs-nav{ role: 'tablist' }
- tabs.each do |tab|
%li.nav-item{ role: 'presentation' }
%a.nav-link.gl-tab-nav-item{ role: 'tab', class: (active_classes if tab[:key] == active_tab), href: tab[:href] }
= tab[:text]
.tab-content.gl-tab-content
.tab-pane.active{ role: 'tabpanel' }
= yield
.tab-content.gl-tab-content
.tab-pane.gl-pt-3.active{ role: 'tabpanel' }
= yield

View file

@ -3,4 +3,8 @@
- page_title @integration.title, _('Integrations')
- @content_class = 'limit-container-width' unless fluid_layout
= render 'shared/integrations/form', integration: @integration
%h3.page-title
= @integration.title
= render 'shared/integrations/tabs', integration: @integration, active_tab: 'edit' do
= render 'shared/integrations/form', integration: @integration

View file

@ -6,5 +6,5 @@
%h3.page-title
= @integration.title
= render 'shared/integrations/tabs', integration: @integration do
= render 'shared/integrations/tabs', integration: @integration, active_tab: 'overrides' do
.js-vue-integration-overrides{ data: integration_overrides_data(@integration) }

View file

@ -434,6 +434,21 @@ module Gitlab
end
end
# Load JH initializers under JH. Load ordering is:
# 1. prepend_helpers_path
# 2. before_zeitwerk
# 3. let_zeitwerk_take_over
# 4. move_initializers
# 5. load_config_initializers
# 6. load_jh_config_initializers
Gitlab.jh do
initializer :load_jh_config_initializers, after: :load_config_initializers do
Dir[Rails.root.join('jh/config/initializers/*.rb')].sort.each do |initializer|
load_config_initializer(initializer)
end
end
end
# Add assets for variants of GitLab. They should take precedence over CE.
# This means if multiple files exist, e.g.:
#

View file

@ -0,0 +1,48 @@
# frozen_string_literal: true
class UpdateTrialPlansCiDailyPipelineScheduleTriggers < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
PREMIUM_TRIAL = 'premium_trial'
ULTIMATE_TRIAL = 'ultimate_trial'
EVERY_5_MINUTES = (1.day.in_minutes / 5).to_i
class Plan < ActiveRecord::Base
self.table_name = 'plans'
self.inheritance_column = :_type_disabled
has_one :limits, class_name: 'PlanLimits'
end
class PlanLimits < ActiveRecord::Base
self.table_name = 'plan_limits'
self.inheritance_column = :_type_disabled
belongs_to :plan
end
def plan_limits_present?
premium_trial_plan = Plan.find_by(name: PREMIUM_TRIAL)
ultimate_trial_plan = Plan.find_by(name: ULTIMATE_TRIAL)
premium_trial_plan && premium_trial_plan.limits && ultimate_trial_plan && ultimate_trial_plan.limits
end
def up
return unless Gitlab.dev_env_or_com?
if plan_limits_present?
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', PREMIUM_TRIAL, EVERY_5_MINUTES)
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', ULTIMATE_TRIAL, EVERY_5_MINUTES)
end
end
def down
return unless Gitlab.dev_env_or_com?
if plan_limits_present?
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', PREMIUM_TRIAL, 0)
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', ULTIMATE_TRIAL, 0)
end
end
end

View file

@ -0,0 +1 @@
a63f878d89269eb8a2a3cc3b0c81d700861031a079a4a69b56d45d73c4c7946e

View file

@ -14,6 +14,7 @@ anonymized
Ansible
Anthos
Apdex
Apparmor
approvers
architected
architecting
@ -28,6 +29,7 @@ Atlassian
auditability
Auth0
Authentiq
Authy
autocomplete
autocompleted
autocompletes
@ -186,6 +188,7 @@ enum
enums
ETag
Excon
exfiltration
expirable
Facebook
failover
@ -202,6 +205,7 @@ Filebeat
Fio
firewalled
firewalling
fixup
Flawfinder
Flowdock
Fluentd
@ -246,6 +250,7 @@ Haswell
heatmap
heatmaps
Helm
Helmfile
Heroku
Herokuish
Hexo

View file

@ -35,6 +35,7 @@ to do that.
To remove the **primary** site:
1. [Remove all secondary Geo sites](remove_geo_site.md)
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. On the left sidebar, select **Geo > Nodes**.
1. Select **Remove** for the **primary** node.

View file

@ -11,6 +11,16 @@ Review this page for update instructions for your version. These steps
accompany the [general steps](updating_the_geo_nodes.md#general-update-steps)
for updating Geo nodes.
## Updating to GitLab 14.0/14.1
We found an issue where [Primary sites can not be removed from the UI](https://gitlab.com/gitlab-org/gitlab/-/issues/338231).
This bug only exists in the UI and does not block the removal of Primary sites using any other method.
### If you have already updated to an affected version and need to remove your Primary site
You can manually remove the Primary site by using the [Geo Nodes API](../../../api/geo_nodes.md#delete-a-geo-node).
## Updating to GitLab 13.12
We found an issue where [secondary nodes re-download all LFS files](https://gitlab.com/gitlab-org/gitlab/-/issues/334550) upon update. This bug:

View file

@ -146,7 +146,7 @@ Backups of GitLab databases and filesystems are taken every 24 hours, and are ke
- GitLab SaaS creates backups to ensure your data is secure, but you can't use these methods to export or back up your data yourself.
- Issues are stored in the database. They can't be stored in Git itself.
- You can use the project export option in:
- [The UI](../user/project/settings/import_export.md#exporting-a-project-and-its-data).
- [The UI](../user/project/settings/import_export.md#export-a-project-and-its-data).
- [The API](../api/project_import_export.md#schedule-an-export).
- [Group export](../user/group/settings/import_export.md) does *not* export the projects in it, but does export:
- Epics

View file

@ -466,7 +466,7 @@ sudo gitlab-rake cache:clear
### Export a repository
It's typically recommended to export a project through [the web interface](../../user/project/settings/import_export.md#exporting-a-project-and-its-data) or through [the API](../../api/project_import_export.md). In situations where this is not working as expected, it may be preferable to export a project directly via the Rails console:
It's typically recommended to export a project through [the web interface](../../user/project/settings/import_export.md#export-a-project-and-its-data) or through [the API](../../api/project_import_export.md). In situations where this is not working as expected, it may be preferable to export a project directly via the Rails console:
```ruby
user = User.find_by_username('USERNAME')

View file

@ -112,8 +112,8 @@ Supported attributes:
| Attribute | Type | Required | Description |
| :-------- | :------- | :------- | :---------- |
| `id` | datatype | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `sha` | datatype | yes | The blob SHA. |
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `sha` | string | yes | The blob SHA. |
## Get file archive

View file

@ -16,7 +16,7 @@ There are several ways to import a project.
### Importing via UI
The first option is to simply [import the Project tarball file via the GitLab UI](../user/project/settings/import_export.md#importing-the-project):
The first option is to simply [import the Project tarball file via the GitLab UI](../user/project/settings/import_export.md#import-the-project):
1. Create the group `qa-perf-testing`
1. Import the [GitLab FOSS project tarball](https://gitlab.com/gitlab-org/quality/performance-data/-/blob/master/projects_export/gitlabhq_export.tar.gz) into the Group.

View file

@ -27,10 +27,11 @@ Email notifications are available in projects for triggered alerts. Project
members with the **Owner** or **Maintainer** roles have the option to receive
a single email notification for new alerts.
1. Navigate to **Settings > Monitor**.
1. Expand the **Alerts** section.
1. In the **Integration settings** tab, select the checkbox
**Send a single email notification to Owners and Maintainers for new alerts**.
1. On the top bar, select **Menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Monitor**.
1. Expand **Alerts**.
1. On the **Alert settings** tab, select the
**Send a single email notification to Owners and Maintainers for new alerts** checkbox.
1. Select **Save changes**.
## Paging **(PREMIUM)**

View file

@ -39,19 +39,23 @@ To configure a GitLab Status Page you must:
Only AWS S3 is supported as a deploy target.
Prerequisite:
- You must have at least the Maintainer [role](../../user/permissions.md).
To provide GitLab with the AWS account information needed to push content to your Status Page:
1. Sign into GitLab as a user with Maintainer or greater [permissions](../../user/permissions.md).
1. Navigate to **{settings}** **Settings > Monitor**. Next to **Status Page**,
click **Expand**.
1. Click **Active** to enable the Status Page feature.
1. In **Status Page URL**, provide the URL to your external status page.
1. Provide the **S3 Bucket name**. For more information, see
1. On the top bar, select **Menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Monitor**.
1. Expand **Status Page**.
1. Select the **Active** checkbox.
1. In the **Status Page URL** box, provide the URL for your external status page.
1. In the **S3 Bucket name** box, type the name of your S3 bucket. For more information, see
[Bucket configuration documentation](https://docs.aws.amazon.com/AmazonS3/latest/dev/HostingWebsiteOnS3Setup.html).
1. Provide the **AWS region** for your bucket. For more information, see the
1. In the **AWS region** box, type the region for your bucket. For more information, see the
[AWS documentation](https://github.com/aws/aws-sdk-ruby#configuration).
1. Provide your **AWS access key ID** and **AWS Secret access key**.
1. Click **Save changes**.
1. Enter your **AWS access key ID** and **AWS Secret access key**.
1. Select **Save changes**.
### Configure your AWS account
@ -69,8 +73,8 @@ the necessary CI/CD variables to deploy the Status Page to AWS S3:
1. Fork the [Status Page](https://gitlab.com/gitlab-org/status-page) project.
You can do this through [Repository Mirroring](https://gitlab.com/gitlab-org/status-page#repository-mirroring),
which ensures you get the up-to-date Status Page features.
1. Navigate to **{settings}** **Settings > CI/CD**.
1. Scroll to **Variables**, and click **Expand**.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **Variables**.
1. Add the following variables from your Amazon Console:
- `S3_BUCKET_NAME` - The name of the Amazon S3 bucket.
If no bucket with the provided name exists, the first pipeline run creates
@ -80,8 +84,8 @@ the necessary CI/CD variables to deploy the Status Page to AWS S3:
- `AWS_DEFAULT_REGION` - The AWS region.
- `AWS_ACCESS_KEY_ID` - The AWS access key ID.
- `AWS_SECRET_ACCESS_KEY` - The AWS secret.
1. Navigate to **CI/CD > Pipelines > Run Pipeline**, and run the pipeline to
deploy the Status Page to S3.
1. On the left sidebar, select **CI/CD > Pipelines**.
1. To deploy the Status Page to S3, select **Run pipeline**.
WARNING:
Consider limiting who can access issues in this project, as any user who can view
@ -92,7 +96,9 @@ the issue can potentially [publish comments to your GitLab Status Page](#publish
After creating the CI/CD variables, configure the Project you want to use for
Incident issues:
1. To view the Status Page settings, navigate to **{settings}** **Settings > Monitor > Status Page**.
1. On the top bar, select **Menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Monitor**.
1. Expand **Status page**.
1. Fill in your cloud provider's credentials and make sure to select the **Active** checkbox.
1. Select **Save changes**.

View file

@ -44,7 +44,7 @@ feature is available.
> - DAST and SAST metrics [added](https://gitlab.com/gitlab-org/gitlab/-/issues/328033) in GitLab 14.1.
> - Fuzz Testing metrics [added](https://gitlab.com/gitlab-org/gitlab/-/issues/330398) in GitLab 14.2.
> - Dependency Scanning metrics [added](https://gitlab.com/gitlab-org/gitlab/-/issues/328034) in GitLab 14.2.
> - Multiselect [added](https://gitlab.com/gitlab-org/gitlab/-/issues/333586) in GitLab 14.2.
> - Multi-select [added](https://gitlab.com/gitlab-org/gitlab/-/issues/333586) in GitLab 14.2.
DevOps Adoption shows you which groups in your organization are using the most essential features of GitLab:

View file

@ -8,8 +8,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60933) in GitLab Free 13.12.
Federated Learning of Conhorts (FLoC) is a feature that the Chrome browser has
rolled out, where users are categorized into different cohorts, so that
Federated Learning of Cohorts (FLoC) is a new feature of the Chrome browser.
It works by categorizing users into different cohorts, so that
advertisers can use this data to uniquely target and track users. For more
information, visit the [FLoC repository](https://github.com/WICG/floc).

View file

@ -17,7 +17,7 @@ To change the note creation rate limit:
1. On the left sidebar, select **Settings > Network**.
1. Expand **Notes Rate Limits**.
1. Under **Max requests per minute per user**, enter the new value.
1. Optional. Under **List of users to be excluded from the limit**, list users to be excluded fromt the limit.
1. Optional. Under **List of users to be excluded from the limit**, list users to be excluded from the limit.
1. Select **Save changes**.
This limit is:

View file

@ -211,7 +211,7 @@ You can specify from which hosting sites users can [import their projects](../..
## Enable project export
To enable the export of
[projects and their data](../../../user/project/settings/import_export.md#exporting-a-project-and-its-data):
[projects and their data](../../../user/project/settings/import_export.md#export-a-project-and-its-data):
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu >** **{admin}** **Admin**.

View file

@ -124,9 +124,9 @@ From the previous example we see the time used for each stage:
- **Issue**: 2 hrs (09:00 to 11:00)
- **Plan**: 1 hr (11:00 to 12:00)
- **Code**: 2 hrs (12:00 to 14:00)
- **Test**: 5 mins
- **Test**: 5 minutes
- **Review**: 5 hrs (14:00 to 19:00)
- **Staging**: 30 mins (19:00 to 19:30)
- **Staging**: 30 minutes (19:00 to 19:30)
More information:

View file

@ -53,13 +53,13 @@ project. This image consists of a set of Bash utility scripts to support [Helm v
This file has a list of paths to other Helmfiles for each app. They're all commented out by default, so you must uncomment
the paths for the apps that you would like to manage.
By default, each `helmfile.yaml` in these sub-paths will have the attribute `installed: true`, which signifies that everytime
the pipeline runs, Helmfile will try to either install or update your apps according to the current state of your
cluster and Helm releases. If you change this attribute to `installed: false`, Helmfile will try to uninstall this app
By default, each `helmfile.yaml` in these sub-paths have the attribute `installed: true`. This signifies that every time
the pipeline runs, Helmfile tries to either install or update your apps according to the current state of your
cluster and Helm releases. If you change this attribute to `installed: false`, Helmfile tries try to uninstall this app
from your cluster. [Read more](https://github.com/roboll/helmfile) about how Helmfile works.
Furthermore, each app has an `applications/{app}/values.yaml` file. This is the
place where you can define some default values for your app's Helm chart. Some apps will already have defaults
place where you can define some default values for your app's Helm chart. Some apps already have defaults
pre-defined by GitLab.
#### Built-in applications
@ -80,7 +80,7 @@ The [built-in supported applications](https://gitlab.com/gitlab-org/project-temp
- [Sentry](../infrastructure/clusters/manage/management_project_applications/sentry.md)
- [Vault](../infrastructure/clusters/manage/management_project_applications/vault.md)
### Migrating from GitLab Managed Apps
### Migrate from GitLab Managed Apps
If you had GitLab Managed Apps, either One-Click or CI/CD install, read the docs on how to
[migrate from GitLab Managed Apps to project template](migrating_from_gma_to_project_template.md)

View file

@ -1,6 +1,6 @@
---
stage: Monitor
group: Health
group: Monitor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View file

@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Infrastructure management **(FREE)**
GitLab provides you with great solutions to help you manage your
infrastrucure:
infrastructure:
- [Infrastructure as Code and GitOps](iac/index.md)
- [Kubernetes clusters](../project/clusters/index.md)

View file

@ -42,8 +42,8 @@ providers. To host them on premises and with other providers,
use either the EKS or GKE method to guide you through and enter your cluster's
settings manually:
- [New cluster hosted on Google Kubernetes Engine (GKE)](add_eks_clusters.md).
- [New cluster hosted on Amazon Elastic Kubernetes Service (EKS)](add_gke_clusters.md).
- [New cluster hosted on Google Kubernetes Engine (GKE)](add_gke_clusters.md).
- [New cluster hosted on Amazon Elastic Kubernetes Service (EKS)](add_eks_clusters.md).
## Add existing cluster

View file

@ -15,7 +15,7 @@ To get to the importer page you need to go to "New project" page.
NOTE:
If you are interested in importing Wiki and Merge Request data to your new instance,
you'll need to follow the instructions for [exporting a project](../settings/import_export.md#exporting-a-project-and-its-data)
you'll need to follow the instructions for [exporting a project](../settings/import_export.md#export-a-project-and-its-data)
![New project page](img/gitlab_new_project_page_v12_2.png)

View file

@ -121,7 +121,7 @@ Kubernetes, Slack, and a lot more.
- [Bitbucket to GitLab](import/bitbucket.md)
- [Gitea to GitLab](import/gitea.md)
- [FogBugz to GitLab](import/fogbugz.md)
- [Export a project from GitLab](settings/import_export.md#exporting-a-project-and-its-data)
- [Export a project from GitLab](settings/import_export.md#export-a-project-and-its-data)
- [Importing and exporting projects between GitLab instances](settings/import_export.md)
## GitLab Workflow - VS Code extension

View file

@ -23,7 +23,7 @@ over [`git filter-branch`](https://git-scm.com/docs/git-filter-branch) and
WARNING:
Rewriting repository history is a destructive operation. Make sure to back up your repository before
you begin. The best way back up a repository is to
[export the project](../settings/import_export.md#exporting-a-project-and-its-data).
[export the project](../settings/import_export.md#export-a-project-and-its-data).
## Purge files from repository history
@ -44,7 +44,7 @@ To purge files from a GitLab repository:
using a supported package manager or from source.
1. Generate a fresh [export from the
project](../settings/import_export.html#exporting-a-project-and-its-data) and download it.
project](../settings/import_export.html#export-a-project-and-its-data) and download it.
This project export contains a backup copy of your repository *and* refs
we can use to purge files from your repository.

View file

@ -32,8 +32,8 @@ To set up a project import/export:
Note the following:
- Before you can import a project, you need to export the data first.
See [Exporting a project and its data](#exporting-a-project-and-its-data)
- Before you can import a project, you must export the data first.
See [Export a project and its data](#export-a-project-and-its-data)
for how you can export a project through the UI.
- Imports from a newer version of GitLab are not supported.
The Importing GitLab version must be greater than or equal to the Exporting GitLab version.
@ -42,7 +42,7 @@ Note the following:
- Exports are generated in your configured `shared_path`, a temporary shared directory,
and are moved to your configured `uploads_directory`. Every 24 hours, a specific worker deletes these export files.
- Group members are exported as project members, as long as the user has
maintainer or administrator access to the group where the exported project lives.
a maintainer or administrator role in the group where the exported project lives.
- Project members with the [Owner role](../../permissions.md) are imported as Maintainers.
- Imported users can be mapped by their primary email on self-managed instances, if an administrative user (not an owner) does the import.
Otherwise, a supplementary comment is left to mention that the original author and
@ -51,10 +51,10 @@ Note the following:
possible through a [professional services engagement](https://about.gitlab.com/services/migration/).
- If an imported project contains merge requests originating from forks,
then new branches associated with such merge requests are created
within a project during the import/export. Thus, the number of branches
in a project during the import/export. Thus, the number of branches
in the exported project could be bigger than in the original project.
- Deploy keys allowed to push to protected branches are not exported. Therefore,
you need to recreate this association by first enabling these deploy keys in your
you must recreate this association by first enabling these deploy keys in your
imported project and then updating your protected branches accordingly.
## Version history
@ -141,7 +141,7 @@ NOTE:
For more details on the specific data persisted in a project export, see the
[`import_export.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/import_export/project/import_export.yml) file.
## Exporting a project and its data
## Export a project and its data
Full project export functionality is limited to project maintainers and owners.
You can configure such functionality through [project settings](index.md):
@ -156,18 +156,18 @@ To export a project and its data, follow these steps:
![Export button](img/import_export_export_button.png)
1. Once the export is generated, you should receive an email with a link to
1. After the export is generated, you should receive an email with a link to
download the file:
![Email download link](img/import_export_mail_link.png)
1. Alternatively, you can come back to the project settings and download the
file from there, or generate a new export. Once the file is available, the page
file from there, or generate a new export. After the file is available, the page
should show the **Download export** button:
![Download export](img/import_export_download_export.png)
## Importing the project
## Import the project
1. The GitLab project import feature is the first import option when creating a
new project. Click on **GitLab export**:
@ -215,7 +215,7 @@ GitLab.com may have [different settings](../../gitlab_com/index.md#importexport)
### Import workaround for large repositories
[Maximum import size limitations](#importing-the-project)
[Maximum import size limitations](#import-the-project)
can prevent an import from being successful.
If changing the import limits is not possible,
the following local workflow can be used to temporarily

View file

@ -271,7 +271,7 @@ Enable [Service Desk](../service_desk.md) for your project to offer customer sup
### Export project
Learn how to [export a project](import_export.md#importing-the-project) in GitLab.
Learn how to [export a project](import_export.md#import-the-project) in GitLab.
### Advanced settings

View file

@ -7181,6 +7181,9 @@ msgstr ""
msgid "ClusterAgents|Go to the repository"
msgstr ""
msgid "ClusterAgents|Install a new GitLab Agent"
msgstr ""
msgid "ClusterAgents|Install new Agent"
msgstr ""
@ -7196,9 +7199,6 @@ msgstr ""
msgid "ClusterAgents|Learn how to create an agent access token"
msgstr ""
msgid "ClusterAgents|Learn more about installing the GitLab Agent"
msgstr ""
msgid "ClusterAgents|Name"
msgstr ""
@ -14966,13 +14966,10 @@ msgstr ""
msgid "Geo|Remove node"
msgstr ""
msgid "Geo|Remove secondary node"
msgstr ""
msgid "Geo|Remove tracking database entry"
msgstr ""
msgid "Geo|Removing a Geo secondary node stops the synchronization to that node. Are you sure?"
msgid "Geo|Removing a Geo node stops the synchronization to and from that node. Are you sure?"
msgstr ""
msgid "Geo|Replicated data is verified with the secondary node(s) using checksums"
@ -17912,6 +17909,9 @@ msgstr ""
msgid "Integrations|All projects inheriting these settings will also be reset."
msgstr ""
msgid "Integrations|An error occurred while loading projects using custom settings."
msgstr ""
msgid "Integrations|Browser limitations"
msgstr ""
@ -18032,6 +18032,9 @@ msgstr ""
msgid "Integrations|Standard"
msgstr ""
msgid "Integrations|There are no projects using custom settings"
msgstr ""
msgid "Integrations|This integration, and inheriting projects were reset."
msgstr ""
@ -39694,8 +39697,10 @@ msgstr ""
msgid "mrWidget|Closed by"
msgstr ""
msgid "mrWidget|Closes"
msgstr ""
msgid "mrWidget|Closes issue"
msgid_plural "mrWidget|Closes issues"
msgstr[0] ""
msgstr[1] ""
msgid "mrWidget|Delete source branch"
msgstr ""
@ -39730,8 +39735,10 @@ msgstr ""
msgid "mrWidget|Members who can merge are allowed to add commits."
msgstr ""
msgid "mrWidget|Mentions"
msgstr ""
msgid "mrWidget|Mentions issue"
msgid_plural "mrWidget|Mentions issues"
msgstr[0] ""
msgstr[1] ""
msgid "mrWidget|Merge"
msgstr ""

View file

@ -125,7 +125,7 @@
"dateformat": "^4.5.1",
"deckar01-task_list": "^2.3.1",
"diff": "^3.4.0",
"dompurify": "^2.3.0",
"dompurify": "^2.3.1",
"dropzone": "^4.2.0",
"editorconfig": "^0.15.3",
"emoji-regex": "^7.0.3",

View file

@ -11,6 +11,24 @@ RSpec.describe 'User activates the instance-level Mattermost Slash Command integ
end
let(:edit_path) { edit_admin_application_settings_integration_path(:mattermost_slash_commands) }
let(:overrides_path) { overrides_admin_application_settings_integration_path(:mattermost_slash_commands) }
include_examples 'user activates the Mattermost Slash Command integration'
it 'displays navigation tabs' do
expect(page).to have_link('Settings', href: edit_path)
expect(page).to have_link('Projects using custom settings', href: overrides_path)
end
context 'when instance_level_integration_overrides is disabled' do
before do
stub_feature_flags(instance_level_integration_overrides: false)
visit_instance_integration('Mattermost slash commands')
end
it 'does not display the overrides tab' do
expect(page).not_to have_link('Settings', href: edit_path)
expect(page).not_to have_link('Projects using custom settings', href: overrides_path)
end
end
end

View file

@ -31,7 +31,7 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_description) { "Description\n\nclosing #{issue_1.to_reference}, #{issue_2.to_reference}" }
it 'does not display closing issue message' do
expect(page).to have_content("Closes #{issue_1.to_reference} and #{issue_2.to_reference}")
expect(page).to have_content("Closes issues #{issue_1.to_reference} and #{issue_2.to_reference}")
end
end
@ -39,7 +39,7 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_description) { "Description\n\nRefers to #{issue_1.to_reference} and #{issue_2.to_reference}" }
it 'does not display closing issue message' do
expect(page).to have_content("Mentions #{issue_1.to_reference} and #{issue_2.to_reference}")
expect(page).to have_content("Mentions issues #{issue_1.to_reference} and #{issue_2.to_reference}")
end
end
@ -47,8 +47,8 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_title) { "closes #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" }
it 'does not display closing issue message' do
expect(page).to have_content("Closes #{issue_1.to_reference}")
expect(page).to have_content("Mentions #{issue_2.to_reference}")
expect(page).to have_content("Closes issue #{issue_1.to_reference}")
expect(page).to have_content("Mentions issue #{issue_2.to_reference}")
end
end
@ -56,7 +56,7 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_title) { "closing #{issue_1.to_reference}, #{issue_2.to_reference}" }
it 'does not display closing issue message' do
expect(page).to have_content("Closes #{issue_1.to_reference} and #{issue_2.to_reference}")
expect(page).to have_content("Closes issues #{issue_1.to_reference} and #{issue_2.to_reference}")
end
end
@ -64,7 +64,7 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_title) { "Refers to #{issue_1.to_reference} and #{issue_2.to_reference}" }
it 'does not display closing issue message' do
expect(page).to have_content("Mentions #{issue_1.to_reference} and #{issue_2.to_reference}")
expect(page).to have_content("Mentions issues #{issue_1.to_reference} and #{issue_2.to_reference}")
end
end
@ -72,8 +72,8 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_title) { "closes #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" }
it 'does not display closing issue message' do
expect(page).to have_content("Closes #{issue_1.to_reference}")
expect(page).to have_content("Mentions #{issue_2.to_reference}")
expect(page).to have_content("Closes issue #{issue_1.to_reference}")
expect(page).to have_content("Mentions issue #{issue_2.to_reference}")
end
end
end

View file

@ -29,17 +29,17 @@ describe('content_editor/components/toolbar_table_button', () => {
wrapper.destroy();
});
it('renders a grid of 3x3 buttons to create a table', () => {
expect(getNumButtons()).toBe(9); // 3 x 3
it('renders a grid of 5x5 buttons to create a table', () => {
expect(getNumButtons()).toBe(25); // 5x5
});
describe.each`
row | col | numButtons | tableSize
${1} | ${2} | ${9} | ${'1x2'}
${2} | ${2} | ${9} | ${'2x2'}
${2} | ${3} | ${12} | ${'2x3'}
${3} | ${2} | ${12} | ${'3x2'}
${3} | ${3} | ${16} | ${'3x3'}
${3} | ${4} | ${25} | ${'3x4'}
${4} | ${4} | ${25} | ${'4x4'}
${4} | ${5} | ${30} | ${'4x5'}
${5} | ${4} | ${30} | ${'5x4'}
${5} | ${5} | ${36} | ${'5x5'}
`('button($row, $col) in the table creator grid', ({ row, col, numButtons, tableSize }) => {
describe('on mouse over', () => {
beforeEach(async () => {
@ -50,9 +50,7 @@ describe('content_editor/components/toolbar_table_button', () => {
it('marks all rows and cols before it as active', () => {
const prevRow = Math.max(1, row - 1);
const prevCol = Math.max(1, col - 1);
expect(wrapper.findByTestId(`table-${prevRow}-${prevCol}`).element).toHaveClass(
'gl-bg-blue-50!',
);
expect(wrapper.findByTestId(`table-${prevRow}-${prevCol}`).element).toHaveClass('active');
});
it('shows a help text indicating the size of the table being inserted', () => {
@ -89,8 +87,8 @@ describe('content_editor/components/toolbar_table_button', () => {
});
});
it('does not create more buttons than a 8x8 grid', async () => {
for (let i = 3; i < 8; i += 1) {
it('does not create more buttons than a 10x10 grid', async () => {
for (let i = 5; i < 10; i += 1) {
expect(getNumButtons()).toBe(i * i);
// eslint-disable-next-line no-await-in-loop
@ -98,6 +96,6 @@ describe('content_editor/components/toolbar_table_button', () => {
expect(findDropdown().element).toHaveText(`Insert a ${i}x${i} table.`);
}
expect(getNumButtons()).toBe(64); // 8x8 (and not 9x9)
expect(getNumButtons()).toBe(100); // 10x10 (and not 11x11)
});
});

View file

@ -0,0 +1,146 @@
import { GlTable, GlLink, GlPagination } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
import { DEFAULT_PER_PAGE } from '~/api';
import createFlash from '~/flash';
import IntegrationOverrides from '~/integrations/overrides/components/integration_overrides.vue';
import axios from '~/lib/utils/axios_utils';
import httpStatus from '~/lib/utils/http_status';
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
jest.mock('~/flash');
const mockOverrides = Array(DEFAULT_PER_PAGE * 3)
.fill(1)
.map((_, index) => ({
name: `test-proj-${index}`,
avatar_url: `avatar-${index}`,
full_path: `test-proj-${index}`,
full_name: `test-proj-${index}`,
}));
describe('IntegrationOverrides', () => {
let wrapper;
let mockAxios;
const defaultProps = {
overridesPath: 'mock/overrides',
};
const createComponent = ({ mountFn = shallowMount } = {}) => {
wrapper = mountFn(IntegrationOverrides, {
propsData: defaultProps,
});
};
beforeEach(() => {
mockAxios = new MockAdapter(axios);
mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, mockOverrides, {
'X-TOTAL': mockOverrides.length,
'X-PAGE': 1,
});
});
afterEach(() => {
mockAxios.restore();
wrapper.destroy();
});
const findGlTable = () => wrapper.findComponent(GlTable);
const findPagination = () => wrapper.findComponent(GlPagination);
const findRowsAsModel = () =>
findGlTable()
.findAllComponents(GlLink)
.wrappers.map((link) => {
const avatar = link.findComponent(ProjectAvatar);
return {
href: link.attributes('href'),
avatarUrl: avatar.props('projectAvatarUrl'),
avatarName: avatar.props('projectName'),
text: link.text(),
};
});
describe('while loading', () => {
it('sets GlTable `busy` attribute to `true`', () => {
createComponent();
const table = findGlTable();
expect(table.exists()).toBe(true);
expect(table.attributes('busy')).toBe('true');
});
});
describe('when initial request is successful', () => {
it('sets GlTable `busy` attribute to `false`', async () => {
createComponent();
await waitForPromises();
const table = findGlTable();
expect(table.exists()).toBe(true);
expect(table.attributes('busy')).toBeFalsy();
});
describe('table template', () => {
beforeEach(async () => {
createComponent({ mountFn: mount });
await waitForPromises();
});
it('renders overrides as rows in table', () => {
expect(findRowsAsModel()).toEqual(
mockOverrides.map((x) => ({
href: x.full_path,
avatarUrl: x.avatar_url,
avatarName: x.name,
text: expect.stringContaining(x.full_name),
})),
);
});
});
});
describe('when request fails', () => {
beforeEach(async () => {
mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.INTERNAL_SERVER_ERROR);
createComponent();
await waitForPromises();
});
it('calls createFlash', () => {
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith({
message: IntegrationOverrides.i18n.defaultErrorMessage,
captureError: true,
error: expect.any(Error),
});
});
});
describe('pagination', () => {
it('triggers fetch when `input` event is emitted', async () => {
createComponent();
jest.spyOn(axios, 'get');
await waitForPromises();
await findPagination().vm.$emit('input', 2);
expect(axios.get).toHaveBeenCalledWith(defaultProps.overridesPath, {
params: { page: 2, per_page: DEFAULT_PER_PAGE },
});
});
it('does not render with <=1 page', async () => {
mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, [mockOverrides[0]], {
'X-TOTAL': 1,
'X-PAGE': 1,
});
createComponent();
await waitForPromises();
expect(findPagination().exists()).toBe(false);
});
});
});

View file

@ -20,6 +20,7 @@ describe('Stages Dropdown', () => {
const findPipelineInfoText = () => wrapper.findByTestId('pipeline-info').text();
const findPipelinePath = () => wrapper.findByTestId('pipeline-path').attributes('href');
const findMRLinkPath = () => wrapper.findByTestId('mr-link').attributes('href');
const findCopySourceBranchBtn = () => wrapper.findByTestId('copy-source-ref-link');
const findSourceBranchLinkPath = () =>
wrapper.findByTestId('source-branch-link').attributes('href');
const findTargetBranchLinkPath = () =>
@ -70,6 +71,10 @@ describe('Stages Dropdown', () => {
expect(actual).toBe(expected);
});
it(`renders the source ref copy button`, () => {
expect(findCopySourceBranchBtn().exists()).toBe(true);
});
});
describe('with an "attached" merge request pipeline', () => {
@ -103,6 +108,10 @@ describe('Stages Dropdown', () => {
mockPipelineWithAttachedMR.merge_request.target_branch_path,
);
});
it(`renders the source ref copy button`, () => {
expect(findCopySourceBranchBtn().exists()).toBe(true);
});
});
describe('with a detached merge request pipeline', () => {
@ -130,5 +139,9 @@ describe('Stages Dropdown', () => {
mockPipelineDetached.merge_request.source_branch_path,
);
});
it(`renders the source ref copy button`, () => {
expect(findCopySourceBranchBtn().exists()).toBe(true);
});
});
});

View file

@ -134,4 +134,18 @@ describe('Comment Field Layout Component', () => {
]);
});
});
describe('issue has email participants, but note is confidential', () => {
it('does not show EmailParticipantsWarning', () => {
createWrapper({
noteableData: {
...noteableDataMock,
issue_email_participants: [{ email: 'someone@gitlab.com' }],
},
noteIsConfidential: true,
});
expect(findEmailParticipantsWarning().exists()).toBe(false);
});
});
});

View file

@ -17,7 +17,7 @@ describe('MRWidgetRelatedLinks', () => {
it('returns Closes text for open merge request', () => {
createComponent({ state: 'open', relatedLinks: {} });
expect(wrapper.vm.closesText).toBe('Closes');
expect(wrapper.vm.closesText).toBe('Closes issues');
});
it('returns correct text for closed merge request', () => {
@ -38,6 +38,7 @@ describe('MRWidgetRelatedLinks', () => {
createComponent({
relatedLinks: {
closing: '<a href="#">#23</a> and <a>#42</a>',
closingCount: 2,
},
});
const content = wrapper
@ -45,7 +46,7 @@ describe('MRWidgetRelatedLinks', () => {
.replace(/\n(\s)+/g, ' ')
.trim();
expect(content).toContain('Closes #23 and #42');
expect(content).toContain('Closes issues #23 and #42');
expect(content).not.toContain('Mentions');
});
@ -53,11 +54,17 @@ describe('MRWidgetRelatedLinks', () => {
createComponent({
relatedLinks: {
mentioned: '<a href="#">#7</a>',
mentionedCount: 1,
},
});
expect(wrapper.text().trim()).toContain('Mentions #7');
expect(wrapper.text().trim()).not.toContain('Closes');
const content = wrapper
.text()
.replace(/\n(\s)+/g, ' ')
.trim();
expect(content).toContain('Mentions issue #7');
expect(content).not.toContain('Closes issues');
});
it('should have closing and mentioned issues at the same time', () => {
@ -65,6 +72,8 @@ describe('MRWidgetRelatedLinks', () => {
relatedLinks: {
closing: '<a href="#">#7</a>',
mentioned: '<a href="#">#23</a> and <a>#42</a>',
closingCount: 1,
mentionedCount: 2,
},
});
const content = wrapper
@ -72,8 +81,8 @@ describe('MRWidgetRelatedLinks', () => {
.replace(/\n(\s)+/g, ' ')
.trim();
expect(content).toContain('Closes #7');
expect(content).toContain('Mentions #23 and #42');
expect(content).toContain('Closes issue #7');
expect(content).toContain('Mentions issues #23 and #42');
});
it('should have assing issues link', () => {

View file

@ -82,6 +82,10 @@ RSpec.describe ClustersHelper do
expect(subject[:get_started_docs_url]).to eq(help_page_path('user/clusters/agent/index', anchor: 'define-a-configuration-repository'))
expect(subject[:integration_docs_url]).to eq(help_page_path('user/clusters/agent/index', anchor: 'get-started-with-gitops-and-the-gitlab-agent'))
end
it 'displays kas address' do
expect(subject[:kas_address]).to eq(Gitlab::Kas.external_url)
end
end
describe '#js_clusters_list_data' do

View file

@ -0,0 +1,137 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!('update_trial_plans_ci_daily_pipeline_schedule_triggers')
RSpec.describe UpdateTrialPlansCiDailyPipelineScheduleTriggers, :migration do
let!(:plans) { table(:plans) }
let!(:plan_limits) { table(:plan_limits) }
let!(:premium_trial_plan) { plans.create!(name: 'premium_trial', title: 'Premium Trial') }
let!(:ultimate_trial_plan) { plans.create!(name: 'ultimate_trial', title: 'Ultimate Trial') }
describe '#up' do
let!(:premium_trial_plan_limits) { plan_limits.create!(plan_id: premium_trial_plan.id, ci_daily_pipeline_schedule_triggers: 0) }
let!(:ultimate_trial_plan_limits) { plan_limits.create!(plan_id: ultimate_trial_plan.id, ci_daily_pipeline_schedule_triggers: 0) }
context 'when the environment is dev or com' do
before do
allow(Gitlab).to receive(:dev_env_or_com?).and_return(true)
end
it 'sets the trial plan limits for ci_daily_pipeline_schedule_triggers' do
disable_migrations_output { migrate! }
expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
end
it 'does not change the plan limits if the ultimate trial plan is missing' do
ultimate_trial_plan.destroy!
expect { disable_migrations_output { migrate! } }.not_to change { plan_limits.count }
expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
end
it 'does not change the plan limits if the ultimate trial plan limits is missing' do
ultimate_trial_plan_limits.destroy!
expect { disable_migrations_output { migrate! } }.not_to change { plan_limits.count }
expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
end
it 'does not change the plan limits if the premium trial plan is missing' do
premium_trial_plan.destroy!
expect { disable_migrations_output { migrate! } }.not_to change { plan_limits.count }
expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
end
it 'does not change the plan limits if the premium trial plan limits is missing' do
premium_trial_plan_limits.destroy!
expect { disable_migrations_output { migrate! } }.not_to change { plan_limits.count }
expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
end
end
context 'when the environment is anything other than dev or com' do
before do
allow(Gitlab).to receive(:dev_env_or_com?).and_return(false)
end
it 'does not update the plan limits' do
disable_migrations_output { migrate! }
expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
end
end
end
describe '#down' do
let!(:premium_trial_plan_limits) { plan_limits.create!(plan_id: premium_trial_plan.id, ci_daily_pipeline_schedule_triggers: 288) }
let!(:ultimate_trial_plan_limits) { plan_limits.create!(plan_id: ultimate_trial_plan.id, ci_daily_pipeline_schedule_triggers: 288) }
context 'when the environment is dev or com' do
before do
allow(Gitlab).to receive(:dev_env_or_com?).and_return(true)
end
it 'sets the trial plan limits ci_daily_pipeline_schedule_triggers to zero' do
migrate_down!
expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
end
it 'does not change the plan limits if the ultimate trial plan is missing' do
ultimate_trial_plan.destroy!
expect { migrate_down! }.not_to change { plan_limits.count }
expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
end
it 'does not change the plan limits if the ultimate trial plan limits is missing' do
ultimate_trial_plan_limits.destroy!
expect { migrate_down! }.not_to change { plan_limits.count }
expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
end
it 'does not change the plan limits if the premium trial plan is missing' do
premium_trial_plan.destroy!
expect { migrate_down! }.not_to change { plan_limits.count }
expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
end
it 'does not change the plan limits if the premium trial plan limits is missing' do
premium_trial_plan_limits.destroy!
expect { migrate_down! }.not_to change { plan_limits.count }
expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
end
end
context 'when the environment is anything other than dev or com' do
before do
allow(Gitlab).to receive(:dev_env_or_com?).and_return(false)
end
it 'does not change the ultimate trial plan limits' do
migrate_down!
expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
end
end
end
def migrate_down!
disable_migrations_output do
migrate!
described_class.new.down
end
end
end

View file

@ -58,7 +58,7 @@ RSpec.describe MergeRequestWidgetEntity do
data = described_class.new(resource, request: request, issues_links: true).as_json
expect(data).to include(:issues_links)
expect(data[:issues_links]).to include(:assign_to_closing, :closing, :mentioned_but_not_closing)
expect(data[:issues_links]).to include(:assign_to_closing, :closing, :mentioned_but_not_closing, :closing_count, :mentioned_count)
end
it 'omits issue links by default' do

View file

@ -4568,10 +4568,10 @@ domhandler@^4.0.0, domhandler@^4.2.0:
dependencies:
domelementtype "^2.2.0"
dompurify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.0.tgz#07bb39515e491588e5756b1d3e8375b5964814e2"
integrity sha512-VV5C6Kr53YVHGOBKO/F86OYX6/iLTw2yVSI721gKetxpHCK/V5TaLEf9ODjRgl1KLSWRMY6cUhAbv/c+IUnwQw==
dompurify@^2.3.0, dompurify@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.1.tgz#a47059ca21fd1212d3c8f71fdea6943b8bfbdf6a"
integrity sha512-xGWt+NHAQS+4tpgbOAI08yxW0Pr256Gu/FNE2frZVTbgrBUn8M7tz7/ktS/LZ2MHeGqz6topj0/xY+y8R5FBFw==
domutils@^1.5.1:
version "1.7.0"