Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
heptapod
heptapod
Commits
a6d7a24b051f
Commit
91e530df
authored
Oct 06, 2017
by
Shinya Maeda
Browse files
Merge branch 'master' into feature/sm/35954-create-kubernetes-cluster-on-gke-from-k8s-service
parents
a9e01b51a036
c655a1130acb
Changes
56
Hide whitespace changes
Inline
Side-by-side
app/assets/javascripts/build_artifacts.js
View file @
a6d7a24b
/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-unused-vars, no-return-assign, max-len */
import
{
visitUrl
}
from
'
./lib/utils/url_utility
'
;
import
{
convertPermissionToBoolean
}
from
'
./lib/utils/common_utils
'
;
window
.
BuildArtifacts
=
(
function
()
{
function
BuildArtifacts
()
{
this
.
disablePropagation
();
this
.
setupEntryClick
();
this
.
setupTooltips
();
}
BuildArtifacts
.
prototype
.
disablePropagation
=
function
()
{
...
...
@@ -17,9 +20,28 @@ window.BuildArtifacts = (function() {
BuildArtifacts
.
prototype
.
setupEntryClick
=
function
()
{
return
$
(
'
.tree-holder
'
).
on
(
'
click
'
,
'
tr[data-link]
'
,
function
(
e
)
{
return
window
.
location
=
this
.
dataset
.
l
ink
;
visitUrl
(
this
.
dataset
.
link
,
convertPermissionToBoolean
(
this
.
dataset
.
externalL
ink
))
;
});
};
BuildArtifacts
.
prototype
.
setupTooltips
=
function
()
{
$
(
'
.js-artifact-tree-tooltip
'
).
tooltip
({
placement
:
'
bottom
'
,
// Stop the tooltip from hiding when we stop hovering the element directly
// We handle all the showing/hiding below
trigger
:
'
manual
'
,
});
// We want the tooltip to show if you hover anywhere on the row
// But be placed below and in the middle of the file name
$
(
'
.js-artifact-tree-row
'
)
.
on
(
'
mouseenter
'
,
(
e
)
=>
{
$
(
e
.
currentTarget
).
find
(
'
.js-artifact-tree-tooltip
'
).
tooltip
(
'
show
'
);
})
.
on
(
'
mouseleave
'
,
(
e
)
=>
{
$
(
e
.
currentTarget
).
find
(
'
.js-artifact-tree-tooltip
'
).
tooltip
(
'
hide
'
);
});
};
return
BuildArtifacts
;
})();
app/assets/javascripts/gl_dropdown.js
View file @
a6d7a24b
...
...
@@ -738,7 +738,7 @@ GitLabDropdown = (function() {
:
selectedObject
.
id
;
if
(
isInput
)
{
field
=
$
(
this
.
el
);
}
else
if
(
value
)
{
}
else
if
(
value
!=
null
)
{
field
=
this
.
dropdown
.
parent
().
find
(
"
input[name='
"
+
fieldName
+
"
'][value='
"
+
value
.
toString
().
replace
(
/'/g
,
'
\\\'
'
)
+
"
']
"
);
}
...
...
@@ -746,7 +746,7 @@ GitLabDropdown = (function() {
return
;
}
if
(
el
.
hasClass
(
ACTIVE_CLASS
))
{
if
(
el
.
hasClass
(
ACTIVE_CLASS
)
&&
value
!==
0
)
{
isMarking
=
false
;
el
.
removeClass
(
ACTIVE_CLASS
);
if
(
field
&&
field
.
length
)
{
...
...
@@ -852,7 +852,7 @@ GitLabDropdown = (function() {
if
(
href
&&
href
!==
'
#
'
)
{
gl
.
utils
.
visitUrl
(
href
);
}
else
{
$el
.
first
().
trigger
(
'
click
'
);
$el
.
trigger
(
'
click
'
);
}
}
};
...
...
app/assets/javascripts/lib/utils/url_utility.js
View file @
a6d7a24b
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, one-var, one-var-declaration-per-line, no-void, guard-for-in, no-restricted-syntax, prefer-template, quotes, max-len */
var
base
;
var
w
=
window
;
if
(
w
.
gl
==
null
)
{
...
...
@@ -86,6 +87,21 @@ w.gl.utils.getLocationHash = function(url) {
w
.
gl
.
utils
.
refreshCurrentPage
=
()
=>
gl
.
utils
.
visitUrl
(
document
.
location
.
href
);
w
.
gl
.
utils
.
visitUrl
=
(
url
)
=>
{
document
.
location
.
href
=
url
;
// eslint-disable-next-line import/prefer-default-export
export
function
visitUrl
(
url
,
external
=
false
)
{
if
(
external
)
{
// Simulate `target="blank" rel="noopener noreferrer"`
// See https://mathiasbynens.github.io/rel-noopener/
const
otherWindow
=
window
.
open
();
otherWindow
.
opener
=
null
;
otherWindow
.
location
=
url
;
}
else
{
document
.
location
.
href
=
url
;
}
}
window
.
gl
=
window
.
gl
||
{};
window
.
gl
.
utils
=
{
...(
window
.
gl
.
utils
||
{}),
visitUrl
,
};
app/assets/javascripts/protected_branches/protected_branch_create.js
View file @
a6d7a24b
import
_
from
'
underscore
'
;
import
ProtectedBranchAccessDropdown
from
'
./protected_branch_access_dropdown
'
;
import
ProtectedBranchDropdown
from
'
./protected_branch_dropdown
'
;
import
AccessorUtilities
from
'
../lib/utils/accessor
'
;
const
PB_LOCAL_STORAGE_KEY
=
'
protected-branches-defaults
'
;
export
default
class
ProtectedBranchCreate
{
constructor
()
{
this
.
$form
=
$
(
'
.js-new-protected-branch
'
);
this
.
isLocalStorageAvailable
=
AccessorUtilities
.
isLocalStorageAccessSafe
();
this
.
currentProjectUserDefaults
=
{};
this
.
buildDropdowns
();
}
buildDropdowns
()
{
const
$allowedToMergeDropdown
=
this
.
$form
.
find
(
'
.js-allowed-to-merge
'
);
const
$allowedToPushDropdown
=
this
.
$form
.
find
(
'
.js-allowed-to-push
'
);
const
$protectedBranchDropdown
=
this
.
$form
.
find
(
'
.js-protected-branch-select
'
);
// Cache callback
this
.
onSelectCallback
=
this
.
onSelect
.
bind
(
this
);
...
...
@@ -28,15 +35,13 @@ export default class ProtectedBranchCreate {
onSelect
:
this
.
onSelectCallback
,
});
// Select default
$allowedToPushDropdown
.
data
(
'
glDropdown
'
).
selectRowAtIndex
(
0
);
$allowedToMergeDropdown
.
data
(
'
glDropdown
'
).
selectRowAtIndex
(
0
);
// Protected branch dropdown
this
.
protectedBranchDropdown
=
new
ProtectedBranchDropdown
({
$dropdown
:
this
.
$form
.
find
(
'
.js-
protected
-b
ranch
-select
'
)
,
$dropdown
:
$
protected
B
ranch
Dropdown
,
onSelect
:
this
.
onSelectCallback
,
});
this
.
loadPreviousSelection
(
$allowedToMergeDropdown
.
data
(
'
glDropdown
'
),
$allowedToPushDropdown
.
data
(
'
glDropdown
'
));
}
// This will run after clicked callback
...
...
@@ -45,7 +50,41 @@ export default class ProtectedBranchCreate {
const
$branchInput
=
this
.
$form
.
find
(
'
input[name="protected_branch[name]"]
'
);
const
$allowedToMergeInput
=
this
.
$form
.
find
(
'
input[name="protected_branch[merge_access_levels_attributes][0][access_level]"]
'
);
const
$allowedToPushInput
=
this
.
$form
.
find
(
'
input[name="protected_branch[push_access_levels_attributes][0][access_level]"]
'
);
const
completedForm
=
!
(
$branchInput
.
val
()
&&
$allowedToMergeInput
.
length
&&
$allowedToPushInput
.
length
);
this
.
savePreviousSelection
(
$allowedToMergeInput
.
val
(),
$allowedToPushInput
.
val
());
this
.
$form
.
find
(
'
input[type="submit"]
'
).
attr
(
'
disabled
'
,
completedForm
);
}
loadPreviousSelection
(
mergeDropdown
,
pushDropdown
)
{
let
mergeIndex
=
0
;
let
pushIndex
=
0
;
if
(
this
.
isLocalStorageAvailable
)
{
const
savedDefaults
=
JSON
.
parse
(
window
.
localStorage
.
getItem
(
PB_LOCAL_STORAGE_KEY
));
if
(
savedDefaults
!=
null
)
{
mergeIndex
=
_
.
findLastIndex
(
mergeDropdown
.
fullData
.
roles
,
{
id
:
parseInt
(
savedDefaults
.
mergeSelection
,
0
),
});
pushIndex
=
_
.
findLastIndex
(
pushDropdown
.
fullData
.
roles
,
{
id
:
parseInt
(
savedDefaults
.
pushSelection
,
0
),
});
}
}
mergeDropdown
.
selectRowAtIndex
(
mergeIndex
);
pushDropdown
.
selectRowAtIndex
(
pushIndex
);
}
this
.
$form
.
find
(
'
input[type="submit"]
'
).
attr
(
'
disabled
'
,
!
(
$branchInput
.
val
()
&&
$allowedToMergeInput
.
length
&&
$allowedToPushInput
.
length
));
savePreviousSelection
(
mergeSelection
,
pushSelection
)
{
if
(
this
.
isLocalStorageAvailable
)
{
const
branchDefaults
=
{
mergeSelection
,
pushSelection
,
};
window
.
localStorage
.
setItem
(
PB_LOCAL_STORAGE_KEY
,
JSON
.
stringify
(
branchDefaults
));
}
}
}
app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
View file @
a6d7a24b
...
...
@@ -67,7 +67,7 @@ export default {
return
defaultClass
;
},
iconClass
()
{
if
(
this
.
status
===
'
failed
'
||
!
this
.
commitMessage
.
length
||
!
this
.
isMergeAllowed
()
||
this
.
mr
.
preventMerge
)
{
if
(
this
.
status
===
'
failed
'
||
!
this
.
commitMessage
.
length
||
!
this
.
mr
.
isMergeAllowed
||
this
.
mr
.
preventMerge
)
{
return
'
failed
'
;
}
return
'
success
'
;
...
...
@@ -100,13 +100,8 @@ export default {
},
},
methods
:
{
isMergeAllowed
()
{
return
!
this
.
mr
.
onlyAllowMergeIfPipelineSucceeds
||
this
.
mr
.
isPipelinePassing
||
this
.
mr
.
isPipelineSkipped
;
},
shouldShowMergeControls
()
{
return
this
.
isMergeAllowed
()
||
this
.
shouldShowMergeWhenPipelineSucceedsText
;
return
this
.
mr
.
isMergeAllowed
||
this
.
shouldShowMergeWhenPipelineSucceedsText
;
},
updateCommitMessage
()
{
const
cmwd
=
this
.
mr
.
commitMessageWithDescription
;
...
...
app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
View file @
a6d7a24b
...
...
@@ -73,6 +73,7 @@ export default class MergeRequestStore {
this
.
canCancelAutomaticMerge
=
!!
data
.
cancel_merge_when_pipeline_succeeds_path
;
this
.
hasSHAChanged
=
this
.
sha
!==
data
.
diff_head_sha
;
this
.
canBeMerged
=
data
.
can_be_merged
||
false
;
this
.
isMergeAllowed
=
data
.
mergeable
||
false
;
this
.
mergeOngoing
=
data
.
merge_ongoing
;
// Cherry-pick and Revert actions related
...
...
app/assets/stylesheets/pages/tree.scss
View file @
a6d7a24b
...
...
@@ -169,6 +169,14 @@
}
}
.tree-item-file-external-link
{
margin-right
:
4px
;
span
{
text-decoration
:
inherit
;
}
}
.tree_commit
{
max-width
:
320px
;
...
...
app/controllers/dashboard/todos_controller.rb
View file @
a6d7a24b
...
...
@@ -7,9 +7,8 @@ class Dashboard::TodosController < Dashboard::ApplicationController
def
index
@sort
=
params
[
:sort
]
@todos
=
@todos
.
page
(
params
[
:page
])
if
@todos
.
out_of_range?
&&
@todos
.
total_pages
!=
0
redirect_to
url_for
(
params
.
merge
(
page:
@todos
.
total_pages
,
only_path:
true
))
end
return
if
redirect_out_of_range
(
@todos
)
end
def
destroy
...
...
@@ -60,7 +59,7 @@ def authorize_read_project!
end
def
find_todos
@todos
||=
TodosFinder
.
new
(
current_user
,
params
).
execute
@todos
||=
TodosFinder
.
new
(
current_user
,
todo_
params
).
execute
end
def
todos_counts
...
...
@@ -69,4 +68,27 @@ def todos_counts
done_count:
number_with_delimiter
(
current_user
.
todos_done_count
)
}
end
def
todo_params
params
.
permit
(
:action_id
,
:author_id
,
:project_id
,
:type
,
:sort
,
:state
)
end
def
redirect_out_of_range
(
todos
)
total_pages
=
if
todo_params
.
except
(
:sort
,
:page
).
empty?
(
current_user
.
todos_pending_count
/
todos
.
limit_value
).
ceil
else
todos
.
total_pages
end
return
false
if
total_pages
.
zero?
out_of_range
=
todos
.
current_page
>
total_pages
if
out_of_range
redirect_to
url_for
(
params
.
merge
(
page:
total_pages
,
only_path:
true
))
end
out_of_range
end
end
app/controllers/projects/artifacts_controller.rb
View file @
a6d7a24b
...
...
@@ -29,13 +29,17 @@ def file
blob
=
@entry
.
blob
conditionally_expand_blob
(
blob
)
respond_to
do
|
format
|
format
.
html
do
render
'file'
end
format
.
json
do
render_blob_json
(
blob
)
if
blob
.
external_link?
(
build
)
redirect_to
blob
.
external_url
(
@project
,
build
)
else
respond_to
do
|
format
|
format
.
html
do
render
'file'
end
format
.
json
do
render_blob_json
(
blob
)
end
end
end
end
...
...
app/controllers/sessions_controller.rb
View file @
a6d7a24b
...
...
@@ -13,7 +13,7 @@ class SessionsController < Devise::SessionsController
before_action
:auto_sign_in_with_provider
,
only:
[
:new
]
before_action
:load_recaptcha
after_action
:log_failed_login
,
only:
[
:new
]
after_action
:log_failed_login
,
only:
[
:new
]
,
if: :failed_login?
def
new
set_minimum_password_length
...
...
@@ -46,8 +46,6 @@ def destroy
private
def
log_failed_login
return
unless
failed_login?
Gitlab
::
AppLogger
.
info
(
"Failed Login: username=
#{
user_params
[
:login
]
}
ip=
#{
request
.
remote_ip
}
"
)
end
...
...
app/models/ci/artifact_blob.rb
View file @
a6d7a24b
...
...
@@ -2,6 +2,8 @@ module Ci
class
ArtifactBlob
include
BlobLike
EXTENTIONS_SERVED_BY_PAGES
=
%w[.html .htm .txt .json]
.
freeze
attr_reader
:entry
def
initialize
(
entry
)
...
...
@@ -17,6 +19,7 @@ def id
def
size
entry
.
metadata
[
:size
]
end
alias_method
:external_size
,
:size
def
data
"Build artifact
#{
path
}
"
...
...
@@ -30,6 +33,27 @@ def external_storage
:build_artifact
end
alias_method
:external_size
,
:size
def
external_url
(
project
,
job
)
return
unless
external_link?
(
job
)
components
=
project
.
full_path_components
components
<<
"-/jobs/
#{
job
.
id
}
/artifacts/file/
#{
path
}
"
artifact_path
=
components
[
1
..-
1
].
join
(
'/'
)
"
#{
pages_config
.
protocol
}
://
#{
components
[
0
]
}
.
#{
pages_config
.
host
}
/
#{
artifact_path
}
"
end
def
external_link?
(
job
)
pages_config
.
enabled
&&
pages_config
.
artifacts_server
&&
EXTENTIONS_SERVED_BY_PAGES
.
include?
(
File
.
extname
(
name
))
&&
job
.
project
.
public?
end
private
def
pages_config
Gitlab
.
config
.
pages
end
end
end
app/models/concerns/repository_mirroring.rb
View file @
a6d7a24b
module
RepositoryMirroring
def
set_remote_as_mirror
(
name
)
config
=
raw_repository
.
rugged
.
config
IMPORT_HEAD_REFS
=
'+refs/heads/*:refs/heads/*'
.
freeze
IMPORT_TAG_REFS
=
'+refs/tags/*:refs/tags/*'
.
freeze
def
set_remote_as_mirror
(
name
)
# This is used to define repository as equivalent as "git clone --mirror"
config
[
"remote.
#{
name
}
.fetch"
]
=
'refs/*:refs/*'
config
[
"remote.
#{
name
}
.mirror"
]
=
true
config
[
"remote.
#{
name
}
.prune"
]
=
true
raw_repository
.
rugged
.
config
[
"remote.
#{
name
}
.fetch"
]
=
'refs/*:refs/*'
raw_repository
.
rugged
.
config
[
"remote.
#{
name
}
.mirror"
]
=
true
raw_repository
.
rugged
.
config
[
"remote.
#{
name
}
.prune"
]
=
true
end
def
set_import_remote_as_mirror
(
remote_name
)
# Add first fetch with Rugged so it does not create its own.
raw_repository
.
rugged
.
config
[
"remote.
#{
remote_name
}
.fetch"
]
=
IMPORT_HEAD_REFS
add_remote_fetch_config
(
remote_name
,
IMPORT_TAG_REFS
)
raw_repository
.
rugged
.
config
[
"remote.
#{
remote_name
}
.mirror"
]
=
true
raw_repository
.
rugged
.
config
[
"remote.
#{
remote_name
}
.prune"
]
=
true
end
def
add_remote_fetch_config
(
remote_name
,
refspec
)
run_git
(
%W[config --add remote.
#{
remote_name
}
.fetch
#{
refspec
}
]
)
end
def
fetch_mirror
(
remote
,
url
)
...
...
app/models/concerns/routable.rb
View file @
a6d7a24b
...
...
@@ -106,6 +106,10 @@ def full_path
RequestStore
[
full_path_key
]
||=
uncached_full_path
end
def
full_path_components
full_path
.
split
(
'/'
)
end
def
expires_full_path_cache
RequestStore
.
delete
(
full_path_key
)
if
RequestStore
.
active?
@full_path
=
nil
...
...
app/models/merge_request.rb
View file @
a6d7a24b
...
...
@@ -415,6 +415,8 @@ def ensure_merge_request_diff
end
def
create_merge_request_diff
fetch_ref
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37435
Gitlab
::
GitalyClient
.
allow_n_plus_1_calls
do
merge_request_diffs
.
create
...
...
@@ -462,6 +464,7 @@ def reload_diff(current_user = nil)
return
unless
open
?
old_diff_refs
=
self
.
diff_refs
create_merge_request_diff
MergeRequests
::
MergeRequestDiffCacheService
.
new
.
execute
(
self
)
new_diff_refs
=
self
.
diff_refs
...
...
app/models/merge_request_diff.rb
View file @
a6d7a24b
...
...
@@ -55,7 +55,6 @@ def save_git_content
end
def
ensure_commit_shas
merge_request
.
fetch_ref
self
.
start_commit_sha
||=
merge_request
.
target_branch_sha
self
.
head_commit_sha
||=
merge_request
.
source_branch_sha
self
.
base_commit_sha
||=
find_base_sha
...
...
app/models/project.rb
View file @
a6d7a24b
...
...
@@ -1035,6 +1035,8 @@ def check_repository_path_availability
end
true
rescue
GRPC
::
Internal
# if the path is too long
false
end
def
create_repository
(
force:
false
)
...
...
app/serializers/merge_request_entity.rb
View file @
a6d7a24b
...
...
@@ -42,6 +42,7 @@ class MergeRequestEntity < IssuableEntity
expose
:commits_count
expose
:cannot_be_merged?
,
as: :has_conflicts
expose
:can_be_merged?
,
as: :can_be_merged
expose
:mergeable?
,
as: :mergeable
expose
:remove_source_branch?
,
as: :remove_source_branch
expose
:project_archived
do
|
merge_request
|
...
...
app/views/projects/artifacts/_tree_file.html.haml
View file @
a6d7a24b
-
blob
=
file
.
blob
-
path_to_file
=
file_project_job_artifacts_path
(
@project
,
@build
,
path:
file
.
path
)
-
external_link
=
blob
.
external_link?
(
@build
)
%tr
.tree-item
{
'data-link'
=>
path_to_file
}
-
blob
=
file
.
blob
%tr
.tree-item.js-artifact-tree-row
{
data:
{
link:
path_to_file
,
external_link:
"#{external_link}"
}
}
%td
.tree-item-file-name
=
tree_icon
(
'file'
,
blob
.
mode
,
blob
.
name
)
=
link_to
path_to_file
do
%span
.str-truncated
=
blob
.
name
-
if
external_link
=
link_to
path_to_file
,
class:
'tree-item-file-external-link js-artifact-tree-tooltip'
,
target:
'_blank'
,
rel:
'noopener noreferrer'
,
title:
_
(
'Opens in a new window'
)
do
%span
.str-truncated
>=
blob
.
name
=
icon
(
'external-link'
,
class:
'js-artifact-tree-external-icon'
)
-
else
=
link_to
path_to_file
do
%span
.str-truncated
=
blob
.
name
%td
=
number_to_human_size
(
blob
.
size
,
precision:
2
)
changelogs/unreleased/32163-protected-branch-form-should-have-sane-defaults-for-dropdowns.yml
0 → 100644
View file @
a6d7a24b
---
title
:
Added defaults for protected branches dropdowns on the repository settings
merge_request
:
14278
author
:
type
:
changed
changelogs/unreleased/34102-online-view-of-artifacts-fe.yml
0 → 100644
View file @
a6d7a24b
---
title
:
Add online view of HTML artifacts for public projects
merge_request
:
14399
author
:
type
:
added
Prev
1
2
3
Next
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