Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
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
Léo-Paul Géneau
gitlab-ce
Commits
e646439e
Commit
e646439e
authored
Oct 05, 2016
by
Ruben Davila
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit 'dev/8-12-stable' into 8-12-stable
parents
467e1ca4
ba8aeb7c
Changes
39
Show whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
566 additions
and
73 deletions
+566
-73
CHANGELOG
CHANGELOG
+16
-1
VERSION
VERSION
+1
-1
app/assets/javascripts/compare_autocomplete.js
app/assets/javascripts/compare_autocomplete.js
+3
-2
app/assets/javascripts/copy_to_clipboard.js
app/assets/javascripts/copy_to_clipboard.js
+9
-9
app/assets/stylesheets/pages/builds.scss
app/assets/stylesheets/pages/builds.scss
+10
-3
app/assets/stylesheets/pages/projects.scss
app/assets/stylesheets/pages/projects.scss
+57
-1
app/controllers/concerns/authenticates_with_two_factor.rb
app/controllers/concerns/authenticates_with_two_factor.rb
+13
-2
app/models/merge_request.rb
app/models/merge_request.rb
+4
-0
app/models/project_feature.rb
app/models/project_feature.rb
+4
-1
app/models/service.rb
app/models/service.rb
+1
-0
app/models/user.rb
app/models/user.rb
+16
-0
app/services/projects/create_service.rb
app/services/projects/create_service.rb
+7
-1
app/views/projects/builds/_sidebar.html.haml
app/views/projects/builds/_sidebar.html.haml
+2
-2
app/views/projects/compare/_form.html.haml
app/views/projects/compare/_form.html.haml
+11
-6
app/views/projects/compare/_ref_dropdown.html.haml
app/views/projects/compare/_ref_dropdown.html.haml
+1
-0
lib/gitlab/github_import/importer.rb
lib/gitlab/github_import/importer.rb
+1
-2
lib/gitlab/github_import/project_creator.rb
lib/gitlab/github_import/project_creator.rb
+24
-11
lib/gitlab/import_export/attribute_cleaner.rb
lib/gitlab/import_export/attribute_cleaner.rb
+13
-0
lib/gitlab/import_export/command_line_util.rb
lib/gitlab/import_export/command_line_util.rb
+8
-1
lib/gitlab/import_export/file_importer.rb
lib/gitlab/import_export/file_importer.rb
+1
-1
lib/gitlab/import_export/project_tree_restorer.rb
lib/gitlab/import_export/project_tree_restorer.rb
+3
-2
lib/gitlab/import_export/project_tree_saver.rb
lib/gitlab/import_export/project_tree_saver.rb
+3
-1
lib/gitlab/import_export/relation_factory.rb
lib/gitlab/import_export/relation_factory.rb
+9
-3
lib/gitlab/import_export/repo_restorer.rb
lib/gitlab/import_export/repo_restorer.rb
+1
-1
lib/gitlab/import_export/repo_saver.rb
lib/gitlab/import_export/repo_saver.rb
+1
-1
lib/gitlab/import_export/version_saver.rb
lib/gitlab/import_export/version_saver.rb
+3
-1
lib/gitlab/import_export/wiki_repo_saver.rb
lib/gitlab/import_export/wiki_repo_saver.rb
+1
-1
lib/gitlab/lfs_token.rb
lib/gitlab/lfs_token.rb
+2
-7
spec/controllers/sessions_controller_spec.rb
spec/controllers/sessions_controller_spec.rb
+38
-0
spec/features/compare_spec.rb
spec/features/compare_spec.rb
+17
-9
spec/features/projects/import_export/export_file_spec.rb
spec/features/projects/import_export/export_file_spec.rb
+2
-0
spec/lib/gitlab/github_import/project_creator_spec.rb
spec/lib/gitlab/github_import/project_creator_spec.rb
+22
-2
spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
+34
-0
spec/lib/gitlab/import_export/relation_factory_spec.rb
spec/lib/gitlab/import_export/relation_factory_spec.rb
+125
-0
spec/models/merge_request_spec.rb
spec/models/merge_request_spec.rb
+24
-0
spec/models/service_spec.rb
spec/models/service_spec.rb
+17
-0
spec/services/merge_requests/merge_service_spec.rb
spec/services/merge_requests/merge_service_spec.rb
+36
-0
spec/services/projects/destroy_service_spec.rb
spec/services/projects/destroy_service_spec.rb
+22
-1
spec/support/import_export/export_file_helper.rb
spec/support/import_export/export_file_helper.rb
+4
-0
No files found.
CHANGELOG
View file @
e646439e
Please view this file on the master branch, on stable branches it's out of date.
v 8.12.4 (unreleased)
v 8.12.5 (unreleased)
v 8.12.4
- Fix "Copy to clipboard" tooltip to say "Copied!" when clipboard button is clicked. !6294 (lukehowell)
- Fix padding in build sidebar. !6506
- Changed compare dropdowns to dropdowns with isolated search input. !6550
- Fix race condition on LFS Token. !6592
- Fix type mismatch bug when closing Jira issue. !6619
- Fix lint-doc error. !6623
- Skip wiki creation when GitHub project has wiki enabled. !6665
- Fix issues importing services via Import/Export. !6667
- Restrict failed login attempts for users with 2FA enabled. !6668
- Fix failed project deletion when feature visibility set to private. !6688
- Prevent claiming associated model IDs via import.
- Set GitLab project exported file permissions to owner only
v 8.12.3
- Update Gitlab Shell to support low IO priority for storage moves
...
...
@@ -8,6 +22,7 @@ v 8.12.3
v 8.12.2
- Fix Import/Export not recognising correctly the imported services.
- Fix snippets pagination
- Fix "Create project" button layout when visibility options are restricted
- Fix List-Unsubscribe header in emails
- Fix IssuesController#show degradation including project on loaded notes
- Fix an issue with the "Commits" section of the cycle analytics summary. !6513
...
...
VERSION
View file @
e646439e
8.12.
3
8.12.
4
app/assets/javascripts/compare_autocomplete.js
View file @
e646439e
...
...
@@ -23,8 +23,9 @@
selectable
:
true
,
filterable
:
true
,
filterByText
:
true
,
fieldName
:
$dropdown
.
attr
(
'
name
'
),
filterInput
:
'
input[type="text"]
'
,
toggleLabel
:
true
,
fieldName
:
$dropdown
.
data
(
'
field-name
'
),
filterInput
:
'
input[type="search"]
'
,
renderRow
:
function
(
ref
)
{
var
link
;
if
(
ref
.
header
!=
null
)
{
...
...
app/assets/javascripts/copy_to_clipboard.js
View file @
e646439e
...
...
@@ -26,15 +26,15 @@
};
showTooltip
=
function
(
target
,
title
)
{
return
$
(
target
).
tooltip
({
container
:
'
body
'
,
html
:
'
true
'
,
placement
:
'
auto bottom
'
,
title
:
title
,
trigger
:
'
manual
'
}).
tooltip
(
'
show
'
).
one
(
'
mouseleave
'
,
function
()
{
return
$
(
this
).
tooltip
(
'
hide
'
);
}
);
var
$target
=
$
(
target
);
var
originalTitle
=
$target
.
data
(
'
original-title
'
);
$target
.
attr
(
'
title
'
,
'
Copied!
'
)
.
tooltip
(
'
fixTitle
'
)
.
tooltip
(
'
show
'
)
.
attr
(
'
title
'
,
originalTitle
)
.
tooltip
(
'
fixTitle
'
);
};
$
(
function
()
{
...
...
app/assets/stylesheets/pages/builds.scss
View file @
e646439e
...
...
@@ -107,10 +107,14 @@
.block
{
width
:
100%
;
&
.coverage
{
padding
:
0
16px
11px
;
}
.block-first
{
padding
:
5px
16px
11px
;
.btn-group-justified
{
margin-top
:
5px
;
}
}
.js-build-variable
{
...
...
@@ -214,6 +218,9 @@
.build-detail-row
{
margin-bottom
:
5px
;
&
:last-of-type
{
margin-bottom
:
0
;
}
}
.build-light-text
{
...
...
app/assets/stylesheets/pages/projects.scss
View file @
e646439e
...
...
@@ -743,6 +743,62 @@ pre.light-well {
.dropdown-menu
{
width
:
300px
;
}
&
.from
.compare-dropdown-toggle
{
width
:
237px
;
}
&
.to
.compare-dropdown-toggle
{
width
:
254px
;
}
.dropdown-toggle-text
{
display
:
block
;
height
:
100%
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
width
:
100%
;
}
}
.compare-ellipsis
{
display
:
inline
;
}
@media
(
max-width
:
$screen-xs-max
)
{
.compare-form-group
{
.input-group
{
width
:
100%
;
&
>
.compare-dropdown-toggle
{
width
:
100%
;
}
}
.dropdown-menu
{
width
:
100%
;
}
}
.compare-switch-container
{
text-align
:
center
;
padding
:
0
0
$gl-padding
;
.commits-compare-switch
{
float
:
none
;
}
}
.compare-ellipsis
{
display
:
block
;
text-align
:
center
;
padding
:
0
0
$gl-padding
;
}
.commits-compare-btn
{
width
:
100%
;
}
}
.clearable-input
{
...
...
app/controllers/concerns/authenticates_with_two_factor.rb
View file @
e646439e
...
...
@@ -23,15 +23,24 @@ module AuthenticatesWithTwoFactor
#
# Returns nil
def
prompt_for_two_factor
(
user
)
return
locked_user_redirect
(
user
)
if
user
.
access_locked?
session
[
:otp_user_id
]
=
user
.
id
setup_u2f_authentication
(
user
)
render
'devise/sessions/two_factor'
end
def
locked_user_redirect
(
user
)
flash
.
now
[
:alert
]
=
'Invalid Login or password'
render
'devise/sessions/new'
end
def
authenticate_with_two_factor
user
=
self
.
resource
=
find_user
if
user_params
[
:otp_attempt
].
present?
&&
session
[
:otp_user_id
]
if
user
.
access_locked?
locked_user_redirect
(
user
)
elsif
user_params
[
:otp_attempt
].
present?
&&
session
[
:otp_user_id
]
authenticate_with_two_factor_via_otp
(
user
)
elsif
user_params
[
:device_response
].
present?
&&
session
[
:otp_user_id
]
authenticate_with_two_factor_via_u2f
(
user
)
...
...
@@ -50,8 +59,9 @@ module AuthenticatesWithTwoFactor
remember_me
(
user
)
if
user_params
[
:remember_me
]
==
'1'
sign_in
(
user
)
else
user
.
increment_failed_attempts!
flash
.
now
[
:alert
]
=
'Invalid two-factor code.'
render
:two_factor
prompt_for_two_factor
(
user
)
end
end
...
...
@@ -65,6 +75,7 @@ module AuthenticatesWithTwoFactor
remember_me
(
user
)
if
user_params
[
:remember_me
]
==
'1'
sign_in
(
user
)
else
user
.
increment_failed_attempts!
flash
.
now
[
:alert
]
=
'Authentication via U2F device failed.'
prompt_for_two_factor
(
user
)
end
...
...
app/models/merge_request.rb
View file @
e646439e
...
...
@@ -507,9 +507,13 @@ class MergeRequest < ActiveRecord::Base
# `MergeRequestsClosingIssues` model. This is a performance optimization.
# Calculating this information for a number of merge requests requires
# running `ReferenceExtractor` on each of them separately.
# This optimization does not apply to issues from external sources.
def
cache_merge_request_closes_issues!
(
current_user
=
self
.
author
)
return
if
project
.
has_external_issue_tracker?
transaction
do
self
.
merge_requests_closing_issues
.
delete_all
closes_issues
(
current_user
).
each
do
|
issue
|
self
.
merge_requests_closing_issues
.
create!
(
issue:
issue
)
end
...
...
app/models/project_feature.rb
View file @
e646439e
...
...
@@ -20,7 +20,10 @@ class ProjectFeature < ActiveRecord::Base
FEATURES
=
%i(issues merge_requests wiki snippets builds)
belongs_to
:project
# Default scopes force us to unscope here since a service may need to check
# permissions for a project in pending_delete
# http://stackoverflow.com/questions/1540645/how-to-disable-default-scope-for-a-belongs-to
belongs_to
:project
,
->
{
unscope
(
where: :pending_delete
)
}
default_value_for
:builds_access_level
,
value:
ENABLED
,
allows_nil:
false
default_value_for
:issues_access_level
,
value:
ENABLED
,
allows_nil:
false
...
...
app/models/service.rb
View file @
e646439e
...
...
@@ -136,6 +136,7 @@ class Service < ActiveRecord::Base
end
def #{arg}=(value)
self.properties ||= {}
updated_properties['#{arg}'] = #{arg} unless #{arg}_changed?
self.properties['#{arg}'] = value
end
...
...
app/models/user.rb
View file @
e646439e
...
...
@@ -827,6 +827,22 @@ class User < ActiveRecord::Base
todos_pending_count
(
force:
true
)
end
# This is copied from Devise::Models::Lockable#valid_for_authentication?, as our auth
# flow means we don't call that automatically (and can't conveniently do so).
#
# See:
# <https://github.com/plataformatec/devise/blob/v4.0.0/lib/devise/models/lockable.rb#L92>
#
def
increment_failed_attempts!
self
.
failed_attempts
||=
0
self
.
failed_attempts
+=
1
if
attempts_exceeded?
lock_access!
unless
access_locked?
else
save
(
validate:
false
)
end
end
private
def
projects_union
(
min_access_level
=
nil
)
...
...
app/services/projects/create_service.rb
View file @
e646439e
...
...
@@ -7,6 +7,8 @@ module Projects
def
execute
forked_from_project_id
=
params
.
delete
(
:forked_from_project_id
)
import_data
=
params
.
delete
(
:import_data
)
@skip_wiki
=
params
.
delete
(
:skip_wiki
)
@project
=
Project
.
new
(
params
)
# Make sure that the user is allowed to use the specified visibility level
...
...
@@ -92,7 +94,7 @@ module Projects
log_info
(
"
#{
@project
.
owner
.
name
}
created a new project
\"
#{
@project
.
name_with_namespace
}
\"
"
)
unless
@project
.
gitlab_project_import?
@project
.
create_wiki
if
@project
.
feature_available?
(
:wiki
,
current_user
)
@project
.
create_wiki
unless
skip_wiki?
@project
.
build_missing_services
@project
.
create_labels
...
...
@@ -106,6 +108,10 @@ module Projects
end
end
def
skip_wiki?
!
@project
.
feature_available?
(
:wiki
,
current_user
)
||
@skip_wiki
end
def
save_project_and_import_data
(
import_data
)
Project
.
transaction
do
@project
.
create_or_update_import_data
(
data:
import_data
[
:data
],
credentials:
import_data
[
:credentials
])
if
import_data
...
...
app/views/projects/builds/_sidebar.html.haml
View file @
e646439e
...
...
@@ -8,7 +8,7 @@
%a
.gutter-toggle.pull-right.js-sidebar-build-toggle
{
href:
"#"
}
=
icon
(
'angle-double-right'
)
-
if
@build
.
coverage
.block.
block-first
.block.
coverage
.title
Test coverage
%p
.build-detail-row
...
...
app/views/projects/compare/_form.html.haml
View file @
e646439e
=
form_tag
namespace_project_compare_index_path
(
@project
.
namespace
,
@project
),
method: :post
,
class:
'form-inline js-requires-input'
do
.clearfix
-
if
params
[
:to
]
&&
params
[
:from
]
.compare-switch-container
=
link_to
icon
(
'exchange'
),
{
from:
params
[
:to
],
to:
params
[
:from
]},
{
class:
'commits-compare-switch has-tooltip'
,
title:
'Switch base of comparison'
}
.form-group.dropdown.compare-form-group.js-compare-from-dropdown
.form-group.dropdown.compare-form-group.
from.
js-compare-from-dropdown
.input-group.inline-input-group
%span
.input-group-addon
from
=
text_field_tag
:from
,
params
[
:from
],
class:
"form-control js-compare-dropdown"
,
required:
true
,
data:
{
refs_url:
refs_namespace_project_path
(
@project
.
namespace
,
@project
),
toggle:
"dropdown"
,
target:
".js-compare-from-dropdown"
,
selected:
params
[
:from
].
presence
}
=
hidden_field_tag
:from
,
params
[
:from
]
=
button_tag
type:
'button'
,
class:
"form-control compare-dropdown-toggle js-compare-dropdown"
,
required:
true
,
data:
{
refs_url:
refs_namespace_project_path
(
@project
.
namespace
,
@project
),
toggle:
"dropdown"
,
target:
".js-compare-from-dropdown"
,
selected:
params
[
:from
],
field_name: :from
}
do
.dropdown-toggle-text
=
params
[
:from
]
||
'Select branch/tag'
=
render
"ref_dropdown"
=
"..."
.form-group.dropdown.compare-form-group.js-compare-to-dropdown
.compare-ellipsis
...
.form-group.dropdown.compare-form-group.
to.
js-compare-to-dropdown
.input-group.inline-input-group
%span
.input-group-addon
to
=
text_field_tag
:to
,
params
[
:to
],
class:
"form-control js-compare-dropdown"
,
required:
true
,
data:
{
refs_url:
refs_namespace_project_path
(
@project
.
namespace
,
@project
),
toggle:
"dropdown"
,
target:
".js-compare-to-dropdown"
,
selected:
params
[
:to
].
presence
}
=
hidden_field_tag
:to
,
params
[
:to
]
=
button_tag
type:
'button'
,
class:
"form-control compare-dropdown-toggle js-compare-dropdown"
,
required:
true
,
data:
{
refs_url:
refs_namespace_project_path
(
@project
.
namespace
,
@project
),
toggle:
"dropdown"
,
target:
".js-compare-to-dropdown"
,
selected:
params
[
:to
],
field_name: :to
}
do
.dropdown-toggle-text
=
params
[
:to
]
||
'Select branch/tag'
=
render
"ref_dropdown"
=
button_tag
"Compare"
,
class:
"btn btn-create commits-compare-btn"
...
...
app/views/projects/compare/_ref_dropdown.html.haml
View file @
e646439e
.dropdown-menu.dropdown-menu-selectable
=
dropdown_title
"Select branch/tag"
=
dropdown_filter
"Filter by branch/tag"
=
dropdown_content
=
dropdown_loading
lib/gitlab/github_import/importer.rb
View file @
e646439e
...
...
@@ -165,10 +165,9 @@ module Gitlab
end
def
import_wiki
unless
project
.
wiki
_enabled
?
unless
project
.
wiki
.
repository_exists
?
wiki
=
WikiFormatter
.
new
(
project
)
gitlab_shell
.
import_repository
(
project
.
repository_storage_path
,
wiki
.
path_with_namespace
,
wiki
.
import_url
)
project
.
project
.
update_attribute
(
:wiki_access_level
,
ProjectFeature
::
ENABLED
)
end
rescue
Gitlab
::
Shell
::
Error
=>
e
# GitHub error message when the wiki repo has not been created,
...
...
lib/gitlab/github_import/project_creator.rb
View file @
e646439e
module
Gitlab
module
GithubImport
class
ProjectCreator
attr_reader
:repo
,
:namespace
,
:current_user
,
:session_data
attr_reader
:repo
,
:name
,
:name
space
,
:current_user
,
:session_data
def
initialize
(
repo
,
name
,
namespace
,
current_user
,
session_data
)
@repo
=
repo
...
...
@@ -12,24 +12,37 @@ module Gitlab
end
def
execute
project
=
::
Projects
::
CreateService
.
new
(
::
Projects
::
CreateService
.
new
(
current_user
,
name:
@
name
,
path:
@
name
,
name:
name
,
path:
name
,
description:
repo
.
description
,
namespace_id:
namespace
.
id
,
visibility_level:
repo
.
private
?
Gitlab
::
VisibilityLevel
::
PRIVATE
:
ApplicationSetting
.
current
.
default_project_visibility
,
visibility_level:
visibility_level
,
import_type:
"github"
,
import_source:
repo
.
full_name
,
import_url:
repo
.
clone_url
.
sub
(
"https://"
,
"https://
#{
@session_data
[
:github_access_token
]
}
@"
)
import_url:
import_url
,
skip_wiki:
skip_wiki
).
execute
end
private
def
import_url
repo
.
clone_url
.
sub
(
'https://'
,
"https://
#{
session_data
[
:github_access_token
]
}
@"
)
end
# If repo has wiki we'll import it later
if
repo
.
has_wiki?
&&
project
project
.
project_feature
.
update_attribute
(
:wiki_access_level
,
ProjectFeature
::
DISABLED
)
def
visibility_level
repo
.
private
?
Gitlab
::
VisibilityLevel
::
PRIVATE
:
ApplicationSetting
.
current
.
default_project_visibility
end
project
#
# If the GitHub project repository has wiki, we should not create the
# default wiki. Otherwise the GitHub importer will fail because the wiki
# repository already exist.
#
def
skip_wiki
repo
.
has_wiki?
end
end
end
...
...
lib/gitlab/import_export/attribute_cleaner.rb
0 → 100644
View file @
e646439e
module
Gitlab
module
ImportExport
class
AttributeCleaner
ALLOWED_REFERENCES
=
RelationFactory
::
PROJECT_REFERENCES
+
RelationFactory
::
USER_REFERENCES
def
self
.
clean!
(
relation_hash
:)
relation_hash
.
reject!
do
|
key
,
_value
|
key
.
end_with?
(
'_id'
)
&&
!
ALLOWED_REFERENCES
.
include?
(
key
)
end
end
end
end
end
lib/gitlab/import_export/command_line_util.rb
View file @
e646439e
module
Gitlab
module
ImportExport
module
CommandLineUtil
DEFAULT_MODE
=
0700
def
tar_czf
(
archive
:,
dir
:)
tar_with_options
(
archive:
archive
,
dir:
dir
,
options:
'czf'
)
end
...
...
@@ -21,6 +23,11 @@ module Gitlab
execute
(
%W(
#{
Gitlab
.
config
.
gitlab_shell
.
path
}
/bin/create-hooks)
+
repository_storage_paths_args
)
end
def
mkdir_p
(
path
)
FileUtils
.
mkdir_p
(
path
,
mode:
DEFAULT_MODE
)
FileUtils
.
chmod
(
DEFAULT_MODE
,
path
)
end
private
def
tar_with_options
(
archive
:,
dir
:,
options
:)
...
...
@@ -45,7 +52,7 @@ module Gitlab
# if we are copying files, create the destination folder
destination_folder
=
File
.
file?
(
source
)
?
File
.
dirname
(
destination
)
:
destination
FileUtils
.
mkdir_p
(
destination_folder
)
mkdir_p
(
destination_folder
)
FileUtils
.
copy_entry
(
source
,
destination
)
true
end
...
...
lib/gitlab/import_export/file_importer.rb
View file @
e646439e
...
...
@@ -15,7 +15,7 @@ module Gitlab
end
def
import
FileUtils
.
mkdir_p
(
@shared
.
export_path
)
mkdir_p
(
@shared
.
export_path
)
wait_for_archived_file
do
decompress_archive
...
...
lib/gitlab/import_export/project_tree_restorer.rb
View file @
e646439e
...
...
@@ -110,9 +110,10 @@ module Gitlab
def
create_relation
(
relation
,
relation_hash_list
)
relation_array
=
[
relation_hash_list
].
flatten
.
map
do
|
relation_hash
|
Gitlab
::
ImportExport
::
RelationFactory
.
create
(
relation_sym:
relation
.
to_sym
,
relation_hash:
relation_hash
.
merge
(
'project_id'
=>
restored_project
.
id
)
,
relation_hash:
relation_hash
,
members_mapper:
members_mapper
,
user:
@user
)
user:
@user
,
project_id:
restored_project
.
id
)
end
relation_hash_list
.
is_a?
(
Array
)
?
relation_array
:
relation_array
.
first
...
...
lib/gitlab/import_export/project_tree_saver.rb
View file @
e646439e
module
Gitlab
module
ImportExport
class
ProjectTreeSaver
include
Gitlab
::
ImportExport
::
CommandLineUtil
attr_reader
:full_path
def
initialize
(
project
:,
shared
:)
...
...
@@ -10,7 +12,7 @@ module Gitlab
end
def
save
FileUtils
.
mkdir_p
(
@shared
.
export_path
)
mkdir_p
(
@shared
.
export_path
)
File
.
write
(
full_path
,
project_json_tree
)
true
...
...
lib/gitlab/import_export/relation_factory.rb
View file @
e646439e
...
...
@@ -13,6 +13,8 @@ module Gitlab
USER_REFERENCES
=
%w[author_id assignee_id updated_by_id user_id]
.
freeze
PROJECT_REFERENCES
=
%w[project_id source_project_id gl_project_id target_project_id]
.
freeze
BUILD_MODELS
=
%w[Ci::Build commit_status]
.
freeze
IMPORTED_OBJECT_MAX_RETRIES
=
5
.
freeze
...
...
@@ -25,9 +27,9 @@ module Gitlab
new
(
*
args
).
create
end
def
initialize
(
relation_sym
:,
relation_hash
:,
members_mapper
:,
user
:)
def
initialize
(
relation_sym
:,
relation_hash
:,
members_mapper
:,
user
:
,
project_id
:
)
@relation_name
=
OVERRIDES
[
relation_sym
]
||
relation_sym
@relation_hash
=
relation_hash
.
except
(
'id'
,
'noteable_id'
)
@relation_hash
=
relation_hash
.
except
(
'id'
,
'noteable_id'
)
.
merge
(
'project_id'
=>
project_id
)
@members_mapper
=
members_mapper
@user
=
user
@imported_object_retries
=
0
...
...
@@ -153,7 +155,11 @@ module Gitlab
end
def
parsed_relation_hash
@parsed_relation_hash
||=
@relation_hash
.
reject
{
|
k
,
_v
|
!
relation_class
.
attribute_method?
(
k
)
}
@parsed_relation_hash
||=
begin
Gitlab
::
ImportExport
::
AttributeCleaner
.
clean!
(
relation_hash:
@relation_hash
)
@relation_hash
.
reject
{
|
k
,
_v
|
!
relation_class
.
attribute_method?
(
k
)
}
end
end
def
set_st_diffs
...
...
lib/gitlab/import_export/repo_restorer.rb
View file @
e646439e
...
...
@@ -12,7 +12,7 @@ module Gitlab
def
restore
return
true
unless
File
.
exist?
(
@path_to_bundle
)
FileUtils
.
mkdir_p
(
path_to_repo
)
mkdir_p
(
path_to_repo
)
git_unbundle
(
repo_path:
path_to_repo
,
bundle_path:
@path_to_bundle
)
&&
repo_restore_hooks
rescue
=>
e
...
...
lib/gitlab/import_export/repo_saver.rb
View file @
e646439e
...
...
@@ -20,7 +20,7 @@ module Gitlab
private
def
bundle_to_disk
FileUtils
.
mkdir_p
(
@shared
.
export_path
)
mkdir_p
(
@shared
.
export_path
)
git_bundle
(
repo_path:
path_to_repo
,
bundle_path:
@full_path
)
rescue
=>
e
@shared
.
error
(
e
)
...
...
lib/gitlab/import_export/version_saver.rb
View file @
e646439e
module
Gitlab
module
ImportExport
class
VersionSaver
include
Gitlab
::
ImportExport
::
CommandLineUtil
def
initialize
(
shared
:)
@shared
=
shared
end
def
save
FileUtils
.
mkdir_p
(
@shared
.
export_path
)
mkdir_p
(
@shared
.
export_path
)
File
.
write
(
version_file
,
Gitlab
::
ImportExport
.
version
,
mode:
'w'
)
rescue
=>
e
...
...
lib/gitlab/import_export/wiki_repo_saver.rb
View file @
e646439e
...
...
@@ -9,7 +9,7 @@ module Gitlab
end
def
bundle_to_disk
(
full_path
)
FileUtils
.
mkdir_p
(
@shared
.
export_path
)
mkdir_p
(
@shared
.
export_path
)
git_bundle
(
repo_path:
path_to_repo
,
bundle_path:
full_path
)
rescue
=>
e
@shared
.
error
(
e
)
...
...
lib/gitlab/lfs_token.rb
View file @
e646439e
...
...
@@ -20,13 +20,8 @@ module Gitlab
def
token
Gitlab
::
Redis
.
with
do
|
redis
|
token
=
redis
.
get
(
redis_key
)
if
token
redis
.
expire
(
redis_key
,
EXPIRY_TIME
)
else
token
=
Devise
.
friendly_token
(
TOKEN_LENGTH
)
token
||=
Devise
.
friendly_token
(
TOKEN_LENGTH
)
redis
.
set
(
redis_key
,
token
,
ex:
EXPIRY_TIME
)
end
token
end
...
...
spec/controllers/sessions_controller_spec.rb
View file @
e646439e
...
...
@@ -109,6 +109,44 @@ describe SessionsController do
end
end
context
'when the user is on their last attempt'
do
before
do
user
.
update
(
failed_attempts:
User
.
maximum_attempts
.
pred
)
end
context
'when OTP is valid'
do
it
'authenticates correctly'
do
authenticate_2fa
(
otp_attempt:
user
.
current_otp
)
expect
(
subject
.
current_user
).
to
eq
user
end
end
context
'when OTP is invalid'
do
before
{
authenticate_2fa
(
otp_attempt:
'invalid'
)
}
it
'does not authenticate'
do
expect
(
subject
.
current_user
).
not_to
eq
user
end
it
'warns about invalid login'
do
expect
(
response
).
to
set_flash
.
now
[
:alert
]
.
to
/Invalid Login or password/
end
it
'locks the user'
do
expect
(
user
.
reload
).
to
be_access_locked
end
it
'keeps the user locked on future login attempts'
do
post
(
:create
,
user:
{
login:
user
.
username
,
password:
user
.
password
})
expect
(
response
)
.
to
set_flash
.
now
[
:alert
].
to
/Invalid Login or password/
end
end
end
context
'when another user does not have 2FA enabled'
do
let
(
:another_user
)
{
create
(
:user
)
}
...
...
spec/features/compare_spec.rb
View file @
e646439e
...
...
@@ -12,15 +12,16 @@ describe "Compare", js: true do
describe
"branches"
do
it
"pre-populates fields"
do
expect
(
page
.
find_field
(
"from"
).
value
).
to
eq
(
"master"
)
expect
(
find
(
".js-compare-from-dropdown .dropdown-toggle-text"
)).
to
have_content
(
"master"
)
expect
(
find
(
".js-compare-to-dropdown .dropdown-toggle-text"
)).
to
have_content
(
"master"
)
end
it
"compares branches"
do
fill_in
"from"
,
with:
"fea
"
find
(
"#from"
).
click
select_using_dropdown
"from"
,
"feature
"
expect
(
find
(
".js-compare-from-dropdown .dropdown-toggle-text"
)).
to
have_content
(
"feature"
)
click_link
"feature
"
expect
(
page
.
find_field
(
"from"
).
value
).
to
eq
(
"feature
"
)
select_using_dropdown
"to"
,
"binary-encoding
"
expect
(
find
(
".js-compare-to-dropdown .dropdown-toggle-text"
)).
to
have_content
(
"binary-encoding
"
)
click_button
"Compare"
expect
(
page
).
to
have_content
"Commits"
...
...
@@ -29,14 +30,21 @@ describe "Compare", js: true do
describe
"tags"
do
it
"compares tags"
do
fill_in
"from"
,
with:
"v1
.0"
find
(
"#from"
).
click
select_using_dropdown
"from"
,
"v1.0
.0"
expect
(
find
(
".js-compare-from-dropdown .dropdown-toggle-text"
)).
to
have_content
(
"v1.0.0"
)
click_link
"v1.0
.0"
expect
(
page
.
find_field
(
"from"
).
value
).
to
eq
(
"v1.0
.0"
)
select_using_dropdown
"to"
,
"v1.1
.0"
expect
(
find
(
".js-compare-to-dropdown .dropdown-toggle-text"
)).
to
have_content
(
"v1.1
.0"
)
click_button
"Compare"
expect
(
page
).
to
have_content
"Commits"
end
end
def
select_using_dropdown
(
dropdown_type
,
selection
)
dropdown
=
find
(
".js-compare-
#{
dropdown_type
}
-dropdown"
)
dropdown
.
find
(
".compare-dropdown-toggle"
).
click
dropdown
.
fill_in
(
"Filter by branch/tag"
,
with:
selection
)
click_link
selection
end
end
spec/features/projects/import_export/export_file_spec.rb
View file @
e646439e
...
...
@@ -47,6 +47,8 @@ feature 'Import/Export - project export integration test', feature: true, js: tr
expect
(
page
).
to
have_content
(
'Download export'
)
expect
(
file_permissions
(
project
.
export_path
)).
to
eq
(
0700
)
in_directory_with_expanded_export
(
project
)
do
|
exit_status
,
tmpdir
|
expect
(
exit_status
).
to
eq
(
0
)
...
...
spec/lib/gitlab/github_import/project_creator_spec.rb
View file @
e646439e
...
...
@@ -33,7 +33,7 @@ describe Gitlab::GithubImport::ProjectCreator, lib: true do
expect
(
project
.
import_data
.
credentials
).
to
eq
(
user:
'asdffg'
,
password:
nil
)
end
context
'when Git
h
ub project is private'
do
context
'when Git
H
ub project is private'
do
it
'sets project visibility to private'
do
repo
.
private
=
true
...
...
@@ -43,7 +43,7 @@ describe Gitlab::GithubImport::ProjectCreator, lib: true do
end
end
context
'when Git
h
ub project is public'
do
context
'when Git
H
ub project is public'
do
before
do
allow_any_instance_of
(
ApplicationSetting
).
to
receive
(
:default_project_visibility
).
and_return
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
...
...
@@ -56,5 +56,25 @@ describe Gitlab::GithubImport::ProjectCreator, lib: true do
expect
(
project
.
visibility_level
).
to
eq
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
end
context
'when GitHub project has wiki'
do
it
'does not create the wiki repository'
do
allow
(
repo
).
to
receive
(
:has_wiki?
).
and_return
(
true
)
project
=
service
.
execute
expect
(
project
.
wiki
.
repository_exists?
).
to
eq
false
end
end
context
'when GitHub project does not have wiki'
do
it
'creates the wiki repository'
do
allow
(
repo
).
to
receive
(
:has_wiki?
).
and_return
(
false
)
project
=
service
.
execute
expect
(
project
.
wiki
.
repository_exists?
).
to
eq
true
end
end
end
end
spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
0 → 100644
View file @
e646439e
require
'spec_helper'
describe
Gitlab
::
ImportExport
::
AttributeCleaner
,
lib:
true
do
let
(
:unsafe_hash
)
do
{
'service_id'
=>
99
,
'moved_to_id'
=>
99
,
'namespace_id'
=>
99
,
'ci_id'
=>
99
,
'random_project_id'
=>
99
,
'random_id'
=>
99
,
'milestone_id'
=>
99
,
'project_id'
=>
99
,
'user_id'
=>
99
,
'random_id_in_the_middle'
=>
99
,
'notid'
=>
99
}
end
let
(
:post_safe_hash
)
do
{
'project_id'
=>
99
,
'user_id'
=>
99
,
'random_id_in_the_middle'
=>
99
,
'notid'
=>
99
}
end
it
'removes unwanted attributes from the hash'
do
described_class
.
clean!
(
relation_hash:
unsafe_hash
)
expect
(
unsafe_hash
).
to
eq
(
post_safe_hash
)
end
end
spec/lib/gitlab/import_export/relation_factory_spec.rb
0 → 100644
View file @
e646439e
require
'spec_helper'
describe
Gitlab
::
ImportExport
::
RelationFactory
,
lib:
true
do
let
(
:project
)
{
create
(
:empty_project
)
}
let
(
:members_mapper
)
{
double
(
'members_mapper'
).
as_null_object
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:created_object
)
do
described_class
.
create
(
relation_sym:
relation_sym
,
relation_hash:
relation_hash
,
members_mapper:
members_mapper
,
user:
user
,
project_id:
project
.
id
)
end
context
'hook object'
do
let
(
:relation_sym
)
{
:hooks
}
let
(
:id
)
{
999
}
let
(
:service_id
)
{
99
}
let
(
:original_project_id
)
{
8
}
let
(
:token
)
{
'secret'
}
let
(
:relation_hash
)
do
{
'id'
=>
id
,
'url'
=>
'https://example.json'
,
'project_id'
=>
original_project_id
,
'created_at'
=>
'2016-08-12T09:41:03.462Z'
,
'updated_at'
=>
'2016-08-12T09:41:03.462Z'
,
'service_id'
=>
service_id
,
'push_events'
=>
true
,
'issues_events'
=>
false
,
'merge_requests_events'
=>
true
,
'tag_push_events'
=>
false
,
'note_events'
=>
true
,
'enable_ssl_verification'
=>
true
,
'build_events'
=>
false
,
'wiki_page_events'
=>
true
,
'token'
=>
token
}
end
it
'does not have the original ID'
do
expect
(
created_object
.
id
).
not_to
eq
(
id
)
end
it
'does not have the original service_id'
do
expect
(
created_object
.
service_id
).
not_to
eq
(
service_id
)
end
it
'does not have the original project_id'
do
expect
(
created_object
.
project_id
).
not_to
eq
(
original_project_id
)
end
it
'has the new project_id'
do
expect
(
created_object
.
project_id
).
to
eq
(
project
.
id
)
end
it
'has a token'
do
expect
(
created_object
.
token
).
to
eq
(
token
)
end
context
'original service exists'
do
let
(
:service_id
)
{
Service
.
create
(
project:
project
).
id
}
it
'does not have the original service_id'
do
expect
(
created_object
.
service_id
).
not_to
eq
(
service_id
)
end
end
end
# Mocks an ActiveRecordish object with the dodgy columns
class
FooModel
include
ActiveModel
::
Model
def
initialize
(
params
)
params
.
each
{
|
key
,
value
|
send
(
"
#{
key
}
="
,
value
)
}
end
def
values
instance_variables
.
map
{
|
ivar
|
instance_variable_get
(
ivar
)
}
end
end
# `project_id`, `described_class.USER_REFERENCES`, noteable_id, target_id, and some project IDs are already
# re-assigned by described_class.
context
'Potentially hazardous foreign keys'
do
let
(
:relation_sym
)
{
:hazardous_foo_model
}
let
(
:relation_hash
)
do
{
'service_id'
=>
99
,
'moved_to_id'
=>
99
,
'namespace_id'
=>
99
,
'ci_id'
=>
99
,
'random_project_id'
=>
99
,
'random_id'
=>
99
,
'milestone_id'
=>
99
,
'project_id'
=>
99
,
'user_id'
=>
99
,
}
end
class
HazardousFooModel
<
FooModel
attr_accessor
:service_id
,
:moved_to_id
,
:namespace_id
,
:ci_id
,
:random_project_id
,
:random_id
,
:milestone_id
,
:project_id
end
it
'does not preserve any foreign key IDs'
do
expect
(
created_object
.
values
).
not_to
include
(
99
)
end
end
context
'Project references'
do
let
(
:relation_sym
)
{
:project_foo_model
}
let
(
:relation_hash
)
do
Gitlab
::
ImportExport
::
RelationFactory
::
PROJECT_REFERENCES
.
map
{
|
ref
|
{
ref
=>
99
}
}.
inject
(
:merge
)
end
class
ProjectFooModel
<
FooModel
attr_accessor
(
*
Gitlab
::
ImportExport
::
RelationFactory
::
PROJECT_REFERENCES
)
end
it
'does not preserve any project foreign key IDs'
do
expect
(
created_object
.
values
).
not_to
include
(
99
)
end
end
end
spec/models/merge_request_spec.rb
View file @
e646439e
...
...
@@ -86,6 +86,30 @@ describe MergeRequest, models: true do
end
end
describe
'#cache_merge_request_closes_issues!'
do
before
do
subject
.
project
.
team
<<
[
subject
.
author
,
:developer
]
subject
.
target_branch
=
subject
.
project
.
default_branch
end
it
'caches closed issues'
do
issue
=
create
:issue
,
project:
subject
.
project
commit
=
double
(
'commit1'
,
safe_message:
"Fixes
#{
issue
.
to_reference
}
"
)
allow
(
subject
).
to
receive
(
:commits
).
and_return
([
commit
])
expect
{
subject
.
cache_merge_request_closes_issues!
}.
to
change
(
subject
.
merge_requests_closing_issues
,
:count
).
by
(
1
)
end
it
'does not cache issues from external trackers'
do
subject
.
project
.
update_attribute
(
:has_external_issue_tracker
,
true
)
issue
=
ExternalIssue
.
new
(
'JIRA-123'
,
subject
.
project
)
commit
=
double
(
'commit1'
,
safe_message:
"Fixes
#{
issue
.
to_reference
}
"
)
allow
(
subject
).
to
receive
(
:commits
).
and_return
([
commit
])
expect
{
subject
.
cache_merge_request_closes_issues!
}.
not_to
change
(
subject
.
merge_requests_closing_issues
,
:count
)
end
end
describe
'#source_branch_sha'
do
let
(
:last_branch_commit
)
{
subject
.
source_project
.
repository
.
commit
(
subject
.
source_branch
)
}
...
...
spec/models/service_spec.rb
View file @
e646439e
...
...
@@ -203,6 +203,23 @@ describe Service, models: true do
end
end
describe
'initialize service with no properties'
do
let
(
:service
)
do
GitlabIssueTrackerService
.
create
(
project:
create
(
:project
),
title:
'random title'
)
end
it
'does not raise error'
do
expect
{
service
}.
not_to
raise_error
end
it
'creates the properties'
do
expect
(
service
.
properties
).
to
eq
({
"title"
=>
"random title"
})
end
end
describe
"callbacks"
do
let
(
:project
)
{
create
(
:project
)
}
let!
(
:service
)
do
...
...
spec/services/merge_requests/merge_service_spec.rb
View file @
e646439e
...
...
@@ -38,6 +38,42 @@ describe MergeRequests::MergeService, services: true do
end
end
context
'closes related issues'
do
let
(
:service
)
{
described_class
.
new
(
project
,
user
,
commit_message:
'Awesome message'
)
}
before
do
allow
(
project
).
to
receive
(
:default_branch
).
and_return
(
merge_request
.
target_branch
)
end
it
'closes GitLab issue tracker issues'
do
issue
=
create
:issue
,
project:
project
commit
=
double
(
'commit'
,
safe_message:
"Fixes
#{
issue
.
to_reference
}
"
)
allow
(
merge_request
).
to
receive
(
:commits
).
and_return
([
commit
])
service
.
execute
(
merge_request
)
expect
(
issue
.
reload
.
closed?
).
to
be_truthy
end
context
'with JIRA integration'
do
include
JiraServiceHelper
let
(
:jira_tracker
)
{
project
.
create_jira_service
}
before
{
jira_service_settings
}
it
'closes issues on JIRA issue tracker'
do
jira_issue
=
ExternalIssue
.
new
(
'JIRA-123'
,
project
)
commit
=
double
(
'commit'
,
safe_message:
"Fixes
#{
jira_issue
.
to_reference
}
"
)
allow
(
merge_request
).
to
receive
(
:commits
).
and_return
([
commit
])
expect_any_instance_of
(
JiraService
).
to
receive
(
:close_issue
).
with
(
merge_request
,
jira_issue
).
once
service
.
execute
(
merge_request
)
end
end
end
context
'remove source branch by author'
do
let
(
:service
)
do
merge_request
.
merge_params
[
'force_remove_source_branch'
]
=
'1'
...
...
spec/services/projects/destroy_service_spec.rb
View file @
e646439e
...
...
@@ -5,6 +5,7 @@ describe Projects::DestroyService, services: true do
let!
(
:project
)
{
create
(
:project
,
namespace:
user
.
namespace
)
}
let!
(
:path
)
{
project
.
repository
.
path_to_repo
}
let!
(
:remove_path
)
{
path
.
sub
(
/\.git\Z/
,
"+
#{
project
.
id
}
+deleted.git"
)
}
let!
(
:async
)
{
false
}
# execute or async_execute
context
'Sidekiq inline'
do
before
do
...
...
@@ -28,6 +29,22 @@ describe Projects::DestroyService, services: true do
it
{
expect
(
Dir
.
exist?
(
remove_path
)).
to
be_truthy
}
end
context
'async delete of project with private issue visibility'
do
let!
(
:async
)
{
true
}
before
do
project
.
project_feature
.
update_attribute
(
"issues_access_level"
,
ProjectFeature
::
PRIVATE
)
# Run sidekiq immediately to check that renamed repository will be removed
Sidekiq
::
Testing
.
inline!
{
destroy_project
(
project
,
user
,
{})
}
end
it
'deletes the project'
do
expect
(
Project
.
all
).
not_to
include
(
project
)
expect
(
Dir
.
exist?
(
path
)).
to
be_falsey
expect
(
Dir
.
exist?
(
remove_path
)).
to
be_falsey
end
end
context
'container registry'
do
before
do
stub_container_registry_config
(
enabled:
true
)
...
...
@@ -52,6 +69,10 @@ describe Projects::DestroyService, services: true do
end
def
destroy_project
(
project
,
user
,
params
)
if
async
Projects
::
DestroyService
.
new
(
project
,
user
,
params
).
async_execute
else
Projects
::
DestroyService
.
new
(
project
,
user
,
params
).
execute
end
end
end
spec/support/import_export/export_file_helper.rb
View file @
e646439e
...
...
@@ -130,4 +130,8 @@ module ExportFileHelper
(
parsed_model_attributes
-
parent
.
keys
-
excluded_attributes
).
empty?
end
def
file_permissions
(
file
)
File
.
stat
(
file
).
mode
&
0777
end
end
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