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:
Diffstat (limited to 'app/services/merge_requests/mergeability')
-rw-r--r--app/services/merge_requests/mergeability/detailed_merge_status_service.rb63
-rw-r--r--app/services/merge_requests/mergeability/logger.rb103
-rw-r--r--app/services/merge_requests/mergeability/run_checks_service.rb13
3 files changed, 178 insertions, 1 deletions
diff --git a/app/services/merge_requests/mergeability/detailed_merge_status_service.rb b/app/services/merge_requests/mergeability/detailed_merge_status_service.rb
new file mode 100644
index 00000000000..d25234183fd
--- /dev/null
+++ b/app/services/merge_requests/mergeability/detailed_merge_status_service.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+module MergeRequests
+ module Mergeability
+ class DetailedMergeStatusService
+ include ::Gitlab::Utils::StrongMemoize
+
+ def initialize(merge_request:)
+ @merge_request = merge_request
+ end
+
+ def execute
+ return :checking if checking?
+ return :unchecked if unchecked?
+
+ if check_results.success?
+
+ # If everything else is mergeable, but CI is not, the frontend expects two potential states to be returned
+ # See discussion: gitlab.com/gitlab-org/gitlab/-/merge_requests/96778#note_1093063523
+ if check_ci_results.success?
+ :mergeable
+ else
+ ci_check_failure_reason
+ end
+ else
+ check_results.failure_reason
+ end
+ end
+
+ private
+
+ attr_reader :merge_request, :checks, :ci_check
+
+ def checking?
+ merge_request.cannot_be_merged_rechecking? || merge_request.preparing? || merge_request.checking?
+ end
+
+ def unchecked?
+ merge_request.unchecked?
+ end
+
+ def check_results
+ strong_memoize(:check_results) do
+ merge_request.execute_merge_checks(params: { skip_ci_check: true })
+ end
+ end
+
+ def check_ci_results
+ strong_memoize(:check_ci_results) do
+ ::MergeRequests::Mergeability::CheckCiStatusService.new(merge_request: merge_request, params: {}).execute
+ end
+ end
+
+ def ci_check_failure_reason
+ if merge_request.actual_head_pipeline&.running?
+ :ci_still_running
+ else
+ check_ci_results.payload.fetch(:reason)
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/merge_requests/mergeability/logger.rb b/app/services/merge_requests/mergeability/logger.rb
new file mode 100644
index 00000000000..8b45d231e03
--- /dev/null
+++ b/app/services/merge_requests/mergeability/logger.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+module MergeRequests
+ module Mergeability
+ class Logger
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(merge_request:, destination: Gitlab::AppJsonLogger)
+ @destination = destination
+ @merge_request = merge_request
+ end
+
+ def commit
+ return unless enabled?
+
+ commit_logs
+ end
+
+ def instrument(mergeability_name:)
+ raise ArgumentError, 'block not given' unless block_given?
+
+ return yield unless enabled?
+
+ op_start_db_counters = current_db_counter_payload
+ op_started_at = current_monotonic_time
+
+ result = yield
+
+ observe("mergeability.#{mergeability_name}.duration_s", current_monotonic_time - op_started_at)
+
+ observe_sql_counters(mergeability_name, op_start_db_counters, current_db_counter_payload)
+
+ result
+ end
+
+ private
+
+ attr_reader :destination, :merge_request
+
+ def observe(name, value)
+ return unless enabled?
+
+ observations[name.to_s].push(value)
+ end
+
+ def commit_logs
+ attributes = Gitlab::ApplicationContext.current.merge({
+ mergeability_project_id: merge_request.project.id
+ })
+
+ attributes[:mergeability_merge_request_id] = merge_request.id
+ attributes.merge!(observations_hash)
+ attributes.compact!
+ attributes.stringify_keys!
+
+ destination.info(attributes)
+ end
+
+ def observations_hash
+ transformed = observations.transform_values do |values|
+ next if values.empty?
+
+ {
+ 'values' => values
+ }
+ end.compact
+
+ transformed.each_with_object({}) do |key, hash|
+ key[1].each { |k, v| hash["#{key[0]}.#{k}"] = v }
+ end
+ end
+
+ def observations
+ strong_memoize(:observations) do
+ Hash.new { |hash, key| hash[key] = [] }
+ end
+ end
+
+ def observe_sql_counters(name, start_db_counters, end_db_counters)
+ end_db_counters.each do |key, value|
+ result = value - start_db_counters.fetch(key, 0)
+ next if result == 0
+
+ observe("mergeability.#{name}.#{key}", result)
+ end
+ end
+
+ def current_db_counter_payload
+ ::Gitlab::Metrics::Subscribers::ActiveRecord.db_counter_payload
+ end
+
+ def enabled?
+ strong_memoize(:enabled) do
+ ::Feature.enabled?(:mergeability_checks_logger, merge_request.project)
+ end
+ end
+
+ def current_monotonic_time
+ ::Gitlab::Metrics::System.monotonic_time
+ end
+ end
+ end
+end
diff --git a/app/services/merge_requests/mergeability/run_checks_service.rb b/app/services/merge_requests/mergeability/run_checks_service.rb
index 68f842b3322..7f205c8dd6c 100644
--- a/app/services/merge_requests/mergeability/run_checks_service.rb
+++ b/app/services/merge_requests/mergeability/run_checks_service.rb
@@ -15,12 +15,17 @@ module MergeRequests
next if check.skip?
- check_result = run_check(check)
+ check_result = logger.instrument(mergeability_name: check_class.to_s.demodulize.underscore) do
+ run_check(check)
+ end
+
result_hash << check_result
break result_hash if check_result.failed?
end
+ logger.commit
+
self
end
@@ -57,6 +62,12 @@ module MergeRequests
Gitlab::MergeRequests::Mergeability::ResultsStore.new(merge_request: merge_request)
end
end
+
+ def logger
+ strong_memoize(:logger) do
+ MergeRequests::Mergeability::Logger.new(merge_request: merge_request)
+ end
+ end
end
end
end