Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-08-27 21:10:27 +00:00
parent da50206243
commit 2947190073
25 changed files with 287 additions and 199 deletions

View file

@ -1,13 +1,15 @@
<script>
/* eslint-disable vue/no-v-html */
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import animateMixin from '../mixins/animate';
import eventHub from '../event_hub';
import tooltip from '../../vue_shared/directives/tooltip';
import { spriteIcon } from '../../lib/utils/common_utils';
export default {
components: {
GlButton,
},
directives: {
tooltip,
GlTooltip: GlTooltipDirective,
},
mixins: [animateMixin],
props: {
@ -41,11 +43,6 @@ export default {
titleEl: document.querySelector('title'),
};
},
computed: {
pencilIcon() {
return spriteIcon('pencil', 'link-highlight');
},
},
watch: {
titleHtml() {
this.setPageTitle();
@ -76,17 +73,13 @@ export default {
dir="auto"
v-html="titleHtml"
></h2>
<button
<gl-button
v-if="showInlineEditButton && canUpdate"
v-tooltip
type="button"
class="btn btn-default btn-edit btn-svg js-issuable-edit
qa-edit-button"
v-gl-tooltip.bottom
icon="pencil"
class="btn-edit js-issuable-edit qa-edit-button"
title="Edit title and description"
data-placement="bottom"
data-container="body"
@click="edit"
v-html="pencilIcon"
></button>
/>
</div>
</template>

View file

@ -86,7 +86,7 @@ export default {
<slot name="modal-body"></slot>
<p class="gl-mb-1">{{ $options.strings.confirmText }}</p>
<p>
<code>{{ confirmPhrase }}</code>
<code class="ws-pre-wrap">{{ confirmPhrase }}</code>
</p>
<gl-form-input
id="confirm_name_input"

View file

@ -50,6 +50,7 @@
.title-container {
display: flex;
align-items: flex-start;
}
.title {
@ -65,7 +66,6 @@
.btn-edit {
margin-left: auto;
height: $gl-padding * 2;
}
.emoji-block {

View file

@ -51,7 +51,7 @@ module Milestoneable
# Overridden on EE module
#
def supports_milestone?
respond_to?(:milestone_id)
respond_to?(:milestone_id) && !incident?
end
end

View file

@ -104,6 +104,7 @@ class IssuableSidebarBasicEntity < Grape::Entity
end
expose :supports_time_tracking?, as: :supports_time_tracking
expose :supports_milestone?, as: :supports_milestone
private

View file

@ -29,33 +29,34 @@
= render_if_exists 'shared/issuable/sidebar_item_epic', issuable_sidebar: issuable_sidebar
- milestone = issuable_sidebar[:milestone] || {}
.block.milestone{ data: { qa_selector: 'milestone_block' } }
.sidebar-collapsed-icon.has-tooltip{ title: sidebar_milestone_tooltip_label(milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } }
= sprite_icon('clock')
%span.milestone-title.collapse-truncated-title
- if issuable_sidebar[:supports_milestone]
- milestone = issuable_sidebar[:milestone] || {}
.block.milestone{ data: { qa_selector: 'milestone_block' } }
.sidebar-collapsed-icon.has-tooltip{ title: sidebar_milestone_tooltip_label(milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } }
= sprite_icon('clock')
%span.milestone-title.collapse-truncated-title
- if milestone.present?
= milestone[:title]
- else
= _('None')
.title.hide-collapsed
= _('Milestone')
= loading_icon(css_class: 'gl-vertical-align-text-bottom hidden block-loading')
- if can_edit_issuable
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { qa_selector: "edit_milestone_link", track_label: "right_sidebar", track_property: "milestone", track_event: "click_edit_button", track_value: "" }
.value.hide-collapsed
- if milestone.present?
= milestone[:title]
- milestone_title = milestone[:expired] ? _("%{milestone_name} (Past due)").html_safe % { milestone_name: milestone[:title] } : milestone[:title]
= link_to milestone_title, milestone[:web_url], class: "bold has-tooltip", title: sidebar_milestone_remaining_days(milestone), data: { container: "body", html: 'true', boundary: 'viewport', qa_selector: 'milestone_link', qa_title: milestone[:title] }
- else
= _('None')
.title.hide-collapsed
= _('Milestone')
= loading_icon(css_class: 'gl-vertical-align-text-bottom hidden block-loading')
- if can_edit_issuable
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { qa_selector: "edit_milestone_link", track_label: "right_sidebar", track_property: "milestone", track_event: "click_edit_button", track_value: "" }
.value.hide-collapsed
- if milestone.present?
- milestone_title = milestone[:expired] ? _("%{milestone_name} (Past due)").html_safe % { milestone_name: milestone[:title] } : milestone[:title]
= link_to milestone_title, milestone[:web_url], class: "bold has-tooltip", title: sidebar_milestone_remaining_days(milestone), data: { container: "body", html: 'true', boundary: 'viewport', qa_selector: 'milestone_link', qa_title: milestone[:title] }
- else
%span.no-value
= _('None')
%span.no-value
= _('None')
.selectbox.hide-collapsed
= f.hidden_field 'milestone_id', value: milestone[:id], id: nil
= dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable_type}[milestone_id]", project_id: issuable_sidebar[:project_id], issuable_id: issuable_sidebar[:id], ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], use_id: true, default_no: true, selected: milestone[:title], null_default: true, display: 'static' }})
- if @project.group.present?
= render_if_exists 'shared/issuable/iteration_select', { can_edit: can_edit_issuable, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type }
.selectbox.hide-collapsed
= f.hidden_field 'milestone_id', value: milestone[:id], id: nil
= dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable_type}[milestone_id]", project_id: issuable_sidebar[:project_id], issuable_id: issuable_sidebar[:id], ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], use_id: true, default_no: true, selected: milestone[:title], null_default: true, display: 'static' }})
- if @project.group.present?
= render_if_exists 'shared/issuable/iteration_select', { can_edit: can_edit_issuable, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type }
- if issuable_sidebar[:supports_time_tracking]
#issuable-time-tracker.block

View file

@ -0,0 +1,5 @@
---
title: Update issue edit button to gl-button
merge_request: 40438
author:
type: changed

View file

@ -0,0 +1,5 @@
---
title: "Remove milestone and iteration feature from Incidents sidebar"
merge_request: 40283
author:
type: other

View file

@ -0,0 +1,5 @@
---
title: Fix delete confirm message not displaying trailing spaces
merge_request: 40549
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: Increase performance of rendering large amounts of markdown data
merge_request: 40448
author:
type: performance

View file

@ -16,6 +16,8 @@ This integration works with most LDAP-compliant directory servers, including:
- Open LDAP
- 389 Server
Users added through LDAP take a [licensed seat](../../../subscriptions/index.md#choosing-the-number-of-users).
GitLab Enterprise Editions (EE) include enhanced integration,
including group membership syncing as well as multiple LDAP servers support.

View file

@ -955,3 +955,38 @@ For Omnibus GitLab installations, GitLab Monitor logs reside in `/var/log/gitlab
## GitLab Exporter
For Omnibus GitLab installations, GitLab Exporter logs reside in `/var/log/gitlab/gitlab-exporter/`.
## Gathering logs
When [troubleshooting](troubleshooting/index.md) issues that aren't localized to one of the
previously listed components, it's helpful to simultaneously gather multiple logs and statistics
from a GitLab instance.
### GitLabSOS
If performance degradations or cascading errors occur that can't readily be attributed to one
of the previously listed GitLab components, [GitLabSOS](https://gitlab.com/gitlab-com/support/toolbox/gitlabsos/)
can provide a perspective spanning all of Omnibus GitLab. For more details and instructions
to run it, see [the GitLabSOS documentation](https://gitlab.com/gitlab-com/support/toolbox/gitlabsos/#gitlabsos).
NOTE: **Note:**
GitLab Support likes to use this custom-made tool.
### Briefly tail the main logs
If the bug or error is readily reproducible bug or error, save the main GitLab logs
[to a file](troubleshooting/linux_cheat_sheet.md#files--dirs) while reproducing the
problem once or more times:
```shell
sudo gitlab-ctl tail | tee /tmp/<case-ID-and-keywords>.log
```
Conclude the log gathering with <kbd>Ctrl</kbd> + <kbd>C</kbd>.
### Fast-stats
[Fast-stats](https://gitlab.com/gitlab-com/support/toolbox/fast-stats) is a tool
for creating and comparing performance statistics from GitLab logs.
For more details and instructions to run it, see
[read the documentation for fast-stats](https://gitlab.com/gitlab-com/support/toolbox/fast-stats#usage).

View file

@ -157,25 +157,34 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `geo_lfs_objects_synced_missing_on_primary` | Gauge | 10.7 | Number of LFS objects marked as synced due to the file missing on the primary | `url` |
| `geo_job_artifacts_synced_missing_on_primary` | Gauge | 10.7 | Number of job artifacts marked as synced due to the file missing on the primary | `url` |
| `geo_attachments_synced_missing_on_primary` | Gauge | 10.7 | Number of attachments marked as synced due to the file missing on the primary | `url` |
| `geo_repositories_checksummed_count` | Gauge | 10.7 | Number of repositories checksummed on primary | `url` |
| `geo_repositories_checksum_failed_count` | Gauge | 10.7 | Number of repositories failed to calculate the checksum on primary | `url` |
| `geo_wikis_checksummed_count` | Gauge | 10.7 | Number of wikis checksummed on primary | `url` |
| `geo_wikis_checksum_failed_count` | Gauge | 10.7 | Number of wikis failed to calculate the checksum on primary | `url` |
| `geo_repositories_verified_count` | Gauge | 10.7 | Number of repositories verified on secondary | `url` |
| `geo_repositories_verification_failed_count` | Gauge | 10.7 | Number of repositories failed to verify on secondary | `url` |
| `geo_repositories_checksum_mismatch_count` | Gauge | 10.7 | Number of repositories that checksum mismatch on secondary | `url` |
| `geo_wikis_verified_count` | Gauge | 10.7 | Number of wikis verified on secondary | `url` |
| `geo_wikis_verification_failed_count` | Gauge | 10.7 | Number of wikis failed to verify on secondary | `url` |
| `geo_wikis_checksum_mismatch_count` | Gauge | 10.7 | Number of wikis that checksum mismatch on secondary | `url` |
| `geo_repositories_checked_count` | Gauge | 11.1 | Number of repositories that have been checked via `git fsck` | `url` |
| `geo_repositories_checked_failed_count` | Gauge | 11.1 | Number of repositories that have a failure from `git fsck` | `url` |
| `geo_repositories_retrying_verification_count` | Gauge | 11.2 | Number of repositories verification failures that Geo is actively trying to correct on secondary | `url` |
| `geo_wikis_retrying_verification_count` | Gauge | 11.2 | Number of wikis verification failures that Geo is actively trying to correct on secondary | `url` |
| `geo_repositories_checksummed` | Gauge | 10.7 | Number of repositories checksummed on primary | `url` |
| `geo_repositories_checksum_failed` | Gauge | 10.7 | Number of repositories failed to calculate the checksum on primary | `url` |
| `geo_wikis_checksummed` | Gauge | 10.7 | Number of wikis checksummed on primary | `url` |
| `geo_wikis_checksum_failed` | Gauge | 10.7 | Number of wikis failed to calculate the checksum on primary | `url` |
| `geo_repositories_verified` | Gauge | 10.7 | Number of repositories verified on secondary | `url` |
| `geo_repositories_verification_failed` | Gauge | 10.7 | Number of repositories failed to verify on secondary | `url` |
| `geo_repositories_checksum_mismatch` | Gauge | 10.7 | Number of repositories that checksum mismatch on secondary | `url` |
| `geo_wikis_verified` | Gauge | 10.7 | Number of wikis verified on secondary | `url` |
| `geo_wikis_verification_failed` | Gauge | 10.7 | Number of wikis failed to verify on secondary | `url` |
| `geo_wikis_checksum_mismatch` | Gauge | 10.7 | Number of wikis that checksum mismatch on secondary | `url` |
| `geo_repositories_checked` | Gauge | 11.1 | Number of repositories that have been checked via `git fsck` | `url` |
| `geo_repositories_checked_failed` | Gauge | 11.1 | Number of repositories that have a failure from `git fsck` | `url` |
| `geo_repositories_retrying_verification` | Gauge | 11.2 | Number of repositories verification failures that Geo is actively trying to correct on secondary | `url` |
| `geo_wikis_retrying_verification` | Gauge | 11.2 | Number of wikis verification failures that Geo is actively trying to correct on secondary | `url` |
| `geo_package_files` | Gauge | 13.0 | Number of package files on primary | `url` |
| `geo_package_files_checksummed` | Gauge | 13.0 | Number of package files checksummed on primary | `url` |
| `geo_package_files_checksum_failed` | Gauge | 13.0 | Number of package files failed to calculate the checksum on primary | `url` |
| `geo_package_files_synced` | Gauge | 13.3 | Number of syncable package files synced on secondary | `url` |
| `geo_package_files_failed` | Gauge | 13.3 | Number of syncable package files failed to sync on secondary | `url` |
| `geo_package_files_registry` | Gauge | 13.3 | Number of package files in the registry | `url` |
| `geo_terraform_states` | Gauge | 13.3 | Number of terraform states on primary | `url` |
| `geo_terraform_states_checksummed` | Gauge | 13.3 | Number of terraform states checksummed on primary | `url` |
| `geo_terraform_states_checksum_failed` | Gauge | 13.3 | Number of terraform states failed to calculate the checksum on primary | `url` |
| `geo_terraform_states_synced` | Gauge | 13.3 | Number of syncable terraform states synced on secondary | `url` |
| `geo_terraform_states_failed` | Gauge | 13.3 | Number of syncable terraform states failed to sync on secondary | `url` |
| `geo_terraform_states_registry` | Gauge | 13.3 | Number of terraform states in the registry | `url` |
| `global_search_bulk_cron_queue_size` | Gauge | 12.10 | Number of database records waiting to be synchronized to Elasticsearch | |
| `global_search_awaiting_indexing_queue_size` | Gauge | 13.2 | Number of database updates waiting to be synchronized to Elasticsearch while indexing is paused | |
| `package_files_count` | Gauge | 13.0 | Number of package files on primary | `url` |
| `package_files_checksummed_count` | Gauge | 13.0 | Number of package files checksummed on primary | `url` |
| `package_files_checksum_failed_count` | Gauge | 13.0 | Number of package files failed to calculate the checksum on primary
## Database load balancing metrics **(PREMIUM ONLY)**

View file

@ -447,7 +447,13 @@ Example response:
"package_files_checksum_failed_count": 0,
"package_files_registry_count": 10,
"package_files_synced_count": 6,
"package_files_failed_count": 3
"package_files_failed_count": 3,
"terraform_states_count": 10,
"terraform_states_checksummed_count": 10,
"terraform_states_checksum_failed_count": 0,
"terraform_states_registry_count": 10,
"terraform_states_synced_count": 6,
"terraform_states_failed_count": 3
}
]
```

View file

@ -520,44 +520,37 @@ Widgets should now be verified by Geo!
Metrics are gathered by `Geo::MetricsUpdateWorker`, persisted in
`GeoNodeStatus` for display in the UI, and sent to Prometheus.
1. Add fields `widget_count`, `widget_checksummed_count`,
`widget_checksum_failed_count`, `widget_synced_count`,
`widget_failed_count`, and `widget_registry_count` to
`GeoNodeStatus#RESOURCE_STATUS_FIELDS` array in
`ee/app/models/geo_node_status.rb`.
1. Add the same fields to `GeoNodeStatus#PROMETHEUS_METRICS` hash in
`ee/app/models/geo_node_status.rb`.
1. Add the same fields to `Sidekiq metrics` table in
`doc/administration/monitoring/prometheus/gitlab_metrics.md`.
1. Add fields `widgets_count`, `widgets_checksummed_count`,
`widgets_checksum_failed_count`, `widgets_synced_count`,
`widgets_failed_count`, and `widgets_registry_count` to
`GET /geo_nodes/status` example response in
`doc/api/geo_nodes.md`.
1. Add the same fields to `GET /geo_nodes/status` example response in
`doc/api/geo_nodes.md`.
1. Add the same fields to `ee/spec/models/geo_node_status_spec.rb` and
`ee/spec/factories/geo_node_statuses.rb`.
1. Set `widget_count` in `GeoNodeStatus#load_data_from_current_node`:
1. Add fields `geo_widgets`, `geo_widgets_checksummed`,
`geo_widgets_checksum_failed`, `geo_widgets_synced`,
`geo_widgets_failed`, and `geo_widgets_registry` to
`Sidekiq metrics` table in
`doc/administration/monitoring/prometheus/gitlab_metrics.md`.
1. Add the following to the parameterized table in
`ee/spec/models/geo_node_status_spec.rb`:
```ruby
self.widget_count = Geo::WidgetReplicator.primary_total_count
Geo::WidgetReplicator | :widget | :geo_widget_registry
```
1. Add `GeoNodeStatus#load_widgets_data` to set `widget_synced_count`,
`widget_failed_count`, and `widget_registry_count`:
1. Add the following to `spec/factories/widgets.rb`:
```ruby
def load_widget_data
self.widget_synced_count = Geo::WidgetReplicator.synced_count
self.widget_failed_count = Geo::WidgetReplicator.failed_count
self.widget_registry_count = Geo::WidgetReplicator.registry_count
trait(:checksummed) do
with_file
verification_checksum { 'abc' }
end
```
1. Call `GeoNodeStatus#load_widgets_data` in
`GeoNodeStatus#load_secondary_data`.
1. Set `widget_checksummed_count` and `widget_checksum_failed_count` in
`GeoNodeStatus#load_verification_data`:
```ruby
self.widget_checksummed_count = Geo::WidgetReplicator.checksummed_count self.widget_checksum_failed_count = Geo::WidgetReplicator.checksum_failed_count
trait(:checksum_failure) do
with_file
verification_failure { 'Could not calculate the checksum' }
end
```
Widget replication and verification metrics should now be available in the API,

View file

@ -9,6 +9,62 @@ module Gitlab
# extractor = Gitlab::QuickActions::Extractor.new([:open, :assign, :labels])
# ```
class Extractor
CODE_REGEX = %r{
(?<code>
# Code blocks:
# ```
# Anything, including `/cmd arg` which are ignored by this filter
# ```
^```
.+?
\n```$
)
}mix.freeze
INLINE_CODE_REGEX = %r{
(?<inline_code>
# Inline code on separate rows:
# `
# Anything, including `/cmd arg` which are ignored by this filter
# `
^.*`\n*
.+?
\n*`$
)
}mix.freeze
HTML_BLOCK_REGEX = %r{
(?<html>
# HTML block:
# <tag>
# Anything, including `/cmd arg` which are ignored by this filter
# </tag>
^<[^>]+?>\n
.+?
\n<\/[^>]+?>$
)
}mix.freeze
QUOTE_BLOCK_REGEX = %r{
(?<html>
# Quote block:
# >>>
# Anything, including `/cmd arg` which are ignored by this filter
# >>>
^>>>
.+?
\n>>>$
)
}mix.freeze
EXCLUSION_REGEX = %r{
#{CODE_REGEX} | #{INLINE_CODE_REGEX} | #{HTML_BLOCK_REGEX} | #{QUOTE_BLOCK_REGEX}
}mix.freeze
attr_reader :command_definitions
def initialize(command_definitions)
@ -35,9 +91,7 @@ module Gitlab
def extract_commands(content, only: nil)
return [content, []] unless content
content, commands = perform_regex(content, only: only)
perform_substitutions(content, commands)
perform_regex(content, only: only)
end
# Encloses quick action commands into code span markdown
@ -55,13 +109,19 @@ module Gitlab
private
def perform_regex(content, only: nil, redact: false)
commands = []
content = content.dup
names = command_names(limit_to_commands: only).map(&:to_s)
sub_names = substitution_names.map(&:to_s)
commands = []
content = content.dup
content.delete!("\r")
names = command_names(limit_to_commands: only).map(&:to_s)
content.gsub!(commands_regex(names: names)) do
command, output = process_commands($~, redact)
content.gsub!(commands_regex(names: names, sub_names: sub_names)) do
command, output = if $~[:substitution]
process_substitutions($~)
else
process_commands($~, redact)
end
commands << command
output
end
@ -86,6 +146,21 @@ module Gitlab
[command, output]
end
def process_substitutions(matched_text)
output = matched_text[0]
command = []
if matched_text[:substitution]
cmd = matched_text[:substitution].downcase
command = [cmd, matched_text[:arg]].reject(&:blank?)
substitution = substitution_definitions.find { |definition| definition.all_names.include?(cmd.to_sym) }
output = substitution.perform_substitution(self, output) if substitution
end
[command, output]
end
# Builds a regular expression to match known commands.
# First match group captures the command name and
# second match group captures its arguments.
@ -93,51 +168,9 @@ module Gitlab
# It looks something like:
#
# /^\/(?<cmd>close|reopen|...)(?:( |$))(?<arg>[^\/\n]*)(?:\n|$)/
def commands_regex(names:)
def commands_regex(names:, sub_names:)
@commands_regex[names] ||= %r{
(?<code>
# Code blocks:
# ```
# Anything, including `/cmd arg` which are ignored by this filter
# ```
^```
.+?
\n```$
)
|
(?<inline_code>
# Inline code on separate rows:
# `
# Anything, including `/cmd arg` which are ignored by this filter
# `
^.*`\n*
.+?
\n*`$
)
|
(?<html>
# HTML block:
# <tag>
# Anything, including `/cmd arg` which are ignored by this filter
# </tag>
^<[^>]+?>\n
.+?
\n<\/[^>]+?>$
)
|
(?<html>
# Quote block:
# >>>
# Anything, including `/cmd arg` which are ignored by this filter
# >>>
^>>>
.+?
\n>>>$
)
#{EXCLUSION_REGEX}
|
(?:
# Command not in a blockquote, blockcode, or HTML tag:
@ -151,34 +184,21 @@ module Gitlab
)?
(?:\s*\n|$)
)
|
(?:
# Substitution not in a blockquote, blockcode, or HTML tag:
^\/
(?<substitution>#{Regexp.new(Regexp.union(sub_names).source, Regexp::IGNORECASE)})
(?:
[ ]
(?<arg>[^\n]*)
)?
(?:\s*\n|$)
)
}mix
end
def perform_substitutions(content, commands)
return unless content
substitution_definitions = self.command_definitions.select do |definition|
definition.is_a?(Gitlab::QuickActions::SubstitutionDefinition)
end
substitution_definitions.each do |substitution|
regex = commands_regex(names: substitution.all_names)
content = content.gsub(regex) do |text|
if $~[:cmd]
command = [substitution.name.to_s]
command << $~[:arg] if $~[:arg].present?
commands << command
substitution.perform_substitution(self, text)
else
text
end
end
end
[content, commands]
end
def command_names(limit_to_commands:)
command_definitions.flat_map do |command|
next if command.noop?
@ -190,6 +210,17 @@ module Gitlab
command.all_names
end.compact
end
def substitution_names
substitution_definitions.flat_map { |command| command.all_names }
.compact
end
def substitution_definitions
@substition_definitions ||= command_definitions.select do |command|
command.is_a?(Gitlab::QuickActions::SubstitutionDefinition)
end
end
end
end
end

View file

@ -9,10 +9,6 @@ module Gitlab
true
end
def match(content)
content.match %r{^/#{all_names.join('|')}(?![\S]) ?(.*)$}
end
def perform_substitution(context, content)
return unless content

View file

@ -15,5 +15,15 @@ FactoryBot.define do
locked_at { Time.current }
locked_by_user { create(:user) }
end
trait(:checksummed) do
with_file
verification_checksum { 'abc' }
end
trait(:checksum_failure) do
with_file
verification_failure { 'Could not calculate the checksum' }
end
end
end

View file

@ -43,6 +43,7 @@
"toggle_subscription_path": { "type": "string" },
"move_issue_path": { "type": "string" },
"projects_autocomplete_path": { "type": "string" },
"supports_time_tracking": { "type": "boolean" }
"supports_time_tracking": { "type": "boolean" },
"supports_milestone": { "type": "boolean" }
}
}

View file

@ -52,6 +52,7 @@
"toggle_subscription_path": { "type": "string" },
"move_issue_path": { "type": "string" },
"projects_autocomplete_path": { "type": "string" },
"supports_time_tracking": { "type": "boolean" }
"supports_time_tracking": { "type": "boolean" },
"supports_milestone": { "type": "boolean" }
}
}

View file

@ -95,13 +95,10 @@ describe('AlertManagementTable', () => {
});
}
beforeEach(() => {
mountComponent({ data: { alerts: mockAlerts, alertsCount } });
});
afterEach(() => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
});

View file

@ -66,7 +66,9 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
</p>
<p>
<code>
<code
class="ws-pre-wrap"
>
foo
</code>
</p>

View file

@ -55,7 +55,9 @@ exports[`Project remove modal intialized matches the snapshot 1`] = `
</p>
<p>
<code>
<code
class="ws-pre-wrap"
>
foo
</code>
</p>

View file

@ -46,24 +46,4 @@ EOF
end
end
end
describe '#match' do
it 'checks the content for the command' do
expect(subject.match(content)).to be_truthy
end
it 'returns the match data' do
data = subject.match(content)
expect(data).to be_a(MatchData)
expect(data[1]).to eq('I like this stuff')
end
it 'is nil if content does not have the command' do
expect(subject.match('blah')).to be_falsey
end
it 'is nil if content contains the command as prefix' do
expect(subject.match('/sub_namex')).to be_falsey
end
end
end

View file

@ -100,6 +100,14 @@ RSpec.describe Milestoneable do
expect(merge_request.supports_milestone?).to be_truthy
end
end
context "for incidents" do
let(:incident) { build(:incident) }
it 'returns false' do
expect(incident.supports_milestone?).to be_falsy
end
end
end
describe 'release scopes' do