Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean McGivern <sean@gitlab.com>2016-08-18 17:49:32 +0300
committerSean McGivern <sean@gitlab.com>2016-08-18 17:54:07 +0300
commit8b1656282bcc39a0c1c7a3dccf74c98b1c3adae2 (patch)
treea5375c1ff8150d7777a120f29cfbd4d544ca4865 /app/services
parent21a73302e8a8b9f22e51f1707a306f04d3faad07 (diff)
parent2c1062f81e3c39cf8a45185c203995a43b91bf65 (diff)
Merge branch 'master' into expiration-date-on-memberships
Diffstat (limited to 'app/services')
-rw-r--r--app/services/akismet_service.rb79
-rw-r--r--app/services/boards/base_service.rb5
-rw-r--r--app/services/boards/create_service.rb16
-rw-r--r--app/services/boards/issues/list_service.rb63
-rw-r--r--app/services/boards/issues/move_service.rb59
-rw-r--r--app/services/boards/lists/create_service.rb22
-rw-r--r--app/services/boards/lists/destroy_service.rb25
-rw-r--r--app/services/boards/lists/generate_service.rb36
-rw-r--r--app/services/boards/lists/move_service.rb51
-rw-r--r--app/services/ci/create_builds_service.rb62
-rw-r--r--app/services/ci/create_pipeline_builds_service.rb42
-rw-r--r--app/services/ci/create_pipeline_service.rb96
-rw-r--r--app/services/ci/create_trigger_request_service.rb17
-rw-r--r--app/services/ci/process_pipeline_service.rb77
-rw-r--r--app/services/compare_service.rb6
-rw-r--r--app/services/create_commit_builds_service.rb69
-rw-r--r--app/services/create_spam_log_service.rb13
-rw-r--r--app/services/delete_branch_service.rb9
-rw-r--r--app/services/delete_tag_service.rb9
-rw-r--r--app/services/delete_user_service.rb9
-rw-r--r--app/services/destroy_group_service.rb16
-rw-r--r--app/services/files/base_service.rb1
-rw-r--r--app/services/files/update_service.rb23
-rw-r--r--app/services/git_push_service.rb28
-rw-r--r--app/services/git_tag_push_service.rb22
-rw-r--r--app/services/ham_service.rb26
-rw-r--r--app/services/import_export_clean_up_service.rb24
-rw-r--r--app/services/issuable_base_service.rb3
-rw-r--r--app/services/issues/create_service.rb35
-rw-r--r--app/services/issues/update_service.rb7
-rw-r--r--app/services/members/destroy_service.rb5
-rw-r--r--app/services/merge_requests/base_service.rb9
-rw-r--r--app/services/merge_requests/build_service.rb2
-rw-r--r--app/services/merge_requests/get_urls_service.rb63
-rw-r--r--app/services/merge_requests/merge_request_diff_cache_service.rb8
-rw-r--r--app/services/merge_requests/refresh_service.rb2
-rw-r--r--app/services/merge_requests/resolve_service.rb31
-rw-r--r--app/services/merge_requests/update_service.rb11
-rw-r--r--app/services/notes/post_process_service.rb2
-rw-r--r--app/services/notification_service.rb39
-rw-r--r--app/services/projects/destroy_service.rb8
-rw-r--r--app/services/projects/enable_deploy_key_service.rb17
-rw-r--r--app/services/protected_branches/create_service.rb18
-rw-r--r--app/services/repository_archive_clean_up_service.rb4
-rw-r--r--app/services/spam_check_service.rb38
-rw-r--r--app/services/spam_service.rb78
-rw-r--r--app/services/test_hook_service.rb2
-rw-r--r--app/services/todo_service.rb3
-rw-r--r--app/services/user_agent_detail_service.rb13
49 files changed, 1011 insertions, 292 deletions
diff --git a/app/services/akismet_service.rb b/app/services/akismet_service.rb
new file mode 100644
index 00000000000..5c60addbe7c
--- /dev/null
+++ b/app/services/akismet_service.rb
@@ -0,0 +1,79 @@
+class AkismetService
+ attr_accessor :owner, :text, :options
+
+ def initialize(owner, text, options = {})
+ @owner = owner
+ @text = text
+ @options = options
+ end
+
+ def is_spam?
+ return false unless akismet_enabled?
+
+ params = {
+ type: 'comment',
+ text: text,
+ created_at: DateTime.now,
+ author: owner.name,
+ author_email: owner.email,
+ referrer: options[:referrer],
+ }
+
+ begin
+ is_spam, is_blatant = akismet_client.check(options[:ip_address], options[:user_agent], params)
+ is_spam || is_blatant
+ rescue => e
+ Rails.logger.error("Unable to connect to Akismet: #{e}, skipping check")
+ false
+ end
+ end
+
+ def submit_ham
+ return false unless akismet_enabled?
+
+ params = {
+ type: 'comment',
+ text: text,
+ author: owner.name,
+ author_email: owner.email
+ }
+
+ begin
+ akismet_client.submit_ham(options[:ip_address], options[:user_agent], params)
+ true
+ rescue => e
+ Rails.logger.error("Unable to connect to Akismet: #{e}, skipping!")
+ false
+ end
+ end
+
+ def submit_spam
+ return false unless akismet_enabled?
+
+ params = {
+ type: 'comment',
+ text: text,
+ author: owner.name,
+ author_email: owner.email
+ }
+
+ begin
+ akismet_client.submit_spam(options[:ip_address], options[:user_agent], params)
+ true
+ rescue => e
+ Rails.logger.error("Unable to connect to Akismet: #{e}, skipping!")
+ false
+ end
+ end
+
+ private
+
+ def akismet_client
+ @akismet_client ||= ::Akismet::Client.new(current_application_settings.akismet_api_key,
+ Gitlab.config.gitlab.url)
+ end
+
+ def akismet_enabled?
+ current_application_settings.akismet_enabled
+ end
+end
diff --git a/app/services/boards/base_service.rb b/app/services/boards/base_service.rb
new file mode 100644
index 00000000000..b2069ca825a
--- /dev/null
+++ b/app/services/boards/base_service.rb
@@ -0,0 +1,5 @@
+module Boards
+ class BaseService < ::BaseService
+ delegate :board, to: :project
+ end
+end
diff --git a/app/services/boards/create_service.rb b/app/services/boards/create_service.rb
new file mode 100644
index 00000000000..072a0749285
--- /dev/null
+++ b/app/services/boards/create_service.rb
@@ -0,0 +1,16 @@
+module Boards
+ class CreateService < Boards::BaseService
+ def execute
+ create_board! unless project.board.present?
+ project.board
+ end
+
+ private
+
+ def create_board!
+ project.create_board
+ project.board.lists.create(list_type: :backlog)
+ project.board.lists.create(list_type: :done)
+ end
+ end
+end
diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb
new file mode 100644
index 00000000000..435a8c6e681
--- /dev/null
+++ b/app/services/boards/issues/list_service.rb
@@ -0,0 +1,63 @@
+module Boards
+ module Issues
+ class ListService < Boards::BaseService
+ def execute
+ issues = IssuesFinder.new(current_user, filter_params).execute
+ issues = without_board_labels(issues) unless list.movable?
+ issues = with_list_label(issues) if list.movable?
+ issues
+ end
+
+ private
+
+ def list
+ @list ||= board.lists.find(params[:id])
+ end
+
+ def filter_params
+ set_default_scope
+ set_default_sort
+ set_project
+ set_state
+
+ params
+ end
+
+ def set_default_scope
+ params[:scope] = 'all'
+ end
+
+ def set_default_sort
+ params[:sort] = 'priority'
+ end
+
+ def set_project
+ params[:project_id] = project.id
+ end
+
+ def set_state
+ params[:state] = list.done? ? 'closed' : 'opened'
+ end
+
+ def board_label_ids
+ @board_label_ids ||= board.lists.movable.pluck(:label_id)
+ end
+
+ def without_board_labels(issues)
+ return issues unless board_label_ids.any?
+
+ issues.where.not(
+ LabelLink.where("label_links.target_type = 'Issue' AND label_links.target_id = issues.id")
+ .where(label_id: board_label_ids).limit(1).arel.exists
+ )
+ end
+
+ def with_list_label(issues)
+ issues.where(
+ LabelLink.where("label_links.target_type = 'Issue' AND label_links.target_id = issues.id")
+ .where("label_links.label_id = ?", list.label_id).limit(1).arel.exists
+ )
+ end
+ end
+ end
+end
diff --git a/app/services/boards/issues/move_service.rb b/app/services/boards/issues/move_service.rb
new file mode 100644
index 00000000000..84dc3f70e76
--- /dev/null
+++ b/app/services/boards/issues/move_service.rb
@@ -0,0 +1,59 @@
+module Boards
+ module Issues
+ class MoveService < Boards::BaseService
+ def execute(issue)
+ return false unless can?(current_user, :update_issue, issue)
+ return false unless valid_move?
+
+ update_service.execute(issue)
+ end
+
+ private
+
+ def valid_move?
+ moving_from_list.present? && moving_to_list.present? &&
+ moving_from_list != moving_to_list
+ end
+
+ def moving_from_list
+ @moving_from_list ||= board.lists.find_by(id: params[:from_list_id])
+ end
+
+ def moving_to_list
+ @moving_to_list ||= board.lists.find_by(id: params[:to_list_id])
+ end
+
+ def update_service
+ ::Issues::UpdateService.new(project, current_user, issue_params)
+ end
+
+ def issue_params
+ {
+ add_label_ids: add_label_ids,
+ remove_label_ids: remove_label_ids,
+ state_event: issue_state
+ }
+ end
+
+ def issue_state
+ return 'reopen' if moving_from_list.done?
+ return 'close' if moving_to_list.done?
+ end
+
+ def add_label_ids
+ [moving_to_list.label_id].compact
+ end
+
+ def remove_label_ids
+ label_ids =
+ if moving_to_list.movable?
+ moving_from_list.label_id
+ else
+ board.lists.movable.pluck(:label_id)
+ end
+
+ Array(label_ids).compact
+ end
+ end
+ end
+end
diff --git a/app/services/boards/lists/create_service.rb b/app/services/boards/lists/create_service.rb
new file mode 100644
index 00000000000..5cb408b9d20
--- /dev/null
+++ b/app/services/boards/lists/create_service.rb
@@ -0,0 +1,22 @@
+module Boards
+ module Lists
+ class CreateService < Boards::BaseService
+ def execute
+ List.transaction do
+ create_list_at(next_position)
+ end
+ end
+
+ private
+
+ def next_position
+ max_position = board.lists.movable.maximum(:position)
+ max_position.nil? ? 0 : max_position.succ
+ end
+
+ def create_list_at(position)
+ board.lists.create(params.merge(list_type: :label, position: position))
+ end
+ end
+ end
+end
diff --git a/app/services/boards/lists/destroy_service.rb b/app/services/boards/lists/destroy_service.rb
new file mode 100644
index 00000000000..25da3bfb56d
--- /dev/null
+++ b/app/services/boards/lists/destroy_service.rb
@@ -0,0 +1,25 @@
+module Boards
+ module Lists
+ class DestroyService < Boards::BaseService
+ def execute(list)
+ return false unless list.destroyable?
+
+ list.with_lock do
+ decrement_higher_lists(list)
+ remove_list(list)
+ end
+ end
+
+ private
+
+ def decrement_higher_lists(list)
+ board.lists.movable.where('position > ?', list.position)
+ .update_all('position = position - 1')
+ end
+
+ def remove_list(list)
+ list.destroy
+ end
+ end
+ end
+end
diff --git a/app/services/boards/lists/generate_service.rb b/app/services/boards/lists/generate_service.rb
new file mode 100644
index 00000000000..1c48b9786e4
--- /dev/null
+++ b/app/services/boards/lists/generate_service.rb
@@ -0,0 +1,36 @@
+module Boards
+ module Lists
+ class GenerateService < Boards::BaseService
+ def execute
+ return false unless board.lists.movable.empty?
+
+ List.transaction do
+ label_params.each { |params| create_list(params) }
+ end
+
+ true
+ end
+
+ private
+
+ def create_list(params)
+ label = find_or_create_label(params)
+ Lists::CreateService.new(project, current_user, label_id: label.id).execute
+ end
+
+ def find_or_create_label(params)
+ project.labels.create_with(color: params[:color])
+ .find_or_create_by(name: params[:name])
+ end
+
+ def label_params
+ [
+ { name: 'Development', color: '#5CB85C' },
+ { name: 'Testing', color: '#F0AD4E' },
+ { name: 'Production', color: '#FF5F00' },
+ { name: 'Ready', color: '#FF0000' }
+ ]
+ end
+ end
+ end
+end
diff --git a/app/services/boards/lists/move_service.rb b/app/services/boards/lists/move_service.rb
new file mode 100644
index 00000000000..020ff69f4a7
--- /dev/null
+++ b/app/services/boards/lists/move_service.rb
@@ -0,0 +1,51 @@
+module Boards
+ module Lists
+ class MoveService < Boards::BaseService
+ def execute(list)
+ @old_position = list.position
+ @new_position = params[:position]
+
+ return false unless list.movable?
+ return false unless valid_move?
+
+ list.with_lock do
+ reorder_intermediate_lists
+ update_list_position(list)
+ end
+ end
+
+ private
+
+ attr_reader :old_position, :new_position
+
+ def valid_move?
+ new_position.present? && new_position != old_position &&
+ new_position >= 0 && new_position < board.lists.movable.size
+ end
+
+ def reorder_intermediate_lists
+ if old_position < new_position
+ decrement_intermediate_lists
+ else
+ increment_intermediate_lists
+ end
+ end
+
+ def decrement_intermediate_lists
+ board.lists.movable.where('position > ?', old_position)
+ .where('position <= ?', new_position)
+ .update_all('position = position - 1')
+ end
+
+ def increment_intermediate_lists
+ board.lists.movable.where('position >= ?', new_position)
+ .where('position < ?', old_position)
+ .update_all('position = position + 1')
+ end
+
+ def update_list_position(list)
+ list.update_attribute(:position, new_position)
+ end
+ end
+ end
+end
diff --git a/app/services/ci/create_builds_service.rb b/app/services/ci/create_builds_service.rb
deleted file mode 100644
index 4946f7076fd..00000000000
--- a/app/services/ci/create_builds_service.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-module Ci
- class CreateBuildsService
- def initialize(pipeline)
- @pipeline = pipeline
- @config = pipeline.config_processor
- end
-
- def execute(stage, user, status, trigger_request = nil)
- builds_attrs = @config.builds_for_stage_and_ref(stage, @pipeline.ref, @pipeline.tag, trigger_request)
-
- # check when to create next build
- builds_attrs = builds_attrs.select do |build_attrs|
- case build_attrs[:when]
- when 'on_success'
- status == 'success'
- when 'on_failure'
- status == 'failed'
- when 'always', 'manual'
- %w(success failed).include?(status)
- end
- end
-
- # don't create the same build twice
- builds_attrs.reject! do |build_attrs|
- @pipeline.builds.find_by(ref: @pipeline.ref,
- tag: @pipeline.tag,
- trigger_request: trigger_request,
- name: build_attrs[:name])
- end
-
- builds_attrs.map do |build_attrs|
- build_attrs.slice!(:name,
- :commands,
- :tag_list,
- :options,
- :allow_failure,
- :stage,
- :stage_idx,
- :environment,
- :when,
- :yaml_variables)
-
- build_attrs.merge!(pipeline: @pipeline,
- ref: @pipeline.ref,
- tag: @pipeline.tag,
- trigger_request: trigger_request,
- user: user,
- project: @pipeline.project)
-
- # TODO: The proper implementation for this is in
- # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5295
- build_attrs[:status] = 'skipped' if build_attrs[:when] == 'manual'
-
- ##
- # We do not persist new builds here.
- # Those will be persisted when @pipeline is saved.
- #
- @pipeline.builds.new(build_attrs)
- end
- end
- end
-end
diff --git a/app/services/ci/create_pipeline_builds_service.rb b/app/services/ci/create_pipeline_builds_service.rb
new file mode 100644
index 00000000000..005014fa1de
--- /dev/null
+++ b/app/services/ci/create_pipeline_builds_service.rb
@@ -0,0 +1,42 @@
+module Ci
+ class CreatePipelineBuildsService < BaseService
+ attr_reader :pipeline
+
+ def execute(pipeline)
+ @pipeline = pipeline
+
+ new_builds.map do |build_attributes|
+ create_build(build_attributes)
+ end
+ end
+
+ private
+
+ def create_build(build_attributes)
+ build_attributes = build_attributes.merge(
+ pipeline: pipeline,
+ project: pipeline.project,
+ ref: pipeline.ref,
+ tag: pipeline.tag,
+ user: current_user,
+ trigger_request: trigger_request
+ )
+ pipeline.builds.create(build_attributes)
+ end
+
+ def new_builds
+ @new_builds ||= pipeline.config_builds_attributes.
+ reject { |build| existing_build_names.include?(build[:name]) }
+ end
+
+ def existing_build_names
+ @existing_build_names ||= pipeline.builds.pluck(:name)
+ end
+
+ def trigger_request
+ return @trigger_request if defined?(@trigger_request)
+
+ @trigger_request ||= pipeline.trigger_requests.first
+ end
+ end
+end
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index be91bf0db85..cde856b0186 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -1,49 +1,101 @@
module Ci
class CreatePipelineService < BaseService
- def execute
- pipeline = project.pipelines.new(params)
- pipeline.user = current_user
+ attr_reader :pipeline
- unless ref_names.include?(params[:ref])
- pipeline.errors.add(:base, 'Reference not found')
- return pipeline
+ def execute(ignore_skip_ci: false, save_on_errors: true, trigger_request: nil)
+ @pipeline = Ci::Pipeline.new(
+ project: project,
+ ref: ref,
+ sha: sha,
+ before_sha: before_sha,
+ tag: tag?,
+ trigger_requests: Array(trigger_request),
+ user: current_user
+ )
+
+ unless project.builds_enabled?
+ return error('Pipeline is disabled')
end
- if commit
- pipeline.sha = commit.id
- else
- pipeline.errors.add(:base, 'Commit not found')
- return pipeline
+ unless trigger_request || can?(current_user, :create_pipeline, project)
+ return error('Insufficient permissions to create a new pipeline')
end
- unless can?(current_user, :create_pipeline, project)
- pipeline.errors.add(:base, 'Insufficient permissions to create a new pipeline')
- return pipeline
+ unless branch? || tag?
+ return error('Reference not found')
+ end
+
+ unless commit
+ return error('Commit not found')
end
unless pipeline.config_processor
- pipeline.errors.add(:base, pipeline.yaml_errors || 'Missing .gitlab-ci.yml file')
- return pipeline
+ unless pipeline.ci_yaml_file
+ return error('Missing .gitlab-ci.yml file')
+ end
+ return error(pipeline.yaml_errors, save: save_on_errors)
end
- pipeline.save!
+ if !ignore_skip_ci && skip_ci?
+ pipeline.skip if save_on_errors
+ return pipeline
+ end
- unless pipeline.create_builds(current_user)
- pipeline.errors.add(:base, 'No builds for this pipeline.')
+ unless pipeline.config_builds_attributes.present?
+ return error('No builds for this pipeline.')
end
pipeline.save
+ pipeline.process!
pipeline
end
private
- def ref_names
- @ref_names ||= project.repository.ref_names
+ def skip_ci?
+ pipeline.git_commit_message =~ /\[(ci skip|skip ci)\]/i if pipeline.git_commit_message
end
def commit
- @commit ||= project.commit(params[:ref])
+ @commit ||= project.commit(origin_sha || origin_ref)
+ end
+
+ def sha
+ commit.try(:id)
+ end
+
+ def before_sha
+ params[:checkout_sha] || params[:before] || Gitlab::Git::BLANK_SHA
+ end
+
+ def origin_sha
+ params[:checkout_sha] || params[:after]
+ end
+
+ def origin_ref
+ params[:ref]
+ end
+
+ def branch?
+ project.repository.ref_exists?(Gitlab::Git::BRANCH_REF_PREFIX + ref)
+ end
+
+ def tag?
+ project.repository.ref_exists?(Gitlab::Git::TAG_REF_PREFIX + ref)
+ end
+
+ def ref
+ Gitlab::Git.ref_name(origin_ref)
+ end
+
+ def valid_sha?
+ origin_sha && origin_sha != Gitlab::Git::BLANK_SHA
+ end
+
+ def error(message, save: false)
+ pipeline.errors.add(:base, message)
+ pipeline.drop if save
+ pipeline
end
end
end
diff --git a/app/services/ci/create_trigger_request_service.rb b/app/services/ci/create_trigger_request_service.rb
index 1e629cf119a..6af3c1ca5b1 100644
--- a/app/services/ci/create_trigger_request_service.rb
+++ b/app/services/ci/create_trigger_request_service.rb
@@ -1,20 +1,11 @@
module Ci
class CreateTriggerRequestService
def execute(project, trigger, ref, variables = nil)
- commit = project.commit(ref)
- return unless commit
+ trigger_request = trigger.trigger_requests.create(variables: variables)
- # check if ref is tag
- tag = project.repository.find_tag(ref).present?
-
- pipeline = project.pipelines.create(sha: commit.sha, ref: ref, tag: tag)
-
- trigger_request = trigger.trigger_requests.create!(
- variables: variables,
- pipeline: pipeline,
- )
-
- if pipeline.create_builds(nil, trigger_request)
+ pipeline = Ci::CreatePipelineService.new(project, nil, ref: ref).
+ execute(ignore_skip_ci: true, trigger_request: trigger_request)
+ if pipeline.persisted?
trigger_request
end
end
diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb
new file mode 100644
index 00000000000..6f7610d42ba
--- /dev/null
+++ b/app/services/ci/process_pipeline_service.rb
@@ -0,0 +1,77 @@
+module Ci
+ class ProcessPipelineService < BaseService
+ attr_reader :pipeline
+
+ def execute(pipeline)
+ @pipeline = pipeline
+
+ # This method will ensure that our pipeline does have all builds for all stages created
+ if created_builds.empty?
+ create_builds!
+ end
+
+ new_builds =
+ stage_indexes_of_created_builds.map do |index|
+ process_stage(index)
+ end
+
+ # Return a flag if a when builds got enqueued
+ new_builds.flatten.any?
+ end
+
+ private
+
+ def create_builds!
+ Ci::CreatePipelineBuildsService.new(project, current_user).execute(pipeline)
+ end
+
+ def process_stage(index)
+ current_status = status_for_prior_stages(index)
+
+ created_builds_in_stage(index).select do |build|
+ process_build(build, current_status)
+ end
+ end
+
+ def process_build(build, current_status)
+ return false unless Statuseable::COMPLETED_STATUSES.include?(current_status)
+
+ if valid_statuses_for_when(build.when).include?(current_status)
+ build.enqueue
+ true
+ else
+ build.skip
+ false
+ end
+ end
+
+ def valid_statuses_for_when(value)
+ case value
+ when 'on_success'
+ %w[success]
+ when 'on_failure'
+ %w[failed]
+ when 'always'
+ %w[success failed]
+ else
+ []
+ end
+ end
+
+ def status_for_prior_stages(index)
+ pipeline.builds.where('stage_idx < ?', index).latest.status || 'success'
+ end
+
+ def stage_indexes_of_created_builds
+ created_builds.order(:stage_idx).pluck('distinct stage_idx')
+ end
+
+ def created_builds_in_stage(index)
+ created_builds.where(stage_idx: index)
+ end
+
+ def created_builds
+ pipeline.builds.created
+ end
+ end
+end
diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb
index 149822aa647..6d6075628af 100644
--- a/app/services/compare_service.rb
+++ b/app/services/compare_service.rb
@@ -20,10 +20,12 @@ class CompareService
)
end
- Gitlab::Git::Compare.new(
+ raw_compare = Gitlab::Git::Compare.new(
target_project.repository.raw_repository,
target_branch,
- source_sha,
+ source_sha
)
+
+ Compare.new(raw_compare, target_project)
end
end
diff --git a/app/services/create_commit_builds_service.rb b/app/services/create_commit_builds_service.rb
deleted file mode 100644
index 0b66b854dea..00000000000
--- a/app/services/create_commit_builds_service.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-class CreateCommitBuildsService
- def execute(project, user, params)
- return unless project.builds_enabled?
-
- before_sha = params[:checkout_sha] || params[:before]
- sha = params[:checkout_sha] || params[:after]
- origin_ref = params[:ref]
-
- ref = Gitlab::Git.ref_name(origin_ref)
- tag = Gitlab::Git.tag_ref?(origin_ref)
-
- # Skip branch removal
- if sha == Gitlab::Git::BLANK_SHA
- return false
- end
-
- @pipeline = Ci::Pipeline.new(
- project: project,
- sha: sha,
- ref: ref,
- before_sha: before_sha,
- tag: tag,
- user: user)
-
- ##
- # Skip creating pipeline if no gitlab-ci.yml is found
- #
- unless @pipeline.ci_yaml_file
- return false
- end
-
- ##
- # Skip creating builds for commits that have [ci skip]
- # but save pipeline object
- #
- if @pipeline.skip_ci?
- return save_pipeline!
- end
-
- ##
- # Skip creating builds when CI config is invalid
- # but save pipeline object
- #
- unless @pipeline.config_processor
- return save_pipeline!
- end
-
- ##
- # Skip creating pipeline object if there are no builds for it.
- #
- unless @pipeline.create_builds(user)
- @pipeline.errors.add(:base, 'No builds created')
- return false
- end
-
- save_pipeline!
- end
-
- private
-
- ##
- # Create a new pipeline and touch object to calculate status
- #
- def save_pipeline!
- @pipeline.save!
- @pipeline.touch
- @pipeline
- end
-end
diff --git a/app/services/create_spam_log_service.rb b/app/services/create_spam_log_service.rb
deleted file mode 100644
index 59a66fde47a..00000000000
--- a/app/services/create_spam_log_service.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class CreateSpamLogService < BaseService
- def initialize(project, user, params)
- super(project, user, params)
- end
-
- def execute
- spam_params = params.merge({ user_id: @current_user.id,
- project_id: @project.id } )
- spam_log = SpamLog.new(spam_params)
- spam_log.save
- spam_log
- end
-end
diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb
index 87f066edb6f..918eddaa53a 100644
--- a/app/services/delete_branch_service.rb
+++ b/app/services/delete_branch_service.rb
@@ -39,7 +39,12 @@ class DeleteBranchService < BaseService
end
def build_push_data(branch)
- Gitlab::PushDataBuilder
- .build(project, current_user, branch.target.sha, Gitlab::Git::BLANK_SHA, "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch.name}", [])
+ Gitlab::DataBuilder::Push.build(
+ project,
+ current_user,
+ branch.target.sha,
+ Gitlab::Git::BLANK_SHA,
+ "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch.name}",
+ [])
end
end
diff --git a/app/services/delete_tag_service.rb b/app/services/delete_tag_service.rb
index 32e0eed6b63..d0cb151a010 100644
--- a/app/services/delete_tag_service.rb
+++ b/app/services/delete_tag_service.rb
@@ -33,7 +33,12 @@ class DeleteTagService < BaseService
end
def build_push_data(tag)
- Gitlab::PushDataBuilder
- .build(project, current_user, tag.target.sha, Gitlab::Git::BLANK_SHA, "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", [])
+ Gitlab::DataBuilder::Push.build(
+ project,
+ current_user,
+ tag.target.sha,
+ Gitlab::Git::BLANK_SHA,
+ "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}",
+ [])
end
end
diff --git a/app/services/delete_user_service.rb b/app/services/delete_user_service.rb
index ce79287e35a..eaff88d6463 100644
--- a/app/services/delete_user_service.rb
+++ b/app/services/delete_user_service.rb
@@ -18,9 +18,14 @@ class DeleteUserService
user.personal_projects.each do |project|
# Skip repository removal because we remove directory with namespace
# that contain all this repositories
- ::Projects::DestroyService.new(project, current_user, skip_repo: true).pending_delete!
+ ::Projects::DestroyService.new(project, current_user, skip_repo: true).async_execute
end
- user.destroy
+ # Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
+ namespace = user.namespace
+ user_data = user.destroy
+ namespace.really_destroy!
+
+ user_data
end
end
diff --git a/app/services/destroy_group_service.rb b/app/services/destroy_group_service.rb
index 3c42ac61be4..0081364b8aa 100644
--- a/app/services/destroy_group_service.rb
+++ b/app/services/destroy_group_service.rb
@@ -5,13 +5,23 @@ class DestroyGroupService
@group, @current_user = group, user
end
+ def async_execute
+ group.transaction do
+ # Soft delete via paranoia gem
+ group.destroy
+ job_id = GroupDestroyWorker.perform_async(group.id, current_user.id)
+ Rails.logger.info("User #{current_user.id} scheduled a deletion of group ID #{group.id} with job ID #{job_id}")
+ end
+ end
+
def execute
group.projects.each do |project|
+ # Execute the destruction of the models immediately to ensure atomic cleanup.
# Skip repository removal because we remove directory with namespace
- # that contain all this repositories
- ::Projects::DestroyService.new(project, current_user, skip_repo: true).pending_delete!
+ # that contain all these repositories
+ ::Projects::DestroyService.new(project, current_user, skip_repo: true).execute
end
- group.destroy
+ group.really_destroy!
end
end
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index c4a206f785e..ea94818713b 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -15,6 +15,7 @@ module Files
else
params[:file_content]
end
+ @last_commit_sha = params[:last_commit_sha]
# Validate parameters
validate
diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb
index 8d2b5083179..4fc3b640799 100644
--- a/app/services/files/update_service.rb
+++ b/app/services/files/update_service.rb
@@ -2,11 +2,34 @@ require_relative "base_service"
module Files
class UpdateService < Files::BaseService
+ class FileChangedError < StandardError; end
+
def commit
repository.update_file(current_user, @file_path, @file_content,
branch: @target_branch,
previous_path: @previous_path,
message: @commit_message)
end
+
+ private
+
+ def validate
+ super
+
+ if file_has_changed?
+ raise FileChangedError.new("You are attempting to update a file that has changed since you started editing it.")
+ end
+ end
+
+ def file_has_changed?
+ return false unless @last_commit_sha && last_commit
+
+ @last_commit_sha != last_commit.sha
+ end
+
+ def last_commit
+ @last_commit ||= Gitlab::Git::Commit.
+ last_for_path(@source_project.repository, @source_branch, @file_path)
+ end
end
end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 3f6a177bf3a..78feb37aa2a 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -69,7 +69,7 @@ class GitPushService < BaseService
SystemHooksService.new.execute_hooks(build_push_data_system_hook.dup, :push_hooks)
@project.execute_hooks(build_push_data.dup, :push_hooks)
@project.execute_services(build_push_data.dup, :push_hooks)
- CreateCommitBuildsService.new.execute(@project, current_user, build_push_data)
+ Ci::CreatePipelineService.new(project, current_user, build_push_data).execute
ProjectCacheWorker.perform_async(@project.id)
end
@@ -91,12 +91,12 @@ class GitPushService < BaseService
params = {
name: @project.default_branch,
- push_access_level_attributes: {
+ push_access_levels_attributes: [{
access_level: current_application_settings.default_branch_protection == PROTECTION_DEV_CAN_PUSH ? Gitlab::Access::DEVELOPER : Gitlab::Access::MASTER
- },
- merge_access_level_attributes: {
+ }],
+ merge_access_levels_attributes: [{
access_level: current_application_settings.default_branch_protection == PROTECTION_DEV_CAN_MERGE ? Gitlab::Access::DEVELOPER : Gitlab::Access::MASTER
- }
+ }]
}
ProtectedBranches::CreateService.new(@project, current_user, params).execute
@@ -138,13 +138,23 @@ class GitPushService < BaseService
end
def build_push_data
- @push_data ||= Gitlab::PushDataBuilder.
- build(@project, current_user, params[:oldrev], params[:newrev], params[:ref], push_commits)
+ @push_data ||= Gitlab::DataBuilder::Push.build(
+ @project,
+ current_user,
+ params[:oldrev],
+ params[:newrev],
+ params[:ref],
+ push_commits)
end
def build_push_data_system_hook
- @push_data_system ||= Gitlab::PushDataBuilder.
- build(@project, current_user, params[:oldrev], params[:newrev], params[:ref], [])
+ @push_data_system ||= Gitlab::DataBuilder::Push.build(
+ @project,
+ current_user,
+ params[:oldrev],
+ params[:newrev],
+ params[:ref],
+ [])
end
def push_to_existing_branch?
diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb
index 969530c4fdc..e6002b03b93 100644
--- a/app/services/git_tag_push_service.rb
+++ b/app/services/git_tag_push_service.rb
@@ -11,7 +11,7 @@ class GitTagPushService < BaseService
SystemHooksService.new.execute_hooks(build_system_push_data.dup, :tag_push_hooks)
project.execute_hooks(@push_data.dup, :tag_push_hooks)
project.execute_services(@push_data.dup, :tag_push_hooks)
- CreateCommitBuildsService.new.execute(project, current_user, @push_data)
+ Ci::CreatePipelineService.new(project, current_user, @push_data).execute
ProjectCacheWorker.perform_async(project.id)
true
@@ -34,12 +34,24 @@ class GitTagPushService < BaseService
end
end
- Gitlab::PushDataBuilder.
- build(project, current_user, params[:oldrev], params[:newrev], params[:ref], commits, message)
+ Gitlab::DataBuilder::Push.build(
+ project,
+ current_user,
+ params[:oldrev],
+ params[:newrev],
+ params[:ref],
+ commits,
+ message)
end
def build_system_push_data
- Gitlab::PushDataBuilder.
- build(project, current_user, params[:oldrev], params[:newrev], params[:ref], [], '')
+ Gitlab::DataBuilder::Push.build(
+ project,
+ current_user,
+ params[:oldrev],
+ params[:newrev],
+ params[:ref],
+ [],
+ '')
end
end
diff --git a/app/services/ham_service.rb b/app/services/ham_service.rb
new file mode 100644
index 00000000000..b0e1799b489
--- /dev/null
+++ b/app/services/ham_service.rb
@@ -0,0 +1,26 @@
+class HamService
+ attr_accessor :spam_log
+
+ def initialize(spam_log)
+ @spam_log = spam_log
+ end
+
+ def mark_as_ham!
+ if akismet.submit_ham
+ spam_log.update_attribute(:submitted_as_ham, true)
+ else
+ false
+ end
+ end
+
+ private
+
+ def akismet
+ @akismet ||= AkismetService.new(
+ spam_log.user,
+ spam_log.text,
+ ip_address: spam_log.source_ip,
+ user_agent: spam_log.user_agent
+ )
+ end
+end
diff --git a/app/services/import_export_clean_up_service.rb b/app/services/import_export_clean_up_service.rb
new file mode 100644
index 00000000000..6442406d77e
--- /dev/null
+++ b/app/services/import_export_clean_up_service.rb
@@ -0,0 +1,24 @@
+class ImportExportCleanUpService
+ LAST_MODIFIED_TIME_IN_MINUTES = 1440
+
+ attr_reader :mmin, :path
+
+ def initialize(mmin = LAST_MODIFIED_TIME_IN_MINUTES)
+ @mmin = mmin
+ @path = Gitlab::ImportExport.storage_path
+ end
+
+ def execute
+ Gitlab::Metrics.measure(:import_export_clean_up) do
+ return unless File.directory?(path)
+
+ clean_up_export_files
+ end
+ end
+
+ private
+
+ def clean_up_export_files
+ Gitlab::Popen.popen(%W(find #{path} -not -path #{path} -mmin +#{mmin} -delete))
+ end
+end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 2d96efe1042..b0ea7c905f8 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -104,11 +104,12 @@ class IssuableBaseService < BaseService
change_subscription(issuable)
filter_params
old_labels = issuable.labels.to_a
+ old_mentioned_users = issuable.mentioned_users.to_a
if params.present? && update_issuable(issuable, params)
issuable.reset_events_cache
handle_common_system_notes(issuable, old_labels: old_labels)
- handle_changes(issuable, old_labels: old_labels)
+ handle_changes(issuable, old_labels: old_labels, old_mentioned_users: old_mentioned_users)
issuable.create_new_cross_references!(current_user)
execute_hooks(issuable, 'update')
end
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index 5e2de2ccf64..65550ab8ec6 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -3,29 +3,34 @@ module Issues
def execute
filter_params
label_params = params.delete(:label_ids)
- request = params.delete(:request)
- api = params.delete(:api)
- issue = project.issues.new(params)
- issue.author = params[:author] || current_user
+ @request = params.delete(:request)
+ @api = params.delete(:api)
+ @issue = project.issues.new(params)
+ @issue.author = params[:author] || current_user
- issue.spam = spam_check_service.execute(request, api)
+ @issue.spam = spam_service.check(@api)
- if issue.save
- issue.update_attributes(label_ids: label_params)
- notification_service.new_issue(issue, current_user)
- todo_service.new_issue(issue, current_user)
- event_service.open_issue(issue, current_user)
- issue.create_cross_references!(current_user)
- execute_hooks(issue, 'open')
+ if @issue.save
+ @issue.update_attributes(label_ids: label_params)
+ notification_service.new_issue(@issue, current_user)
+ todo_service.new_issue(@issue, current_user)
+ event_service.open_issue(@issue, current_user)
+ user_agent_detail_service.create
+ @issue.create_cross_references!(current_user)
+ execute_hooks(@issue, 'open')
end
- issue
+ @issue
end
private
- def spam_check_service
- SpamCheckService.new(project, current_user, params)
+ def spam_service
+ SpamService.new(@issue, @request)
+ end
+
+ def user_agent_detail_service
+ UserAgentDetailService.new(@issue, @request)
end
end
end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index c7d406cc331..a2111b3806b 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -4,7 +4,7 @@ module Issues
update(issue)
end
- def handle_changes(issue, old_labels: [])
+ def handle_changes(issue, old_labels: [], old_mentioned_users: [])
if has_changes?(issue, old_labels: old_labels)
todo_service.mark_pending_todos_as_done(issue, current_user)
end
@@ -32,6 +32,11 @@ module Issues
if added_labels.present?
notification_service.relabeled_issue(issue, added_labels, current_user)
end
+
+ added_mentions = issue.mentioned_users - old_mentioned_users
+ if added_mentions.present?
+ notification_service.new_mentions_in_issue(issue, added_mentions, current_user)
+ end
end
def reopen_service
diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb
index 5228da4d457..9a2bf82ef51 100644
--- a/app/services/members/destroy_service.rb
+++ b/app/services/members/destroy_service.rb
@@ -2,8 +2,9 @@ module Members
class DestroyService < BaseService
attr_accessor :member, :current_user
- def initialize(member, user)
- @member, @current_user = member, user
+ def initialize(member, current_user)
+ @member = member
+ @current_user = current_user
end
def execute
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index bc3606a14c2..ba424b09463 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -17,16 +17,19 @@ module MergeRequests
end
end
- def hook_data(merge_request, action)
+ def hook_data(merge_request, action, oldrev = nil)
hook_data = merge_request.to_hook_data(current_user)
hook_data[:object_attributes][:url] = Gitlab::UrlBuilder.build(merge_request)
hook_data[:object_attributes][:action] = action
+ if oldrev && !Gitlab::Git.blank_ref?(oldrev)
+ hook_data[:object_attributes][:oldrev] = oldrev
+ end
hook_data
end
- def execute_hooks(merge_request, action = 'open')
+ def execute_hooks(merge_request, action = 'open', oldrev = nil)
if merge_request.project
- merge_data = hook_data(merge_request, action)
+ merge_data = hook_data(merge_request, action, oldrev)
merge_request.project.execute_hooks(merge_data, :merge_request_hooks)
merge_request.project.execute_services(merge_data, :merge_request_hooks)
end
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index 7fe57747265..290742f1506 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -34,7 +34,7 @@ module MergeRequests
# At this point we decide if merge request can be created
# If we have at least one commit to merge -> creation allowed
if commits.present?
- merge_request.compare_commits = Commit.decorate(commits, merge_request.source_project)
+ merge_request.compare_commits = commits
merge_request.can_be_created = true
merge_request.compare = compare
else
diff --git a/app/services/merge_requests/get_urls_service.rb b/app/services/merge_requests/get_urls_service.rb
new file mode 100644
index 00000000000..08c1f72d65a
--- /dev/null
+++ b/app/services/merge_requests/get_urls_service.rb
@@ -0,0 +1,63 @@
+module MergeRequests
+ class GetUrlsService < BaseService
+ attr_reader :project
+
+ def initialize(project)
+ @project = project
+ end
+
+ def execute(changes)
+ branches = get_branches(changes)
+ merge_requests_map = opened_merge_requests_from_source_branches(branches)
+ branches.map do |branch|
+ existing_merge_request = merge_requests_map[branch]
+ if existing_merge_request
+ url_for_existing_merge_request(existing_merge_request)
+ else
+ url_for_new_merge_request(branch)
+ end
+ end
+ end
+
+ private
+
+ def opened_merge_requests_from_source_branches(branches)
+ merge_requests = MergeRequest.from_project(project).opened.from_source_branches(branches)
+ merge_requests.inject({}) do |hash, mr|
+ hash[mr.source_branch] = mr
+ hash
+ end
+ end
+
+ def get_branches(changes)
+ return [] if project.empty_repo?
+ return [] unless project.merge_requests_enabled
+
+ changes_list = Gitlab::ChangesList.new(changes)
+ changes_list.map do |change|
+ next unless Gitlab::Git.branch_ref?(change[:ref])
+
+ # Deleted branch
+ next if Gitlab::Git.blank_ref?(change[:newrev])
+
+ # Default branch
+ branch_name = Gitlab::Git.branch_name(change[:ref])
+ next if branch_name == project.default_branch
+
+ branch_name
+ end.compact
+ end
+
+ def url_for_new_merge_request(branch_name)
+ merge_request_params = { source_branch: branch_name }
+ url = Gitlab::Routing.url_helpers.new_namespace_project_merge_request_url(project.namespace, project, merge_request: merge_request_params)
+ { branch_name: branch_name, url: url, new_merge_request: true }
+ end
+
+ def url_for_existing_merge_request(merge_request)
+ target_project = merge_request.target_project
+ url = Gitlab::Routing.url_helpers.namespace_project_merge_request_url(target_project.namespace, target_project, merge_request)
+ { branch_name: merge_request.source_branch, url: url, new_merge_request: false }
+ end
+ end
+end
diff --git a/app/services/merge_requests/merge_request_diff_cache_service.rb b/app/services/merge_requests/merge_request_diff_cache_service.rb
new file mode 100644
index 00000000000..2945a7fd4e4
--- /dev/null
+++ b/app/services/merge_requests/merge_request_diff_cache_service.rb
@@ -0,0 +1,8 @@
+module MergeRequests
+ class MergeRequestDiffCacheService
+ def execute(merge_request)
+ # Executing the iteration we cache all the highlighted diff information
+ merge_request.diffs.diff_files.to_a
+ end
+ end
+end
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 1daf6bbf553..5cedd6f11d9 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -137,7 +137,7 @@ module MergeRequests
# Call merge request webhook with update branches
def execute_mr_web_hooks
merge_requests_for_source_branch.each do |merge_request|
- execute_hooks(merge_request, 'update')
+ execute_hooks(merge_request, 'update', @oldrev)
end
end
diff --git a/app/services/merge_requests/resolve_service.rb b/app/services/merge_requests/resolve_service.rb
new file mode 100644
index 00000000000..adc71b0c2bc
--- /dev/null
+++ b/app/services/merge_requests/resolve_service.rb
@@ -0,0 +1,31 @@
+module MergeRequests
+ class ResolveService < MergeRequests::BaseService
+ attr_accessor :conflicts, :rugged, :merge_index
+
+ def execute(merge_request)
+ @conflicts = merge_request.conflicts
+ @rugged = project.repository.rugged
+ @merge_index = conflicts.merge_index
+
+ conflicts.files.each do |file|
+ write_resolved_file_to_index(file, params[:sections])
+ end
+
+ commit_params = {
+ message: params[:commit_message] || conflicts.default_commit_message,
+ parents: [conflicts.our_commit, conflicts.their_commit].map(&:oid),
+ tree: merge_index.write_tree(rugged)
+ }
+
+ project.repository.resolve_conflicts(current_user, merge_request.source_branch, commit_params)
+ end
+
+ def write_resolved_file_to_index(file, resolutions)
+ new_file = file.resolve_lines(resolutions).map(&:text).join("\n")
+ our_path = file.our_path
+
+ merge_index.add(path: our_path, oid: rugged.write(new_file, :blob), mode: file.our_mode)
+ merge_index.conflict_remove(our_path)
+ end
+ end
+end
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 026a37997d4..30c5f24988c 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -16,7 +16,7 @@ module MergeRequests
update(merge_request)
end
- def handle_changes(merge_request, old_labels: [])
+ def handle_changes(merge_request, old_labels: [], old_mentioned_users: [])
if has_changes?(merge_request, old_labels: old_labels)
todo_service.mark_pending_todos_as_done(merge_request, current_user)
end
@@ -55,6 +55,15 @@ module MergeRequests
current_user
)
end
+
+ added_mentions = merge_request.mentioned_users - old_mentioned_users
+ if added_mentions.present?
+ notification_service.new_mentions_in_merge_request(
+ merge_request,
+ added_mentions,
+ current_user
+ )
+ end
end
def reopen_service
diff --git a/app/services/notes/post_process_service.rb b/app/services/notes/post_process_service.rb
index 534c48aefff..e4cd3fc7833 100644
--- a/app/services/notes/post_process_service.rb
+++ b/app/services/notes/post_process_service.rb
@@ -16,7 +16,7 @@ module Notes
end
def hook_data
- Gitlab::NoteDataBuilder.build(@note, @note.author)
+ Gitlab::DataBuilder::Note.build(@note, @note.author)
end
def execute_note_hooks
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index ab6e51209ee..2291bc0f127 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -35,6 +35,20 @@ class NotificationService
new_resource_email(issue, issue.project, :new_issue_email)
end
+ # When issue text is updated, we should send an email to:
+ #
+ # * newly mentioned project team members with notification level higher than Participating
+ #
+ def new_mentions_in_issue(issue, new_mentioned_users, current_user)
+ new_mentions_in_resource_email(
+ issue,
+ issue.project,
+ new_mentioned_users,
+ current_user,
+ :new_mention_in_issue_email
+ )
+ end
+
# When we close an issue we should send an email to:
#
# * issue author if their notification level is not Disabled
@@ -75,6 +89,20 @@ class NotificationService
new_resource_email(merge_request, merge_request.target_project, :new_merge_request_email)
end
+ # When merge request text is updated, we should send an email to:
+ #
+ # * newly mentioned project team members with notification level higher than Participating
+ #
+ def new_mentions_in_merge_request(merge_request, new_mentioned_users, current_user)
+ new_mentions_in_resource_email(
+ merge_request,
+ merge_request.target_project,
+ new_mentioned_users,
+ current_user,
+ :new_mention_in_merge_request_email
+ )
+ end
+
# When we reassign a merge_request we should send an email to:
#
# * merge_request old assignee if their notification level is not Disabled
@@ -177,7 +205,7 @@ class NotificationService
# build notify method like 'note_commit_email'
notify_method = "note_#{note.noteable_type.underscore}_email".to_sym
-
+
recipients.each do |recipient|
mailer.send(notify_method, recipient.id, note.id).deliver_later
end
@@ -471,6 +499,15 @@ class NotificationService
end
end
+ def new_mentions_in_resource_email(target, project, new_mentioned_users, current_user, method)
+ recipients = build_recipients(target, project, current_user, action: "new")
+ recipients = recipients & new_mentioned_users
+
+ recipients.each do |recipient|
+ mailer.send(method, recipient.id, target.id, current_user.id).deliver_later
+ end
+ end
+
def close_resource_email(target, project, current_user, method)
action = method == :merged_merge_request_email ? "merge" : "close"
recipients = build_recipients(target, project, current_user, action: action)
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index 882606e38d0..8a53f65aec1 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -6,8 +6,12 @@ module Projects
DELETED_FLAG = '+deleted'
- def pending_delete!
- project.schedule_delete!(current_user.id, params)
+ def async_execute
+ project.transaction do
+ project.update_attribute(:pending_delete, true)
+ job_id = ProjectDestroyWorker.perform_async(project.id, current_user.id, params)
+ Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.path_with_namespace} with job ID #{job_id}")
+ end
end
def execute
diff --git a/app/services/projects/enable_deploy_key_service.rb b/app/services/projects/enable_deploy_key_service.rb
new file mode 100644
index 00000000000..3cf4264ce9b
--- /dev/null
+++ b/app/services/projects/enable_deploy_key_service.rb
@@ -0,0 +1,17 @@
+module Projects
+ class EnableDeployKeyService < BaseService
+ def execute
+ key = accessible_keys.find_by(id: params[:key_id] || params[:id])
+ return unless key
+
+ project.deploy_keys << key
+ key
+ end
+
+ private
+
+ def accessible_keys
+ current_user.accessible_deploy_keys
+ end
+ end
+end
diff --git a/app/services/protected_branches/create_service.rb b/app/services/protected_branches/create_service.rb
index 6150a2a83c9..a84e335340d 100644
--- a/app/services/protected_branches/create_service.rb
+++ b/app/services/protected_branches/create_service.rb
@@ -5,23 +5,7 @@ module ProtectedBranches
def execute
raise Gitlab::Access::AccessDeniedError unless can?(current_user, :admin_project, project)
- protected_branch = project.protected_branches.new(params)
-
- ProtectedBranch.transaction do
- protected_branch.save!
-
- if protected_branch.push_access_level.blank?
- protected_branch.create_push_access_level!(access_level: Gitlab::Access::MASTER)
- end
-
- if protected_branch.merge_access_level.blank?
- protected_branch.create_merge_access_level!(access_level: Gitlab::Access::MASTER)
- end
- end
-
- protected_branch
- rescue ActiveRecord::RecordInvalid
- protected_branch
+ project.protected_branches.create(params)
end
end
end
diff --git a/app/services/repository_archive_clean_up_service.rb b/app/services/repository_archive_clean_up_service.rb
index 0b56b09738d..aa84d36a206 100644
--- a/app/services/repository_archive_clean_up_service.rb
+++ b/app/services/repository_archive_clean_up_service.rb
@@ -1,6 +1,8 @@
class RepositoryArchiveCleanUpService
LAST_MODIFIED_TIME_IN_MINUTES = 120
+ attr_reader :mmin, :path
+
def initialize(mmin = LAST_MODIFIED_TIME_IN_MINUTES)
@mmin = mmin
@path = Gitlab.config.gitlab.repository_downloads_path
@@ -17,8 +19,6 @@ class RepositoryArchiveCleanUpService
private
- attr_reader :mmin, :path
-
def clean_up_old_archives
run(%W(find #{path} -not -path #{path} -type f \( -name \*.tar -o -name \*.bz2 -o -name \*.tar.gz -o -name \*.zip \) -maxdepth 2 -mmin +#{mmin} -delete))
end
diff --git a/app/services/spam_check_service.rb b/app/services/spam_check_service.rb
deleted file mode 100644
index 7c3e692bde9..00000000000
--- a/app/services/spam_check_service.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-class SpamCheckService < BaseService
- include Gitlab::AkismetHelper
-
- attr_accessor :request, :api
-
- def execute(request, api)
- @request, @api = request, api
- return false unless request || check_for_spam?(project)
- return false unless is_spam?(request.env, current_user, text)
-
- create_spam_log
-
- true
- end
-
- private
-
- def text
- [params[:title], params[:description]].reject(&:blank?).join("\n")
- end
-
- def spam_log_attrs
- {
- user_id: current_user.id,
- project_id: project.id,
- title: params[:title],
- description: params[:description],
- source_ip: client_ip(request.env),
- user_agent: user_agent(request.env),
- noteable_type: 'Issue',
- via_api: api
- }
- end
-
- def create_spam_log
- CreateSpamLogService.new(project, current_user, spam_log_attrs).execute
- end
-end
diff --git a/app/services/spam_service.rb b/app/services/spam_service.rb
new file mode 100644
index 00000000000..48903291799
--- /dev/null
+++ b/app/services/spam_service.rb
@@ -0,0 +1,78 @@
+class SpamService
+ attr_accessor :spammable, :request, :options
+
+ def initialize(spammable, request = nil)
+ @spammable = spammable
+ @request = request
+ @options = {}
+
+ if @request
+ @options[:ip_address] = @request.env['action_dispatch.remote_ip'].to_s
+ @options[:user_agent] = @request.env['HTTP_USER_AGENT']
+ @options[:referrer] = @request.env['HTTP_REFERRER']
+ else
+ @options[:ip_address] = @spammable.ip_address
+ @options[:user_agent] = @spammable.user_agent
+ end
+ end
+
+ def check(api = false)
+ return false unless request && check_for_spam?
+
+ return false unless akismet.is_spam?
+
+ create_spam_log(api)
+ true
+ end
+
+ def mark_as_spam!
+ return false unless spammable.submittable_as_spam?
+
+ if akismet.submit_spam
+ spammable.user_agent_detail.update_attribute(:submitted, true)
+ else
+ false
+ end
+ end
+
+ private
+
+ def akismet
+ @akismet ||= AkismetService.new(
+ spammable_owner,
+ spammable.spammable_text,
+ options
+ )
+ end
+
+ def spammable_owner
+ @user ||= User.find(spammable_owner_id)
+ end
+
+ def spammable_owner_id
+ @owner_id ||=
+ if spammable.respond_to?(:author_id)
+ spammable.author_id
+ elsif spammable.respond_to?(:creator_id)
+ spammable.creator_id
+ end
+ end
+
+ def check_for_spam?
+ spammable.check_for_spam?
+ end
+
+ def create_spam_log(api)
+ SpamLog.create(
+ {
+ user_id: spammable_owner_id,
+ title: spammable.spam_title,
+ description: spammable.spam_description,
+ source_ip: options[:ip_address],
+ user_agent: options[:user_agent],
+ noteable_type: spammable.class.to_s,
+ via_api: api
+ }
+ )
+ end
+end
diff --git a/app/services/test_hook_service.rb b/app/services/test_hook_service.rb
index e85e58751e7..280c81f7d2d 100644
--- a/app/services/test_hook_service.rb
+++ b/app/services/test_hook_service.rb
@@ -1,6 +1,6 @@
class TestHookService
def execute(hook, current_user)
- data = Gitlab::PushDataBuilder.build_sample(hook.project, current_user)
+ data = Gitlab::DataBuilder::Push.build_sample(hook.project, current_user)
hook.execute(data, 'push_hooks')
end
end
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index 6b48d68cccb..eb833dd82ac 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -144,8 +144,9 @@ class TodoService
def mark_todos_as_done(todos, current_user)
todos = current_user.todos.where(id: todos.map(&:id)) unless todos.respond_to?(:update_all)
- todos.update_all(state: :done)
+ marked_todos = todos.update_all(state: :done)
current_user.update_todos_count_cache
+ marked_todos
end
# When user marks an issue as todo
diff --git a/app/services/user_agent_detail_service.rb b/app/services/user_agent_detail_service.rb
new file mode 100644
index 00000000000..a1ee3df5fe1
--- /dev/null
+++ b/app/services/user_agent_detail_service.rb
@@ -0,0 +1,13 @@
+class UserAgentDetailService
+ attr_accessor :spammable, :request
+
+ def initialize(spammable, request)
+ @spammable, @request = spammable, request
+ end
+
+ def create
+ return unless request
+
+ spammable.create_user_agent_detail(user_agent: request.env['HTTP_USER_AGENT'], ip_address: request.env['action_dispatch.remote_ip'].to_s)
+ end
+end