Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e6bcd6e738
commit
f6d19ed8eb
|
@ -1,11 +1,11 @@
|
|||
<script>
|
||||
import { GlModal, GlModalDirective, GlDeprecatedButton } from '@gitlab/ui';
|
||||
import { GlModal, GlModalDirective, GlButton } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlModal,
|
||||
GlDeprecatedButton,
|
||||
GlButton,
|
||||
},
|
||||
directives: {
|
||||
'gl-modal': GlModalDirective,
|
||||
|
@ -33,9 +33,9 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<div class="d-inline-block float-right mr-3">
|
||||
<gl-deprecated-button v-gl-modal="$options.modalId" variant="danger">
|
||||
<gl-button v-gl-modal="$options.modalId" variant="danger" category="primary">
|
||||
{{ __('Delete') }}
|
||||
</gl-deprecated-button>
|
||||
</gl-button>
|
||||
<gl-modal
|
||||
:title="s__('Metrics|Delete metric?')"
|
||||
:ok-title="s__('Metrics|Delete metric')"
|
||||
|
|
|
@ -113,8 +113,8 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
...mapActions('diffs', ['showCommentForm']),
|
||||
showNewDiscussionForm() {
|
||||
this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.diffFileHash });
|
||||
showNewDiscussionForm(lineCode) {
|
||||
this.showCommentForm({ lineCode, fileHash: this.diffFileHash });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -134,7 +134,7 @@ export default {
|
|||
v-if="!hasDraftLeft"
|
||||
:has-form="showLeftSideCommentForm"
|
||||
:render-reply-placeholder="shouldRenderReplyPlaceholderOnLeft"
|
||||
@showNewDiscussionForm="showNewDiscussionForm"
|
||||
@showNewDiscussionForm="showNewDiscussionForm(line.left.line_code)"
|
||||
>
|
||||
<template #form>
|
||||
<diff-line-note-form
|
||||
|
@ -159,7 +159,7 @@ export default {
|
|||
v-if="!hasDraftRight"
|
||||
:has-form="showRightSideCommentForm"
|
||||
:render-reply-placeholder="shouldRenderReplyPlaceholderOnRight"
|
||||
@showNewDiscussionForm="showNewDiscussionForm"
|
||||
@showNewDiscussionForm="showNewDiscussionForm(line.right.line_code)"
|
||||
>
|
||||
<template #form>
|
||||
<diff-line-note-form
|
||||
|
|
|
@ -45,13 +45,6 @@ export default {
|
|||
loading() {
|
||||
return this.$apollo.queries.alert.loading;
|
||||
},
|
||||
alertTableFields() {
|
||||
if (this.alert) {
|
||||
const { detailsUrl, __typename, ...restDetails } = this.alert;
|
||||
return restDetails;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -64,7 +57,7 @@ export default {
|
|||
<description-component v-bind="$attrs" />
|
||||
</gl-tab>
|
||||
<gl-tab v-if="alert" class="alert-management-details" :title="s__('Incident|Alert details')">
|
||||
<alert-details-table :alert="alertTableFields" :loading="loading" />
|
||||
<alert-details-table :alert="alert" :loading="loading" />
|
||||
</gl-tab>
|
||||
</gl-tabs>
|
||||
</div>
|
||||
|
|
|
@ -132,7 +132,9 @@ function mountLockComponent() {
|
|||
({ store }) => store,
|
||||
);
|
||||
} else {
|
||||
importStore = import(/* webpackChunkName: 'mrNotesStore' */ '~/mr_notes/stores');
|
||||
importStore = import(/* webpackChunkName: 'mrNotesStore' */ '~/mr_notes/stores').then(
|
||||
store => store.default,
|
||||
);
|
||||
}
|
||||
|
||||
importStore
|
||||
|
|
|
@ -31,6 +31,15 @@ export default class TaskList {
|
|||
init() {
|
||||
this.disable(); // Prevent duplicate event bindings
|
||||
|
||||
const taskListFields = document.querySelectorAll(
|
||||
`${this.taskListContainerSelector} .js-task-list-field[data-value]`,
|
||||
);
|
||||
|
||||
taskListFields.forEach(taskListField => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
taskListField.value = taskListField.dataset.value;
|
||||
});
|
||||
|
||||
$(this.taskListContainerSelector).taskList('enable');
|
||||
$(document).on('tasklist:changed', this.taskListContainerSelector, this.updateHandler);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,22 @@ import {
|
|||
|
||||
const thClass = 'gl-bg-transparent! gl-border-1! gl-border-b-solid! gl-border-gray-200!';
|
||||
const tdClass = 'gl-border-gray-100! gl-p-5!';
|
||||
const allowedFields = [
|
||||
'iid',
|
||||
'title',
|
||||
'severity',
|
||||
'status',
|
||||
'startedAt',
|
||||
'eventCount',
|
||||
'monitoringTool',
|
||||
'service',
|
||||
'description',
|
||||
'endedAt',
|
||||
'details',
|
||||
];
|
||||
|
||||
const filterAllowedFields = ([fieldName]) => allowedFields.includes(fieldName);
|
||||
const arrayToObject = ([fieldName, value]) => ({ fieldName, value });
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -46,10 +62,9 @@ export default {
|
|||
if (!this.alert) {
|
||||
return [];
|
||||
}
|
||||
return Object.entries(this.alert).map(([fieldName, value]) => ({
|
||||
fieldName,
|
||||
value,
|
||||
}));
|
||||
return Object.entries(this.alert)
|
||||
.filter(filterAllowedFields)
|
||||
.map(arrayToObject);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1050,14 +1050,6 @@ button.mini-pipeline-graph-dropdown-toggle {
|
|||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.legend-all {
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
.legend-success {
|
||||
color: $green-500;
|
||||
}
|
||||
|
||||
.test-reports-table {
|
||||
.build-trace {
|
||||
@include build-trace();
|
||||
|
|
|
@ -66,9 +66,8 @@
|
|||
.title-container
|
||||
%h2.title= markdown_field(@issue, :title)
|
||||
- if @issue.description.present?
|
||||
.description{ class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : '' }
|
||||
.description
|
||||
.md= markdown_field(@issue, :description)
|
||||
%textarea.hidden.js-task-list-field= @issue.description
|
||||
|
||||
= edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue-edited-ago js-issue-edited-ago')
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
.description.qa-description{ class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : '' }
|
||||
.md
|
||||
= markdown_field(@merge_request, :description)
|
||||
%textarea.hidden.js-task-list-field
|
||||
= @merge_request.description
|
||||
%textarea.hidden.js-task-list-field{ data: { value: @merge_request.description } }
|
||||
|
||||
= edited_time_ago_with_tooltip(@merge_request, placement: 'bottom')
|
||||
|
|
|
@ -1 +1 @@
|
|||
%textarea.hidden.js-task-list-field.original-task-list{ data: { update_url: note_url(note) } }= note.note
|
||||
%textarea.hidden.js-task-list-field.original-task-list{ data: { update_url: note_url(note), value: note.note } }
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
.description
|
||||
.md
|
||||
= markdown_field(@snippet, :description)
|
||||
%textarea.hidden.js-task-list-field
|
||||
= @snippet.description
|
||||
|
||||
- if @snippet.updated_at != @snippet.created_at
|
||||
= edited_time_ago_with_tooltip(@snippet, placement: 'bottom', exclude_author: true)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix checking of task lists when MR description starts with a blank line
|
||||
merge_request: 43125
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix branches_to_be_notified API param for hangouts chat service
|
||||
merge_request: 35599
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove internal fields from alert details table
|
||||
merge_request: 43076
|
||||
author:
|
||||
type: changed
|
|
@ -19,7 +19,6 @@
|
|||
- auto_devops
|
||||
- backup_restore
|
||||
- behavior_analytics
|
||||
- billing
|
||||
- chatops
|
||||
- cloud_native_installation
|
||||
- cluster_cost_optimization
|
||||
|
@ -87,6 +86,8 @@
|
|||
- planning_analytics
|
||||
- product_analytics
|
||||
- projects
|
||||
- provision
|
||||
- purchase
|
||||
- quality_management
|
||||
- release_evidence
|
||||
- release_orchestration
|
||||
|
|
|
@ -67,3 +67,7 @@ That's totally fine. We use HTTP(s) to fetch repository changes from the **prima
|
|||
## Is this possible to set up a Docker Registry for a **secondary** node that mirrors the one on the **primary** node?
|
||||
|
||||
Yes. See [Docker Registry for a **secondary** node](docker_registry.md).
|
||||
|
||||
## Can I login to a secondary node?
|
||||
|
||||
Yes, but secondary nodes receive all authentication data (like user accounts and logins) from the primary instance. This means you will be re-directed to the primary for authentication and routed back afterwards.
|
||||
|
|
|
@ -659,7 +659,7 @@ Parameters:
|
|||
| `webhook` | string | true | The Hangouts Chat webhook. For example, `https://chat.googleapis.com/v1/spaces...`. |
|
||||
| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines |
|
||||
| `notify_only_default_branch` | boolean | false | DEPRECATED: This parameter has been replaced with `branches_to_be_notified` |
|
||||
| `branches_to_be_notified` | string | all | Branches to send notifications for. Valid options are "all", "default", "protected", and "default_and_protected" |
|
||||
| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are "all", "default", "protected", and "default_and_protected" |
|
||||
| `push_events` | boolean | false | Enable notifications for push events |
|
||||
| `issues_events` | boolean | false | Enable notifications for issue events |
|
||||
| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events |
|
||||
|
|
|
@ -91,8 +91,6 @@ module Geo
|
|||
::Packages::PackageFile
|
||||
end
|
||||
|
||||
# Change this to `true` to release replication of this model. Then remove
|
||||
# this override in the next release.
|
||||
# The feature flag follows the format `geo_#{replicable_name}_replication`,
|
||||
# so here it would be `geo_package_file_replication`
|
||||
def self.replication_enabled_by_default?
|
||||
|
@ -220,8 +218,6 @@ For example, to add support for files referenced by a `Widget` model with a
|
|||
model_record.file
|
||||
end
|
||||
|
||||
# Change this to `true` to release replication of this model. Then remove
|
||||
# this override in the next release.
|
||||
# The feature flag follows the format `geo_#{replicable_name}_replication`,
|
||||
# so here it would be `geo_widget_replication`
|
||||
def self.replication_enabled_by_default?
|
||||
|
@ -693,3 +689,33 @@ To do: This should be done as part of
|
|||
|
||||
Widget sync and verification data (aggregate and individual) should now be
|
||||
available in the Admin UI!
|
||||
|
||||
#### Releasing the feature
|
||||
|
||||
1. In `ee/app/replicators/geo/widget_replicator.rb`, delete the `self.replication_enabled_by_default?` method:
|
||||
|
||||
```ruby
|
||||
module Geo
|
||||
class WidgetReplicator < Gitlab::Geo::Replicator
|
||||
...
|
||||
|
||||
# REMOVE THIS METHOD
|
||||
def self.replication_enabled_by_default?
|
||||
false
|
||||
end
|
||||
# REMOVE THIS METHOD
|
||||
|
||||
...
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
1. In `ee/app/graphql/types/geo/geo_node_type.rb`, remove the `feature_flag` option for the released type:
|
||||
|
||||
```ruby
|
||||
field :widget_registries, ::Types::Geo::WidgetRegistryType.connection_type,
|
||||
null: true,
|
||||
resolver: ::Resolvers::Geo::WidgetRegistriesResolver,
|
||||
description: 'Find widget registries on this Geo node',
|
||||
feature_flag: :geo_widget_replication # REMOVE THIS LINE
|
||||
```
|
||||
|
|
|
@ -381,6 +381,12 @@ module API
|
|||
type: String,
|
||||
desc: 'The Hangouts Chat webhook. e.g. https://chat.googleapis.com/v1/spaces…'
|
||||
},
|
||||
{
|
||||
required: false,
|
||||
name: :branches_to_be_notified,
|
||||
type: String,
|
||||
desc: 'Branches for which notifications are to be sent'
|
||||
},
|
||||
chat_notification_events
|
||||
].flatten,
|
||||
'hipchat' => [
|
||||
|
|
|
@ -8,15 +8,20 @@
|
|||
# In order to not use a possible complex time consuming query when calculating min and max for batch_distinct_count
|
||||
# the start and finish can be sent specifically
|
||||
#
|
||||
# Grouped relations can be used as well. However, the preferred batch count should be around 10K because group by count is more expensive.
|
||||
#
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22705
|
||||
#
|
||||
# Examples:
|
||||
# extend ::Gitlab::Database::BatchCount
|
||||
# batch_count(User.active)
|
||||
# batch_count(::Clusters::Cluster.aws_installed.enabled, :cluster_id)
|
||||
# batch_count(Namespace.group(:type))
|
||||
# batch_distinct_count(::Project, :creator_id)
|
||||
# batch_distinct_count(::Project.with_active_services.service_desk_enabled.where(time_period), start: ::User.minimum(:id), finish: ::User.maximum(:id))
|
||||
# batch_distinct_count(Project.group(:visibility_level), :creator_id)
|
||||
# batch_sum(User, :sign_in_count)
|
||||
# batch_sum(Issue.group(:state_id), :weight))
|
||||
module Gitlab
|
||||
module Database
|
||||
module BatchCount
|
||||
|
@ -77,12 +82,12 @@ module Gitlab
|
|||
raise "Batch counting expects positive values only for #{@column}" if start < 0 || finish < 0
|
||||
return FALLBACK if unwanted_configuration?(finish, batch_size, start)
|
||||
|
||||
counter = 0
|
||||
results = nil
|
||||
batch_start = start
|
||||
|
||||
while batch_start <= finish
|
||||
begin
|
||||
counter += batch_fetch(batch_start, batch_start + batch_size, mode)
|
||||
results = merge_results(results, batch_fetch(batch_start, batch_start + batch_size, mode))
|
||||
batch_start += batch_size
|
||||
rescue ActiveRecord::QueryCanceled
|
||||
# retry with a safe batch size & warmer cache
|
||||
|
@ -95,7 +100,17 @@ module Gitlab
|
|||
sleep(SLEEP_TIME_IN_SECONDS)
|
||||
end
|
||||
|
||||
counter
|
||||
results
|
||||
end
|
||||
|
||||
def merge_results(results, object)
|
||||
return object unless results
|
||||
|
||||
if object.is_a?(Hash)
|
||||
results.merge!(object) { |_, a, b| a + b }
|
||||
else
|
||||
results + object
|
||||
end
|
||||
end
|
||||
|
||||
def batch_fetch(start, finish, mode)
|
||||
|
@ -118,11 +133,11 @@ module Gitlab
|
|||
end
|
||||
|
||||
def actual_start(start)
|
||||
start || @relation.minimum(@column) || 0
|
||||
start || @relation.unscope(:group).minimum(@column) || 0
|
||||
end
|
||||
|
||||
def actual_finish(finish)
|
||||
finish || @relation.maximum(@column) || 0
|
||||
finish || @relation.unscope(:group).maximum(@column) || 0
|
||||
end
|
||||
|
||||
def check_mode!(mode)
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
# frozen_string_literal: true
|
||||
# TODO use shared examples to merge this spec with discussion_lock_spec.rb
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/255910
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Merge Request Discussion Lock', :js do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let(:merge_request) { create(:merge_request, source_project: project, author: user) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
context 'when a user is a team member' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
context 'when the discussion is unlocked' do
|
||||
it 'the user can lock the merge_request' do
|
||||
visit project_merge_request_path(merge_request.project, merge_request)
|
||||
|
||||
expect(find('.issuable-sidebar')).to have_content('Unlocked')
|
||||
|
||||
page.within('.issuable-sidebar') do
|
||||
find('.lock-edit').click
|
||||
click_button('Lock')
|
||||
end
|
||||
|
||||
expect(find('[data-testid="lock-status"]')).to have_content('Locked')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the discussion is locked' do
|
||||
before do
|
||||
merge_request.update_attribute(:discussion_locked, true)
|
||||
visit project_merge_request_path(merge_request.project, merge_request)
|
||||
end
|
||||
|
||||
it 'the user can unlock the merge_request' do
|
||||
expect(find('.issuable-sidebar')).to have_content('Locked')
|
||||
|
||||
page.within('.issuable-sidebar') do
|
||||
find('.lock-edit').click
|
||||
click_button('Unlock')
|
||||
end
|
||||
|
||||
expect(find('[data-testid="lock-status"]')).to have_content('Unlocked')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a user is not a team member' do
|
||||
context 'when the discussion is unlocked' do
|
||||
before do
|
||||
visit project_merge_request_path(merge_request.project, merge_request)
|
||||
end
|
||||
|
||||
it 'the user can not lock the merge_request' do
|
||||
expect(find('.issuable-sidebar')).to have_content('Unlocked')
|
||||
expect(find('.issuable-sidebar')).not_to have_selector('.lock-edit')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the discussion is locked' do
|
||||
before do
|
||||
merge_request.update_attribute(:discussion_locked, true)
|
||||
visit project_merge_request_path(merge_request.project, merge_request)
|
||||
end
|
||||
|
||||
it 'the user can not unlock the merge_request' do
|
||||
expect(find('.issuable-sidebar')).to have_content('Locked')
|
||||
expect(find('.issuable-sidebar')).not_to have_selector('.lock-edit')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,7 +22,7 @@ RSpec.describe 'User views an open merge request' do
|
|||
# returns the whole document, not the node's actual parent element
|
||||
expect(find(:xpath, "#{node.path}/..").text).to eq(merge_request.description[2..-1])
|
||||
|
||||
expect(page).to have_content(merge_request.title).and have_content(merge_request.description)
|
||||
expect(page).to have_content(merge_request.title)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -6,19 +6,22 @@ RSpec.describe "User comments on commit", :js do
|
|||
include Spec::Support::Helpers::Features::NotesHelpers
|
||||
include RepoHelpers
|
||||
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:comment_text) { "XML attached" }
|
||||
|
||||
before_all do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
project.add_developer(user)
|
||||
|
||||
visit(project_commit_path(project, sample_commit.id))
|
||||
end
|
||||
|
||||
context "when adding new comment" do
|
||||
it "adds comment" do
|
||||
visit(project_commit_path(project, sample_commit.id))
|
||||
|
||||
emoji_code = ":+1:"
|
||||
|
||||
page.within(".js-main-target-form") do
|
||||
|
@ -57,6 +60,8 @@ RSpec.describe "User comments on commit", :js do
|
|||
|
||||
context "when editing comment" do
|
||||
before do
|
||||
visit(project_commit_path(project, sample_commit.id))
|
||||
|
||||
add_note(comment_text)
|
||||
end
|
||||
|
||||
|
@ -87,6 +92,8 @@ RSpec.describe "User comments on commit", :js do
|
|||
|
||||
context "when deleting comment" do
|
||||
before do
|
||||
visit(project_commit_path(project, sample_commit.id))
|
||||
|
||||
add_note(comment_text)
|
||||
end
|
||||
|
||||
|
@ -108,4 +115,35 @@ RSpec.describe "User comments on commit", :js do
|
|||
expect(page).not_to have_css(".note")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when checking task lists' do
|
||||
let(:note_with_task) do
|
||||
<<-EOT.strip_heredoc
|
||||
|
||||
- [ ] Task 1
|
||||
EOT
|
||||
end
|
||||
|
||||
before do
|
||||
create(:note_on_commit, project: project, commit_id: sample_commit.id, note: note_with_task, author: user)
|
||||
create(:note_on_commit, project: project, commit_id: sample_commit.id, note: note_with_task, author: user)
|
||||
|
||||
visit(project_commit_path(project, sample_commit.id))
|
||||
end
|
||||
|
||||
it 'allows the tasks to be checked' do
|
||||
expect(page).to have_selector('li.task-list-item', count: 2)
|
||||
expect(page).to have_selector('li.task-list-item input[checked]', count: 0)
|
||||
|
||||
all('.task-list-item-checkbox').each do |checkbox|
|
||||
checkbox.click
|
||||
end
|
||||
wait_for_requests
|
||||
|
||||
visit(project_commit_path(project, sample_commit.id))
|
||||
|
||||
expect(page).to have_selector('li.task-list-item', count: 2)
|
||||
expect(page).to have_selector('li.task-list-item input[checked]', count: 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Task Lists' do
|
||||
RSpec.describe 'Task Lists', :js do
|
||||
include Warden::Test::Helpers
|
||||
|
||||
let_it_be(:project) { create(:project, :public, :repository) }
|
||||
|
@ -38,41 +38,7 @@ RSpec.describe 'Task Lists' do
|
|||
MARKDOWN
|
||||
end
|
||||
|
||||
let(:nested_tasks_markdown) do
|
||||
<<-EOT.strip_heredoc
|
||||
- [ ] Task a
|
||||
- [x] Task a.1
|
||||
- [ ] Task a.2
|
||||
- [ ] Task b
|
||||
|
||||
1. [ ] Task 1
|
||||
1. [ ] Task 1.1
|
||||
1. [x] Task 1.2
|
||||
EOT
|
||||
end
|
||||
|
||||
let(:commented_tasks_markdown) do
|
||||
<<-EOT.strip_heredoc
|
||||
<!--
|
||||
- [ ] a
|
||||
-->
|
||||
|
||||
- [ ] b
|
||||
EOT
|
||||
end
|
||||
|
||||
let(:summary_no_blank_line_markdown) do
|
||||
<<-EOT.strip_heredoc
|
||||
<details>
|
||||
<summary>No blank line after summary element breaks task list</summary>
|
||||
1. [ ] People Ops: do such and such
|
||||
</details>
|
||||
|
||||
* [ ] Task 1
|
||||
EOT
|
||||
end
|
||||
|
||||
before(:all) do
|
||||
before_all do
|
||||
project.add_maintainer(user)
|
||||
project.add_guest(user2)
|
||||
end
|
||||
|
@ -86,7 +52,7 @@ RSpec.describe 'Task Lists' do
|
|||
end
|
||||
|
||||
describe 'for Issues' do
|
||||
describe 'multiple tasks', :js do
|
||||
describe 'multiple tasks' do
|
||||
let!(:issue) { create(:issue, description: markdown, author: user, project: project) }
|
||||
|
||||
it 'renders' do
|
||||
|
@ -127,7 +93,7 @@ RSpec.describe 'Task Lists' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'single incomplete task', :js do
|
||||
describe 'single incomplete task' do
|
||||
let!(:issue) { create(:issue, description: singleIncompleteMarkdown, author: user, project: project) }
|
||||
|
||||
it 'renders' do
|
||||
|
@ -146,7 +112,7 @@ RSpec.describe 'Task Lists' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'single complete task', :js do
|
||||
describe 'single complete task' do
|
||||
let!(:issue) { create(:issue, description: singleCompleteMarkdown, author: user, project: project) }
|
||||
|
||||
it 'renders' do
|
||||
|
@ -175,7 +141,7 @@ RSpec.describe 'Task Lists' do
|
|||
project: project, author: user)
|
||||
end
|
||||
|
||||
it 'renders for note body', :js do
|
||||
it 'renders for note body' do
|
||||
visit_issue(project, issue)
|
||||
|
||||
expect(page).to have_selector('.note ul.task-list', count: 1)
|
||||
|
@ -183,14 +149,14 @@ RSpec.describe 'Task Lists' do
|
|||
expect(page).to have_selector('.note ul input[checked]', count: 2)
|
||||
end
|
||||
|
||||
it 'contains the required selectors', :js do
|
||||
it 'contains the required selectors' do
|
||||
visit_issue(project, issue)
|
||||
|
||||
expect(page).to have_selector('.note .js-task-list-container')
|
||||
expect(page).to have_selector('.note .js-task-list-container .task-list .task-list-item .task-list-item-checkbox')
|
||||
end
|
||||
|
||||
it 'is only editable by author', :js do
|
||||
it 'is only editable by author' do
|
||||
visit_issue(project, issue)
|
||||
|
||||
expect(page).to have_selector('.js-task-list-container')
|
||||
|
@ -209,7 +175,7 @@ RSpec.describe 'Task Lists' do
|
|||
project: project, author: user)
|
||||
end
|
||||
|
||||
it 'renders for note body', :js do
|
||||
it 'renders for note body' do
|
||||
visit_issue(project, issue)
|
||||
|
||||
expect(page).to have_selector('.note ul.task-list', count: 1)
|
||||
|
@ -224,7 +190,7 @@ RSpec.describe 'Task Lists' do
|
|||
project: project, author: user)
|
||||
end
|
||||
|
||||
it 'renders for note body', :js do
|
||||
it 'renders for note body' do
|
||||
visit_issue(project, issue)
|
||||
|
||||
expect(page).to have_selector('.note ul.task-list', count: 1)
|
||||
|
@ -240,7 +206,7 @@ RSpec.describe 'Task Lists' do
|
|||
end
|
||||
|
||||
shared_examples 'multiple tasks' do
|
||||
it 'renders for description', :js do
|
||||
it 'renders for description' do
|
||||
visit_merge_request(project, merge)
|
||||
wait_for_requests
|
||||
|
||||
|
@ -249,7 +215,7 @@ RSpec.describe 'Task Lists' do
|
|||
expect(page).to have_selector('ul input[checked]', count: 2)
|
||||
end
|
||||
|
||||
it 'contains the required selectors', :js do
|
||||
it 'contains the required selectors' do
|
||||
visit_merge_request(project, merge)
|
||||
wait_for_requests
|
||||
|
||||
|
@ -261,7 +227,7 @@ RSpec.describe 'Task Lists' do
|
|||
expect(page).to have_selector('form.js-issuable-update')
|
||||
end
|
||||
|
||||
it 'is only editable by author', :js do
|
||||
it 'is only editable by author' do
|
||||
visit_merge_request(project, merge)
|
||||
wait_for_requests
|
||||
|
||||
|
@ -300,7 +266,7 @@ RSpec.describe 'Task Lists' do
|
|||
describe 'single incomplete task' do
|
||||
let!(:merge) { create(:merge_request, :simple, description: singleIncompleteMarkdown, author: user, source_project: project) }
|
||||
|
||||
it 'renders for description', :js do
|
||||
it 'renders for description' do
|
||||
visit_merge_request(project, merge)
|
||||
wait_for_requests
|
||||
|
||||
|
@ -319,7 +285,7 @@ RSpec.describe 'Task Lists' do
|
|||
describe 'single complete task' do
|
||||
let!(:merge) { create(:merge_request, :simple, description: singleCompleteMarkdown, author: user, source_project: project) }
|
||||
|
||||
it 'renders for description', :js do
|
||||
it 'renders for description' do
|
||||
visit_merge_request(project, merge)
|
||||
wait_for_requests
|
||||
|
||||
|
@ -337,7 +303,17 @@ RSpec.describe 'Task Lists' do
|
|||
end
|
||||
|
||||
describe 'markdown task edge cases' do
|
||||
describe 'commented tasks', :js do
|
||||
describe 'commented tasks' do
|
||||
let(:commented_tasks_markdown) do
|
||||
<<-EOT.strip_heredoc
|
||||
<!--
|
||||
- [ ] a
|
||||
-->
|
||||
|
||||
- [ ] b
|
||||
EOT
|
||||
end
|
||||
|
||||
let!(:issue) { create(:issue, description: commented_tasks_markdown, author: user, project: project) }
|
||||
|
||||
it 'renders' do
|
||||
|
@ -360,7 +336,18 @@ RSpec.describe 'Task Lists' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'summary with no blank line', :js do
|
||||
describe 'summary with no blank line' do
|
||||
let(:summary_no_blank_line_markdown) do
|
||||
<<-EOT.strip_heredoc
|
||||
<details>
|
||||
<summary>No blank line after summary element breaks task list</summary>
|
||||
1. [ ] People Ops: do such and such
|
||||
</details>
|
||||
|
||||
* [ ] Task 1
|
||||
EOT
|
||||
end
|
||||
|
||||
let!(:issue) { create(:issue, description: summary_no_blank_line_markdown, author: user, project: project) }
|
||||
|
||||
it 'renders' do
|
||||
|
@ -382,5 +369,31 @@ RSpec.describe 'Task Lists' do
|
|||
expect(page).to have_selector('ul input[checked]', count: 1)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'markdown starting with new line character' do
|
||||
let(:markdown_starting_with_new_line) do
|
||||
<<-EOT.strip_heredoc
|
||||
|
||||
- [ ] Task 1
|
||||
EOT
|
||||
end
|
||||
|
||||
let(:merge_request) { create(:merge_request, description: markdown_starting_with_new_line, author: user, source_project: project) }
|
||||
|
||||
it 'allows the task to be checked' do
|
||||
visit project_merge_request_path(project, merge_request)
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_selector('ul input[checked]', count: 0)
|
||||
|
||||
find('.task-list-item-checkbox').click
|
||||
wait_for_requests
|
||||
|
||||
visit project_merge_request_path(project, merge_request)
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_selector('ul input[checked]', count: 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -79,7 +79,7 @@ describe('Incident Tabs component', () => {
|
|||
it('renders the alert details table with the correct props', () => {
|
||||
const alert = { iid: mockAlert.iid };
|
||||
|
||||
expect(findAlertDetailsComponent().props('alert')).toEqual(alert);
|
||||
expect(findAlertDetailsComponent().props('alert')).toMatchObject(alert);
|
||||
expect(findAlertDetailsComponent().props('loading')).toBe(true);
|
||||
});
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ const mockAlert = {
|
|||
assignees: { nodes: [] },
|
||||
notes: { nodes: [] },
|
||||
todos: { nodes: [] },
|
||||
__typename: 'AlertManagementAlert',
|
||||
};
|
||||
|
||||
describe('AlertDetails', () => {
|
||||
|
@ -35,6 +36,8 @@ describe('AlertDetails', () => {
|
|||
});
|
||||
|
||||
const findTableComponent = () => wrapper.find(GlTable);
|
||||
const findTableKeys = () => findTableComponent().findAll('tbody td:first-child');
|
||||
const findTableField = (fields, fieldName) => fields.filter(row => row.text() === fieldName);
|
||||
|
||||
describe('Alert details', () => {
|
||||
describe('empty state', () => {
|
||||
|
@ -69,6 +72,24 @@ describe('AlertDetails', () => {
|
|||
it('renders a cell based on alert data', () => {
|
||||
expect(findTableComponent().text()).toContain('SyntaxError: Invalid or unexpected token');
|
||||
});
|
||||
|
||||
it('should show allowed alert fields', () => {
|
||||
const fields = findTableKeys();
|
||||
|
||||
expect(findTableField(fields, 'Iid').exists()).toBe(true);
|
||||
expect(findTableField(fields, 'Title').exists()).toBe(true);
|
||||
expect(findTableField(fields, 'Severity').exists()).toBe(true);
|
||||
expect(findTableField(fields, 'Status').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should not show disallowed alert fields', () => {
|
||||
const fields = findTableKeys();
|
||||
|
||||
expect(findTableField(fields, 'Typename').exists()).toBe(false);
|
||||
expect(findTableField(fields, 'Todos').exists()).toBe(false);
|
||||
expect(findTableField(fields, 'Notes').exists()).toBe(false);
|
||||
expect(findTableField(fields, 'Assignees').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -108,6 +108,24 @@ RSpec.describe Gitlab::Database::BatchCount do
|
|||
expect { described_class.batch_count(model.distinct(column)) }.to raise_error 'Use distinct count for optimized distinct counting'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a relation is grouped' do
|
||||
let!(:one_more_issue) { create(:issue, author: user, project: model.first.project) }
|
||||
|
||||
before do
|
||||
stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 1)
|
||||
end
|
||||
|
||||
context 'count by default column' do
|
||||
let(:count) do
|
||||
described_class.batch_count(model.group(column), batch_size: 2)
|
||||
end
|
||||
|
||||
it 'counts grouped records' do
|
||||
expect(count).to eq({ user.id => 4, another_user.id => 2 })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#batch_distinct_count' do
|
||||
|
@ -175,6 +193,24 @@ RSpec.describe Gitlab::Database::BatchCount do
|
|||
end.to raise_error 'Use distinct count only with non id fields'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a relation is grouped' do
|
||||
let!(:one_more_issue) { create(:issue, author: user, project: model.first.project) }
|
||||
|
||||
before do
|
||||
stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 1)
|
||||
end
|
||||
|
||||
context 'distinct count by non-unique column' do
|
||||
let(:count) do
|
||||
described_class.batch_distinct_count(model.group(column), :project_id, batch_size: 2)
|
||||
end
|
||||
|
||||
it 'counts grouped records' do
|
||||
expect(count).to eq({ user.id => 3, another_user.id => 2 })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#batch_sum' do
|
||||
|
|
|
@ -264,4 +264,34 @@ RSpec.describe API::Services do
|
|||
expect(json_response['properties']['notify_only_broken_pipelines']).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Hangouts Chat service' do
|
||||
let(:service_name) { 'hangouts-chat' }
|
||||
let(:params) do
|
||||
{
|
||||
webhook: 'https://hook.example.com',
|
||||
branches_to_be_notified: 'default'
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
project.create_hangouts_chat_service(
|
||||
active: true,
|
||||
properties: params
|
||||
)
|
||||
end
|
||||
|
||||
it 'accepts branches_to_be_notified for update', :aggregate_failures do
|
||||
put api("/projects/#{project.id}/services/#{service_name}", user), params: params.merge(branches_to_be_notified: 'all')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['properties']['branches_to_be_notified']).to eq('all')
|
||||
end
|
||||
|
||||
it 'only requires the webhook param' do
|
||||
put api("/projects/#{project.id}/services/#{service_name}", user), params: { webhook: 'https://hook.example.com' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue