Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-shell
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-shell
Commits
e0824f17
Commit
e0824f17
authored
Apr 03, 2019
by
Jacob Vosmaer
Committed by
Nick Thomas
Apr 03, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove hooks, they belong to Gitaly now
parent
433cc965
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
11 additions
and
998 deletions
+11
-998
README.md
README.md
+2
-6
hooks/post-receive
hooks/post-receive
+3
-21
hooks/pre-receive
hooks/pre-receive
+3
-31
hooks/update
hooks/update
+3
-17
lib/gitlab_access.rb
lib/gitlab_access.rb
+0
-43
lib/gitlab_custom_hook.rb
lib/gitlab_custom_hook.rb
+0
-98
lib/gitlab_net.rb
lib/gitlab_net.rb
+0
-1
lib/gitlab_post_receive.rb
lib/gitlab_post_receive.rb
+0
-125
spec/gitlab_access_spec.rb
spec/gitlab_access_spec.rb
+0
-77
spec/gitlab_custom_hook_spec.rb
spec/gitlab_custom_hook_spec.rb
+0
-295
spec/gitlab_post_receive_spec.rb
spec/gitlab_post_receive_spec.rb
+0
-284
No files found.
README.md
View file @
e0824f17
...
...
@@ -20,7 +20,7 @@ An overview of the four cases described above:
## Git hooks
For historical reasons the gitlab-shell repository also contains
the
The gitlab-shell repository used to also contain
the
Git hooks that allow GitLab to validate Git pushes (e.g. "is this user
allowed to push to this protected branch"). These hooks also trigger
events in GitLab (e.g. to start a CI pipeline after a push).
...
...
@@ -30,17 +30,13 @@ require direct disk access to Git repositories, and that is only
possible on Gitaly servers. It makes no sense to have to install
gitlab-shell on Gitaly servers.
As of GitLab 11.
9
[
the actual Git hooks are in the Gitaly
As of GitLab 11.
10
[
the actual Git hooks are in the Gitaly
repository
](
https://gitlab.com/gitlab-org/gitaly/tree/v1.22.0/ruby/vendor/gitlab-shell/hooks
)
,
but gitlab-shell must still be installed on Gitaly servers because the
hooks rely on configuration data (e.g. the GitLab internal API URL) that
is not yet available in Gitaly itself. Also see the
[
transition
plan
](
https://gitlab.com/gitlab-org/gitaly/issues/1226#note_126519133
)
.
This means that for GitLab 11.9 and up, it is pointless to make changes
to Git hook code in the gitlab-shell repository, because the code that
gets run is in the Gitaly repository instead.
## Code status
[
![pipeline status
](
https://gitlab.com/gitlab-org/gitlab-shell/badges/master/pipeline.svg
)
](https://gitlab.com/gitlab-org/gitlab-shell/commits/master)
...
...
hooks/post-receive
View file @
e0824f17
#!/usr/bin/env ruby
#!/bin/sh
echo
"The gitlab-shell hooks have been migrated to Gitaly, see https://gitlab.com/gitlab-org/gitaly/issues/1226"
exit
1
# This file was placed here by GitLab. It makes sure that your pushed commits
# will be processed properly.
refs
=
$stdin
.
read
key_id
=
ENV
.
delete
(
'GL_ID'
)
gl_repository
=
ENV
[
'GL_REPOSITORY'
]
repo_path
=
Dir
.
pwd
require_relative
'../lib/gitlab_custom_hook'
require_relative
'../lib/hooks_utils'
require_relative
'../lib/gitlab_post_receive'
push_options
=
HooksUtils
.
get_push_options
if
GitlabPostReceive
.
new
(
gl_repository
,
repo_path
,
key_id
,
refs
,
push_options
).
exec
&&
GitlabCustomHook
.
new
(
repo_path
,
key_id
).
post_receive
(
refs
)
exit
0
else
exit
1
end
hooks/pre-receive
View file @
e0824f17
#!/usr/bin/env ruby
#!/bin/sh
echo
"The gitlab-shell hooks have been migrated to Gitaly, see https://gitlab.com/gitlab-org/gitaly/issues/1226"
exit
1
# This file was placed here by GitLab. It makes sure that your pushed commits
# will be processed properly.
refs
=
$stdin
.
read
key_id
=
ENV
.
delete
(
'GL_ID'
)
protocol
=
ENV
.
delete
(
'GL_PROTOCOL'
)
repo_path
=
Dir
.
pwd
gl_repository
=
ENV
[
'GL_REPOSITORY'
]
def
increase_reference_counter
(
gl_repository
,
repo_path
)
result
=
GitlabNet
.
new
.
pre_receive
(
gl_repository
)
result
&&
result
[
'reference_counter_increased'
]
end
require_relative
'../lib/gitlab_custom_hook'
require_relative
'../lib/gitlab_access'
require_relative
'../lib/gitlab_net'
# It's important that on pre-receive `increase_reference_counter` gets executed
# last so that it only runs if everything else succeeded. On post-receive on the
# other hand, we run GitlabPostReceive first because the push is already done
# and we don't want to skip it if the custom hook fails.
if
GitlabAccess
.
new
(
gl_repository
,
repo_path
,
key_id
,
refs
,
protocol
).
exec
&&
GitlabCustomHook
.
new
(
repo_path
,
key_id
).
pre_receive
(
refs
)
&&
increase_reference_counter
(
gl_repository
,
repo_path
)
exit
0
else
exit
1
end
hooks/update
View file @
e0824f17
#!/usr/bin/env ruby
#!/bin/sh
echo
"The gitlab-shell hooks have been migrated to Gitaly, see https://gitlab.com/gitlab-org/gitaly/issues/1226"
exit
1
# This file was placed here by GitLab. It makes sure that your pushed commits
# will be processed properly.
ref_name
=
ARGV
[
0
]
old_value
=
ARGV
[
1
]
new_value
=
ARGV
[
2
]
repo_path
=
Dir
.
pwd
key_id
=
ENV
.
delete
(
'GL_ID'
)
require_relative
'../lib/gitlab_custom_hook'
if
GitlabCustomHook
.
new
(
repo_path
,
key_id
).
update
(
ref_name
,
old_value
,
new_value
)
exit
0
else
exit
1
end
lib/gitlab_access.rb
deleted
100644 → 0
View file @
433cc965
require_relative
'gitlab_init'
require_relative
'gitlab_net'
require_relative
'gitlab_access_status'
require_relative
'gitlab_metrics'
require_relative
'object_dirs_helper'
require
'json'
class
GitlabAccess
class
AccessDeniedError
<
StandardError
;
end
attr_reader
:config
,
:gl_repository
,
:repo_path
,
:changes
,
:protocol
def
initialize
(
gl_repository
,
repo_path
,
actor
,
changes
,
protocol
)
@config
=
GitlabConfig
.
new
@gl_repository
=
gl_repository
@repo_path
=
repo_path
.
strip
@actor
=
actor
@changes
=
changes
.
lines
@protocol
=
protocol
end
def
exec
status
=
GitlabMetrics
.
measure
(
'check-access:git-receive-pack'
)
do
api
.
check_access
(
'git-receive-pack'
,
@gl_repository
,
@repo_path
,
@actor
,
@changes
,
@protocol
,
env:
ObjectDirsHelper
.
all_attributes
.
to_json
)
end
raise
AccessDeniedError
,
status
.
message
unless
status
.
allowed?
true
rescue
GitlabNet
::
ApiUnreachableError
$stderr
.
puts
"GitLab: Failed to authorize your Git request: internal API unreachable"
false
rescue
AccessDeniedError
=>
ex
$stderr
.
puts
"GitLab:
#{
ex
.
message
}
"
false
end
protected
def
api
GitlabNet
.
new
end
end
lib/gitlab_custom_hook.rb
deleted
100644 → 0
View file @
433cc965
require
'open3'
require_relative
'gitlab_init'
require_relative
'gitlab_metrics'
class
GitlabCustomHook
attr_reader
:vars
,
:config
def
initialize
(
repo_path
,
key_id
)
@repo_path
=
repo_path
@vars
=
{
'GL_ID'
=>
key_id
}
@config
=
GitlabConfig
.
new
end
def
pre_receive
(
changes
)
GitlabMetrics
.
measure
(
"pre-receive-hook"
)
do
find_hooks
(
'pre-receive'
).
all?
do
|
hook
|
call_receive_hook
(
hook
,
changes
)
end
end
end
def
post_receive
(
changes
)
GitlabMetrics
.
measure
(
"post-receive-hook"
)
do
find_hooks
(
'post-receive'
).
all?
do
|
hook
|
call_receive_hook
(
hook
,
changes
)
end
end
end
def
update
(
ref_name
,
old_value
,
new_value
)
GitlabMetrics
.
measure
(
"update-hook"
)
do
find_hooks
(
'update'
).
all?
do
|
hook
|
system
(
vars
,
hook
,
ref_name
,
old_value
,
new_value
)
end
end
end
private
def
call_receive_hook
(
hook
,
changes
)
# Prepare the hook subprocess. Attach a pipe to its stdin, and merge
# both its stdout and stderr into our own stdout.
stdin_reader
,
stdin_writer
=
IO
.
pipe
hook_pid
=
spawn
(
vars
,
hook
,
in:
stdin_reader
,
err: :out
)
stdin_reader
.
close
# Submit changes to the hook via its stdin.
begin
IO
.
copy_stream
(
StringIO
.
new
(
changes
),
stdin_writer
)
rescue
Errno
::
EPIPE
# rubocop:disable Lint/HandleExceptions
# It is not an error if the hook does not consume all of its input.
end
# Close the pipe to let the hook know there is no further input.
stdin_writer
.
close
Process
.
wait
(
hook_pid
)
$?
.
success?
end
# lookup hook files in this order:
#
# 1. <repository>.git/custom_hooks/<hook_name> - per project hook
# 2. <repository>.git/custom_hooks/<hook_name>.d/* - per project hooks
# 3. <repository>.git/hooks/<hook_name>.d/* - global hooks
#
def
find_hooks
(
hook_name
)
hook_files
=
[]
# <repository>.git/custom_hooks/<hook_name>
project_custom_hook_file
=
File
.
join
(
@repo_path
,
'custom_hooks'
,
hook_name
)
hook_files
.
push
(
project_custom_hook_file
)
if
File
.
executable?
(
project_custom_hook_file
)
# <repository>.git/custom_hooks/<hook_name>.d/*
project_custom_hooks_dir
=
File
.
join
(
@repo_path
,
'custom_hooks'
,
"
#{
hook_name
}
.d"
)
hook_files
+=
match_hook_files
(
project_custom_hooks_dir
)
# <repository>.git/hooks/<hook_name>.d/* OR <custom_hook_dir>/<hook_name>.d/*
global_custom_hooks_parent
=
config
.
custom_hooks_dir
(
default:
File
.
join
(
@repo_path
,
'hooks'
))
global_custom_hooks_dir
=
File
.
join
(
global_custom_hooks_parent
,
"
#{
hook_name
}
.d"
)
hook_files
+=
match_hook_files
(
global_custom_hooks_dir
)
hook_files
end
# match files from path:
# 1. file must be executable
# 2. file must not match backup file
#
# the resulting list is sorted
def
match_hook_files
(
path
)
return
[]
unless
Dir
.
exist?
(
path
)
Dir
[
"
#{
path
}
/*"
].
select
do
|
f
|
!
f
.
end_with?
(
'~'
)
&&
File
.
executable?
(
f
)
end
.
sort
end
end
lib/gitlab_net.rb
View file @
e0824f17
...
...
@@ -3,7 +3,6 @@ require 'openssl'
require
'json'
require_relative
'gitlab_config'
require_relative
'gitlab_access'
require_relative
'gitlab_lfs_authentication'
require_relative
'http_helper'
...
...
lib/gitlab_post_receive.rb
deleted
100644 → 0
View file @
433cc965
require_relative
'gitlab_init'
require_relative
'gitlab_net'
require_relative
'gitlab_metrics'
require
'json'
require
'base64'
require
'securerandom'
class
GitlabPostReceive
attr_reader
:config
,
:gl_repository
,
:repo_path
,
:changes
,
:jid
def
initialize
(
gl_repository
,
repo_path
,
actor
,
changes
,
push_options
)
@config
=
GitlabConfig
.
new
@gl_repository
=
gl_repository
@repo_path
=
repo_path
.
strip
@actor
=
actor
@changes
=
changes
@push_options
=
push_options
@jid
=
SecureRandom
.
hex
(
12
)
end
def
exec
response
=
GitlabMetrics
.
measure
(
"post-receive"
)
do
api
.
post_receive
(
gl_repository
,
@actor
,
changes
,
@push_options
)
end
return
false
unless
response
print_formatted_alert_message
(
response
[
'broadcast_message'
])
if
response
[
'broadcast_message'
]
print_merge_request_links
(
response
[
'merge_request_urls'
])
if
response
[
'merge_request_urls'
]
puts
response
[
'redirected_message'
]
if
response
[
'redirected_message'
]
puts
response
[
'project_created_message'
]
if
response
[
'project_created_message'
]
print_warnings
(
response
[
'warnings'
])
if
response
[
'warnings'
]
response
[
'reference_counter_decreased'
]
rescue
GitlabNet
::
ApiUnreachableError
false
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
)
message
=
if
merge_request
[
"new_merge_request"
]
"To create a merge request for
#{
merge_request
[
'branch_name'
]
}
, visit:"
else
"View merge request for
#{
merge_request
[
'branch_name'
]
}
:"
end
puts
message
puts
((
" "
*
2
)
+
merge_request
[
"url"
])
puts
end
def
print_warnings
(
warnings
)
message
=
"WARNINGS:
\n
#{
warnings
}
"
print_formatted_alert_message
(
message
)
end
def
print_formatted_alert_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
# rubocop:disable Performance/FixedSize
# 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>".
msg_start_idx
=
0
lines
=
[]
while
msg_start_idx
<
message
.
length
parsed_line
=
parse_broadcast_msg
(
message
[
msg_start_idx
..-
1
],
text_width
)
msg_start_idx
+=
parsed_line
.
length
lines
.
push
(
parsed_line
.
strip
)
end
puts
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
private
def
parse_broadcast_msg
(
msg
,
text_length
)
msg
||=
""
# just return msg if shorter than or equal to text length
return
msg
if
msg
.
length
<=
text_length
# search for word break shorter than text length
truncate_to_space
=
msg
.
match
(
/\A(.{,
#{
text_length
}
})(?=\s|$)(\s*)/
).
to_s
if
truncate_to_space
.
empty?
# search for word break longer than text length
truncate_to_space
=
msg
.
match
(
/\A\S+/
).
to_s
end
truncate_to_space
end
end
spec/gitlab_access_spec.rb
deleted
100644 → 0
View file @
433cc965
require
'spec_helper'
require
'gitlab_access'
describe
GitlabAccess
do
let
(
:repository_path
)
{
"/home/git/repositories"
}
let
(
:repo_name
)
{
'dzaporozhets/gitlab-ci'
}
let
(
:repo_path
)
{
File
.
join
(
repository_path
,
repo_name
)
+
".git"
}
let
(
:api
)
do
double
(
GitlabNet
).
tap
do
|
api
|
allow
(
api
).
to
receive
(
:check_access
).
and_return
(
GitAccessStatus
.
new
(
true
,
'200'
,
'ok'
,
gl_repository:
'project-1'
,
gl_project_path:
'group/subgroup/project'
,
gl_id:
'user-123'
,
gl_username:
'testuser'
,
git_config_options:
[
'receive.MaxInputSize=10000'
],
gitaly:
nil
,
git_protocol:
'version=2'
))
end
end
subject
do
GitlabAccess
.
new
(
nil
,
repo_path
,
'key-123'
,
'wow'
,
'ssh'
).
tap
do
|
access
|
allow
(
access
).
to
receive
(
:exec_cmd
).
and_return
(
:exec_called
)
allow
(
access
).
to
receive
(
:api
).
and_return
(
api
)
end
end
before
do
allow_any_instance_of
(
GitlabConfig
).
to
receive
(
:repos_path
).
and_return
(
repository_path
)
end
describe
:initialize
do
it
{
expect
(
subject
.
repo_path
).
to
eq
(
repo_path
)
}
it
{
expect
(
subject
.
changes
).
to
eq
([
'wow'
])
}
it
{
expect
(
subject
.
protocol
).
to
eq
(
'ssh'
)
}
end
describe
"#exec"
do
context
"access is granted"
do
it
"returns true"
do
expect
(
subject
.
exec
).
to
be_truthy
end
end
context
"access is denied"
do
before
do
allow
(
api
).
to
receive
(
:check_access
).
and_return
(
GitAccessStatus
.
new
(
false
,
'401'
,
'denied'
,
gl_repository:
nil
,
gl_project_path:
nil
,
gl_id:
nil
,
gl_username:
nil
,
git_config_options:
nil
,
gitaly:
nil
,
git_protocol:
nil
))
end
it
"returns false"
do
expect
(
subject
.
exec
).
to
be_falsey
end
end
context
"API connection fails"
do
before
do
allow
(
api
).
to
receive
(
:check_access
).
and_raise
(
GitlabNet
::
ApiUnreachableError
)
end
it
"returns false"
do
expect
(
subject
.
exec
).
to
be_falsey
end
end
end
end
spec/gitlab_custom_hook_spec.rb
deleted
100644 → 0
View file @
433cc965
This diff is collapsed.
Click to expand it.
spec/gitlab_post_receive_spec.rb
deleted
100644 → 0
View file @
433cc965
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment