1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
require_relative 'gitlab_init'
require_relative 'gitlab_net'
require_relative 'gitlab_reference_counter'
require_relative 'gitlab_metrics'
require 'json'
require 'base64'
require 'securerandom'
class GitlabPostReceive
include NamesHelper
attr_reader :config, :gl_repository, :repo_path, :changes, :jid
def initialize(gl_repository, repo_path, actor, changes)
@config = GitlabConfig.new
@gl_repository = gl_repository
@repo_path, @actor = repo_path.strip, actor
@changes = changes
@jid = SecureRandom.hex(12)
end
def exec
result = update_redis
begin
broadcast_message = GitlabMetrics.measure("broadcast-message") do
api.broadcast_message
end
if broadcast_message.has_key?("message")
puts
print_broadcast_message(broadcast_message["message"])
end
merge_request_urls = GitlabMetrics.measure("merge-request-urls") do
api.merge_request_urls(@gl_repository, @repo_path, @changes)
end
print_merge_request_links(merge_request_urls)
api.notify_post_receive(gl_repository, repo_path)
rescue GitlabNet::ApiUnreachableError
nil
end
result && GitlabReferenceCounter.new(repo_path).decrease
end
protected
def api
@api ||= GitlabNet.new
end
def print_merge_request_links(merge_request_urls)
return if merge_request_urls.empty?
puts
merge_request_urls.each { |mr| print_merge_request_link(mr) }
end
def print_merge_request_link(merge_request)
if merge_request["new_merge_request"]
message = "To create a merge request for #{merge_request["branch_name"]}, visit:"
else
message = "View merge request for #{merge_request["branch_name"]}:"
end
puts message
puts((" " * 2) + merge_request["url"])
puts
end
def print_broadcast_message(message)
# A standard terminal window is (at least) 80 characters wide.
total_width = 80
# Git prefixes remote messages with "remote: ", so this width is subtracted
# from the width available to us.
total_width -= "remote: ".length
# Our centered text shouldn't start or end right at the edge of the window,
# so we add some horizontal padding: 2 chars on either side.
text_width = total_width - 2 * 2
# Automatically wrap message at text_width (= 68) characters:
# Splits the message up into the longest possible chunks matching
# "<between 0 and text_width characters><space or end-of-line>".
# The last result is always an empty string (0 chars and the end-of-line),
# so drop that.
# message.scan returns a nested array of capture groups, so flatten.
lines = message.scan(/(.{,#{text_width}})(?:\s|$)/)[0...-1].flatten
puts "=" * total_width
puts
lines.each do |line|
line.strip!
# Center the line by calculating the left padding measured in characters.
line_padding = [(total_width - line.length) / 2, 0].max
puts((" " * line_padding) + line)
end
puts
puts "=" * total_width
end
def update_redis
# Encode changes as base64 so we don't run into trouble with non-UTF-8 input.
changes = Base64.encode64(@changes)
# TODO: Change to `@gl_repository` in next release.
# See https://gitlab.com/gitlab-org/gitlab-shell/merge_requests/130#note_28747613
project_identifier = @gl_repository || @repo_path
queue = "#{config.redis_namespace}:queue:post_receive"
msg = JSON.dump({
'class' => 'PostReceive',
'args' => [project_identifier, @actor, changes],
'jid' => @jid,
'enqueued_at' => Time.now.to_f
})
begin
GitlabNet.new.redis_client.rpush(queue, msg)
true
rescue => e
$stderr.puts "GitLab: An unexpected error occurred in writing to Redis: #{e}"
false
end
end
end
|