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
Jérome Perrin
gitlab-ce
Commits
4fac95a6
Commit
4fac95a6
authored
Nov 08, 2017
by
Shinya Maeda
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into 38464-k8s-apps
parents
02878cd9
396f45ad
Changes
66
Hide whitespace changes
Inline
Side-by-side
Showing
66 changed files
with
764 additions
and
440 deletions
+764
-440
app/assets/javascripts/repo/components/repo_file.vue
app/assets/javascripts/repo/components/repo_file.vue
+23
-3
app/assets/javascripts/repo/components/repo_loading_file.vue
app/assets/javascripts/repo/components/repo_loading_file.vue
+14
-27
app/assets/javascripts/repo/components/repo_sidebar.vue
app/assets/javascripts/repo/components/repo_sidebar.vue
+1
-1
app/assets/javascripts/repo/services/index.js
app/assets/javascripts/repo/services/index.js
+7
-0
app/assets/javascripts/repo/stores/actions.js
app/assets/javascripts/repo/stores/actions.js
+17
-1
app/assets/javascripts/repo/stores/actions/file.js
app/assets/javascripts/repo/stores/actions/file.js
+2
-0
app/assets/javascripts/repo/stores/actions/tree.js
app/assets/javascripts/repo/stores/actions/tree.js
+55
-3
app/assets/javascripts/repo/stores/mutation_types.js
app/assets/javascripts/repo/stores/mutation_types.js
+2
-0
app/assets/javascripts/repo/stores/mutations.js
app/assets/javascripts/repo/stores/mutations.js
+7
-0
app/assets/javascripts/repo/stores/mutations/tree.js
app/assets/javascripts/repo/stores/mutations/tree.js
+6
-24
app/assets/javascripts/repo/stores/state.js
app/assets/javascripts/repo/stores/state.js
+1
-0
app/assets/javascripts/repo/stores/utils.js
app/assets/javascripts/repo/stores/utils.js
+28
-9
app/assets/javascripts/smart_interval.js
app/assets/javascripts/smart_interval.js
+22
-7
app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
...javascripts/vue_merge_request_widget/mr_widget_options.js
+5
-4
app/assets/javascripts/vue_shared/components/skeleton_loading_container.vue
...ipts/vue_shared/components/skeleton_loading_container.vue
+37
-0
app/controllers/concerns/issuable_actions.rb
app/controllers/concerns/issuable_actions.rb
+1
-7
app/controllers/concerns/issuable_collections.rb
app/controllers/concerns/issuable_collections.rb
+50
-41
app/controllers/concerns/issues_action.rb
app/controllers/concerns/issues_action.rb
+4
-4
app/controllers/concerns/merge_requests_action.rb
app/controllers/concerns/merge_requests_action.rb
+4
-5
app/controllers/projects/issues_controller.rb
app/controllers/projects/issues_controller.rb
+7
-10
app/controllers/projects/merge_requests_controller.rb
app/controllers/projects/merge_requests_controller.rb
+8
-24
app/controllers/projects/refs_controller.rb
app/controllers/projects/refs_controller.rb
+9
-1
app/controllers/projects_controller.rb
app/controllers/projects_controller.rb
+2
-1
app/helpers/issuables_helper.rb
app/helpers/issuables_helper.rb
+0
-2
app/models/clusters/providers/gcp.rb
app/models/clusters/providers/gcp.rb
+1
-1
app/models/commit_status.rb
app/models/commit_status.rb
+11
-1
app/models/concerns/issuable.rb
app/models/concerns/issuable.rb
+2
-0
app/models/issue.rb
app/models/issue.rb
+0
-2
app/models/merge_request.rb
app/models/merge_request.rb
+0
-2
app/serializers/blob_entity.rb
app/serializers/blob_entity.rb
+0
-4
app/serializers/tree_entity.rb
app/serializers/tree_entity.rb
+0
-4
app/serializers/tree_root_entity.rb
app/serializers/tree_root_entity.rb
+4
-0
app/services/ci/ensure_stage_service.rb
app/services/ci/ensure_stage_service.rb
+39
-0
app/views/projects/clusters/_form.html.haml
app/views/projects/clusters/_form.html.haml
+1
-1
app/views/projects/commit/_commit_box.html.haml
app/views/projects/commit/_commit_box.html.haml
+1
-1
app/views/projects/issues/_nav_btns.html.haml
app/views/projects/issues/_nav_btns.html.haml
+2
-2
app/views/shared/issuable/_filter.html.haml
app/views/shared/issuable/_filter.html.haml
+0
-1
changelogs/unreleased/38394-smarter-interval.yml
changelogs/unreleased/38394-smarter-interval.yml
+5
-0
changelogs/unreleased/39649-change-default-size-for-gke-cluster-creation.yml
...ed/39649-change-default-size-for-gke-cluster-creation.yml
+5
-0
changelogs/unreleased/39878-commit-pipeline-reads-wrong-key.yml
...logs/unreleased/39878-commit-pipeline-reads-wrong-key.yml
+5
-0
changelogs/unreleased/fix-import-export-arguments.yml
changelogs/unreleased/fix-import-export-arguments.yml
+5
-0
changelogs/unreleased/fix-mysql-grant-check.yml
changelogs/unreleased/fix-mysql-grant-check.yml
+5
-0
doc/user/project/issue_board.md
doc/user/project/issue_board.md
+20
-6
lib/gitlab/ci/status/build/failed_allowed.rb
lib/gitlab/ci/status/build/failed_allowed.rb
+1
-1
lib/gitlab/database/grant.rb
lib/gitlab/database/grant.rb
+19
-11
lib/gitlab/import_export/merge_request_parser.rb
lib/gitlab/import_export/merge_request_parser.rb
+1
-1
lib/tasks/gitlab/backup.rake
lib/tasks/gitlab/backup.rake
+22
-17
spec/controllers/concerns/issuable_collections_spec.rb
spec/controllers/concerns/issuable_collections_spec.rb
+0
-54
spec/controllers/projects/refs_controller_spec.rb
spec/controllers/projects/refs_controller_spec.rb
+12
-2
spec/factories/commit_statuses.rb
spec/factories/commit_statuses.rb
+1
-0
spec/features/projects/commit/mini_pipeline_graph_spec.rb
spec/features/projects/commit/mini_pipeline_graph_spec.rb
+7
-0
spec/features/projects/import_export/test_project_export.tar.gz
...eatures/projects/import_export/test_project_export.tar.gz
+0
-0
spec/features/projects/tree/create_directory_spec.rb
spec/features/projects/tree/create_directory_spec.rb
+0
-5
spec/javascripts/repo/components/repo_file_spec.js
spec/javascripts/repo/components/repo_file_spec.js
+2
-3
spec/javascripts/smart_interval_spec.js
spec/javascripts/smart_interval_spec.js
+128
-115
spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+11
-7
spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js
.../vue_shared/components/skeleton_loading_container_spec.js
+49
-0
spec/lib/gitlab/ci/status/build/factory_spec.rb
spec/lib/gitlab/ci/status/build/factory_spec.rb
+1
-1
spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
+1
-1
spec/lib/gitlab/database/grant_spec.rb
spec/lib/gitlab/database/grant_spec.rb
+5
-17
spec/lib/gitlab/import_export/merge_request_parser_spec.rb
spec/lib/gitlab/import_export/merge_request_parser_spec.rb
+11
-1
spec/lib/google_api/cloud_platform/client_spec.rb
spec/lib/google_api/cloud_platform/client_spec.rb
+1
-1
spec/models/clusters/providers/gcp_spec.rb
spec/models/clusters/providers/gcp_spec.rb
+1
-1
spec/models/commit_status_spec.rb
spec/models/commit_status_spec.rb
+71
-2
spec/serializers/pipeline_details_entity_spec.rb
spec/serializers/pipeline_details_entity_spec.rb
+1
-1
spec/support/cycle_analytics_helpers.rb
spec/support/cycle_analytics_helpers.rb
+1
-0
No files found.
app/assets/javascripts/repo/components/repo_file.vue
View file @
4fac95a6
<
script
>
import
{
mapActions
,
mapGetters
}
from
'
vuex
'
;
import
timeAgoMixin
from
'
../../vue_shared/mixins/timeago
'
;
import
skeletonLoadingContainer
from
'
../../vue_shared/components/skeleton_loading_container.vue
'
;
export
default
{
mixins
:
[
timeAgoMixin
,
],
components
:
{
skeletonLoadingContainer
,
},
props
:
{
file
:
{
type
:
Object
,
...
...
@@ -16,6 +20,9 @@
...
mapGetters
([
'
isCollapsed
'
,
]),
isSubmodule
()
{
return
this
.
file
.
type
===
'
submodule
'
;
},
fileIcon
()
{
return
{
'
fa-spinner fa-spin
'
:
this
.
file
.
loading
,
...
...
@@ -31,6 +38,9 @@
shortId
()
{
return
this
.
file
.
id
.
substr
(
0
,
8
);
},
submoduleColSpan
()
{
return
!
this
.
isCollapsed
&&
this
.
isSubmodule
?
3
:
1
;
},
},
methods
:
{
...
mapActions
([
...
...
@@ -44,7 +54,7 @@
<tr
class=
"file"
@
click.prevent=
"clickedTreeRow(file)"
>
<td>
<td
:colspan=
"submoduleColSpan"
>
<i
class=
"fa fa-fw file-icon"
:class=
"fileIcon"
...
...
@@ -58,7 +68,7 @@
>
{{
file
.
name
}}
</a>
<template
v-if=
"
file.type === 'submodule'
&& file.id"
>
<template
v-if=
"
isSubmodule
&& file.id"
>
@
<span
class=
"commit-sha"
>
<a
...
...
@@ -71,15 +81,20 @@
</
template
>
</td>
<
template
v-if=
"!isCollapsed"
>
<
template
v-if=
"!isCollapsed
&& !isSubmodule
"
>
<td
class=
"hidden-sm hidden-xs"
>
<a
v-if=
"file.lastCommit.message"
@
click
.
stop
:href=
"file.lastCommit.url"
class=
"commit-message"
>
{{
file
.
lastCommit
.
message
}}
</a>
<skeleton-loading-container
v-else
:small=
"true"
/>
</td>
<td
class=
"commit-update hidden-xs text-right"
>
...
...
@@ -89,6 +104,11 @@
>
{{
timeFormated
(
file
.
lastCommit
.
updatedAt
)
}}
</span>
<skeleton-loading-container
v-else
class=
"animation-container-right"
:small=
"true"
/>
</td>
</
template
>
</tr>
...
...
app/assets/javascripts/repo/components/repo_loading_file.vue
View file @
4fac95a6
<
script
>
import
{
mapGetters
}
from
'
vuex
'
;
import
skeletonLoadingContainer
from
'
../../vue_shared/components/skeleton_loading_container.vue
'
;
export
default
{
components
:
{
skeletonLoadingContainer
,
},
computed
:
{
...
mapGetters
([
'
isCollapsed
'
,
]),
},
methods
:
{
lineOfCode
(
n
)
{
return
`skeleton-line-
${
n
}
`
;
},
},
};
</
script
>
...
...
@@ -21,36 +20,24 @@
aria-label=
"Loading files"
>
<td>
<div
class=
"animation-container animation-container-small"
>
<div
v-for=
"n in 6"
:key=
"n"
:class=
"lineOfCode(n)"
>
</div>
</div>
<skeleton-loading-container
:small=
"true"
/>
</td>
<template
v-if=
"!isCollapsed"
>
<td
class=
"hidden-sm hidden-xs"
>
<div
class=
"animation-container"
>
<div
v-for=
"n in 6"
:key=
"n"
:class=
"lineOfCode(n)"
>
</div>
</div>
<skeleton-loading-container
:small=
"true"
/>
</td>
<td
class=
"hidden-xs"
>
<div
class=
"animation-container animation-container-small animation-container-right"
>
<div
v-for=
"n in 6"
:key=
"n"
:class=
"lineOfCode(n)"
>
</div>
</div>
<skeleton-loading-container
class=
"animation-container-right"
:small=
"true"
/>
</td>
</
template
>
</tr>
...
...
app/assets/javascripts/repo/components/repo_sidebar.vue
View file @
4fac95a6
...
...
@@ -80,7 +80,7 @@ export default {
/>
<repo-file
v-for=
"(file, index) in treeList"
:key=
"
index
"
:key=
"
file.key
"
:file=
"file"
/>
</tbody>
...
...
app/assets/javascripts/repo/services/index.js
View file @
4fac95a6
...
...
@@ -30,4 +30,11 @@ export default {
commit
(
projectId
,
payload
)
{
return
Api
.
commitMultiple
(
projectId
,
payload
);
},
getTreeLastCommit
(
endpoint
)
{
return
Vue
.
http
.
get
(
endpoint
,
{
params
:
{
format
:
'
json
'
,
},
});
},
};
app/assets/javascripts/repo/stores/actions.js
View file @
4fac95a6
...
...
@@ -64,7 +64,7 @@ export const checkCommitStatus = ({ state }) => service.getBranchData(
})
.
catch
(()
=>
flash
(
'
Error checking branch data. Please try again.
'
));
export
const
commitChanges
=
({
commit
,
state
,
dispatch
},
{
payload
,
newMr
})
=>
export
const
commitChanges
=
({
commit
,
state
,
dispatch
,
getters
},
{
payload
,
newMr
})
=>
service
.
commit
(
state
.
project
.
id
,
payload
)
.
then
((
data
)
=>
{
const
{
branch
}
=
payload
;
...
...
@@ -73,12 +73,28 @@ export const commitChanges = ({ commit, state, dispatch }, { payload, newMr }) =
return
;
}
const
lastCommit
=
{
commit_path
:
`
${
state
.
project
.
url
}
/commit/
${
data
.
id
}
`
,
commit
:
{
message
:
data
.
message
,
authored_date
:
data
.
committed_date
,
},
};
flash
(
`Your changes have been committed. Commit
${
data
.
short_id
}
with
${
data
.
stats
.
additions
}
additions,
${
data
.
stats
.
deletions
}
deletions.`
,
'
notice
'
);
if
(
newMr
)
{
redirectToUrl
(
`
${
state
.
endpoints
.
newMergeRequestUrl
}${
branch
}
`
);
}
else
{
commit
(
types
.
SET_COMMIT_REF
,
data
.
id
);
getters
.
changedFiles
.
forEach
((
entry
)
=>
{
commit
(
types
.
SET_LAST_COMMIT_DATA
,
{
entry
,
lastCommit
,
});
});
dispatch
(
'
discardAllChanges
'
);
dispatch
(
'
closeAllFiles
'
);
dispatch
(
'
toggleEditMode
'
);
...
...
app/assets/javascripts/repo/stores/actions/file.js
View file @
4fac95a6
...
...
@@ -27,6 +27,8 @@ export const closeFile = ({ commit, state, dispatch }, { file, force = false })
}
else
if
(
!
state
.
openFiles
.
length
)
{
pushState
(
file
.
parentTreeUrl
);
}
dispatch
(
'
getLastCommitData
'
);
};
export
const
setFileActive
=
({
commit
,
state
,
getters
,
dispatch
},
file
)
=>
{
...
...
app/assets/javascripts/repo/stores/actions/tree.js
View file @
4fac95a6
...
...
@@ -7,10 +7,11 @@ import {
setPageTitle
,
findEntry
,
createTemp
,
createOrMergeEntry
,
}
from
'
../utils
'
;
export
const
getTreeData
=
(
{
commit
,
state
},
{
commit
,
state
,
dispatch
},
{
endpoint
=
state
.
endpoints
.
rootEndpoint
,
tree
=
state
}
=
{},
)
=>
{
commit
(
types
.
TOGGLE_LOADING
,
tree
);
...
...
@@ -24,14 +25,20 @@ export const getTreeData = (
return
res
.
json
();
})
.
then
((
data
)
=>
{
const
prevLastCommitPath
=
tree
.
lastCommitPath
;
if
(
!
state
.
isInitialRoot
)
{
commit
(
types
.
SET_ROOT
,
data
.
path
===
'
/
'
);
}
commit
(
types
.
SET_DIRECTORY_DATA
,
{
data
,
tree
});
dispatch
(
'
updateDirectoryData
'
,
{
data
,
tree
});
commit
(
types
.
SET_PARENT_TREE_URL
,
data
.
parent_tree_url
);
commit
(
types
.
SET_LAST_COMMIT_URL
,
{
tree
,
url
:
data
.
last_commit_path
});
commit
(
types
.
TOGGLE_LOADING
,
tree
);
if
(
prevLastCommitPath
!==
null
)
{
dispatch
(
'
getLastCommitData
'
,
tree
);
}
pushState
(
endpoint
);
})
.
catch
(()
=>
{
...
...
@@ -48,7 +55,7 @@ export const toggleTreeOpen = ({ commit, dispatch }, { endpoint, tree }) => {
pushState
(
tree
.
parentTreeUrl
);
commit
(
types
.
SET_PREVIOUS_URL
,
tree
.
parentTreeUrl
);
commit
(
types
.
SET_DIRECTORY_DATA
,
{
data
,
tree
});
dispatch
(
'
updateDirectoryData
'
,
{
data
,
tree
});
}
else
{
commit
(
types
.
SET_PREVIOUS_URL
,
endpoint
);
dispatch
(
'
getTreeData
'
,
{
endpoint
,
tree
});
...
...
@@ -108,3 +115,48 @@ export const createTempTree = ({ state, commit, dispatch }, name) => {
});
}
};
export
const
getLastCommitData
=
({
state
,
commit
,
dispatch
,
getters
},
tree
=
state
)
=>
{
if
(
tree
.
lastCommitPath
===
null
||
getters
.
isCollapsed
)
return
;
service
.
getTreeLastCommit
(
tree
.
lastCommitPath
)
.
then
((
res
)
=>
{
const
lastCommitPath
=
normalizeHeaders
(
res
.
headers
)[
'
MORE-LOGS-URL
'
]
||
null
;
commit
(
types
.
SET_LAST_COMMIT_URL
,
{
tree
,
url
:
lastCommitPath
});
return
res
.
json
();
})
.
then
((
data
)
=>
{
data
.
forEach
((
lastCommit
)
=>
{
const
entry
=
findEntry
(
tree
,
lastCommit
.
type
,
lastCommit
.
file_name
);
if
(
entry
)
{
commit
(
types
.
SET_LAST_COMMIT_DATA
,
{
entry
,
lastCommit
});
}
});
dispatch
(
'
getLastCommitData
'
,
tree
);
})
.
catch
(()
=>
flash
(
'
Error fetching log data.
'
));
};
export
const
updateDirectoryData
=
({
commit
,
state
},
{
data
,
tree
})
=>
{
const
level
=
tree
.
level
!==
undefined
?
tree
.
level
+
1
:
0
;
const
parentTreeUrl
=
data
.
parent_tree_url
?
`
${
data
.
parent_tree_url
}${
data
.
path
}
`
:
state
.
endpoints
.
rootUrl
;
const
createEntry
=
(
entry
,
type
)
=>
createOrMergeEntry
({
tree
,
entry
,
level
,
type
,
parentTreeUrl
,
});
const
formattedData
=
[
...
data
.
trees
.
map
(
t
=>
createEntry
(
t
,
'
tree
'
)),
...
data
.
submodules
.
map
(
m
=>
createEntry
(
m
,
'
submodule
'
)),
...
data
.
blobs
.
map
(
b
=>
createEntry
(
b
,
'
blob
'
)),
];
commit
(
types
.
SET_DIRECTORY_DATA
,
{
tree
,
data
:
formattedData
});
};
app/assets/javascripts/repo/stores/mutation_types.js
View file @
4fac95a6
...
...
@@ -4,11 +4,13 @@ export const SET_COMMIT_REF = 'SET_COMMIT_REF';
export
const
SET_PARENT_TREE_URL
=
'
SET_PARENT_TREE_URL
'
;
export
const
SET_ROOT
=
'
SET_ROOT
'
;
export
const
SET_PREVIOUS_URL
=
'
SET_PREVIOUS_URL
'
;
export
const
SET_LAST_COMMIT_DATA
=
'
SET_LAST_COMMIT_DATA
'
;
// Tree mutation types
export
const
SET_DIRECTORY_DATA
=
'
SET_DIRECTORY_DATA
'
;
export
const
TOGGLE_TREE_OPEN
=
'
TOGGLE_TREE_OPEN
'
;
export
const
CREATE_TMP_TREE
=
'
CREATE_TMP_TREE
'
;
export
const
SET_LAST_COMMIT_URL
=
'
SET_LAST_COMMIT_URL
'
;
// File mutation types
export
const
SET_FILE_DATA
=
'
SET_FILE_DATA
'
;
...
...
app/assets/javascripts/repo/stores/mutations.js
View file @
4fac95a6
...
...
@@ -48,6 +48,13 @@ export default {
previousUrl
,
});
},
[
types
.
SET_LAST_COMMIT_DATA
](
state
,
{
entry
,
lastCommit
})
{
Object
.
assign
(
entry
.
lastCommit
,
{
url
:
lastCommit
.
commit_path
,
message
:
lastCommit
.
commit
.
message
,
updatedAt
:
lastCommit
.
commit
.
authored_date
,
});
},
...
fileMutations
,
...
treeMutations
,
...
branchMutations
,
...
...
app/assets/javascripts/repo/stores/mutations/tree.js
View file @
4fac95a6
import
*
as
types
from
'
../mutation_types
'
;
import
*
as
utils
from
'
../utils
'
;
export
default
{
[
types
.
TOGGLE_TREE_OPEN
](
state
,
tree
)
{
...
...
@@ -8,30 +7,8 @@ export default {
});
},
[
types
.
SET_DIRECTORY_DATA
](
state
,
{
data
,
tree
})
{
const
level
=
tree
.
level
!==
undefined
?
tree
.
level
+
1
:
0
;
const
parentTreeUrl
=
data
.
parent_tree_url
?
`
${
data
.
parent_tree_url
}${
data
.
path
}
`
:
state
.
endpoints
.
rootUrl
;
Object
.
assign
(
tree
,
{
tree
:
[
...
data
.
trees
.
map
(
t
=>
utils
.
decorateData
({
...
t
,
type
:
'
tree
'
,
parentTreeUrl
,
level
,
},
state
.
project
.
url
)),
...
data
.
submodules
.
map
(
m
=>
utils
.
decorateData
({
...
m
,
type
:
'
submodule
'
,
parentTreeUrl
,
level
,
},
state
.
project
.
url
)),
...
data
.
blobs
.
map
(
b
=>
utils
.
decorateData
({
...
b
,
type
:
'
blob
'
,
parentTreeUrl
,
level
,
},
state
.
project
.
url
)),
],
tree
:
data
,
});
},
[
types
.
SET_PARENT_TREE_URL
](
state
,
url
)
{
...
...
@@ -39,6 +16,11 @@ export default {
parentTreeUrl
:
url
,
});
},
[
types
.
SET_LAST_COMMIT_URL
](
state
,
{
tree
=
state
,
url
})
{
Object
.
assign
(
tree
,
{
lastCommitPath
:
url
,
});
},
[
types
.
CREATE_TMP_TREE
](
state
,
{
parent
,
tmpEntry
})
{
parent
.
tree
.
push
(
tmpEntry
);
},
...
...
app/assets/javascripts/repo/stores/state.js
View file @
4fac95a6
...
...
@@ -8,6 +8,7 @@ export default () => ({
endpoints
:
{},
isRoot
:
false
,
isInitialRoot
:
false
,
lastCommitPath
:
''
,
loading
:
false
,
onTopOfBranch
:
false
,
openFiles
:
[],
...
...
app/assets/javascripts/repo/stores/utils.js
View file @
4fac95a6
export
const
dataStructure
=
()
=>
({
id
:
''
,
key
:
''
,
type
:
''
,
name
:
''
,
url
:
''
,
...
...
@@ -12,7 +13,12 @@ export const dataStructure = () => ({
opened
:
false
,
active
:
false
,
changed
:
false
,
lastCommit
:
{},
lastCommitPath
:
''
,
lastCommit
:
{
url
:
''
,
message
:
''
,
updatedAt
:
''
,
},
tree_url
:
''
,
blamePath
:
''
,
commitsPath
:
''
,
...
...
@@ -27,14 +33,13 @@ export const dataStructure = () => ({
base64
:
false
,
});
export
const
decorateData
=
(
entity
,
projectUrl
=
''
)
=>
{
export
const
decorateData
=
(
entity
)
=>
{
const
{
id
,
type
,
url
,
name
,
icon
,
last_commit
,
tree_url
,
path
,
renderError
,
...
...
@@ -51,6 +56,7 @@ export const decorateData = (entity, projectUrl = '') => {
return
{
...
dataStructure
(),
id
,
key
:
`
${
name
}
-
${
type
}
-
${
id
}
`
,
type
,
name
,
url
,
...
...
@@ -66,12 +72,6 @@ export const decorateData = (entity, projectUrl = '') => {
renderError
,
content
,
base64
,
// eslint-disable-next-line camelcase
lastCommit
:
last_commit
?
{
url
:
`
${
projectUrl
}
/commit/
${
last_commit
.
id
}
`
,
message
:
last_commit
.
message
,
updatedAt
:
last_commit
.
committed_date
,
}
:
{},
};
};
...
...
@@ -106,3 +106,22 @@ export const createTemp = ({ name, path, type, level, changed, content, base64 }
renderError
:
base64
,
});
};
export
const
createOrMergeEntry
=
({
tree
,
entry
,
type
,
parentTreeUrl
,
level
})
=>
{
const
found
=
findEntry
(
tree
,
type
,
entry
.
name
);
if
(
found
)
{
return
Object
.
assign
({},
found
,
{
id
:
entry
.
id
,
url
:
entry
.
url
,
tempFile
:
false
,
});
}
return
decorateData
({
...
entry
,
type
,
parentTreeUrl
,
level
,
});
};
app/assets/javascripts/smart_interval.js
View file @
4fac95a6
...
...
@@ -3,9 +3,10 @@
* and controllable by a public API.
*/
class
SmartInterval
{
export
default
class
SmartInterval
{
/**
* @param { function } opts.callback Function to be called on each iteration (required)
* @param { function } opts.callback Function that returns a promise, called on each iteration
* unless still in progress (required)
* @param { milliseconds } opts.startingInterval `currentInterval` is set to this initially
* @param { milliseconds } opts.maxInterval `currentInterval` will be incremented to this
* @param { milliseconds } opts.hiddenInterval `currentInterval` is set to this
...
...
@@ -42,13 +43,16 @@ class SmartInterval {
const
cfg
=
this
.
cfg
;
const
state
=
this
.
state
;
if
(
cfg
.
immediateExecution
)
{
if
(
cfg
.
immediateExecution
&&
!
this
.
isLoading
)
{
cfg
.
immediateExecution
=
false
;
cfg
.
c
allback
();
this
.
triggerC
allback
();
}
state
.
intervalId
=
window
.
setInterval
(()
=>
{
cfg
.
callback
();
if
(
this
.
isLoading
)
{
return
;
}
this
.
triggerCallback
();
if
(
this
.
getCurrentInterval
()
===
cfg
.
maxInterval
)
{
return
;
...
...
@@ -76,7 +80,7 @@ class SmartInterval {
// start a timer, using the existing interval
resume
()
{
this
.
stopTimer
();
// stop ex
si
ting timer, in case timer was not previously stopped
this
.
stopTimer
();
// stop ex
is
ting timer, in case timer was not previously stopped
this
.
start
();
}
...
...
@@ -104,6 +108,18 @@ class SmartInterval {
this
.
initPageUnloadHandling
();
}
triggerCallback
()
{
this
.
isLoading
=
true
;
this
.
cfg
.
callback
()
.
then
(()
=>
{
this
.
isLoading
=
false
;
})
.
catch
((
err
)
=>
{
this
.
isLoading
=
false
;
throw
err
;
});
}
initVisibilityChangeHandling
()
{
// cancel interval when tab no longer shown (prevents cached pages from polling)
document
.
addEventListener
(
'
visibilitychange
'
,
this
.
handleVisibilityChange
.
bind
(
this
));
...
...
@@ -154,4 +170,3 @@ class SmartInterval {
}
}
window
.
gl
.
SmartInterval
=
SmartInterval
;
app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
View file @
4fac95a6
import
SmartInterval
from
'
~/smart_interval
'
;
import
Flash
from
'
../flash
'
;
import
{
WidgetHeader
,
...
...
@@ -81,7 +82,7 @@ export default {
return
new
MRWidgetService
(
endpoints
);
},
checkStatus
(
cb
)
{
this
.
service
.
checkStatus
()
return
this
.
service
.
checkStatus
()
.
then
(
res
=>
res
.
json
())
.
then
((
res
)
=>
{
this
.
handleNotification
(
res
);
...
...
@@ -97,7 +98,7 @@ export default {
});
},
initPolling
()
{
this
.
pollingInterval
=
new
gl
.
SmartInterval
({
this
.
pollingInterval
=
new
SmartInterval
({
callback
:
this
.
checkStatus
,
startingInterval
:
10000
,
maxInterval
:
30000
,
...
...
@@ -106,7 +107,7 @@ export default {
});
},
initDeploymentsPolling
()
{
this
.
deploymentsInterval
=
new
gl
.
SmartInterval
({
this
.
deploymentsInterval
=
new
SmartInterval
({
callback
:
this
.
fetchDeployments
,
startingInterval
:
30000
,
maxInterval
:
120000
,
...
...
@@ -121,7 +122,7 @@ export default {
}
},
fetchDeployments
()
{
this
.
service
.
fetchDeployments
()
return
this
.
service
.
fetchDeployments
()
.
then
(
res
=>
res
.
json
())
.
then
((
res
)
=>
{
if
(
res
.
length
)
{
...
...
app/assets/javascripts/vue_shared/components/skeleton_loading_container.vue
0 → 100644
View file @
4fac95a6
<
script
>
export
default
{
props
:
{
small
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
lines
:
{
type
:
Number
,
required
:
false
,
default
:
6
,
},
},
computed
:
{
lineClasses
()
{
return
new
Array
(
this
.
lines
).
fill
().
map
((
_
,
i
)
=>
`skeleton-line-
${
i
+
1
}
`
);
},
},
};
</
script
>
<
template
>
<div
class=
"animation-container"
:class=
"
{
'animation-container-small': small,
}"
>
<div
v-for=
"(css, index) in lineClasses"
:key=
"index"
:class=
"css"
>
</div>
</div>
</
template
>
app/controllers/concerns/issuable_actions.rb
View file @
4fac95a6
...
...
@@ -9,9 +9,7 @@ module IssuableActions
def
show
respond_to
do
|
format
|
format
.
html
do
render
show_view
end
format
.
html
format
.
json
do
render
json:
serializer
.
represent
(
issuable
,
serializer:
params
[
:serializer
])
end
...
...
@@ -152,10 +150,6 @@ module IssuableActions
end
end
def
show_view
'show'
end
def
serializer
raise
NotImplementedError
end
...
...
app/controllers/concerns/issuable_collections.rb
View file @
4fac95a6
...
...
@@ -4,58 +4,44 @@ module IssuableCollections
include
Gitlab
::
IssuableMetadata
included
do
helper_method
:issues_finder
helper_method
:merge_requests_finder
helper_method
:finder
end
private
def
set_issues_index
@collection_type
=
"Issue"
@issues
=
issues_collection
@issues
=
@issues
.
page
(
params
[
:page
])
@issuable_meta_data
=
issuable_meta_data
(
@issues
,
@collection_type
)
@total_pages
=
issues_page_count
(
@issues
)
def
set_issuables_index
@issuables
=
issuables_collection
@issuables
=
@issuables
.
page
(
params
[
:page
])
@issuable_meta_data
=
issuable_meta_data
(
@issuables
,
collection_type
)
@total_pages
=
issuable_page_count
return
if
redirect_out_of_range
(
@
issues
,
@
total_pages
)
return
if
redirect_out_of_range
(
@total_pages
)
if
params
[
:label_name
].
present?
@labels
=
LabelsFinder
.
new
(
current_user
,
project_id:
@project
.
id
,
title:
params
[
:label_name
]).
execute
labels_params
=
{
project_id:
@project
.
id
,
title:
params
[
:label_name
]
}
@labels
=
LabelsFinder
.
new
(
current_user
,
labels_params
).
execute
end
@users
=
[]
end
def
issues_collection
issues_finder
.
execute
.
preload
(
:project
,
:author
,
:assignees
,
:labels
,
:milestone
,
project: :namespace
)
end
def
merge_requests_collection
merge_requests_finder
.
execute
.
preload
(
:source_project
,
:target_project
,
:author
,
:assignee
,
:labels
,
:milestone
,
head_pipeline: :project
,
target_project: :namespace
,
merge_request_diff: :merge_request_diff_commits
)
end
if
params
[
:assignee_id
].
present?
assignee
=
User
.
find_by_id
(
params
[
:assignee_id
])
@users
.
push
(
assignee
)
if
assignee
end
def
issues_finder
@issues_finder
||=
issuable_finder_for
(
IssuesFinder
)
if
params
[
:author_id
].
present?
author
=
User
.
find_by_id
(
params
[
:author_id
])
@users
.
push
(
author
)
if
author
end
end
def
merge_requests_finder
@merge_requests_finder
||=
issuable_finder_for
(
MergeRequestsFinder
)
def
issuables_collection
finder
.
execute
.
preload
(
preload_for_collection
)
end
def
redirect_out_of_range
(
relation
,
total_pages
)
def
redirect_out_of_range
(
total_pages
)
return
false
if
total_pages
.
zero?
out_of_range
=
relation
.
current_page
>
total_pages
out_of_range
=
@issuables
.
current_page
>
total_pages
if
out_of_range
redirect_to
(
url_for
(
params
.
merge
(
page:
total_pages
,
only_path:
true
)))
...
...
@@ -64,12 +50,8 @@ module IssuableCollections
out_of_range
end
def
issues_page_count
(
relation
)
page_count_for_relation
(
relation
,
issues_finder
.
row_count
)
end
def
merge_requests_page_count
(
relation
)
page_count_for_relation
(
relation
,
merge_requests_finder
.
row_count
)
def
issuable_page_count
page_count_for_relation
(
@issuables
,
finder
.
row_count
)
end
def
page_count_for_relation
(
relation
,
row_count
)
...
...
@@ -145,4 +127,31 @@ module IssuableCollections
else
value
end
end
def
finder
return
@finder
if
defined?
(
@finder
)
@finder
=
issuable_finder_for
(
@finder_type
)
end
def
collection_type
@collection_type
||=
case
finder
when
IssuesFinder
'Issue'
when
MergeRequestsFinder
'MergeRequest'
end
end
def
preload_for_collection
@preload_for_collection
||=
case
collection_type
when
'Issue'
[
:project
,
:author
,
:assignees
,
:labels
,
:milestone
,
project: :namespace
]
when
'MergeRequest'
[
:source_project
,
:target_project
,
:author
,
:assignee
,
:labels
,
:milestone
,
head_pipeline: :project
,
target_project: :namespace
,
merge_request_diff: :merge_request_diff_commits
]
end
end
end
app/controllers/concerns/issues_action.rb
View file @
4fac95a6
...
...
@@ -3,14 +3,14 @@ module IssuesAction
include
IssuableCollections
def
issues
@label
=
issues_finder
.
labels
.
first
@finder_type
=
IssuesFinder
@label
=
finder
.
labels
.
first
@issues
=
issues_collection
@issues
=
issu
abl
es_collection
.
non_archived
.
page
(
params
[
:page
])
@collection_type
=
"Issue"
@issuable_meta_data
=
issuable_meta_data
(
@issues
,
@collection_type
)
@issuable_meta_data
=
issuable_meta_data
(
@issues
,
collection_type
)
respond_to
do
|
format
|
format
.
html
...
...
app/controllers/concerns/merge_requests_action.rb
View file @
4fac95a6
...
...
@@ -3,13 +3,12 @@ module MergeRequestsAction
include
IssuableCollections
def
merge_requests
@label
=
merge_requests_finder
.
labels
.
first
@finder_type
=
MergeRequestsFinder
@label
=
finder
.
labels
.
first
@merge_requests
=
merge_requests_collection
.
page
(
params
[
:page
])
@merge_requests
=
issuables_collection
.
page
(
params
[
:page
])
@collection_type
=
"MergeRequest"
@issuable_meta_data
=
issuable_meta_data
(
@merge_requests
,
@collection_type
)
@issuable_meta_data
=
issuable_meta_data
(
@merge_requests
,
collection_type
)
end
private
...
...
app/controllers/projects/issues_controller.rb
View file @
4fac95a6
...
...
@@ -10,7 +10,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action
:check_issues_available!
before_action
:issue
,
except:
[
:index
,
:new
,
:create
,
:bulk_update
]
before_action
:set_issues_index
,
only:
[
:index
]
before_action
:set_issu
abl
es_index
,
only:
[
:index
]
# Allow write(create) issue
before_action
:authorize_create_issue!
,
only:
[
:new
,
:create
]
...
...
@@ -24,15 +24,7 @@ class Projects::IssuesController < Projects::ApplicationController
respond_to
:html
def
index
if
params
[
:assignee_id
].
present?
assignee
=
User
.
find_by_id
(
params
[
:assignee_id
])
@users
.
push
(
assignee
)
if
assignee
end
if
params
[
:author_id
].
present?
author
=
User
.
find_by_id
(
params
[
:author_id
])
@users
.
push
(
author
)
if
author
end
@issues
=
@issuables
respond_to
do
|
format
|
format
.
html
...
...
@@ -252,4 +244,9 @@ class Projects::IssuesController < Projects::ApplicationController
update_params
=
issue_params
.
merge
(
spammable_params
)
Issues
::
UpdateService
.
new
(
project
,
current_user
,
update_params
)
end
def
set_issuables_index
@finder_type
=
IssuesFinder
super
end
end
app/controllers/projects/merge_requests_controller.rb
View file @
4fac95a6
...
...
@@ -10,33 +10,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action
:authorize_update_issuable!
,
only:
[
:close
,
:edit
,
:update
,
:remove_wip
,
:sort
]
before_action
:set_issuables_index
,
only:
[
:index
]
before_action
:authenticate_user!
,
only:
[
:assign_related_issues
]
def
index
@collection_type
=
"MergeRequest"
@merge_requests
=
merge_requests_collection
@merge_requests
=
@merge_requests
.
page
(
params
[
:page
])
@merge_requests
=
@merge_requests
.
preload
(
merge_request_diff: :merge_request
)
@issuable_meta_data
=
issuable_meta_data
(
@merge_requests
,
@collection_type
)
@total_pages
=
merge_requests_page_count
(
@merge_requests
)
return
if
redirect_out_of_range
(
@merge_requests
,
@total_pages
)
if
params
[
:label_name
].
present?
labels_params
=
{
project_id:
@project
.
id
,
title:
params
[
:label_name
]
}
@labels
=
LabelsFinder
.
new
(
current_user
,
labels_params
).
execute
end
@users
=
[]
if
params
[
:assignee_id
].
present?
assignee
=
User
.
find_by_id
(
params
[
:assignee_id
])
@users
.
push
(
assignee
)
if
assignee
end
if
params
[
:author_id
].
present?
author
=
User
.
find_by_id
(
params
[
:author_id
])
@users
.
push
(
author
)
if
author
end
@merge_requests
=
@issuables
respond_to
do
|
format
|
format
.
html
...
...
@@ -338,4 +317,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
@target_project
=
@merge_request
.
target_project
@target_branches
=
@merge_request
.
target_project
.
repository
.
branch_names
end
def
set_issuables_index
@finder_type
=
MergeRequestsFinder
super
end
end
app/controllers/projects/refs_controller.rb
View file @
4fac95a6
...
...
@@ -56,9 +56,12 @@ class Projects::RefsController < Projects::ApplicationController
contents
[
@offset
,
@limit
].
to_a
.
map
do
|
content
|
file
=
@path
?
File
.
join
(
@path
,
content
.
name
)
:
content
.
name
last_commit
=
@repo
.
last_commit_for_path
(
@commit
.
id
,
file
)
commit_path
=
project_commit_path
(
@project
,
last_commit
)
if
last_commit
{
file_name:
content
.
name
,
commit:
last_commit
commit:
last_commit
,
type:
content
.
type
,
commit_path:
commit_path
}
end
end
...
...
@@ -70,6 +73,11 @@ class Projects::RefsController < Projects::ApplicationController
respond_to
do
|
format
|
format
.
html
{
render_404
}
format
.
json
do
response
.
headers
[
"More-Logs-Url"
]
=
@more_log_url
render
json:
@logs
end
format
.
js
end
end
...
...
app/controllers/projects_controller.rb
View file @
4fac95a6
...
...
@@ -275,7 +275,8 @@ class ProjectsController < Projects::ApplicationController
@project_wiki
=
@project
.
wiki
@wiki_home
=
@project_wiki
.
find_page
(
'home'
,
params
[
:version_id
])
elsif
@project
.
feature_available?
(
:issues
,
current_user
)
@issues
=
issues_collection
.
page
(
params
[
:page
])
@finder_type
=
IssuesFinder
@issues
=
issuables_collection
.
page
(
params
[
:page
])
@collection_type
=
'Issue'
@issuable_meta_data
=
issuable_meta_data
(
@issues
,
@collection_type
)
end
...
...
app/helpers/issuables_helper.rb
View file @
4fac95a6
...
...
@@ -249,8 +249,6 @@ module IssuablesHelper
end
def
issuables_count_for_state
(
issuable_type
,
state
)
finder
=
public_send
(
"
#{
issuable_type
}
_finder"
)
# rubocop:disable GitlabSecurity/PublicSend
Gitlab
::
IssuablesCountForState
.
new
(
finder
)[
state
]
end
...
...
app/models/clusters/providers/gcp.rb
View file @
4fac95a6
...
...
@@ -7,7 +7,7 @@ module Clusters
default_value_for
:zone
,
'us-central1-a'
default_value_for
:num_nodes
,
3
default_value_for
:machine_type
,
'n1-standard-
4
'
default_value_for
:machine_type
,
'n1-standard-
2
'
attr_encrypted
:access_token
,
mode: :per_attribute_iv
,
...
...
app/models/commit_status.rb
View file @
4fac95a6
...
...
@@ -14,7 +14,6 @@ class CommitStatus < ActiveRecord::Base
delegate
:sha
,
:short_sha
,
to: :pipeline
validates
:pipeline
,
presence:
true
,
unless: :importing?
validates
:name
,
presence:
true
,
unless: :importing?
alias_attribute
:author
,
:user
...
...
@@ -46,6 +45,17 @@ class CommitStatus < ActiveRecord::Base
runner_system_failure:
4
}
##
# We still create some CommitStatuses outside of CreatePipelineService.
#
# These are pages deployments and external statuses.
#
before_create
unless: :importing?
do
Ci
::
EnsureStageService
.
new
(
project
,
user
).
execute
(
self
)
do
|
stage
|
self
.
run_after_commit
{
StageUpdateWorker
.
perform_async
(
stage
.
id
)
}
end
end
state_machine
:status
do
event
:process
do
transition
[
:skipped
,
:manual
]
=>
:created
...
...
app/models/concerns/issuable.rb
View file @
4fac95a6
...
...
@@ -17,6 +17,8 @@ module Issuable
include
Importable
include
Editable
include
AfterCommitQueue
include
Sortable
include
CreatedAtFilterable
# This object is used to gather issuable meta data for displaying
# upvotes, downvotes, notes and closing merge requests count for issues and merge requests
...
...
app/models/issue.rb
View file @
4fac95a6
...
...
@@ -5,11 +5,9 @@ class Issue < ActiveRecord::Base
include
Issuable
include
Noteable
include
Referable
include
Sortable
include
Spammable
include
FasterCacheKeys
include
RelativePositioning
include
CreatedAtFilterable
include
TimeTrackable
DueDateStruct
=
Struct
.
new
(
:title
,
:name
).
freeze
...
...
app/models/merge_request.rb
View file @
4fac95a6
...
...
@@ -3,9 +3,7 @@ class MergeRequest < ActiveRecord::Base
include
Issuable
include
Noteable
include
Referable
include
Sortable
include
IgnorableColumn
include
CreatedAtFilterable
include
TimeTrackable
ignore_column
:locked_at
,
...
...
app/serializers/blob_entity.rb
View file @
4fac95a6
...
...
@@ -3,10 +3,6 @@ class BlobEntity < Grape::Entity
expose
:id
,
:path
,
:name
,
:mode
expose
:last_commit
do
|
blob
|
request
.
project
.
repository
.
last_commit_for_path
(
blob
.
commit_id
,
blob
.
path
)
end
expose
:icon
do
|
blob
|
IconsHelper
.
file_type_icon_class
(
'file'
,
blob
.
mode
,
blob
.
name
)
end
...
...
app/serializers/tree_entity.rb
View file @
4fac95a6
...
...
@@ -3,10 +3,6 @@ class TreeEntity < Grape::Entity
expose
:id
,
:path
,
:name
,
:mode
expose
:last_commit
do
|
tree
|
request
.
project
.
repository
.
last_commit_for_path
(
tree
.
commit_id
,
tree
.
path
)
end
expose
:icon
do
|
tree
|
IconsHelper
.
file_type_icon_class
(
'folder'
,
tree
.
mode
,
tree
.
name
)
end
...
...
app/serializers/tree_root_entity.rb
View file @
4fac95a6
...
...
@@ -18,4 +18,8 @@ class TreeRootEntity < Grape::Entity
project_tree_path
(
request
.
project
,
File
.
join
(
request
.
ref
,
parent_tree_path
))
end
expose
:last_commit_path
do
|
tree
|
logs_file_project_ref_path
(
request
.
project
,
request
.
ref
,
tree
.
path
)
end
end
app/services/ci/ensure_stage_service.rb
0 → 100644
View file @
4fac95a6
module
Ci
##
# We call this service everytime we persist a CI/CD job.
#
# In most cases a job should already have a stage assigned, but in cases it
# doesn't have we need to either find existing one or create a brand new
# stage.
#
class
EnsureStageService
<
BaseService
def
execute
(
build
)
@build
=
build
return
if
build
.
stage_id
.
present?
return
if
build
.
invalid?
ensure_stage
.
tap
do
|
stage
|
build
.
stage_id
=
stage
.
id
yield
stage
if
block_given?
end
end
private
def
ensure_stage
find_stage
||
create_stage
end
def
find_stage
@build
.
pipeline
.
stages
.
find_by
(
name:
@build
.
stage
)
end
def
create_stage
Ci
::
Stage
.
create!
(
name:
@build
.
stage
,
pipeline:
@build
.
pipeline
,
project:
@build
.
project
)
end
end
end
app/views/projects/clusters/_form.html.haml
View file @
4fac95a6
...
...
@@ -29,7 +29,7 @@
.form-group
=
provider_gcp_field
.
label
:machine_type
,
s_
(
'ClusterIntegration|Machine type'
)
=
link_to
(
s_
(
'ClusterIntegration|See machine types'
),
'https://cloud.google.com/compute/docs/machine-types'
,
target:
'_blank'
,
rel:
'noopener noreferrer'
)
=
provider_gcp_field
.
text_field
:machine_type
,
class:
'form-control'
,
placeholder:
'n1-standard-
4
'
=
provider_gcp_field
.
text_field
:machine_type
,
class:
'form-control'
,
placeholder:
'n1-standard-
2
'
.form-group
=
field
.
submit
s_
(
'ClusterIntegration|Create cluster'
),
class:
'btn btn-save'
app/views/projects/commit/_commit_box.html.haml
View file @
4fac95a6
...
...
@@ -67,7 +67,7 @@
-
if
@commit
.
last_pipeline
-
last_pipeline
=
@commit
.
last_pipeline
.well-segment.pipeline-info
.status-icon-container
{
class:
"ci-status-icon-#{
@commit
.status}"
}
.status-icon-container
{
class:
"ci-status-icon-#{
last_pipeline
.status}"
}
=
link_to
project_pipeline_path
(
@project
,
last_pipeline
.
id
)
do
=
ci_icon_for_status
(
last_pipeline
.
status
)
#{
_
(
'Pipeline'
)
}
...
...
app/views/projects/issues/_nav_btns.html.haml
View file @
4fac95a6
...
...
@@ -3,8 +3,8 @@
-
if
@can_bulk_update
=
button_tag
"Edit issues"
,
class:
"btn btn-default append-right-10 js-bulk-update-toggle"
=
link_to
"New issue"
,
new_project_issue_path
(
@project
,
issue:
{
assignee_id:
issues_
finder
.
assignee
.
try
(
:id
),
milestone_id:
issues_
finder
.
milestones
.
first
.
try
(
:id
)
}),
issue:
{
assignee_id:
finder
.
assignee
.
try
(
:id
),
milestone_id:
finder
.
milestones
.
first
.
try
(
:id
)
}),
class:
"btn btn-new"
,
title:
"New issue"
,
id:
"new_issue_link"
app/views/shared/issuable/_filter.html.haml
View file @
4fac95a6
-
finder
=
controller
.
controller_name
==
'issues'
?
issues_finder
:
merge_requests_finder
-
boards_page
=
controller
.
controller_name
==
'boards'
.issues-filters
...
...
changelogs/unreleased/38394-smarter-interval.yml
0 → 100644
View file @
4fac95a6
---
title
:
Update Merge Request polling so there is only one request at a time
merge_request
:
15032
author
:
type
:
fixed
changelogs/unreleased/39649-change-default-size-for-gke-cluster-creation.yml
0 → 100644
View file @
4fac95a6
---
title
:
Change default cluster size to n1-default-2
merge_request
:
39649
author
:
Fabio Busatto
type
:
changed
changelogs/unreleased/39878-commit-pipeline-reads-wrong-key.yml
0 → 100644
View file @
4fac95a6
---
title
:
Fix commit pipeline showing wrong status
merge_request
:
author
:
type
:
fixed
changelogs/unreleased/fix-import-export-arguments.yml
0 → 100644
View file @
4fac95a6
---
title
:
Fix arguments Import/Export error importing project merge requests
merge_request
:
author
:
type
:
fixed
changelogs/unreleased/fix-mysql-grant-check.yml
0 → 100644
View file @
4fac95a6
---
title
:
Fix TRIGGER checks for MySQL
merge_request
:
author
:
type
:
fixed
doc/user/project/issue_board.md
View file @
4fac95a6
...
...
@@ -166,12 +166,26 @@ board itself.
![
Remove issue from list
](
img/issue_boards_remove_issue.png
)
## Re-ordering an issue in a list
> Introduced in GitLab 9.0.
Issues can be re-ordered inside of lists. This is as simple as dragging and dropping
an issue into the order you want.
## Issue ordering in a list
When visiting a board, issues appear ordered in any list. You are able to change
that order simply by dragging and dropping the issues. The changed order will be saved
to the system so that anybody who visits the same board later will see the reordering,
with some exceptions.
The first time a given issue appears in any board (i.e. the first time a user
loads a board containing that issue), it will be ordered with
respect to other issues in that list according to
[
Priority order
][
label-priority
]
.
At that point, that issue will be assigned a relative order value by the system
representing its relative order with respect to the other issues in the list. Any time
you drag-and-drop reorder that issue, its relative order value will change accordingly.
Also, any time that issue appears in any board when it is loaded by a user,
the updated relative order value will be used for the ordering. (It's only the first
time an issue appears that it takes from the Priority order mentioned above.) This means that
if issue
`A`
is drag-and-drop reordered to be above issue
`B`
by any user in
a given board inside your GitLab instance, any time those two issues are subsequently
loaded in any board in the same instance (could be a different project board or a different group board, for example),
that ordering will be maintained.
## Filtering issues
...
...
lib/gitlab/ci/status/build/failed_allowed.rb
View file @
4fac95a6
...
...
@@ -8,7 +8,7 @@ module Gitlab
end
def
icon
'warning'
'
status_
warning'
end
def
group
...
...
lib/gitlab/database/grant.rb
View file @
4fac95a6
...
...
@@ -6,28 +6,36 @@ module Gitlab
if
Database
.
postgresql?
'information_schema.role_table_grants'
else
'
mysql.user
'
'
information_schema.schema_privileges
'
end
def
self
.
scope_to_current_user
if
Database
.
postgresql?
where
(
'grantee = user'
)
else
where
(
"CONCAT(User, '@', Host) = current_user()"
)
end
end
# Returns true if the current user can create and execute triggers on the
# given table.
def
self
.
create_and_execute_trigger?
(
table
)
priv
=
if
Database
.
postgresql?
where
(
privilege_type:
'TRIGGER'
,
table_name:
table
)
.
where
(
'grantee = user'
)
else
where
(
Trigger_priv
:
'Y'
)
queries
=
[
Grant
.
select
(
1
)
.
from
(
'information_schema.user_privileges'
)
.
where
(
"PRIVILEGE_TYPE = 'SUPER'"
)
.
where
(
"GRANTEE = CONCAT('
\\
'', REPLACE(CURRENT_USER(), '@', '
\\
'@
\\
''), '
\\
'')"
),
Grant
.
select
(
1
)
.
from
(
'information_schema.schema_privileges'
)
.
where
(
"PRIVILEGE_TYPE = 'TRIGGER'"
)
.
where
(
'TABLE_SCHEMA = ?'
,
Gitlab
::
Database
.
database_name
)
.
where
(
"GRANTEE = CONCAT('
\\
'', REPLACE(CURRENT_USER(), '@', '
\\
'@
\\
''), '
\\
'')"
)
]
union
=
SQL
::
Union
.
new
(
queries
).
to_sql
Grant
.
from
(
"(
#{
union
}
) privs"
)
end
priv
.
scope_to_current_user
.
any?
priv
.
any?
end
end
end
...
...
lib/gitlab/import_export/merge_request_parser.rb
View file @
4fac95a6
...
...
@@ -26,7 +26,7 @@ module Gitlab
end
def
fetch_ref
@project
.
repository
.
fetch_ref
(
@project
.
repository
.
path
,
@diff_head_sha
,
@merge_request
.
source_branch
)
@project
.
repository
.
fetch_ref
(
@project
.
repository
,
source_ref:
@diff_head_sha
,
target_ref:
@merge_request
.
source_branch
)
end
def
branch_exists?
(
branch_name
)
...
...
lib/tasks/gitlab/backup.rake
View file @
4fac95a6
...
...
@@ -33,24 +33,29 @@ namespace :gitlab do
backup
.
unpack
unless
backup
.
skipped?
(
'db'
)
unless
ENV
[
'force'
]
==
'yes'
warning
=
<<-
MSG
.
strip_heredoc
Before restoring the database we recommend removing all existing
tables to avoid future upgrade problems. Be aware that if you have
custom tables in the GitLab database these tables and all data will be
removed.
MSG
puts
warning
.
color
(
:red
)
ask_to_continue
puts
'Removing all tables. Press `Ctrl-C` within 5 seconds to abort'
.
color
(
:yellow
)
sleep
(
5
)
begin
unless
ENV
[
'force'
]
==
'yes'
warning
=
<<-
MSG
.
strip_heredoc
Before restoring the database, we will remove all existing
tables to avoid future upgrade problems. Be aware that if you have
custom tables in the GitLab database these tables and all data will be
removed.
MSG
puts
warning
.
color
(
:red
)
ask_to_continue
puts
'Removing all tables. Press `Ctrl-C` within 5 seconds to abort'
.
color
(
:yellow
)
sleep
(
5
)
end
# Drop all tables Load the schema to ensure we don't have any newer tables
# hanging out from a failed upgrade
$progress
.
puts
'Cleaning the database ... '
.
color
(
:blue
)
Rake
::
Task
[
'gitlab:db:drop_tables'
].
invoke
$progress
.
puts
'done'
.
color
(
:green
)
Rake
::
Task
[
'gitlab:backup:db:restore'
].
invoke
rescue
Gitlab
::
TaskAbortedByUserError
puts
"Quitting..."
.
color
(
:red
)
exit
1
end
# Drop all tables Load the schema to ensure we don't have any newer tables
# hanging out from a failed upgrade
$progress
.
puts
'Cleaning the database ... '
.
color
(
:blue
)
Rake
::
Task
[
'gitlab:db:drop_tables'
].
invoke
$progress
.
puts
'done'
.
color
(
:green
)
Rake
::
Task
[
'gitlab:backup:db:restore'
].
invoke
end
Rake
::
Task
[
'gitlab:backup:repo:restore'
].
invoke
unless
backup
.
skipped?
(
'repositories'
)
...
...
spec/controllers/concerns/issuable_collections_spec.rb
View file @
4fac95a6
...
...
@@ -17,60 +17,6 @@ describe IssuableCollections do
controller
end
describe
'#redirect_out_of_range'
do
before
do
allow
(
controller
).
to
receive
(
:url_for
)
end
it
'returns true and redirects if the offset is out of range'
do
relation
=
double
(
:relation
,
current_page:
10
)
expect
(
controller
).
to
receive
(
:redirect_to
)
expect
(
controller
.
send
(
:redirect_out_of_range
,
relation
,
2
)).
to
eq
(
true
)
end
it
'returns false if the offset is not out of range'
do
relation
=
double
(
:relation
,
current_page:
1
)
expect
(
controller
).
not_to
receive
(
:redirect_to
)
expect
(
controller
.
send
(
:redirect_out_of_range
,
relation
,
2
)).
to
eq
(
false
)
end
end
describe
'#issues_page_count'
do
it
'returns the number of issue pages'
do
project
=
create
(
:project
,
:public
)
create
(
:issue
,
project:
project
)
finder
=
IssuesFinder
.
new
(
user
)
issues
=
finder
.
execute
allow
(
controller
).
to
receive
(
:issues_finder
)
.
and_return
(
finder
)
expect
(
controller
.
send
(
:issues_page_count
,
issues
)).
to
eq
(
1
)
end
end
describe
'#merge_requests_page_count'
do
it
'returns the number of merge request pages'
do
project
=
create
(
:project
,
:public
)
create
(
:merge_request
,
source_project:
project
,
target_project:
project
)
finder
=
MergeRequestsFinder
.
new
(
user
)
merge_requests
=
finder
.
execute
allow
(
controller
).
to
receive
(
:merge_requests_finder
)
.
and_return
(
finder
)
pages
=
controller
.
send
(
:merge_requests_page_count
,
merge_requests
)
expect
(
pages
).
to
eq
(
1
)
end
end
describe
'#page_count_for_relation'
do
it
'returns the number of pages'
do
relation
=
double
(
:relation
,
limit_value:
20
)
...
...
spec/controllers/projects/refs_controller_spec.rb
View file @
4fac95a6
...
...
@@ -23,12 +23,15 @@ describe Projects::RefsController do
xhr
:get
,
:logs_tree
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
'master'
,
path:
'foo/bar/baz.html'
,
format:
format
project_id:
project
,
id:
'master'
,
path:
'foo/bar/baz.html'
,
format:
format
end
it
'never throws MissingTemplate'
do
expect
{
default_get
}.
not_to
raise_error
expect
{
xhr_get
(
:json
)
}.
not_to
raise_error
expect
{
xhr_get
}.
not_to
raise_error
end
...
...
@@ -42,5 +45,12 @@ describe Projects::RefsController do
xhr_get
(
:js
)
expect
(
response
).
to
be_success
end
it
'renders JSON'
do
xhr_get
(
:json
)
expect
(
response
).
to
be_success
expect
(
json_response
).
to
be_kind_of
(
Array
)
end
end
end
spec/factories/commit_statuses.rb
View file @
4fac95a6
FactoryGirl
.
define
do
factory
:commit_status
,
class:
CommitStatus
do
name
'default'
stage
'test'
status
'success'
description
'commit status'
pipeline
factory: :ci_pipeline_with_one_job
...
...
spec/features/projects/commit/mini_pipeline_graph_spec.rb
View file @
4fac95a6
...
...
@@ -12,6 +12,13 @@ feature 'Mini Pipeline Graph in Commit View', :js do
end
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
it
'display icon with status'
do
build
.
run
visit
project_commit_path
(
project
,
project
.
commit
.
id
)
expect
(
page
).
to
have_selector
(
'.ci-status-icon-running'
)
end
it
'displays a mini pipeline graph'
do
build
.
run
visit
project_commit_path
(
project
,
project
.
commit
.
id
)
...
...
spec/features/projects/import_export/test_project_export.tar.gz
View file @
4fac95a6
No preview for this file type
spec/features/projects/tree/create_directory_spec.rb
View file @
4fac95a6
...
...
@@ -31,10 +31,5 @@ feature 'Multi-file editor new directory', :js do
click_button
(
'Commit 1 file'
)
expect
(
page
).
to
have_selector
(
'td'
,
text:
'commit message'
)
click_link
(
'foldername'
)
expect
(
page
).
to
have_selector
(
'td'
,
text:
'commit message'
,
count:
2
)
expect
(
page
).
to
have_selector
(
'td'
,
text:
'.gitkeep'
)
end
end
spec/javascripts/repo/components/repo_file_spec.js
View file @
4fac95a6
...
...
@@ -20,7 +20,7 @@ describe('RepoFile', () => {
resetStore
(
vm
.
$store
);
});
it
(
'
renders link, icon
, name and last commit details
'
,
()
=>
{
it
(
'
renders link, icon
and name
'
,
()
=>
{
const
RepoFile
=
Vue
.
extend
(
repoFile
);
vm
=
new
RepoFile
({
store
,
...
...
@@ -37,10 +37,9 @@ describe('RepoFile', () => {
expect
(
vm
.
$el
.
querySelector
(
`.
${
vm
.
file
.
icon
}
`
).
style
.
marginLeft
).
toEqual
(
'
0px
'
);
expect
(
name
.
href
).
toMatch
(
`/
${
vm
.
file
.
url
}
`
);
expect
(
name
.
textContent
.
trim
()).
toEqual
(
vm
.
file
.
name
);
expect
(
vm
.
$el
.
querySelector
(
'
.commit-message
'
).
textContent
.
trim
()).
toBe
(
vm
.
file
.
lastCommit
.
message
);
expect
(
vm
.
$el
.
querySelector
(
'
.commit-update
'
).
textContent
.
trim
()).
toBe
(
updated
);
expect
(
fileIcon
.
classList
.
contains
(
vm
.
file
.
icon
)).
toBeTruthy
();
expect
(
fileIcon
.
style
.
marginLeft
).
toEqual
(
`
${
vm
.
file
.
level
*
10
}
px`
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
.animation-container
'
).
length
).
toBe
(
2
);
});
it
(
'
does render if hasFiles is true and is loading tree
'
,
()
=>
{
...
...
spec/javascripts/smart_interval_spec.js
View file @
4fac95a6
import
'
~/smart_interval
'
;
import
SmartInterval
from
'
~/smart_interval
'
;
(()
=>
{
describe
(
'
SmartInterval
'
,
function
()
{
const
DEFAULT_MAX_INTERVAL
=
100
;
const
DEFAULT_STARTING_INTERVAL
=
5
;
const
DEFAULT_SHORT_TIMEOUT
=
75
;
...
...
@@ -9,7 +9,7 @@ import '~/smart_interval';
function
createDefaultSmartInterval
(
config
)
{
const
defaultParams
=
{
callback
:
()
=>
{}
,
callback
:
()
=>
Promise
.
resolve
()
,
startingInterval
:
DEFAULT_STARTING_INTERVAL
,
maxInterval
:
DEFAULT_MAX_INTERVAL
,
incrementByFactorOf
:
DEFAULT_INCREMENT_FACTOR
,
...
...
@@ -22,158 +22,171 @@ import '~/smart_interval';
_
.
extend
(
defaultParams
,
config
);
}
return
new
gl
.
SmartInterval
(
defaultParams
);
return
new
SmartInterval
(
defaultParams
);
}
describe
(
'
SmartInterval
'
,
function
()
{
describe
(
'
Increment Interval
'
,
function
()
{
beforeEach
(
function
()
{
this
.
smartInterval
=
createDefaultSmartInterval
();
});
describe
(
'
Increment Interval
'
,
function
()
{
beforeEach
(
function
()
{
this
.
smartInterval
=
createDefaultSmartInterval
();
});
it
(
'
should increment the interval delay
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
setTimeout
(()
=>
{
const
intervalConfig
=
this
.
smartInterval
.
cfg
;
const
iterationCount
=
4
;
const
maxIntervalAfterIterations
=
intervalConfig
.
startingInterval
*
(
intervalConfig
.
incrementByFactorOf
**
(
iterationCount
-
1
));
// 40
const
currentInterval
=
interval
.
getCurrentInterval
();
// Provide some flexibility for performance of testing environment
expect
(
currentInterval
).
toBeGreaterThan
(
intervalConfig
.
startingInterval
);
expect
(
currentInterval
<=
maxIntervalAfterIterations
).
toBeTruthy
();
done
();
},
DEFAULT_SHORT_TIMEOUT
);
// 4 iterations, increment by 2x = (5 + 10 + 20 + 40)
});
it
(
'
should increment the interval delay
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
setTimeout
(()
=>
{
const
intervalConfig
=
this
.
smartInterval
.
cfg
;
const
iterationCount
=
4
;
const
maxIntervalAfterIterations
=
intervalConfig
.
startingInterval
*
(
intervalConfig
.
incrementByFactorOf
**
(
iterationCount
-
1
));
// 40
const
currentInterval
=
interval
.
getCurrentInterval
();
// Provide some flexibility for performance of testing environment
expect
(
currentInterval
).
toBeGreaterThan
(
intervalConfig
.
startingInterval
);
expect
(
currentInterval
<=
maxIntervalAfterIterations
).
toBeTruthy
();
done
();
},
DEFAULT_SHORT_TIMEOUT
);
// 4 iterations, increment by 2x = (5 + 10 + 20 + 40)
});
it
(
'
should not increment past maxInterval
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
it
(
'
should not increment past maxInterval
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
setTimeout
(()
=>
{
const
currentInterval
=
interval
.
getCurrentInterval
();
expect
(
currentInterval
).
toBe
(
interval
.
cfg
.
maxInterval
);
setTimeout
(()
=>
{
const
currentInterval
=
interval
.
getCurrentInterval
();
expect
(
currentInterval
).
toBe
(
interval
.
cfg
.
maxInterval
);
done
();
},
DEFAULT_LONG_TIMEOUT
);
});
done
();
},
DEFAULT_LONG_TIMEOUT
);
});
describe
(
'
Public methods
'
,
function
()
{
beforeEach
(
function
()
{
this
.
smartInterval
=
createDefaultSmartInterval
();
it
(
'
does not increment while waiting for callback
'
,
function
()
{
jasmine
.
clock
().
install
();
const
smartInterval
=
createDefaultSmartInterval
({
callback
:
()
=>
new
Promise
(
$
.
noop
),
});
it
(
'
should cancel an interval
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
jasmine
.
clock
().
tick
(
DEFAULT_SHORT_TIMEOUT
);
const
oneInterval
=
smartInterval
.
cfg
.
startingInterval
*
DEFAULT_INCREMENT_FACTOR
;
expect
(
smartInterval
.
getCurrentInterval
()).
toEqual
(
oneInterval
);
setTimeout
(()
=>
{
interval
.
cancel
();
jasmine
.
clock
().
uninstall
();
});
});
const
intervalId
=
interval
.
state
.
intervalId
;
const
currentInterval
=
interval
.
getCurrentInterval
();
const
intervalLowerLimit
=
interval
.
cfg
.
startingInterval
;
describe
(
'
Public methods
'
,
function
()
{
beforeEach
(
function
()
{
this
.
smartInterval
=
createDefaultSmartInterval
();
});
expect
(
intervalId
).
toBeUndefined
();
expect
(
currentInterval
).
toBe
(
intervalLowerLimit
)
;
it
(
'
should cancel an interval
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
setTimeout
(()
=>
{
interval
.
cancel
();
it
(
'
should resume an interval
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
const
intervalId
=
interval
.
state
.
intervalId
;
const
currentInterval
=
interval
.
getCurrentInterval
();
const
intervalLowerLimit
=
interval
.
cfg
.
startingInterval
;
setTimeout
(()
=>
{
interval
.
cancel
(
);
expect
(
intervalId
).
toBeUndefined
();
expect
(
currentInterval
).
toBe
(
intervalLowerLimit
);
interval
.
resume
();
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
const
intervalId
=
interval
.
state
.
intervalId
;
it
(
'
should resume an interval
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
expect
(
intervalId
).
toBeTruthy
();
setTimeout
(()
=>
{
interval
.
cancel
();
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
interval
.
resume
();
const
intervalId
=
interval
.
state
.
intervalId
;
expect
(
intervalId
).
toBeTruthy
();
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
});
describe
(
'
DOM Events
'
,
function
()
{
beforeEach
(
function
()
{
// This ensures DOM and DOM events are initialized for these specs.
setFixtures
(
'
<div></div>
'
);
describe
(
'
DOM Events
'
,
function
()
{
beforeEach
(
function
()
{
// This ensures DOM and DOM events are initialized for these specs.
setFixtures
(
'
<div></div>
'
);
this
.
smartInterval
=
createDefaultSmartInterval
();
});
this
.
smartInterval
=
createDefaultSmartInterval
();
});
it
(
'
should pause when page is not visible
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
it
(
'
should pause when page is not visible
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
setTimeout
(()
=>
{
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
setTimeout
(()
=>
{
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
// simulates triggering of visibilitychange event
interval
.
handleVisibilityChange
({
target
:
{
visibilityState
:
'
hidden
'
}
});
// simulates triggering of visibilitychange event
interval
.
handleVisibilityChange
({
target
:
{
visibilityState
:
'
hidden
'
}
});
expect
(
interval
.
state
.
intervalId
).
toBeUndefined
();
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
expect
(
interval
.
state
.
intervalId
).
toBeUndefined
();
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
it
(
'
should change to the hidden interval when page is not visible
'
,
function
(
done
)
{
const
HIDDEN_INTERVAL
=
1500
;
const
interval
=
createDefaultSmartInterval
({
hiddenInterval
:
HIDDEN_INTERVAL
});
it
(
'
should change to the hidden interval when page is not visible
'
,
function
(
done
)
{
const
HIDDEN_INTERVAL
=
1500
;
const
interval
=
createDefaultSmartInterval
({
hiddenInterval
:
HIDDEN_INTERVAL
});
setTimeout
(()
=>
{
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
expect
(
interval
.
getCurrentInterval
()
>=
DEFAULT_STARTING_INTERVAL
&&
interval
.
getCurrentInterval
()
<=
DEFAULT_MAX_INTERVAL
).
toBeTruthy
();
setTimeout
(()
=>
{
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
expect
(
interval
.
getCurrentInterval
()
>=
DEFAULT_STARTING_INTERVAL
&&
interval
.
getCurrentInterval
()
<=
DEFAULT_MAX_INTERVAL
).
toBeTruthy
();
// simulates triggering of visibilitychange event
interval
.
handleVisibilityChange
({
target
:
{
visibilityState
:
'
hidden
'
}
});
// simulates triggering of visibilitychange event
interval
.
handleVisibilityChange
({
target
:
{
visibilityState
:
'
hidden
'
}
});
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
expect
(
interval
.
getCurrentInterval
()).
toBe
(
HIDDEN_INTERVAL
);
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
expect
(
interval
.
getCurrentInterval
()).
toBe
(
HIDDEN_INTERVAL
);
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
it
(
'
should resume when page is becomes visible at the previous interval
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
it
(
'
should resume when page is becomes visible at the previous interval
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
setTimeout
(()
=>
{
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
setTimeout
(()
=>
{
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
// simulates triggering of visibilitychange event
interval
.
handleVisibilityChange
({
target
:
{
visibilityState
:
'
hidden
'
}
});
// simulates triggering of visibilitychange event
interval
.
handleVisibilityChange
({
target
:
{
visibilityState
:
'
hidden
'
}
});
expect
(
interval
.
state
.
intervalId
).
toBeUndefined
();
expect
(
interval
.
state
.
intervalId
).
toBeUndefined
();
// simulates triggering of visibilitychange event
interval
.
handleVisibilityChange
({
target
:
{
visibilityState
:
'
visible
'
}
});
// simulates triggering of visibilitychange event
interval
.
handleVisibilityChange
({
target
:
{
visibilityState
:
'
visible
'
}
});
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
expect
(
interval
.
state
.
intervalId
).
toBeTruthy
();
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
it
(
'
should cancel on page unload
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
it
(
'
should cancel on page unload
'
,
function
(
done
)
{
const
interval
=
this
.
smartInterval
;
setTimeout
(()
=>
{
$
(
document
).
triggerHandler
(
'
beforeunload
'
);
expect
(
interval
.
state
.
intervalId
).
toBeUndefined
();
expect
(
interval
.
getCurrentInterval
()).
toBe
(
interval
.
cfg
.
startingInterval
);
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
setTimeout
(()
=>
{
$
(
document
).
triggerHandler
(
'
beforeunload
'
);
expect
(
interval
.
state
.
intervalId
).
toBeUndefined
();
expect
(
interval
.
getCurrentInterval
()).
toBe
(
interval
.
cfg
.
startingInterval
);
done
();
},
DEFAULT_SHORT_TIMEOUT
);
});
it
(
'
should execute callback before first interval
'
,
function
()
{
const
interval
=
createDefaultSmartInterval
({
immediateExecution
:
true
});
expect
(
interval
.
cfg
.
immediateExecution
).
toBeFalsy
();
});
it
(
'
should execute callback before first interval
'
,
function
()
{
const
interval
=
createDefaultSmartInterval
({
immediateExecution
:
true
});
expect
(
interval
.
cfg
.
immediateExecution
).
toBeFalsy
();
});
});
})
(
window
.
gl
||
(
window
.
gl
=
{}))
;
});
spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
View file @
4fac95a6
...
...
@@ -121,24 +121,28 @@ describe('mrWidgetOptions', () => {
describe
(
'
initPolling
'
,
()
=>
{
it
(
'
should call SmartInterval
'
,
()
=>
{
spyOn
(
gl
,
'
SmartInterval
'
).
and
.
returnValue
({
resume
()
{},
stopTimer
()
{},
});
spyOn
(
vm
,
'
checkStatus
'
).
and
.
returnValue
(
Promise
.
resolve
());
jasmine
.
clock
().
install
();
vm
.
initPolling
();
expect
(
vm
.
checkStatus
).
not
.
toHaveBeenCalled
();
jasmine
.
clock
().
tick
(
10000
);
expect
(
vm
.
pollingInterval
).
toBeDefined
();
expect
(
gl
.
SmartInterval
).
toHaveBeenCalled
();
expect
(
vm
.
checkStatus
).
toHaveBeenCalled
();
jasmine
.
clock
().
uninstall
();
});
});
describe
(
'
initDeploymentsPolling
'
,
()
=>
{
it
(
'
should call SmartInterval
'
,
()
=>
{
spyOn
(
gl
,
'
SmartInterval
'
);
spyOn
(
vm
,
'
fetchDeployments
'
).
and
.
returnValue
(
Promise
.
resolve
()
);
vm
.
initDeploymentsPolling
();
expect
(
vm
.
deploymentsInterval
).
toBeDefined
();
expect
(
gl
.
SmartInterval
).
toHaveBeenCalled
();
expect
(
vm
.
fetchDeployments
).
toHaveBeenCalled
();
});
});
...
...
spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js
0 → 100644
View file @
4fac95a6
import
Vue
from
'
vue
'
;
import
skeletonLoadingContainer
from
'
~/vue_shared/components/skeleton_loading_container.vue
'
;
import
mountComponent
from
'
../../helpers/vue_mount_component_helper
'
;
describe
(
'
Skeleton loading container
'
,
()
=>
{
let
vm
;
beforeEach
(()
=>
{
const
component
=
Vue
.
extend
(
skeletonLoadingContainer
);
vm
=
mountComponent
(
component
);
});
afterEach
(()
=>
{
vm
.
$destroy
();
});
it
(
'
renders 6 skeleton lines by default
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.skeleton-line-6
'
)).
not
.
toBeNull
();
});
it
(
'
renders in full mode by default
'
,
()
=>
{
expect
(
vm
.
$el
.
classList
.
contains
(
'
animation-container-small
'
)).
toBeFalsy
();
});
describe
(
'
small
'
,
()
=>
{
beforeEach
((
done
)
=>
{
vm
.
small
=
true
;
Vue
.
nextTick
(
done
);
});
it
(
'
renders in small mode
'
,
()
=>
{
expect
(
vm
.
$el
.
classList
.
contains
(
'
animation-container-small
'
)).
toBeTruthy
();
});
});
describe
(
'
lines
'
,
()
=>
{
beforeEach
((
done
)
=>
{
vm
.
lines
=
5
;
Vue
.
nextTick
(
done
);
});
it
(
'
renders 5 lines
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.skeleton-line-5
'
)).
not
.
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
.skeleton-line-6
'
)).
toBeNull
();
});
});
});
spec/lib/gitlab/ci/status/build/factory_spec.rb
View file @
4fac95a6
...
...
@@ -84,7 +84,7 @@ describe Gitlab::Ci::Status::Build::Factory do
it
'fabricates status with correct details'
do
expect
(
status
.
text
).
to
eq
'failed'
expect
(
status
.
icon
).
to
eq
'warning'
expect
(
status
.
icon
).
to
eq
'
status_
warning'
expect
(
status
.
favicon
).
to
eq
'favicon_status_failed'
expect
(
status
.
label
).
to
eq
'failed (allowed to fail)'
expect
(
status
).
to
have_details
...
...
spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
View file @
4fac95a6
...
...
@@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Build::FailedAllowed do
describe
'#icon'
do
it
'returns a warning icon'
do
expect
(
subject
.
icon
).
to
eq
'warning'
expect
(
subject
.
icon
).
to
eq
'
status_
warning'
end
end
...
...
spec/lib/gitlab/database/grant_spec.rb
View file @
4fac95a6
require
'spec_helper'
describe
Gitlab
::
Database
::
Grant
do
describe
'.scope_to_current_user'
do
it
'scopes the relation to the current user'
do
user
=
Gitlab
::
Database
.
username
column
=
Gitlab
::
Database
.
postgresql?
?
:grantee
:
:User
names
=
described_class
.
scope_to_current_user
.
pluck
(
column
).
uniq
expect
(
names
).
to
eq
([
user
])
end
end
describe
'.create_and_execute_trigger'
do
it
'returns true when the user can create and execute a trigger'
do
# We assume the DB/user is set up correctly so that triggers can be
...
...
@@ -18,13 +8,11 @@ describe Gitlab::Database::Grant do
expect
(
described_class
.
create_and_execute_trigger?
(
'users'
)).
to
eq
(
true
)
end
it
'returns false when the user can not create and/or execute a trigger'
do
allow
(
described_class
).
to
receive
(
:scope_to_current_user
)
.
and_return
(
described_class
.
none
)
result
=
described_class
.
create_and_execute_trigger?
(
'kittens'
)
expect
(
result
).
to
eq
(
false
)
it
'returns false when the user can not create and/or execute a trigger'
,
:postgresql
do
# In case of MySQL the user may have SUPER permissions, making it
# impossible to have `false` returned when running tests; hence we only
# run these tests on PostgreSQL.
expect
(
described_class
.
create_and_execute_trigger?
(
'foo'
)).
to
eq
(
false
)
end
end
end
spec/lib/gitlab/import_export/merge_request_parser_spec.rb
View file @
4fac95a6
...
...
@@ -13,7 +13,7 @@ describe Gitlab::ImportExport::MergeRequestParser do
let
(
:parsed_merge_request
)
do
described_class
.
new
(
project
,
merge_request
.
diff_head_sha
,
'abcd'
,
merge_request
,
merge_request
.
as_json
).
parse!
end
...
...
@@ -29,4 +29,14 @@ describe Gitlab::ImportExport::MergeRequestParser do
it
'has a target branch'
do
expect
(
project
.
repository
.
branch_exists?
(
parsed_merge_request
.
target_branch
)).
to
be
true
end
it
'parses a MR that has no source branch'
do
allow_any_instance_of
(
described_class
).
to
receive
(
:branch_exists?
).
and_call_original
allow_any_instance_of
(
described_class
).
to
receive
(
:branch_exists?
).
with
(
merge_request
.
source_branch
).
and_return
(
false
)
allow_any_instance_of
(
described_class
).
to
receive
(
:fork_merge_request?
).
and_return
(
true
)
allow
(
Gitlab
::
GitalyClient
).
to
receive
(
:migrate
).
and_call_original
allow
(
Gitlab
::
GitalyClient
).
to
receive
(
:migrate
).
with
(
:fetch_ref
).
and_return
([
nil
,
0
])
expect
(
parsed_merge_request
).
to
eq
(
merge_request
)
end
end
spec/lib/google_api/cloud_platform/client_spec.rb
View file @
4fac95a6
...
...
@@ -69,7 +69,7 @@ describe GoogleApi::CloudPlatform::Client do
let
(
:cluster_name
)
{
'test-cluster'
}
let
(
:cluster_size
)
{
1
}
let
(
:machine_type
)
{
'n1-standard-
4
'
}
let
(
:machine_type
)
{
'n1-standard-
2
'
}
let
(
:operation
)
{
double
}
before
do
...
...
spec/models/clusters/providers/gcp_spec.rb
View file @
4fac95a6
...
...
@@ -10,7 +10,7 @@ describe Clusters::Providers::Gcp do
it
"has default value"
do
expect
(
gcp
.
zone
).
to
eq
(
'us-central1-a'
)
expect
(
gcp
.
num_nodes
).
to
eq
(
3
)
expect
(
gcp
.
machine_type
).
to
eq
(
'n1-standard-
4
'
)
expect
(
gcp
.
machine_type
).
to
eq
(
'n1-standard-
2
'
)
end
end
...
...
spec/models/commit_status_spec.rb
View file @
4fac95a6
require
'spec_helper'
describe
CommitStatus
do
l
et
(
:project
)
{
create
(
:project
,
:repository
)
}
s
et
(
:project
)
{
create
(
:project
,
:repository
)
}
l
et
(
:pipeline
)
do
s
et
(
:pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
)
end
...
...
@@ -464,4 +464,73 @@ describe CommitStatus do
it
{
is_expected
.
to
be_script_failure
}
end
end
describe
'ensure stage assignment'
do
context
'when commit status has a stage_id assigned'
do
let!
(
:stage
)
do
create
(
:ci_stage_entity
,
project:
project
,
pipeline:
pipeline
)
end
let
(
:commit_status
)
do
create
(
:commit_status
,
stage_id:
stage
.
id
,
name:
'rspec'
,
stage:
'test'
)
end
it
'does not create a new stage'
do
expect
{
commit_status
}.
not_to
change
{
Ci
::
Stage
.
count
}
expect
(
commit_status
.
stage_id
).
to
eq
stage
.
id
end
end
context
'when commit status does not have a stage_id assigned'
do
let
(
:commit_status
)
do
create
(
:commit_status
,
name:
'rspec'
,
stage:
'test'
,
status: :success
)
end
let
(
:stage
)
{
Ci
::
Stage
.
first
}
it
'creates a new stage'
do
expect
{
commit_status
}.
to
change
{
Ci
::
Stage
.
count
}.
by
(
1
)
expect
(
stage
.
name
).
to
eq
'test'
expect
(
stage
.
project
).
to
eq
commit_status
.
project
expect
(
stage
.
pipeline
).
to
eq
commit_status
.
pipeline
expect
(
stage
.
status
).
to
eq
commit_status
.
status
expect
(
commit_status
.
stage_id
).
to
eq
stage
.
id
end
end
context
'when commit status does not have stage but it exists'
do
let!
(
:stage
)
do
create
(
:ci_stage_entity
,
project:
project
,
pipeline:
pipeline
,
name:
'test'
)
end
let
(
:commit_status
)
do
create
(
:commit_status
,
project:
project
,
pipeline:
pipeline
,
name:
'rspec'
,
stage:
'test'
,
status: :success
)
end
it
'uses existing stage'
do
expect
{
commit_status
}.
not_to
change
{
Ci
::
Stage
.
count
}
expect
(
commit_status
.
stage_id
).
to
eq
stage
.
id
expect
(
stage
.
reload
.
status
).
to
eq
commit_status
.
status
end
end
context
'when commit status is being imported'
do
let
(
:commit_status
)
do
create
(
:commit_status
,
name:
'rspec'
,
stage:
'test'
,
importing:
true
)
end
it
'does not create a new stage'
do
expect
{
commit_status
}.
not_to
change
{
Ci
::
Stage
.
count
}
expect
(
commit_status
.
stage_id
).
not_to
be_present
end
end
end
end
spec/serializers/pipeline_details_entity_spec.rb
View file @
4fac95a6
...
...
@@ -107,7 +107,7 @@ describe PipelineDetailsEntity do
it
'contains stages'
do
expect
(
subject
).
to
include
(
:details
)
expect
(
subject
[
:details
]).
to
include
(
:stages
)
expect
(
subject
[
:details
][
:stages
].
first
).
to
include
(
name:
'
external
'
)
expect
(
subject
[
:details
][
:stages
].
first
).
to
include
(
name:
'
test
'
)
end
end
...
...
spec/support/cycle_analytics_helpers.rb
View file @
4fac95a6
...
...
@@ -94,6 +94,7 @@ module CycleAnalyticsHelpers
ref:
'master'
,
tag:
false
,
name:
'dummy'
,
stage:
'dummy'
,
pipeline:
dummy_pipeline
,
protected:
false
)
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