gitlab-org--gitlab-foss/lib/gitlab/data_builder/push.rb
Jonathon Reinhart ba781484c7 Add support for Git push options, specifically ci.skip
gitlab-org/gitlab-shell!166 added support for collecting push options
from the environment, and passing them along to the
/internal/post_receive API endpoint.

This change handles the new push_options JSON element in the payload,
and passes them on through to the GitPushService and GitTagPushService
services.

Futhermore, it adds support for the first push option, ci.skip.  With
this change, one can use 'git push -o ci.skip' to skip CI pipe
execution. Note that the pipeline is still created, but in the "skipped"
state, just like with the 'ci skip' commit message text.

Implements #18667
2018-12-31 13:57:53 -05:00

147 lines
4.6 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module DataBuilder
module Push
extend self
SAMPLE_DATA =
{
object_kind: "push",
event_name: "push",
before: "95790bf891e76fee5e1747ab589903a6a1f80f22",
after: "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
ref: "refs/heads/master",
checkout_sha: "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
message: "Hello World",
user_id: 4,
user_name: "John Smith",
user_email: "john@example.com",
user_avatar: "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80",
project_id: 15,
commits: [
{
id: "c5feabde2d8cd023215af4d2ceeb7a64839fc428",
message: "Add simple search to projects in public area",
timestamp: "2013-05-13T18:18:08+00:00",
url: "https://test.example.com/gitlab/gitlabhq/commit/c5feabde2d8cd023215af4d2ceeb7a64839fc428",
author: {
name: "Test User",
email: "test@example.com"
}
}
],
total_commits_count: 1,
push_options: [
"ci.skip",
"custom option"
]
}.freeze
# Produce a hash of post-receive data
#
# data = {
# before: String,
# after: String,
# ref: String,
# user_id: String,
# user_name: String,
# user_username: String,
# user_email: String
# project_id: String,
# repository: {
# name: String,
# url: String,
# description: String,
# homepage: String,
# },
# commits: Array,
# total_commits_count: Fixnum,
# push_options: Array
# }
#
# rubocop:disable Metrics/ParameterLists
def build(project, user, oldrev, newrev, ref, commits = [], message = nil, commits_count: nil, push_options: [])
commits = Array(commits)
# Total commits count
commits_count ||= commits.size
# Get latest 20 commits ASC
commits_limited = commits.last(20)
# For performance purposes maximum 20 latest commits
# will be passed as post receive hook data.
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/38259
commit_attrs = Gitlab::GitalyClient.allow_n_plus_1_calls do
commits_limited.map do |commit|
commit.hook_attrs(with_changed_files: true)
end
end
type = Gitlab::Git.tag_ref?(ref) ? 'tag_push' : 'push'
# Hash to be passed as post_receive_data
{
object_kind: type,
event_name: type,
before: oldrev,
after: newrev,
ref: ref,
checkout_sha: checkout_sha(project.repository, newrev, ref),
message: message,
user_id: user.id,
user_name: user.name,
user_username: user.username,
user_email: user.email,
user_avatar: user.avatar_url(only_path: false),
project_id: project.id,
project: project.hook_attrs,
commits: commit_attrs,
total_commits_count: commits_count,
push_options: push_options,
# DEPRECATED
repository: project.hook_attrs.slice(:name, :url, :description, :homepage,
:git_http_url, :git_ssh_url, :visibility_level)
}
end
# This method provides a sample data generated with
# existing project and commits to test webhooks
def build_sample(project, user)
# Use sample data if repo has no commit
# (expect the case of test service configuration settings)
return sample_data if project.empty_repo?
ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{project.default_branch}"
commits = project.repository.commits(project.default_branch.to_s, limit: 3)
build(project, user, commits.last&.id, commits.first&.id, ref, commits)
end
def sample_data
SAMPLE_DATA
end
private
def checkout_sha(repository, newrev, ref)
# Checkout sha is nil when we remove branch or tag
return if Gitlab::Git.blank_ref?(newrev)
# Find sha for tag, except when it was deleted.
if Gitlab::Git.tag_ref?(ref)
tag_name = Gitlab::Git.ref_name(ref)
tag = repository.find_tag(tag_name)
if tag
commit = repository.commit(tag.dereferenced_target)
commit.try(:sha)
end
else
newrev
end
end
end
end
end