New upstream version 10.6.3+dfsg
This commit is contained in:
parent
a0b2b84db1
commit
427f406db4
40 changed files with 556 additions and 30 deletions
|
@ -2,6 +2,14 @@
|
||||||
documentation](doc/development/changelog.md) for instructions on adding your own
|
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||||
entry.
|
entry.
|
||||||
|
|
||||||
|
## 10.6.3 (2018-04-03)
|
||||||
|
|
||||||
|
### Security (2 changes)
|
||||||
|
|
||||||
|
- Fix XSS on diff view stored on filenames.
|
||||||
|
- Adds confidential notes channel for Slack/Mattermost.
|
||||||
|
|
||||||
|
|
||||||
## 10.6.2 (2018-03-29)
|
## 10.6.2 (2018-03-29)
|
||||||
|
|
||||||
### Fixed (2 changes, 1 of them is from the community)
|
### Fixed (2 changes, 1 of them is from the community)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
10.6.2
|
10.6.3
|
||||||
|
|
|
@ -92,10 +92,10 @@ export default class MilestoneSelect {
|
||||||
if (showMenuAbove) {
|
if (showMenuAbove) {
|
||||||
$dropdown.data('glDropdown').positionMenuAbove();
|
$dropdown.data('glDropdown').positionMenuAbove();
|
||||||
}
|
}
|
||||||
$(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active');
|
$(`[data-milestone-id="${_.escape(selectedMilestone)}"] > a`).addClass('is-active');
|
||||||
}),
|
}),
|
||||||
renderRow: milestone => `
|
renderRow: milestone => `
|
||||||
<li data-milestone-id="${milestone.name}">
|
<li data-milestone-id="${_.escape(milestone.name)}">
|
||||||
<a href='#' class='dropdown-menu-milestone-link'>
|
<a href='#' class='dropdown-menu-milestone-link'>
|
||||||
${_.escape(milestone.title)}
|
${_.escape(milestone.title)}
|
||||||
</a>
|
</a>
|
||||||
|
@ -123,7 +123,6 @@ export default class MilestoneSelect {
|
||||||
return milestone.id;
|
return milestone.id;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isSelected: milestone => milestone.name === selectedMilestone,
|
|
||||||
hidden: () => {
|
hidden: () => {
|
||||||
$selectBox.hide();
|
$selectBox.hide();
|
||||||
// display:block overrides the hide-collapse rule
|
// display:block overrides the hide-collapse rule
|
||||||
|
@ -135,7 +134,7 @@ export default class MilestoneSelect {
|
||||||
selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault;
|
selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault;
|
||||||
}
|
}
|
||||||
$('a.is-active', $el).removeClass('is-active');
|
$('a.is-active', $el).removeClass('is-active');
|
||||||
$(`[data-milestone-id="${selectedMilestone}"] > a`, $el).addClass('is-active');
|
$(`[data-milestone-id="${_.escape(selectedMilestone)}"] > a`, $el).addClass('is-active');
|
||||||
},
|
},
|
||||||
vue: $dropdown.hasClass('js-issue-board-sidebar'),
|
vue: $dropdown.hasClass('js-issue-board-sidebar'),
|
||||||
clicked: (clickEvent) => {
|
clicked: (clickEvent) => {
|
||||||
|
@ -156,6 +155,7 @@ export default class MilestoneSelect {
|
||||||
const isMRIndex = (page === page && page === 'projects:merge_requests:index');
|
const isMRIndex = (page === page && page === 'projects:merge_requests:index');
|
||||||
const isSelecting = (selected.name !== selectedMilestone);
|
const isSelecting = (selected.name !== selectedMilestone);
|
||||||
selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault;
|
selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault;
|
||||||
|
|
||||||
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {
|
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -7,9 +7,11 @@ module ServicesHelper
|
||||||
"Event will be triggered when a new tag is pushed to the repository"
|
"Event will be triggered when a new tag is pushed to the repository"
|
||||||
when "note", "note_events"
|
when "note", "note_events"
|
||||||
"Event will be triggered when someone adds a comment"
|
"Event will be triggered when someone adds a comment"
|
||||||
|
when "confidential_note", "confidential_note_events"
|
||||||
|
"Event will be triggered when someone adds a comment on a confidential issue"
|
||||||
when "issue", "issue_events"
|
when "issue", "issue_events"
|
||||||
"Event will be triggered when an issue is created/updated/closed"
|
"Event will be triggered when an issue is created/updated/closed"
|
||||||
when "confidential_issue", "confidential_issue_events"
|
when "confidential_issue", "confidential_issues_events"
|
||||||
"Event will be triggered when a confidential issue is created/updated/closed"
|
"Event will be triggered when a confidential issue is created/updated/closed"
|
||||||
when "merge_request", "merge_request_events"
|
when "merge_request", "merge_request_events"
|
||||||
"Event will be triggered when a merge request is created/updated/merged"
|
"Event will be triggered when a merge request is created/updated/merged"
|
||||||
|
|
|
@ -7,6 +7,7 @@ class ProjectHook < WebHook
|
||||||
:issue_hooks,
|
:issue_hooks,
|
||||||
:confidential_issue_hooks,
|
:confidential_issue_hooks,
|
||||||
:note_hooks,
|
:note_hooks,
|
||||||
|
:confidential_note_hooks,
|
||||||
:merge_request_hooks,
|
:merge_request_hooks,
|
||||||
:job_hooks,
|
:job_hooks,
|
||||||
:pipeline_hooks,
|
:pipeline_hooks,
|
||||||
|
|
|
@ -268,6 +268,10 @@ class Note < ActiveRecord::Base
|
||||||
self.special_role = Note::SpecialRole::FIRST_TIME_CONTRIBUTOR
|
self.special_role = Note::SpecialRole::FIRST_TIME_CONTRIBUTOR
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def confidential?
|
||||||
|
noteable.try(:confidential?)
|
||||||
|
end
|
||||||
|
|
||||||
def editable?
|
def editable?
|
||||||
!system?
|
!system?
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,8 +21,16 @@ class ChatNotificationService < Service
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def confidential_issue_channel
|
||||||
|
properties['confidential_issue_channel'].presence || properties['issue_channel']
|
||||||
|
end
|
||||||
|
|
||||||
|
def confidential_note_channel
|
||||||
|
properties['confidential_note_channel'].presence || properties['note_channel']
|
||||||
|
end
|
||||||
|
|
||||||
def self.supported_events
|
def self.supported_events
|
||||||
%w[push issue confidential_issue merge_request note tag_push
|
%w[push issue confidential_issue merge_request note confidential_note tag_push
|
||||||
pipeline wiki_page]
|
pipeline wiki_page]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -55,7 +63,9 @@ class ChatNotificationService < Service
|
||||||
|
|
||||||
return false unless message
|
return false unless message
|
||||||
|
|
||||||
channel_name = get_channel_field(object_kind).presence || channel
|
event_type = data[:event_type] || object_kind
|
||||||
|
|
||||||
|
channel_name = get_channel_field(event_type).presence || channel
|
||||||
|
|
||||||
opts = {}
|
opts = {}
|
||||||
opts[:channel] = channel_name if channel_name
|
opts[:channel] = channel_name if channel_name
|
||||||
|
|
|
@ -46,7 +46,7 @@ class HipchatService < Service
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.supported_events
|
def self.supported_events
|
||||||
%w(push issue confidential_issue merge_request note tag_push pipeline)
|
%w(push issue confidential_issue merge_request note confidential_note tag_push pipeline)
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute(data)
|
def execute(data)
|
||||||
|
|
|
@ -14,6 +14,7 @@ class Service < ActiveRecord::Base
|
||||||
default_value_for :merge_requests_events, true
|
default_value_for :merge_requests_events, true
|
||||||
default_value_for :tag_push_events, true
|
default_value_for :tag_push_events, true
|
||||||
default_value_for :note_events, true
|
default_value_for :note_events, true
|
||||||
|
default_value_for :confidential_note_events, true
|
||||||
default_value_for :job_events, true
|
default_value_for :job_events, true
|
||||||
default_value_for :pipeline_events, true
|
default_value_for :pipeline_events, true
|
||||||
default_value_for :wiki_page_events, true
|
default_value_for :wiki_page_events, true
|
||||||
|
@ -42,6 +43,7 @@ class Service < ActiveRecord::Base
|
||||||
scope :confidential_issue_hooks, -> { where(confidential_issues_events: true, active: true) }
|
scope :confidential_issue_hooks, -> { where(confidential_issues_events: true, active: true) }
|
||||||
scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) }
|
scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) }
|
||||||
scope :note_hooks, -> { where(note_events: true, active: true) }
|
scope :note_hooks, -> { where(note_events: true, active: true) }
|
||||||
|
scope :confidential_note_hooks, -> { where(confidential_note_events: true, active: true) }
|
||||||
scope :job_hooks, -> { where(job_events: true, active: true) }
|
scope :job_hooks, -> { where(job_events: true, active: true) }
|
||||||
scope :pipeline_hooks, -> { where(pipeline_events: true, active: true) }
|
scope :pipeline_hooks, -> { where(pipeline_events: true, active: true) }
|
||||||
scope :wiki_page_hooks, -> { where(wiki_page_events: true, active: true) }
|
scope :wiki_page_hooks, -> { where(wiki_page_events: true, active: true) }
|
||||||
|
@ -173,8 +175,10 @@ class Service < ActiveRecord::Base
|
||||||
def self.prop_accessor(*args)
|
def self.prop_accessor(*args)
|
||||||
args.each do |arg|
|
args.each do |arg|
|
||||||
class_eval %{
|
class_eval %{
|
||||||
def #{arg}
|
unless method_defined?(arg)
|
||||||
properties['#{arg}']
|
def #{arg}
|
||||||
|
properties['#{arg}']
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def #{arg}=(value)
|
def #{arg}=(value)
|
||||||
|
|
|
@ -24,8 +24,10 @@ module Notes
|
||||||
|
|
||||||
def execute_note_hooks
|
def execute_note_hooks
|
||||||
note_data = hook_data
|
note_data = hook_data
|
||||||
@note.project.execute_hooks(note_data, :note_hooks)
|
hooks_scope = @note.confidential? ? :confidential_note_hooks : :note_hooks
|
||||||
@note.project.execute_services(note_data, :note_hooks)
|
|
||||||
|
@note.project.execute_hooks(note_data, hooks_scope)
|
||||||
|
@note.project.execute_services(note_data, hooks_scope)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,6 +32,13 @@
|
||||||
%strong Comments
|
%strong Comments
|
||||||
%p.light
|
%p.light
|
||||||
This URL will be triggered when someone adds a comment
|
This URL will be triggered when someone adds a comment
|
||||||
|
%li
|
||||||
|
= form.check_box :confidential_note_events, class: 'pull-left'
|
||||||
|
.prepend-left-20
|
||||||
|
= form.label :confidential_note_events, class: 'list-label' do
|
||||||
|
%strong Confidential Comments
|
||||||
|
%p.light
|
||||||
|
This URL will be triggered when someone adds a comment on a confidential issue
|
||||||
%li
|
%li
|
||||||
= form.check_box :issues_events, class: 'pull-left'
|
= form.check_box :issues_events, class: 'pull-left'
|
||||||
.prepend-left-20
|
.prepend-left-20
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
class AddConfidentialNoteEventsToWebHooks < ActiveRecord::Migration
|
||||||
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
add_column :web_hooks, :confidential_note_events, :boolean
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :web_hooks, :confidential_note_events
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
class AddConfidentialNoteEventsToServices < ActiveRecord::Migration
|
||||||
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
add_column :services, :confidential_note_events, :boolean
|
||||||
|
change_column_default :services, :confidential_note_events, true
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :services, :confidential_note_events
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,23 @@
|
||||||
|
class ScheduleSetConfidentialNoteEventsOnWebhooks < ActiveRecord::Migration
|
||||||
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
|
DOWNTIME = false
|
||||||
|
BATCH_SIZE = 1_000
|
||||||
|
INTERVAL = 5.minutes
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
migration = Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnWebhooks
|
||||||
|
migration_name = migration.to_s.demodulize
|
||||||
|
relation = migration::WebHook.hooks_to_update
|
||||||
|
|
||||||
|
queue_background_migration_jobs_by_range_at_intervals(relation,
|
||||||
|
migration_name,
|
||||||
|
INTERVAL,
|
||||||
|
batch_size: BATCH_SIZE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,23 @@
|
||||||
|
class ScheduleSetConfidentialNoteEventsOnServices < ActiveRecord::Migration
|
||||||
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
|
DOWNTIME = false
|
||||||
|
BATCH_SIZE = 1_000
|
||||||
|
INTERVAL = 20.minutes
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
migration = Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnServices
|
||||||
|
migration_name = migration.to_s.demodulize
|
||||||
|
relation = migration::Service.services_to_update
|
||||||
|
|
||||||
|
queue_background_migration_jobs_by_range_at_intervals(relation,
|
||||||
|
migration_name,
|
||||||
|
INTERVAL,
|
||||||
|
batch_size: BATCH_SIZE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
end
|
||||||
|
end
|
|
@ -1660,6 +1660,7 @@ ActiveRecord::Schema.define(version: 20180320182229) do
|
||||||
t.boolean "confidential_issues_events", default: true, null: false
|
t.boolean "confidential_issues_events", default: true, null: false
|
||||||
t.boolean "commit_events", default: true, null: false
|
t.boolean "commit_events", default: true, null: false
|
||||||
t.boolean "job_events", default: false, null: false
|
t.boolean "job_events", default: false, null: false
|
||||||
|
t.boolean "confidential_note_events", default: true
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
|
add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
|
||||||
|
@ -1997,6 +1998,7 @@ ActiveRecord::Schema.define(version: 20180320182229) do
|
||||||
t.boolean "confidential_issues_events", default: false, null: false
|
t.boolean "confidential_issues_events", default: false, null: false
|
||||||
t.boolean "repository_update_events", default: false, null: false
|
t.boolean "repository_update_events", default: false, null: false
|
||||||
t.boolean "job_events", default: false, null: false
|
t.boolean "job_events", default: false, null: false
|
||||||
|
t.boolean "confidential_note_events"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree
|
add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree
|
||||||
|
|
|
@ -72,7 +72,7 @@ module API
|
||||||
|
|
||||||
class ProjectHook < Hook
|
class ProjectHook < Hook
|
||||||
expose :project_id, :issues_events, :confidential_issues_events
|
expose :project_id, :issues_events, :confidential_issues_events
|
||||||
expose :note_events, :pipeline_events, :wiki_page_events
|
expose :note_events, :confidential_note_events, :pipeline_events, :wiki_page_events
|
||||||
expose :job_events
|
expose :job_events
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -792,7 +792,7 @@ module API
|
||||||
expose :id, :title, :created_at, :updated_at, :active
|
expose :id, :title, :created_at, :updated_at, :active
|
||||||
expose :push_events, :issues_events, :confidential_issues_events
|
expose :push_events, :issues_events, :confidential_issues_events
|
||||||
expose :merge_requests_events, :tag_push_events, :note_events
|
expose :merge_requests_events, :tag_push_events, :note_events
|
||||||
expose :pipeline_events, :wiki_page_events
|
expose :confidential_note_events, :pipeline_events, :wiki_page_events
|
||||||
expose :job_events
|
expose :job_events
|
||||||
# Expose serialized properties
|
# Expose serialized properties
|
||||||
expose :properties do |service, options|
|
expose :properties do |service, options|
|
||||||
|
|
|
@ -14,6 +14,7 @@ module API
|
||||||
optional :merge_requests_events, type: Boolean, desc: "Trigger hook on merge request events"
|
optional :merge_requests_events, type: Boolean, desc: "Trigger hook on merge request events"
|
||||||
optional :tag_push_events, type: Boolean, desc: "Trigger hook on tag push events"
|
optional :tag_push_events, type: Boolean, desc: "Trigger hook on tag push events"
|
||||||
optional :note_events, type: Boolean, desc: "Trigger hook on note(comment) events"
|
optional :note_events, type: Boolean, desc: "Trigger hook on note(comment) events"
|
||||||
|
optional :confidential_note_events, type: Boolean, desc: "Trigger hook on confidential note(comment) events"
|
||||||
optional :job_events, type: Boolean, desc: "Trigger hook on job events"
|
optional :job_events, type: Boolean, desc: "Trigger hook on job events"
|
||||||
optional :pipeline_events, type: Boolean, desc: "Trigger hook on pipeline events"
|
optional :pipeline_events, type: Boolean, desc: "Trigger hook on pipeline events"
|
||||||
optional :wiki_page_events, type: Boolean, desc: "Trigger hook on wiki events"
|
optional :wiki_page_events, type: Boolean, desc: "Trigger hook on wiki events"
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
# rubocop:disable Style/Documentation
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module BackgroundMigration
|
||||||
|
# Ensures services which previously recieved all notes events continue
|
||||||
|
# to recieve confidential ones.
|
||||||
|
class SetConfidentialNoteEventsOnServices
|
||||||
|
class Service < ActiveRecord::Base
|
||||||
|
self.table_name = 'services'
|
||||||
|
|
||||||
|
include ::EachBatch
|
||||||
|
|
||||||
|
def self.services_to_update
|
||||||
|
where(confidential_note_events: nil, note_events: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform(start_id, stop_id)
|
||||||
|
Service.services_to_update
|
||||||
|
.where(id: start_id..stop_id)
|
||||||
|
.update_all(confidential_note_events: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,26 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
# rubocop:disable Style/Documentation
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module BackgroundMigration
|
||||||
|
# Ensures hooks which previously recieved all notes events continue
|
||||||
|
# to recieve confidential ones.
|
||||||
|
class SetConfidentialNoteEventsOnWebhooks
|
||||||
|
class WebHook < ActiveRecord::Base
|
||||||
|
self.table_name = 'web_hooks'
|
||||||
|
|
||||||
|
include ::EachBatch
|
||||||
|
|
||||||
|
def self.hooks_to_update
|
||||||
|
where(confidential_note_events: nil, note_events: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform(start_id, stop_id)
|
||||||
|
WebHook.hooks_to_update
|
||||||
|
.where(id: start_id..stop_id)
|
||||||
|
.update_all(confidential_note_events: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,6 +9,7 @@ module Gitlab
|
||||||
#
|
#
|
||||||
# data = {
|
# data = {
|
||||||
# object_kind: "note",
|
# object_kind: "note",
|
||||||
|
# event_type: "confidential_note",
|
||||||
# user: {
|
# user: {
|
||||||
# name: String,
|
# name: String,
|
||||||
# username: String,
|
# username: String,
|
||||||
|
@ -51,8 +52,11 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_base_data(project, user, note)
|
def build_base_data(project, user, note)
|
||||||
|
event_type = note.confidential? ? 'confidential_note' : 'note'
|
||||||
|
|
||||||
base_data = {
|
base_data = {
|
||||||
object_kind: "note",
|
object_kind: "note",
|
||||||
|
event_type: event_type,
|
||||||
user: user.hook_attrs,
|
user: user.hook_attrs,
|
||||||
project_id: project.id,
|
project_id: project.id,
|
||||||
project: project.hook_attrs,
|
project: project.hook_attrs,
|
||||||
|
|
|
@ -820,7 +820,7 @@ into similar problems in the future (e.g. when new tables are created).
|
||||||
# Each job is scheduled with a `delay_interval` in between.
|
# Each job is scheduled with a `delay_interval` in between.
|
||||||
# If you use a small interval, then some jobs may run at the same time.
|
# If you use a small interval, then some jobs may run at the same time.
|
||||||
#
|
#
|
||||||
# model_class - The table being iterated over
|
# model_class - The table or relation being iterated over
|
||||||
# job_class_name - The background migration job class as a string
|
# job_class_name - The background migration job class as a string
|
||||||
# delay_interval - The duration between each job's scheduled time (must respond to `to_f`)
|
# delay_interval - The duration between each job's scheduled time (must respond to `to_f`)
|
||||||
# batch_size - The maximum number of rows per job
|
# batch_size - The maximum number of rows per job
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
module Gitlab
|
module Gitlab
|
||||||
module Diff
|
module Diff
|
||||||
class InlineDiffMarker < Gitlab::StringRangeMarker
|
class InlineDiffMarker < Gitlab::StringRangeMarker
|
||||||
|
def initialize(line, rich_line = nil)
|
||||||
|
super(line, rich_line || line)
|
||||||
|
end
|
||||||
|
|
||||||
def mark(line_inline_diffs, mode: nil)
|
def mark(line_inline_diffs, mode: nil)
|
||||||
mark = super(line_inline_diffs) do |text, left:, right:|
|
super(line_inline_diffs) do |text, left:, right:|
|
||||||
%{<span class="#{html_class_names(left, right, mode)}">#{text}</span>}
|
%{<span class="#{html_class_names(left, right, mode)}">#{text}</span>}
|
||||||
end
|
end
|
||||||
mark.html_safe
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -11,7 +11,8 @@ module Gitlab
|
||||||
|
|
||||||
def build(user: nil, changes: {})
|
def build(user: nil, changes: {})
|
||||||
hook_data = {
|
hook_data = {
|
||||||
object_kind: issuable.class.name.underscore,
|
object_kind: object_kind,
|
||||||
|
event_type: event_type,
|
||||||
user: user.hook_attrs,
|
user: user.hook_attrs,
|
||||||
project: issuable.project.hook_attrs,
|
project: issuable.project.hook_attrs,
|
||||||
object_attributes: issuable.hook_attrs,
|
object_attributes: issuable.hook_attrs,
|
||||||
|
@ -36,6 +37,18 @@ module Gitlab
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def object_kind
|
||||||
|
issuable.class.name.underscore
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_type
|
||||||
|
if issuable.try(:confidential?)
|
||||||
|
"confidential_#{object_kind}"
|
||||||
|
else
|
||||||
|
object_kind
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def issuable_builder
|
def issuable_builder
|
||||||
case issuable
|
case issuable
|
||||||
when Issue
|
when Issue
|
||||||
|
|
|
@ -15,6 +15,7 @@ FactoryBot.define do
|
||||||
issues_events true
|
issues_events true
|
||||||
confidential_issues_events true
|
confidential_issues_events true
|
||||||
note_events true
|
note_events true
|
||||||
|
confidential_note_events true
|
||||||
job_events true
|
job_events true
|
||||||
pipeline_events true
|
pipeline_events true
|
||||||
wiki_page_events true
|
wiki_page_events true
|
||||||
|
|
|
@ -226,6 +226,23 @@ describe 'New/edit issue', :js do
|
||||||
|
|
||||||
expect(page).to have_selector('.atwho-view')
|
expect(page).to have_selector('.atwho-view')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'milestone' do
|
||||||
|
let!(:milestone) { create(:milestone, title: '"><img src=x onerror=alert(document.domain)>', project: project) }
|
||||||
|
|
||||||
|
it 'escapes milestone' do
|
||||||
|
click_button 'Milestone'
|
||||||
|
|
||||||
|
page.within '.issue-milestone' do
|
||||||
|
click_link milestone.title
|
||||||
|
end
|
||||||
|
|
||||||
|
page.within '.js-milestone-select' do
|
||||||
|
expect(page).to have_content milestone.title
|
||||||
|
expect(page).not_to have_selector 'img'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'edit issue' do
|
context 'edit issue' do
|
||||||
|
|
|
@ -135,11 +135,37 @@ describe DiffHelper do
|
||||||
it "returns strings with marked inline diffs" do
|
it "returns strings with marked inline diffs" do
|
||||||
marked_old_line, marked_new_line = mark_inline_diffs(old_line, new_line)
|
marked_old_line, marked_new_line = mark_inline_diffs(old_line, new_line)
|
||||||
|
|
||||||
expect(marked_old_line).to eq(%q{abc <span class="idiff left right deletion">'def'</span>})
|
expect(marked_old_line).to eq(%q{abc <span class="idiff left right deletion">'def'</span>})
|
||||||
expect(marked_old_line).to be_html_safe
|
expect(marked_old_line).to be_html_safe
|
||||||
expect(marked_new_line).to eq(%q{abc <span class="idiff left right addition">"def"</span>})
|
expect(marked_new_line).to eq(%q{abc <span class="idiff left right addition">"def"</span>})
|
||||||
expect(marked_new_line).to be_html_safe
|
expect(marked_new_line).to be_html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when given HTML' do
|
||||||
|
it 'sanitizes it' do
|
||||||
|
old_line = %{test.txt}
|
||||||
|
new_line = %{<img src=x onerror=alert(document.domain)>}
|
||||||
|
|
||||||
|
marked_old_line, marked_new_line = mark_inline_diffs(old_line, new_line)
|
||||||
|
|
||||||
|
expect(marked_old_line).to eq(%q{<span class="idiff left right deletion">test.txt</span>})
|
||||||
|
expect(marked_old_line).to be_html_safe
|
||||||
|
expect(marked_new_line).to eq(%q{<span class="idiff left right addition"><img src=x onerror=alert(document.domain)></span>})
|
||||||
|
expect(marked_new_line).to be_html_safe
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sanitizes the entire line, not just the changes' do
|
||||||
|
old_line = %{<img src=x onerror=alert(document.domain)>}
|
||||||
|
new_line = %{<img src=y onerror=alert(document.domain)>}
|
||||||
|
|
||||||
|
marked_old_line, marked_new_line = mark_inline_diffs(old_line, new_line)
|
||||||
|
|
||||||
|
expect(marked_old_line).to eq(%q{<img src=<span class="idiff left right deletion">x</span> onerror=alert(document.domain)>})
|
||||||
|
expect(marked_old_line).to be_html_safe
|
||||||
|
expect(marked_new_line).to eq(%q{<img src=<span class="idiff left right addition">y</span> onerror=alert(document.domain)>})
|
||||||
|
expect(marked_new_line).to be_html_safe
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#parallel_diff_discussions' do
|
describe '#parallel_diff_discussions' do
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnServices, :migration, schema: 20180122154930 do
|
||||||
|
let(:services) { table(:services) }
|
||||||
|
|
||||||
|
describe '#perform' do
|
||||||
|
it 'migrates services where note_events is true' do
|
||||||
|
service = services.create(confidential_note_events: nil, note_events: true)
|
||||||
|
|
||||||
|
subject.perform(service.id, service.id)
|
||||||
|
|
||||||
|
expect(service.reload.confidential_note_events).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ignores services where note_events is false' do
|
||||||
|
service = services.create(confidential_note_events: nil, note_events: false)
|
||||||
|
|
||||||
|
subject.perform(service.id, service.id)
|
||||||
|
|
||||||
|
expect(service.reload.confidential_note_events).to eq(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ignores services where confidential_note_events has already been set' do
|
||||||
|
service = services.create(confidential_note_events: false, note_events: true)
|
||||||
|
|
||||||
|
subject.perform(service.id, service.id)
|
||||||
|
|
||||||
|
expect(service.reload.confidential_note_events).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,31 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnWebhooks, :migration, schema: 20180104131052 do
|
||||||
|
let(:web_hooks) { table(:web_hooks) }
|
||||||
|
|
||||||
|
describe '#perform' do
|
||||||
|
it 'migrates hooks where note_events is true' do
|
||||||
|
hook = web_hooks.create(confidential_note_events: nil, note_events: true)
|
||||||
|
|
||||||
|
subject.perform(hook.id, hook.id)
|
||||||
|
|
||||||
|
expect(hook.reload.confidential_note_events).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ignores hooks where note_events is false' do
|
||||||
|
hook = web_hooks.create(confidential_note_events: nil, note_events: false)
|
||||||
|
|
||||||
|
subject.perform(hook.id, hook.id)
|
||||||
|
|
||||||
|
expect(hook.reload.confidential_note_events).to eq(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ignores hooks where confidential_note_events has already been set' do
|
||||||
|
hook = web_hooks.create(confidential_note_events: false, note_events: true)
|
||||||
|
|
||||||
|
subject.perform(hook.id, hook.id)
|
||||||
|
|
||||||
|
expect(hook.reload.confidential_note_events).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -55,6 +55,14 @@ describe Gitlab::DataBuilder::Note do
|
||||||
.to be > issue.hook_attrs['updated_at']
|
.to be > issue.hook_attrs['updated_at']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with confidential issue' do
|
||||||
|
let(:issue) { create(:issue, project: project, confidential: true) }
|
||||||
|
|
||||||
|
it 'sets event_type to confidential_note' do
|
||||||
|
expect(data[:event_type]).to eq('confidential_note')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
include_examples 'project hook data'
|
include_examples 'project hook data'
|
||||||
include_examples 'deprecated repository hook data'
|
include_examples 'deprecated repository hook data'
|
||||||
end
|
end
|
||||||
|
|
|
@ -387,6 +387,7 @@ Service:
|
||||||
- default
|
- default
|
||||||
- wiki_page_events
|
- wiki_page_events
|
||||||
- confidential_issues_events
|
- confidential_issues_events
|
||||||
|
- confidential_note_events
|
||||||
ProjectHook:
|
ProjectHook:
|
||||||
- id
|
- id
|
||||||
- url
|
- url
|
||||||
|
@ -407,6 +408,7 @@ ProjectHook:
|
||||||
- token
|
- token
|
||||||
- group_id
|
- group_id
|
||||||
- confidential_issues_events
|
- confidential_issues_events
|
||||||
|
- confidential_note_events
|
||||||
- repository_update_events
|
- repository_update_events
|
||||||
ProtectedBranch:
|
ProtectedBranch:
|
||||||
- id
|
- id
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require Rails.root.join('db', 'post_migrate', '20180122154930_schedule_set_confidential_note_events_on_services.rb')
|
||||||
|
|
||||||
|
describe ScheduleSetConfidentialNoteEventsOnServices, :migration, :sidekiq do
|
||||||
|
let(:services_table) { table(:services) }
|
||||||
|
let(:migration_class) { Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnServices }
|
||||||
|
let(:migration_name) { migration_class.to_s.demodulize }
|
||||||
|
|
||||||
|
let!(:service_1) { services_table.create!(confidential_note_events: nil, note_events: true) }
|
||||||
|
let!(:service_2) { services_table.create!(confidential_note_events: nil, note_events: true) }
|
||||||
|
let!(:service_migrated) { services_table.create!(confidential_note_events: true, note_events: true) }
|
||||||
|
let!(:service_skip) { services_table.create!(confidential_note_events: nil, note_events: false) }
|
||||||
|
let!(:service_new) { services_table.create!(confidential_note_events: false, note_events: true) }
|
||||||
|
let!(:service_4) { services_table.create!(confidential_note_events: nil, note_events: true) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_const("#{described_class}::BATCH_SIZE", 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'schedules background migrations at correct time' do
|
||||||
|
Sidekiq::Testing.fake! do
|
||||||
|
Timecop.freeze do
|
||||||
|
migrate!
|
||||||
|
|
||||||
|
expect(migration_name).to be_scheduled_delayed_migration(20.minutes, service_1.id, service_1.id)
|
||||||
|
expect(migration_name).to be_scheduled_delayed_migration(40.minutes, service_2.id, service_2.id)
|
||||||
|
expect(migration_name).to be_scheduled_delayed_migration(60.minutes, service_4.id, service_4.id)
|
||||||
|
expect(BackgroundMigrationWorker.jobs.size).to eq 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'correctly processes services' do
|
||||||
|
Sidekiq::Testing.inline! do
|
||||||
|
expect(services_table.where(confidential_note_events: nil).count).to eq 4
|
||||||
|
expect(services_table.where(confidential_note_events: true).count).to eq 1
|
||||||
|
|
||||||
|
migrate!
|
||||||
|
|
||||||
|
expect(services_table.where(confidential_note_events: nil).count).to eq 1
|
||||||
|
expect(services_table.where(confidential_note_events: true).count).to eq 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,8 +4,24 @@ require Rails.root.join('db', 'post_migrate', '20171013104327_migrate_gcp_cluste
|
||||||
describe MigrateGcpClustersToNewClustersArchitectures, :migration do
|
describe MigrateGcpClustersToNewClustersArchitectures, :migration do
|
||||||
let(:projects) { table(:projects) }
|
let(:projects) { table(:projects) }
|
||||||
let(:project) { projects.create }
|
let(:project) { projects.create }
|
||||||
let(:user) { create(:user) }
|
let(:users) { table(:users) }
|
||||||
let(:service) { create(:kubernetes_service, project_id: project.id) }
|
let(:user) { users.create! }
|
||||||
|
let(:service) { GcpMigrationSpec::KubernetesService.create!(project_id: project.id) }
|
||||||
|
|
||||||
|
module GcpMigrationSpec
|
||||||
|
class KubernetesService < ActiveRecord::Base
|
||||||
|
self.table_name = 'services'
|
||||||
|
|
||||||
|
serialize :properties, JSON # rubocop:disable Cop/ActiveRecordSerialize
|
||||||
|
|
||||||
|
default_value_for :active, true
|
||||||
|
default_value_for :type, 'KubernetesService'
|
||||||
|
default_value_for :properties, {
|
||||||
|
api_url: 'https://kubernetes.example.com',
|
||||||
|
token: 'a' * 40
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when cluster is being created' do
|
context 'when cluster is being created' do
|
||||||
let(:project_id) { project.id }
|
let(:project_id) { project.id }
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require Rails.root.join('db', 'post_migrate', '20180104131052_schedule_set_confidential_note_events_on_webhooks.rb')
|
||||||
|
|
||||||
|
describe ScheduleSetConfidentialNoteEventsOnWebhooks, :migration, :sidekiq do
|
||||||
|
let(:web_hooks_table) { table(:web_hooks) }
|
||||||
|
let(:migration_class) { Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnWebhooks }
|
||||||
|
let(:migration_name) { migration_class.to_s.demodulize }
|
||||||
|
|
||||||
|
let!(:web_hook_1) { web_hooks_table.create!(confidential_note_events: nil, note_events: true) }
|
||||||
|
let!(:web_hook_2) { web_hooks_table.create!(confidential_note_events: nil, note_events: true) }
|
||||||
|
let!(:web_hook_migrated) { web_hooks_table.create!(confidential_note_events: true, note_events: true) }
|
||||||
|
let!(:web_hook_skip) { web_hooks_table.create!(confidential_note_events: nil, note_events: false) }
|
||||||
|
let!(:web_hook_new) { web_hooks_table.create!(confidential_note_events: false, note_events: true) }
|
||||||
|
let!(:web_hook_4) { web_hooks_table.create!(confidential_note_events: nil, note_events: true) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_const("#{described_class}::BATCH_SIZE", 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'schedules background migrations at correct time' do
|
||||||
|
Sidekiq::Testing.fake! do
|
||||||
|
Timecop.freeze do
|
||||||
|
migrate!
|
||||||
|
|
||||||
|
expect(migration_name).to be_scheduled_delayed_migration(5.minutes, web_hook_1.id, web_hook_1.id)
|
||||||
|
expect(migration_name).to be_scheduled_delayed_migration(10.minutes, web_hook_2.id, web_hook_2.id)
|
||||||
|
expect(migration_name).to be_scheduled_delayed_migration(15.minutes, web_hook_4.id, web_hook_4.id)
|
||||||
|
expect(BackgroundMigrationWorker.jobs.size).to eq 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'correctly processes web hooks' do
|
||||||
|
Sidekiq::Testing.inline! do
|
||||||
|
expect(web_hooks_table.where(confidential_note_events: nil).count).to eq 4
|
||||||
|
expect(web_hooks_table.where(confidential_note_events: true).count).to eq 1
|
||||||
|
|
||||||
|
migrate!
|
||||||
|
|
||||||
|
expect(web_hooks_table.where(confidential_note_events: nil).count).to eq 1
|
||||||
|
expect(web_hooks_table.where(confidential_note_events: true).count).to eq 4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -191,6 +191,21 @@ describe Note do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "confidential?" do
|
||||||
|
it "delegates to noteable" do
|
||||||
|
issue_note = build(:note, :on_issue)
|
||||||
|
confidential_note = build(:note, noteable: create(:issue, confidential: true))
|
||||||
|
|
||||||
|
expect(issue_note.confidential?).to be_falsy
|
||||||
|
expect(confidential_note.confidential?).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is falsey when noteable can't be confidential" do
|
||||||
|
commit_note = build(:note_on_commit)
|
||||||
|
expect(commit_note.confidential?).to be_falsy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "cross_reference_not_visible_for?" do
|
describe "cross_reference_not_visible_for?" do
|
||||||
let(:private_user) { create(:user) }
|
let(:private_user) { create(:user) }
|
||||||
let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_master(private_user) } }
|
let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_master(private_user) } }
|
||||||
|
|
|
@ -253,6 +253,21 @@ describe HipchatService do
|
||||||
"<b>#{title}</b>" \
|
"<b>#{title}</b>" \
|
||||||
"<pre>issue <strong>note</strong></pre>")
|
"<pre>issue <strong>note</strong></pre>")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with confidential issue' do
|
||||||
|
before do
|
||||||
|
issue.update!(confidential: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'calls Hipchat API with issue comment' do
|
||||||
|
data = Gitlab::DataBuilder::Note.build(issue_note, user)
|
||||||
|
hipchat.execute(data)
|
||||||
|
|
||||||
|
message = hipchat.send(:create_message, data)
|
||||||
|
|
||||||
|
expect(message).to include("<pre>issue <strong>note</strong></pre>")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when snippet comment event triggered' do
|
context 'when snippet comment event triggered' do
|
||||||
|
|
|
@ -10,6 +10,22 @@ describe Service do
|
||||||
it { is_expected.to validate_presence_of(:type) }
|
it { is_expected.to validate_presence_of(:type) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'Scopes' do
|
||||||
|
describe '.confidential_note_hooks' do
|
||||||
|
it 'includes services where confidential_note_events is true' do
|
||||||
|
create(:service, active: true, confidential_note_events: true)
|
||||||
|
|
||||||
|
expect(described_class.confidential_note_hooks.count).to eq 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'excludes services where confidential_note_events is false' do
|
||||||
|
create(:service, active: true, confidential_note_events: false)
|
||||||
|
|
||||||
|
expect(described_class.confidential_note_hooks.count).to eq 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "Test Button" do
|
describe "Test Button" do
|
||||||
describe '#can_test?' do
|
describe '#can_test?' do
|
||||||
let(:service) { create(:service, project: project) }
|
let(:service) { create(:service, project: project) }
|
||||||
|
|
|
@ -33,6 +33,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
|
||||||
expect(json_response.first['merge_requests_events']).to eq(true)
|
expect(json_response.first['merge_requests_events']).to eq(true)
|
||||||
expect(json_response.first['tag_push_events']).to eq(true)
|
expect(json_response.first['tag_push_events']).to eq(true)
|
||||||
expect(json_response.first['note_events']).to eq(true)
|
expect(json_response.first['note_events']).to eq(true)
|
||||||
|
expect(json_response.first['confidential_note_events']).to eq(true)
|
||||||
expect(json_response.first['job_events']).to eq(true)
|
expect(json_response.first['job_events']).to eq(true)
|
||||||
expect(json_response.first['pipeline_events']).to eq(true)
|
expect(json_response.first['pipeline_events']).to eq(true)
|
||||||
expect(json_response.first['wiki_page_events']).to eq(true)
|
expect(json_response.first['wiki_page_events']).to eq(true)
|
||||||
|
@ -62,6 +63,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
|
||||||
expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events)
|
expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events)
|
||||||
expect(json_response['tag_push_events']).to eq(hook.tag_push_events)
|
expect(json_response['tag_push_events']).to eq(hook.tag_push_events)
|
||||||
expect(json_response['note_events']).to eq(hook.note_events)
|
expect(json_response['note_events']).to eq(hook.note_events)
|
||||||
|
expect(json_response['confidential_note_events']).to eq(hook.confidential_note_events)
|
||||||
expect(json_response['job_events']).to eq(hook.job_events)
|
expect(json_response['job_events']).to eq(hook.job_events)
|
||||||
expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
|
expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
|
||||||
expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
|
expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
|
||||||
|
@ -104,6 +106,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
|
||||||
expect(json_response['merge_requests_events']).to eq(false)
|
expect(json_response['merge_requests_events']).to eq(false)
|
||||||
expect(json_response['tag_push_events']).to eq(false)
|
expect(json_response['tag_push_events']).to eq(false)
|
||||||
expect(json_response['note_events']).to eq(false)
|
expect(json_response['note_events']).to eq(false)
|
||||||
|
expect(json_response['confidential_note_events']).to eq(nil)
|
||||||
expect(json_response['job_events']).to eq(true)
|
expect(json_response['job_events']).to eq(true)
|
||||||
expect(json_response['pipeline_events']).to eq(false)
|
expect(json_response['pipeline_events']).to eq(false)
|
||||||
expect(json_response['wiki_page_events']).to eq(true)
|
expect(json_response['wiki_page_events']).to eq(true)
|
||||||
|
@ -152,6 +155,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
|
||||||
expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events)
|
expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events)
|
||||||
expect(json_response['tag_push_events']).to eq(hook.tag_push_events)
|
expect(json_response['tag_push_events']).to eq(hook.tag_push_events)
|
||||||
expect(json_response['note_events']).to eq(hook.note_events)
|
expect(json_response['note_events']).to eq(hook.note_events)
|
||||||
|
expect(json_response['confidential_note_events']).to eq(hook.confidential_note_events)
|
||||||
expect(json_response['job_events']).to eq(hook.job_events)
|
expect(json_response['job_events']).to eq(hook.job_events)
|
||||||
expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
|
expect(json_response['pipeline_events']).to eq(hook.pipeline_events)
|
||||||
expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
|
expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events)
|
||||||
|
|
|
@ -23,5 +23,23 @@ describe Notes::PostProcessService do
|
||||||
|
|
||||||
described_class.new(@note).execute
|
described_class.new(@note).execute
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with a confidential issue' do
|
||||||
|
let(:issue) { create(:issue, :confidential, project: project) }
|
||||||
|
|
||||||
|
it "doesn't call note hooks/services" do
|
||||||
|
expect(project).not_to receive(:execute_hooks).with(anything, :note_hooks)
|
||||||
|
expect(project).not_to receive(:execute_services).with(anything, :note_hooks)
|
||||||
|
|
||||||
|
described_class.new(@note).execute
|
||||||
|
end
|
||||||
|
|
||||||
|
it "calls confidential-note hooks/services" do
|
||||||
|
expect(project).to receive(:execute_hooks).with(anything, :confidential_note_hooks)
|
||||||
|
expect(project).to receive(:execute_services).with(anything, :confidential_note_hooks)
|
||||||
|
|
||||||
|
described_class.new(@note).execute
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,11 @@ RSpec.shared_examples 'slack or mattermost notifications' do
|
||||||
let(:chat_service) { described_class.new }
|
let(:chat_service) { described_class.new }
|
||||||
let(:webhook_url) { 'https://example.gitlab.com/' }
|
let(:webhook_url) { 'https://example.gitlab.com/' }
|
||||||
|
|
||||||
|
def execute_with_options(options)
|
||||||
|
receive(:new).with(webhook_url, options)
|
||||||
|
.and_return(double(:slack_service).as_null_object)
|
||||||
|
end
|
||||||
|
|
||||||
describe "Associations" do
|
describe "Associations" do
|
||||||
it { is_expected.to belong_to :project }
|
it { is_expected.to belong_to :project }
|
||||||
it { is_expected.to have_one :service_hook }
|
it { is_expected.to have_one :service_hook }
|
||||||
|
@ -33,6 +38,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do
|
||||||
let(:project) { create(:project, :repository) }
|
let(:project) { create(:project, :repository) }
|
||||||
let(:username) { 'slack_username' }
|
let(:username) { 'slack_username' }
|
||||||
let(:channel) { 'slack_channel' }
|
let(:channel) { 'slack_channel' }
|
||||||
|
let(:issue_service_options) { { title: 'Awesome issue', description: 'please fix' } }
|
||||||
|
|
||||||
let(:push_sample_data) do
|
let(:push_sample_data) do
|
||||||
Gitlab::DataBuilder::Push.build_sample(project, user)
|
Gitlab::DataBuilder::Push.build_sample(project, user)
|
||||||
|
@ -48,12 +54,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do
|
||||||
|
|
||||||
WebMock.stub_request(:post, webhook_url)
|
WebMock.stub_request(:post, webhook_url)
|
||||||
|
|
||||||
opts = {
|
issue_service = Issues::CreateService.new(project, user, issue_service_options)
|
||||||
title: 'Awesome issue',
|
|
||||||
description: 'please fix'
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_service = Issues::CreateService.new(project, user, opts)
|
|
||||||
@issue = issue_service.execute
|
@issue = issue_service.execute
|
||||||
@issues_sample_data = issue_service.hook_data(@issue, 'open')
|
@issues_sample_data = issue_service.hook_data(@issue, 'open')
|
||||||
|
|
||||||
|
@ -164,6 +165,26 @@ RSpec.shared_examples 'slack or mattermost notifications' do
|
||||||
chat_service.execute(@issues_sample_data)
|
chat_service.execute(@issues_sample_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'for confidential issues' do
|
||||||
|
let(:issue_service_options) { { title: 'Secret', confidential: true } }
|
||||||
|
|
||||||
|
it "uses confidential issue channel" do
|
||||||
|
chat_service.update_attributes(confidential_issue_channel: 'confidential')
|
||||||
|
|
||||||
|
expect(Slack::Notifier).to execute_with_options(channel: 'confidential')
|
||||||
|
|
||||||
|
chat_service.execute(@issues_sample_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'falls back to issue channel' do
|
||||||
|
chat_service.update_attributes(issue_channel: 'fallback_channel')
|
||||||
|
|
||||||
|
expect(Slack::Notifier).to execute_with_options(channel: 'fallback_channel')
|
||||||
|
|
||||||
|
chat_service.execute(@issues_sample_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "uses the right channel for wiki event" do
|
it "uses the right channel for wiki event" do
|
||||||
chat_service.update_attributes(wiki_page_channel: "random")
|
chat_service.update_attributes(wiki_page_channel: "random")
|
||||||
|
|
||||||
|
@ -194,6 +215,32 @@ RSpec.shared_examples 'slack or mattermost notifications' do
|
||||||
|
|
||||||
chat_service.execute(note_data)
|
chat_service.execute(note_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'for confidential notes' do
|
||||||
|
before do
|
||||||
|
issue_note.noteable.update!(confidential: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses confidential channel" do
|
||||||
|
chat_service.update_attributes(confidential_note_channel: "confidential")
|
||||||
|
|
||||||
|
note_data = Gitlab::DataBuilder::Note.build(issue_note, user)
|
||||||
|
|
||||||
|
expect(Slack::Notifier).to execute_with_options(channel: 'confidential')
|
||||||
|
|
||||||
|
chat_service.execute(note_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'falls back to note channel' do
|
||||||
|
chat_service.update_attributes(note_channel: "fallback_channel")
|
||||||
|
|
||||||
|
note_data = Gitlab::DataBuilder::Note.build(issue_note, user)
|
||||||
|
|
||||||
|
expect(Slack::Notifier).to execute_with_options(channel: 'fallback_channel')
|
||||||
|
|
||||||
|
chat_service.execute(note_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -248,8 +295,9 @@ RSpec.shared_examples 'slack or mattermost notifications' do
|
||||||
create(:note_on_issue, project: project, note: "issue note")
|
create(:note_on_issue, project: project, note: "issue note")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:data) { Gitlab::DataBuilder::Note.build(issue_note, user) }
|
||||||
|
|
||||||
it "calls Slack API for issue comment events" do
|
it "calls Slack API for issue comment events" do
|
||||||
data = Gitlab::DataBuilder::Note.build(issue_note, user)
|
|
||||||
chat_service.execute(data)
|
chat_service.execute(data)
|
||||||
|
|
||||||
expect(WebMock).to have_requested(:post, webhook_url).once
|
expect(WebMock).to have_requested(:post, webhook_url).once
|
||||||
|
|
Loading…
Reference in a new issue