debian-mirror-gitlab/app/services/git/branch_hooks_service.rb

258 lines
7.7 KiB
Ruby
Raw Normal View History

2019-07-31 22:56:46 +05:30
# frozen_string_literal: true
module Git
class BranchHooksService < ::Git::BaseHooksService
2021-03-11 19:13:27 +05:30
extend ::Gitlab::Utils::Override
2019-07-31 22:56:46 +05:30
def execute
execute_branch_hooks
super.tap do
2020-03-13 15:44:24 +05:30
enqueue_update_signatures
2019-07-31 22:56:46 +05:30
end
end
private
def hook_name
:push_hooks
end
2021-11-11 11:23:49 +05:30
def limited_commits
strong_memoize(:limited_commits) { threshold_commits.last(PROCESS_COMMIT_LIMIT) }
end
# Taking limit+1 commits allows us to detect when the limit is in effect
def threshold_commits
strong_memoize(:threshold_commits) do
2019-07-31 22:56:46 +05:30
if creating_default_branch?
2021-10-27 15:23:28 +05:30
# The most recent PROCESS_COMMIT_LIMIT commits in the default branch.
# They are returned newest-to-oldest, but we need to present them oldest-to-newest
2021-11-11 11:23:49 +05:30
project.repository.commits(newrev, limit: PROCESS_COMMIT_LIMIT + 1).reverse!
2019-07-31 22:56:46 +05:30
elsif creating_branch?
# Use the pushed commits that aren't reachable by the default branch
# as a heuristic. This may include more commits than are actually
# pushed, but that shouldn't matter because we check for existing
# cross-references later.
2021-11-11 11:23:49 +05:30
project.repository.commits_between(project.default_branch, newrev, limit: PROCESS_COMMIT_LIMIT + 1)
2019-07-31 22:56:46 +05:30
elsif updating_branch?
2021-11-11 11:23:49 +05:30
project.repository.commits_between(oldrev, newrev, limit: PROCESS_COMMIT_LIMIT + 1)
2019-07-31 22:56:46 +05:30
else # removing branch
[]
end
end
end
def commits_count
2021-11-11 11:23:49 +05:30
strong_memoize(:commits_count) do
next threshold_commits.count if
strong_memoized?(:threshold_commits) &&
threshold_commits.count <= PROCESS_COMMIT_LIMIT
2019-07-31 22:56:46 +05:30
2021-11-11 11:23:49 +05:30
if creating_default_branch?
project.repository.commit_count_for_ref(ref)
elsif creating_branch?
project.repository.count_commits_between(project.default_branch, newrev)
elsif updating_branch?
project.repository.count_commits_between(oldrev, newrev)
else # removing branch
0
end
end
2019-07-31 22:56:46 +05:30
end
2021-03-11 19:13:27 +05:30
override :invalidated_file_types
2019-07-31 22:56:46 +05:30
def invalidated_file_types
return super unless default_branch? && !creating_branch?
2021-03-11 19:13:27 +05:30
modified_file_types
end
def modified_file_types
paths = commit_paths.values.reduce(&:merge) || Set.new
2019-07-31 22:56:46 +05:30
Gitlab::FileDetector.types_in_paths(paths)
end
def execute_branch_hooks
project.repository.after_push_commit(branch_name)
branch_create_hooks if creating_branch?
branch_update_hooks if updating_branch?
branch_change_hooks if creating_branch? || updating_branch?
branch_remove_hooks if removing_branch?
2022-08-13 15:12:31 +05:30
track_process_commit_limit_overflow
2019-07-31 22:56:46 +05:30
end
def branch_create_hooks
2019-10-12 21:52:04 +05:30
project.repository.after_create_branch(expire_cache: false)
2019-07-31 22:56:46 +05:30
project.after_create_default_branch if default_branch?
end
def branch_update_hooks
# Update the bare repositories info/attributes file using the contents of
# the default branch's .gitattributes file
2019-12-21 20:55:43 +05:30
project.repository.copy_gitattributes(ref) if default_branch?
2019-07-31 22:56:46 +05:30
end
def branch_change_hooks
enqueue_process_commit_messages
2020-11-24 15:15:51 +05:30
enqueue_jira_connect_sync_messages
2021-01-03 14:25:43 +05:30
enqueue_metrics_dashboard_sync
2021-03-11 19:13:27 +05:30
track_ci_config_change_event
2019-07-31 22:56:46 +05:30
end
def branch_remove_hooks
2019-10-12 21:52:04 +05:30
project.repository.after_remove_branch(expire_cache: false)
2019-07-31 22:56:46 +05:30
end
2021-01-03 14:25:43 +05:30
def enqueue_metrics_dashboard_sync
return unless default_branch?
2021-03-11 19:13:27 +05:30
return unless modified_file_types.include?(:metrics_dashboard)
2021-01-03 14:25:43 +05:30
::Metrics::Dashboard::SyncDashboardsWorker.perform_async(project.id)
end
2021-03-11 19:13:27 +05:30
def track_ci_config_change_event
2021-10-27 15:23:28 +05:30
return unless ::ServicePing::ServicePingSettings.enabled?
2021-03-11 19:13:27 +05:30
return unless default_branch?
commits_changing_ci_config.each do |commit|
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(
'o_pipeline_authoring_unique_users_committing_ciconfigfile', values: commit.author&.id
)
end
end
2022-08-13 15:12:31 +05:30
def track_process_commit_limit_overflow
return if threshold_commits.count <= PROCESS_COMMIT_LIMIT
Gitlab::Metrics.add_event(:process_commit_limit_overflow)
end
2019-07-31 22:56:46 +05:30
# Schedules processing of commit messages
def enqueue_process_commit_messages
2019-10-12 21:52:04 +05:30
referencing_commits = limited_commits.select(&:matches_cross_reference_regex?)
upstream_commit_ids = upstream_commit_ids(referencing_commits)
referencing_commits.each do |commit|
# Avoid reprocessing commits that already exist upstream if the project
# is a fork. This will prevent duplicated/superfluous system notes on
# mentionables referenced by a commit that is pushed to the upstream,
# that is then also pushed to forks when these get synced by users.
next if upstream_commit_ids.include?(commit.id)
2019-07-31 22:56:46 +05:30
ProcessCommitWorker.perform_async(
project.id,
current_user.id,
commit.to_hash,
default_branch?
)
end
end
2020-11-24 15:15:51 +05:30
def enqueue_jira_connect_sync_messages
return unless project.jira_subscription_exists?
branch_to_sync = branch_name if Atlassian::JiraIssueKeyExtractor.has_keys?(branch_name)
commits_to_sync = limited_commits.select { |commit| Atlassian::JiraIssueKeyExtractor.has_keys?(commit.safe_message) }.map(&:sha)
if branch_to_sync || commits_to_sync.any?
2021-02-22 17:27:13 +05:30
JiraConnect::SyncBranchWorker.perform_async(project.id, branch_to_sync, commits_to_sync, Atlassian::JiraConnect::Client.generate_update_sequence_id)
2020-11-24 15:15:51 +05:30
end
end
2023-03-04 22:38:38 +05:30
def signature_types
2023-03-17 16:20:25 +05:30
[
2023-03-04 22:38:38 +05:30
::CommitSignatures::GpgSignature,
2023-03-17 16:20:25 +05:30
::CommitSignatures::X509CommitSignature,
::CommitSignatures::SshSignature
2023-03-04 22:38:38 +05:30
]
2020-03-13 15:44:24 +05:30
end
2023-03-04 22:38:38 +05:30
def unsigned_commit_shas(commits)
commit_shas = commits.map(&:sha)
signature_types
.map { |signature| signature.unsigned_commit_shas(commit_shas) }
.reduce(&:&)
2020-03-13 15:44:24 +05:30
end
def enqueue_update_signatures
2023-03-04 22:38:38 +05:30
unsigned = unsigned_commit_shas(limited_commits)
2019-07-31 22:56:46 +05:30
return if unsigned.empty?
signable = Gitlab::Git::Commit.shas_with_signatures(project.repository, unsigned)
return if signable.empty?
2020-03-13 15:44:24 +05:30
CreateCommitSignatureWorker.perform_async(signable, project.id)
2019-07-31 22:56:46 +05:30
end
2019-09-30 21:07:59 +05:30
# It's not sufficient to just check for a blank SHA as it's possible for the
# branch to be pushed, but for the `post-receive` hook to never run:
2019-12-04 20:38:33 +05:30
# https://gitlab.com/gitlab-org/gitlab-foss/issues/59257
2019-07-31 22:56:46 +05:30
def creating_branch?
2019-09-30 21:07:59 +05:30
strong_memoize(:creating_branch) do
2019-12-21 20:55:43 +05:30
Gitlab::Git.blank_ref?(oldrev) ||
2019-09-30 21:07:59 +05:30
!project.repository.branch_exists?(branch_name)
end
2019-07-31 22:56:46 +05:30
end
def updating_branch?
!creating_branch? && !removing_branch?
end
def removing_branch?
2019-12-21 20:55:43 +05:30
Gitlab::Git.blank_ref?(newrev)
2019-07-31 22:56:46 +05:30
end
def creating_default_branch?
creating_branch? && default_branch?
end
def default_branch?
strong_memoize(:default_branch) do
[nil, branch_name].include?(project.default_branch)
end
end
def branch_name
2019-12-21 20:55:43 +05:30
strong_memoize(:branch_name) { Gitlab::Git.ref_name(ref) }
2019-07-31 22:56:46 +05:30
end
2019-10-12 21:52:04 +05:30
def upstream_commit_ids(commits)
set = Set.new
upstream_project = project.fork_source
if upstream_project
upstream_project
.commits_by(oids: commits.map(&:id))
.each { |commit| set << commit.id }
end
set
end
2021-03-11 19:13:27 +05:30
def commits_changing_ci_config
commit_paths.select do |commit, paths|
next if commit.merge_commit?
paths.include?(project.ci_config_path_or_default)
end.keys
end
def commit_paths
strong_memoize(:commit_paths) do
limited_commits.to_h do |commit|
paths = Set.new(commit.raw_deltas.map(&:new_path))
[commit, paths]
end
end
end
2019-07-31 22:56:46 +05:30
end
end
2019-12-04 20:38:33 +05:30
2021-06-08 01:23:25 +05:30
Git::BranchHooksService.prepend_mod_with('Git::BranchHooksService')