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
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
5ecacec3
Commit
5ecacec3
authored
Oct 04, 2019
by
GitLab Bot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add latest changes from gitlab-org/gitlab@master
parent
0d46bf06
Changes
47
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
47 changed files
with
1527 additions
and
499 deletions
+1527
-499
.gitlab/ci/frontend.gitlab-ci.yml
.gitlab/ci/frontend.gitlab-ci.yml
+24
-6
.gitlab/ci/global.gitlab-ci.yml
.gitlab/ci/global.gitlab-ci.yml
+5
-0
.gitlab/ci/rails.gitlab-ci.yml
.gitlab/ci/rails.gitlab-ci.yml
+19
-0
app/assets/javascripts/gfm_auto_complete.js
app/assets/javascripts/gfm_auto_complete.js
+1
-0
app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
...vascripts/ide/components/commit_sidebar/editor_header.vue
+6
-1
app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
...s/javascripts/ide/components/commit_sidebar/list_item.vue
+3
-0
app/assets/javascripts/ide/components/file_row_extra.vue
app/assets/javascripts/ide/components/file_row_extra.vue
+8
-2
app/assets/javascripts/ide/components/ide_tree_list.vue
app/assets/javascripts/ide/components/ide_tree_list.vue
+2
-5
app/assets/javascripts/ide/components/new_dropdown/modal.vue
app/assets/javascripts/ide/components/new_dropdown/modal.vue
+0
-1
app/assets/javascripts/ide/components/repo_editor.vue
app/assets/javascripts/ide/components/repo_editor.vue
+15
-9
app/assets/javascripts/ide/lib/files.js
app/assets/javascripts/ide/lib/files.js
+1
-3
app/assets/javascripts/ide/stores/actions.js
app/assets/javascripts/ide/stores/actions.js
+47
-24
app/assets/javascripts/ide/stores/actions/file.js
app/assets/javascripts/ide/stores/actions/file.js
+2
-7
app/assets/javascripts/ide/stores/actions/project.js
app/assets/javascripts/ide/stores/actions/project.js
+47
-37
app/assets/javascripts/ide/stores/modules/commit/actions.js
app/assets/javascripts/ide/stores/modules/commit/actions.js
+0
-2
app/assets/javascripts/ide/stores/mutation_types.js
app/assets/javascripts/ide/stores/mutation_types.js
+2
-2
app/assets/javascripts/ide/stores/mutations.js
app/assets/javascripts/ide/stores/mutations.js
+63
-44
app/assets/javascripts/ide/stores/mutations/file.js
app/assets/javascripts/ide/stores/mutations/file.js
+11
-7
app/assets/javascripts/ide/stores/state.js
app/assets/javascripts/ide/stores/state.js
+0
-1
app/assets/javascripts/ide/stores/utils.js
app/assets/javascripts/ide/stores/utils.js
+63
-7
app/assets/javascripts/vue_shared/components/changed_file_icon.vue
...s/javascripts/vue_shared/components/changed_file_icon.vue
+7
-1
app/assets/javascripts/vue_shared/components/file_row.vue
app/assets/javascripts/vue_shared/components/file_row.vue
+1
-1
app/assets/stylesheets/framework/animations.scss
app/assets/stylesheets/framework/animations.scss
+0
-15
app/graphql/resolvers/issues_resolver.rb
app/graphql/resolvers/issues_resolver.rb
+1
-1
app/graphql/types/issuable_sort_enum.rb
app/graphql/types/issuable_sort_enum.rb
+10
-0
app/graphql/types/issue_sort_enum.rb
app/graphql/types/issue_sort_enum.rb
+10
-0
changelogs/unreleased/17596-show-all-matching-labels-when-using-label-quick-action.yml
...how-all-matching-labels-when-using-label-quick-action.yml
+5
-0
jest.config.js
jest.config.js
+4
-1
lib/gitlab/import_export/project_tree_restorer.rb
lib/gitlab/import_export/project_tree_restorer.rb
+2
-2
lib/gitlab/sidekiq_config.rb
lib/gitlab/sidekiq_config.rb
+10
-4
lib/tasks/frontend.rake
lib/tasks/frontend.rake
+4
-1
spec/controllers/projects/environments_controller_spec.rb
spec/controllers/projects/environments_controller_spec.rb
+2
-2
spec/frontend/fixtures/autocomplete_sources.rb
spec/frontend/fixtures/autocomplete_sources.rb
+4
-0
spec/frontend/ide/lib/files_spec.js
spec/frontend/ide/lib/files_spec.js
+2
-2
spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
...vascripts/ide/components/commit_sidebar/list_item_spec.js
+31
-3
spec/javascripts/ide/components/file_row_extra_spec.js
spec/javascripts/ide/components/file_row_extra_spec.js
+21
-0
spec/javascripts/ide/components/ide_tree_list_spec.js
spec/javascripts/ide/components/ide_tree_list_spec.js
+0
-14
spec/javascripts/ide/components/repo_editor_spec.js
spec/javascripts/ide/components/repo_editor_spec.js
+63
-20
spec/javascripts/ide/stores/actions/project_spec.js
spec/javascripts/ide/stores/actions/project_spec.js
+133
-64
spec/javascripts/ide/stores/actions_spec.js
spec/javascripts/ide/stores/actions_spec.js
+294
-57
spec/javascripts/ide/stores/modules/commit/actions_spec.js
spec/javascripts/ide/stores/modules/commit/actions_spec.js
+52
-40
spec/javascripts/ide/stores/mutations/file_spec.js
spec/javascripts/ide/stores/mutations/file_spec.js
+3
-16
spec/javascripts/ide/stores/mutations_spec.js
spec/javascripts/ide/stores/mutations_spec.js
+339
-50
spec/javascripts/ide/stores/utils_spec.js
spec/javascripts/ide/stores/utils_spec.js
+200
-25
spec/javascripts/lazy_loader_spec.js
spec/javascripts/lazy_loader_spec.js
+9
-9
spec/javascripts/vue_shared/components/file_row_spec.js
spec/javascripts/vue_shared/components/file_row_spec.js
+0
-13
spec/lib/gitlab_spec.rb
spec/lib/gitlab_spec.rb
+1
-0
No files found.
.gitlab/ci/frontend.gitlab-ci.yml
View file @
5ecacec3
...
...
@@ -123,7 +123,7 @@ compile-assets pull-cache:
-
.use-pg9
dependencies
:
[
"
compile-assets"
,
"
compile-assets
pull-cache"
,
"
setup-test-env"
]
karma
:
.karma-base
:
extends
:
.only-code-frontend-job-base
variables
:
# we override the max_old_space_size to prevent OOM errors
...
...
@@ -134,6 +134,9 @@ karma:
-
scripts/gitaly-test-spawn
-
date
-
bundle exec rake karma
karma
:
extends
:
.karma-base
coverage
:
'
/^Statements
*:
(\d+\.\d+%)/'
artifacts
:
name
:
coverage-javascript
...
...
@@ -146,7 +149,12 @@ karma:
reports
:
junit
:
junit_karma.xml
jest
:
karma-foss
:
extends
:
-
.karma-base
-
.only-ee-as-if-foss
.jest-base
:
extends
:
.only-code-frontend-job-base
script
:
-
scripts/gitaly-test-spawn
...
...
@@ -154,6 +162,14 @@ jest:
-
bundle exec rake frontend:fixtures
-
date
-
yarn jest --ci --coverage
cache
:
key
:
jest
paths
:
-
tmp/jest/jest/
policy
:
pull-push
jest
:
extends
:
.jest-base
artifacts
:
name
:
coverage-frontend
expire_in
:
31d
...
...
@@ -164,11 +180,13 @@ jest:
-
tmp/tests/frontend/
reports
:
junit
:
junit_jest.xml
jest-foss
:
extends
:
-
.jest-base
-
.only-ee-as-if-foss
cache
:
key
:
jest
paths
:
-
tmp/jest/jest/
policy
:
pull-push
policy
:
pull
.qa-job-base
:
extends
:
...
...
.gitlab/ci/global.gitlab-ci.yml
View file @
5ecacec3
...
...
@@ -149,3 +149,8 @@
variables
:
-
$CI_PROJECT_NAME == "gitlab"
-
$CI_PROJECT_NAME == "gitlab-ee"
# Support former project name for forks/mirrors
.only-ee-as-if-foss
:
extends
:
.only-ee
variables
:
IS_GITLAB_EE
:
'
0'
.gitlab/ci/rails.gitlab-ci.yml
View file @
5ecacec3
...
...
@@ -74,6 +74,12 @@ setup-test-env:
-
.rspec-base
-
.use-pg9
.rspec-base-pg9-foss
:
extends
:
-
.rspec-base
-
.use-pg9
-
.only-ee-as-if-foss
.rspec-base-pg10
:
extends
:
-
.rspec-base
...
...
@@ -84,14 +90,27 @@ rspec unit pg9:
extends
:
.rspec-base-pg9
parallel
:
20
rspec unit pg9-foss
:
extends
:
.rspec-base-pg9-foss
parallel
:
20
rspec integration pg9
:
extends
:
.rspec-base-pg9
parallel
:
6
rspec integration pg9-foss
:
extends
:
.rspec-base-pg9-foss
parallel
:
6
rspec system pg9
:
extends
:
.rspec-base-pg9
parallel
:
24
# TODO: This requires FOSS assets
# rspec system pg9-foss:
# extends: .rspec-base-pg9-foss
# parallel: 24
rspec unit pg10
:
extends
:
.rspec-base-pg10
parallel
:
20
...
...
app/assets/javascripts/gfm_auto_complete.js
View file @
5ecacec3
...
...
@@ -337,6 +337,7 @@ class GfmAutoComplete {
},
// eslint-disable-next-line no-template-curly-in-string
insertTpl
:
'
${atwho-at}${title}
'
,
limit
:
20
,
callbacks
:
{
...
this
.
getDefaultCallbacks
(),
beforeSave
(
merges
)
{
...
...
app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
View file @
5ecacec3
...
...
@@ -43,7 +43,12 @@ export default {
<
template
>
<div
class=
"d-flex ide-commit-editor-header align-items-center"
>
<file-icon
:file-name=
"activeFile.name"
:size=
"16"
class=
"mr-2"
/>
<strong
class=
"mr-2"
>
{{
activeFile
.
path
}}
</strong>
<strong
class=
"mr-2"
>
<template
v-if=
"activeFile.prevPath && activeFile.prevPath !== activeFile.path"
>
{{
activeFile
.
prevPath
}}
→
</
template
>
{{ activeFile.path }}
</strong>
<changed-file-icon
:file=
"activeFile"
:is-centered=
"false"
/>
<div
class=
"ml-auto"
>
<button
...
...
app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
View file @
5ecacec3
...
...
@@ -110,6 +110,9 @@ export default {
>
<span
class=
"multi-file-commit-list-file-path d-flex align-items-center"
>
<file-icon
:file-name=
"file.name"
class=
"append-right-8"
/>
<template
v-if=
"file.prevName && file.prevName !== file.name"
>
{{
file
.
prevName
}}
→
</
template
>
{{ file.name }}
</span>
<div
class=
"ml-auto d-flex align-items-center"
>
...
...
app/assets/javascripts/ide/components/file_row_extra.vue
View file @
5ecacec3
...
...
@@ -34,6 +34,9 @@ export default {
'
getUnstagedFilesCountForPath
'
,
'
getStagedFilesCountForPath
'
,
]),
isTree
()
{
return
this
.
file
.
type
===
'
tree
'
;
},
folderUnstagedCount
()
{
return
this
.
getUnstagedFilesCountForPath
(
this
.
file
.
path
);
},
...
...
@@ -58,10 +61,13 @@ export default {
});
},
showTreeChangesCount
()
{
return
this
.
file
.
type
===
'
tree
'
&&
this
.
changesCount
>
0
&&
!
this
.
file
.
opened
;
return
this
.
isTree
&&
this
.
changesCount
>
0
&&
!
this
.
file
.
opened
;
},
isModified
()
{
return
this
.
file
.
changed
||
this
.
file
.
tempFile
||
this
.
file
.
staged
||
this
.
file
.
prevPath
;
},
showChangedFileIcon
()
{
return
this
.
file
.
changed
||
this
.
file
.
tempFile
||
this
.
file
.
stag
ed
;
return
!
this
.
isTree
&&
this
.
isModifi
ed
;
},
},
};
...
...
app/assets/javascripts/ide/components/ide_tree_list.vue
View file @
5ecacec3
...
...
@@ -30,9 +30,6 @@ export default {
showLoading
()
{
return
!
this
.
currentTree
||
this
.
currentTree
.
loading
;
},
actualTreeList
()
{
return
this
.
currentTree
.
tree
.
filter
(
entry
=>
!
entry
.
moved
);
},
},
mounted
()
{
this
.
updateViewer
(
this
.
viewerType
);
...
...
@@ -57,9 +54,9 @@ export default {
<slot
name=
"header"
></slot>
</header>
<div
class=
"ide-tree-body h-100"
>
<template
v-if=
"
actualTreeList
.length"
>
<template
v-if=
"
currentTree.tree
.length"
>
<file-row
v-for=
"file in
actualTreeList
"
v-for=
"file in
currentTree.tree
"
:key=
"file.key"
:file=
"file"
:level=
"0"
...
...
app/assets/javascripts/ide/components/new_dropdown/modal.vue
View file @
5ecacec3
...
...
@@ -91,7 +91,6 @@ export default {
this
.
renameEntry
({
path
:
this
.
entryModal
.
entry
.
path
,
name
:
entryName
,
entryPath
:
null
,
parentPath
,
}),
)
...
...
app/assets/javascripts/ide/components/repo_editor.vue
View file @
5ecacec3
...
...
@@ -155,15 +155,7 @@ export default {
this
.
editor
.
clearEditor
();
this
.
getFileData
({
path
:
this
.
file
.
path
,
makeFileActive
:
false
,
})
.
then
(()
=>
this
.
getRawFileData
({
path
:
this
.
file
.
path
,
}),
)
this
.
fetchFileData
()
.
then
(()
=>
{
this
.
createEditorInstance
();
})
...
...
@@ -179,6 +171,20 @@ export default {
throw
err
;
});
},
fetchFileData
()
{
if
(
this
.
file
.
tempFile
)
{
return
Promise
.
resolve
();
}
return
this
.
getFileData
({
path
:
this
.
file
.
path
,
makeFileActive
:
false
,
}).
then
(()
=>
this
.
getRawFileData
({
path
:
this
.
file
.
path
,
}),
);
},
createEditorInstance
()
{
this
.
editor
.
dispose
();
...
...
app/assets/javascripts/ide/lib/files.js
View file @
5ecacec3
import
{
viewerInformationForPath
}
from
'
~/vue_shared/components/content_viewer/lib/viewer_utils
'
;
import
{
decorateData
,
sortTree
}
from
'
../stores/utils
'
;
export
const
escapeFileUrl
=
fileUrl
=>
encodeURIComponent
(
fileUrl
).
replace
(
/%2F/g
,
'
/
'
);
import
{
decorateData
,
sortTree
,
escapeFileUrl
}
from
'
../stores/utils
'
;
export
const
splitParent
=
path
=>
{
const
idx
=
path
.
lastIndexOf
(
'
/
'
);
...
...
app/assets/javascripts/ide/stores/actions.js
View file @
5ecacec3
...
...
@@ -9,6 +9,7 @@ import { decorateFiles } from '../lib/files';
import
{
stageKeys
}
from
'
../constants
'
;
import
service
from
'
../services
'
;
import
router
from
'
../ide_router
'
;
import
eventHub
from
'
../eventhub
'
;
export
const
redirectToUrl
=
(
self
,
url
)
=>
visitUrl
(
url
);
...
...
@@ -171,8 +172,10 @@ export const setCurrentBranchId = ({ commit }, currentBranchId) => {
export
const
updateTempFlagForEntry
=
({
commit
,
dispatch
,
state
},
{
file
,
tempFile
})
=>
{
commit
(
types
.
UPDATE_TEMP_FLAG
,
{
path
:
file
.
path
,
tempFile
});
if
(
file
.
parentPath
)
{
dispatch
(
'
updateTempFlagForEntry
'
,
{
file
:
state
.
entries
[
file
.
parentPath
],
tempFile
});
const
parent
=
file
.
parentPath
&&
state
.
entries
[
file
.
parentPath
];
if
(
parent
)
{
dispatch
(
'
updateTempFlagForEntry
'
,
{
file
:
parent
,
tempFile
});
}
};
...
...
@@ -199,51 +202,71 @@ export const openNewEntryModal = ({ commit }, { type, path = '' }) => {
export
const
deleteEntry
=
({
commit
,
dispatch
,
state
},
path
)
=>
{
const
entry
=
state
.
entries
[
path
];
const
{
prevPath
,
prevName
,
prevParentPath
}
=
entry
;
const
isTree
=
entry
.
type
===
'
tree
'
;
if
(
prevPath
)
{
dispatch
(
'
renameEntry
'
,
{
path
,
name
:
prevName
,
parentPath
:
prevParentPath
,
});
dispatch
(
'
deleteEntry
'
,
prevPath
);
return
;
}
if
(
state
.
unusedSeal
)
dispatch
(
'
burstUnusedSeal
'
);
if
(
entry
.
opened
)
dispatch
(
'
closeFile
'
,
entry
);
if
(
entry
.
type
===
'
tree
'
)
{
if
(
isTree
)
{
entry
.
tree
.
forEach
(
f
=>
dispatch
(
'
deleteEntry
'
,
f
.
path
));
}
commit
(
types
.
DELETE_ENTRY
,
path
);
dispatch
(
'
stageChange
'
,
path
);
// Only stage if we're not a directory or a new file
if
(
!
isTree
&&
!
entry
.
tempFile
)
{
dispatch
(
'
stageChange
'
,
path
);
}
dispatch
(
'
triggerFilesChange
'
);
};
export
const
resetOpenFiles
=
({
commit
})
=>
commit
(
types
.
RESET_OPEN_FILES
);
export
const
renameEntry
=
(
{
dispatch
,
commit
,
state
},
{
path
,
name
,
entryPath
=
null
,
parentPath
},
)
=>
{
const
entry
=
state
.
entries
[
entryPath
||
path
];
export
const
renameEntry
=
({
dispatch
,
commit
,
state
},
{
path
,
name
,
parentPath
})
=>
{
const
entry
=
state
.
entries
[
path
];
const
newPath
=
parentPath
?
`
${
parentPath
}
/
${
name
}
`
:
name
;
commit
(
types
.
RENAME_ENTRY
,
{
path
,
name
,
entryPath
,
parentPath
});
commit
(
types
.
RENAME_ENTRY
,
{
path
,
name
,
parentPath
});
if
(
entry
.
type
===
'
tree
'
)
{
const
slashedParentPath
=
parentPath
?
`
${
parentPath
}
/`
:
''
;
const
targetEntry
=
entryPath
?
entryPath
.
split
(
'
/
'
).
pop
()
:
name
;
const
newParentPath
=
`
${
slashedParentPath
}${
targetEntry
}
`
;
state
.
entries
[
entryPath
||
path
].
tree
.
forEach
(
f
=>
{
state
.
entries
[
newPath
].
tree
.
forEach
(
f
=>
{
dispatch
(
'
renameEntry
'
,
{
path
,
name
,
entryPath
:
f
.
path
,
parentPath
:
newParentPath
,
path
:
f
.
path
,
name
:
f
.
name
,
parentPath
:
newPath
,
});
});
}
else
{
const
newPath
=
parentPath
?
`
${
parentPath
}
/
${
name
}
`
:
name
;
const
newEntry
=
state
.
entries
[
newPath
];
commit
(
types
.
TOGGLE_FILE_CHANGED
,
{
file
:
newEntry
,
changed
:
true
});
const
isRevert
=
newPath
===
entry
.
prevPath
;
const
isReset
=
isRevert
&&
!
newEntry
.
changed
&&
!
newEntry
.
tempFile
;
const
isInChanges
=
state
.
changedFiles
.
concat
(
state
.
stagedFiles
)
.
some
(({
key
})
=>
key
===
newEntry
.
key
);
if
(
isReset
)
{
commit
(
types
.
REMOVE_FILE_FROM_STAGED_AND_CHANGED
,
newEntry
);
}
else
if
(
!
isInChanges
)
{
commit
(
types
.
ADD_FILE_TO_CHANGED
,
newPath
);
}
if
(
!
newEntry
.
tempFile
)
{
eventHub
.
$emit
(
`editor.update.model.dispose.
${
entry
.
key
}
`
);
}
if
(
e
ntry
.
opened
)
{
if
(
newE
ntry
.
opened
)
{
router
.
push
(
`/project
${
newEntry
.
url
}
`
);
commit
(
types
.
TOGGLE_FILE_OPEN
,
entry
.
path
);
}
}
...
...
app/assets/javascripts/ide/stores/actions/file.js
View file @
5ecacec3
...
...
@@ -5,7 +5,7 @@ import eventHub from '../../eventhub';
import
service
from
'
../../services
'
;
import
*
as
types
from
'
../mutation_types
'
;
import
router
from
'
../../ide_router
'
;
import
{
setPageTitle
}
from
'
../utils
'
;
import
{
setPageTitle
,
replaceFileUrl
}
from
'
../utils
'
;
import
{
viewerTypes
,
stageKeys
}
from
'
../../constants
'
;
export
const
closeFile
=
({
commit
,
state
,
dispatch
},
file
)
=>
{
...
...
@@ -67,7 +67,7 @@ export const getFileData = (
commit
(
types
.
TOGGLE_LOADING
,
{
entry
:
file
});
const
url
=
file
.
prevPath
?
file
.
url
.
replace
(
file
.
path
,
file
.
prevPath
)
:
file
.
url
;
const
url
=
file
.
prevPath
?
replaceFileUrl
(
file
.
url
,
file
.
path
,
file
.
prevPath
)
:
file
.
url
;
return
service
.
getFileData
(
joinPaths
(
gon
.
relative_url_root
||
''
,
url
.
replace
(
'
/-/
'
,
'
/
'
)))
...
...
@@ -186,11 +186,6 @@ export const discardFileChanges = ({ dispatch, state, commit, getters }, path) =
dispatch
(
'
restoreTree
'
,
file
.
parentPath
);
}
if
(
file
.
movedPath
)
{
commit
(
types
.
DISCARD_FILE_CHANGES
,
file
.
movedPath
);
commit
(
types
.
REMOVE_FILE_FROM_CHANGED
,
file
.
movedPath
);
}
commit
(
types
.
DISCARD_FILE_CHANGES
,
path
);
commit
(
types
.
REMOVE_FILE_FROM_CHANGED
,
path
);
...
...
app/assets/javascripts/ide/stores/actions/project.js
View file @
5ecacec3
...
...
@@ -92,13 +92,27 @@ export const showEmptyState = ({ commit, state }, { projectId, branchId }) => {
});
};
export
const
openBranch
=
({
dispatch
,
state
,
getters
},
{
projectId
,
branchId
,
basePath
})
=>
{
dispatch
(
'
setCurrentBranchId
'
,
branchId
);
export
const
loadFile
=
({
dispatch
,
state
},
{
basePath
})
=>
{
if
(
basePath
)
{
const
path
=
basePath
.
slice
(
-
1
)
===
'
/
'
?
basePath
.
slice
(
0
,
-
1
)
:
basePath
;
const
treeEntryKey
=
Object
.
keys
(
state
.
entries
).
find
(
key
=>
key
===
path
&&
!
state
.
entries
[
key
].
pending
,
);
const
treeEntry
=
state
.
entries
[
treeEntryKey
];
if
(
getters
.
emptyRepo
)
{
return
dispatch
(
'
showEmptyState
'
,
{
projectId
,
branchId
});
if
(
treeEntry
)
{
dispatch
(
'
handleTreeEntryAction
'
,
treeEntry
);
}
else
{
dispatch
(
'
createTempEntry
'
,
{
name
:
path
,
type
:
'
blob
'
,
});
}
}
return
dispatch
(
'
getBranchData
'
,
{
};
export
const
loadBranch
=
({
dispatch
},
{
projectId
,
branchId
})
=>
dispatch
(
'
getBranchData
'
,
{
projectId
,
branchId
,
})
...
...
@@ -107,42 +121,38 @@ export const openBranch = ({ dispatch, state, getters }, { projectId, branchId,
projectId
,
branchId
,
});
dispatch
(
'
getFiles
'
,
{
return
dispatch
(
'
getFiles
'
,
{
projectId
,
branchId
,
})
.
then
(()
=>
{
if
(
basePath
)
{
const
path
=
basePath
.
slice
(
-
1
)
===
'
/
'
?
basePath
.
slice
(
0
,
-
1
)
:
basePath
;
const
treeEntryKey
=
Object
.
keys
(
state
.
entries
).
find
(
key
=>
key
===
path
&&
!
state
.
entries
[
key
].
pending
,
);
const
treeEntry
=
state
.
entries
[
treeEntryKey
];
if
(
treeEntry
)
{
dispatch
(
'
handleTreeEntryAction
'
,
treeEntry
);
}
else
{
dispatch
(
'
createTempEntry
'
,
{
name
:
path
,
type
:
'
blob
'
,
});
}
}
})
.
catch
(
()
=>
new
Error
(
sprintf
(
__
(
'
An error occurred whilst getting files for - %{branchId}
'
),
{
branchId
:
`<strong>
${
_
.
escape
(
projectId
)}
/
${
_
.
escape
(
branchId
)}
</strong>`
,
},
false
,
),
),
);
});
})
.
catch
(()
=>
{
dispatch
(
'
showBranchNotFoundError
'
,
branchId
);
return
Promise
.
reject
();
});
export
const
openBranch
=
({
dispatch
,
state
,
getters
},
{
projectId
,
branchId
,
basePath
})
=>
{
const
currentProject
=
state
.
projects
[
projectId
];
if
(
getters
.
emptyRepo
)
{
return
dispatch
(
'
showEmptyState
'
,
{
projectId
,
branchId
});
}
if
(
!
currentProject
||
!
currentProject
.
branches
[
branchId
])
{
dispatch
(
'
setCurrentBranchId
'
,
branchId
);
return
dispatch
(
'
loadBranch
'
,
{
projectId
,
branchId
})
.
then
(()
=>
dispatch
(
'
loadFile
'
,
{
basePath
}))
.
catch
(
()
=>
new
Error
(
sprintf
(
__
(
'
An error occurred whilst getting files for - %{branchId}
'
),
{
branchId
:
`<strong>
${
_
.
escape
(
projectId
)}
/
${
_
.
escape
(
branchId
)}
</strong>`
,
},
false
,
),
),
);
}
return
Promise
.
resolve
(
dispatch
(
'
loadFile
'
,
{
basePath
}));
};
app/assets/javascripts/ide/stores/modules/commit/actions.js
View file @
5ecacec3
...
...
@@ -154,8 +154,6 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
.
then
(()
=>
{
commit
(
rootTypes
.
CLEAR_STAGED_CHANGES
,
null
,
{
root
:
true
});
commit
(
rootTypes
.
CLEAR_REPLACED_FILES
,
null
,
{
root
:
true
});
setTimeout
(()
=>
{
commit
(
rootTypes
.
SET_LAST_COMMIT_MSG
,
''
,
{
root
:
true
});
},
5000
);
...
...
app/assets/javascripts/ide/stores/mutation_types.js
View file @
5ecacec3
...
...
@@ -59,8 +59,7 @@ export const UPDATE_DELAY_VIEWER_CHANGE = 'UPDATE_DELAY_VIEWER_CHANGE';
export
const
CLEAR_STAGED_CHANGES
=
'
CLEAR_STAGED_CHANGES
'
;
export
const
STAGE_CHANGE
=
'
STAGE_CHANGE
'
;
export
const
UNSTAGE_CHANGE
=
'
UNSTAGE_CHANGE
'
;
export
const
CLEAR_REPLACED_FILES
=
'
CLEAR_REPLACED_FILES
'
;
export
const
REMOVE_FILE_FROM_STAGED_AND_CHANGED
=
'
REMOVE_FILE_FROM_STAGED_AND_CHANGED
'
;
export
const
UPDATE_FILE_AFTER_COMMIT
=
'
UPDATE_FILE_AFTER_COMMIT
'
;
export
const
ADD_PENDING_TAB
=
'
ADD_PENDING_TAB
'
;
...
...
@@ -79,5 +78,6 @@ export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE';
export
const
OPEN_NEW_ENTRY_MODAL
=
'
OPEN_NEW_ENTRY_MODAL
'
;
export
const
DELETE_ENTRY
=
'
DELETE_ENTRY
'
;
export
const
RENAME_ENTRY
=
'
RENAME_ENTRY
'
;
export
const
REVERT_RENAME_ENTRY
=
'
REVERT_RENAME_ENTRY
'
;
export
const
RESTORE_TREE
=
'
RESTORE_TREE
'
;
app/assets/javascripts/ide/stores/mutations.js
View file @
5ecacec3
...
...
@@ -5,7 +5,14 @@ import mergeRequestMutation from './mutations/merge_request';
import
fileMutations
from
'
./mutations/file
'
;
import
treeMutations
from
'
./mutations/tree
'
;
import
branchMutations
from
'
./mutations/branch
'
;
import
{
sortTree
}
from
'
./utils
'
;
import
{
sortTree
,
replaceFileUrl
,
swapInParentTreeWithSorting
,
updateFileCollections
,
removeFromParentTree
,
pathsAreEqual
,
}
from
'
./utils
'
;
export
default
{
[
types
.
SET_INITIAL_DATA
](
state
,
data
)
{
...
...
@@ -56,11 +63,6 @@ export default {
stagedFiles
:
[],
});
},
[
types
.
CLEAR_REPLACED_FILES
](
state
)
{
Object
.
assign
(
state
,
{
replacedFiles
:
[],
});
},
[
types
.
SET_ENTRIES
](
state
,
entries
)
{
Object
.
assign
(
state
,
{
entries
,
...
...
@@ -157,9 +159,14 @@ export default {
changed
:
Boolean
(
changedFile
),
staged
:
false
,
replaces
:
false
,
prevPath
:
''
,
moved
:
false
,
lastCommitSha
:
lastCommit
.
commit
.
id
,
prevId
:
undefined
,
prevPath
:
undefined
,
prevName
:
undefined
,
prevUrl
:
undefined
,
prevKey
:
undefined
,
prevParentPath
:
undefined
,
});
if
(
prevPath
)
{
...
...
@@ -209,7 +216,9 @@ export default {
entry
.
deleted
=
true
;
parent
.
tree
=
parent
.
tree
.
filter
(
f
=>
f
.
path
!==
entry
.
path
);
if
(
parent
)
{
parent
.
tree
=
parent
.
tree
.
filter
(
f
=>
f
.
path
!==
entry
.
path
);
}
if
(
entry
.
type
===
'
blob
'
)
{
if
(
tempFile
)
{
...
...
@@ -219,51 +228,61 @@ export default {
}
}
},
[
types
.
RENAME_ENTRY
](
state
,
{
path
,
name
,
entryPath
=
null
,
parentPath
})
{
const
oldEntry
=
state
.
entries
[
entryPath
||
path
];
const
slashedParentPath
=
parentPath
?
`
${
parentPath
}
/`
:
''
;
const
newPath
=
entryPath
?
`
${
slashedParentPath
}${
oldEntry
.
name
}
`
:
`
${
slashedParentPath
}${
name
}
`
;
[
types
.
RENAME_ENTRY
](
state
,
{
path
,
name
,
parentPath
})
{
const
oldEntry
=
state
.
entries
[
path
];
const
newPath
=
parentPath
?
`
${
parentPath
}
/
${
name
}
`
:
name
;
const
isRevert
=
newPath
===
oldEntry
.
prevPath
;
Vue
.
set
(
state
.
entries
,
newPath
,
{
const
newUrl
=
replaceFileUrl
(
oldEntry
.
url
,
oldEntry
.
path
,
newPath
);
const
newKey
=
oldEntry
.
key
.
replace
(
new
RegExp
(
oldEntry
.
path
,
'
g
'
),
newPath
);
const
baseProps
=
{
...
oldEntry
,
name
,
id
:
newPath
,
key
:
`
${
newPath
}
-
${
oldEntry
.
type
}
-
${
oldEntry
.
path
}
`
,
path
:
newPath
,
name
:
entryPath
?
oldEntry
.
name
:
name
,
tempFile
:
true
,
prevPath
:
oldEntry
.
tempFile
?
null
:
oldEntry
.
path
,
url
:
oldEntry
.
url
.
replace
(
new
RegExp
(
`
${
oldEntry
.
path
}
/?$`
),
newPath
),
tree
:
[],
raw
:
''
,
opened
:
false
,
parentPath
,
});
url
:
newUrl
,
key
:
newKey
,
parentPath
:
parentPath
||
''
,
};
oldEntry
.
moved
=
true
;
oldEntry
.
movedPath
=
newPath
;
const
prevProps
=
oldEntry
.
tempFile
||
isRevert
?
{
prevId
:
undefined
,
prevPath
:
undefined
,
prevName
:
undefined
,
prevUrl
:
undefined
,
prevKey
:
undefined
,
prevParentPath
:
undefined
,
}
:
{
prevId
:
oldEntry
.
prevId
||
oldEntry
.
id
,
prevPath
:
oldEntry
.
prevPath
||
oldEntry
.
path
,
prevName
:
oldEntry
.
prevName
||
oldEntry
.
name
,
prevUrl
:
oldEntry
.
prevUrl
||
oldEntry
.
url
,
prevKey
:
oldEntry
.
prevKey
||
oldEntry
.
key
,
prevParentPath
:
oldEntry
.
prevParentPath
||
oldEntry
.
parentPath
,
};
const
parent
=
parentPath
?
state
.
entries
[
parentPath
]
:
state
.
trees
[
`
${
state
.
currentProjectId
}
/
${
state
.
currentBranchId
}
`
];
const
newEntry
=
state
.
entries
[
newPath
];
parent
.
tree
=
sortTree
(
parent
.
tree
.
concat
(
newEntry
));
Vue
.
set
(
state
.
entries
,
newPath
,
{
...
baseProps
,
...
prevProps
,
});
if
(
newEntry
.
type
===
'
blob
'
)
{
state
.
changedFiles
=
state
.
changedFiles
.
concat
(
newEntry
);
if
(
pathsAreEqual
(
oldEntry
.
parentPath
,
parentPath
))
{
swapInParentTreeWithSorting
(
state
,
oldEntry
.
key
,
newPath
,
parentPath
);
}
else
{
removeFromParentTree
(
state
,
oldEntry
.
key
,
oldEntry
.
parentPath
);
swapInParentTreeWithSorting
(
state
,
oldEntry
.
key
,
newPath
,
parentPath
);
}
if
(
oldEntry
.
tempFile
)
{
const
filterMethod
=
f
=>
f
.
path
!==
oldEntry
.
path
;
state
.
openFiles
=
state
.
openFiles
.
filter
(
filterMethod
);
state
.
changedFiles
=
state
.
changedFiles
.
filter
(
filterMethod
);
parent
.
tree
=
parent
.
tree
.
filter
(
filterMethod
);
Vue
.
delete
(
state
.
entries
,
oldEntry
.
path
);
if
(
oldEntry
.
type
===
'
blob
'
)
{
updateFileCollections
(
state
,
oldEntry
.
key
,
newPath
);
}
Vue
.
delete
(
state
.
entries
,
oldEntry
.
path
);
},
...
projectMutations
,
...
...
app/assets/javascripts/ide/stores/mutations/file.js
View file @
5ecacec3
...
...
@@ -138,8 +138,6 @@ export default {
content
:
stagedFile
?
stagedFile
.
content
:
state
.
entries
[
path
].
raw
,
changed
:
false
,
deleted
:
false
,
moved
:
false
,
movedPath
:
''
,
});
if
(
deleted
)
{
...
...
@@ -179,11 +177,6 @@ export default {
});
if
(
stagedFile
)
{
Object
.
assign
(
state
,
{
replacedFiles
:
state
.
replacedFiles
.
concat
({
...
stagedFile
,
}),
});
Object
.
assign
(
stagedFile
,
{
...
state
.
entries
[
path
],
});
...
...
@@ -252,4 +245,15 @@ export default {
openFiles
:
state
.
openFiles
.
filter
(
f
=>
f
.
key
!==
file
.
key
),
});
},
[
types
.
REMOVE_FILE_FROM_STAGED_AND_CHANGED
](
state
,
file
)
{
Object
.
assign
(
state
,
{
changedFiles
:
state
.
changedFiles
.
filter
(
f
=>
f
.
key
!==
file
.
key
),
stagedFiles
:
state
.
stagedFiles
.
filter
(
f
=>
f
.
key
!==
file
.
key
),
});
Object
.
assign
(
state
.
entries
[
file
.
path
],
{
changed
:
false
,
staged
:
false
,
});
},
};
app/assets/javascripts/ide/stores/state.js
View file @
5ecacec3
...
...
@@ -6,7 +6,6 @@ export default () => ({
currentMergeRequestId
:
''
,
changedFiles
:
[],
stagedFiles
:
[],
replacedFiles
:
[],
endpoints
:
{},
lastCommitMsg
:
''
,
lastCommitPath
:
''
,
...
...
app/assets/javascripts/ide/stores/utils.js
View file @
5ecacec3
...
...
@@ -50,9 +50,7 @@ export const dataStructure = () => ({
lastOpenedAt
:
0
,
mrChange
:
null
,
deleted
:
false
,
prevPath
:
''
,
movedPath
:
''
,
moved
:
false
,
prevPath
:
undefined
,
});
export
const
decorateData
=
entity
=>
{
...
...
@@ -129,7 +127,7 @@ export const commitActionForFile = file => {
export
const
getCommitFiles
=
stagedFiles
=>
stagedFiles
.
reduce
((
acc
,
file
)
=>
{
if
(
file
.
moved
||
file
.
type
===
'
tree
'
)
return
acc
;
if
(
file
.
type
===
'
tree
'
)
return
acc
;
return
acc
.
concat
({
...
file
,
...
...
@@ -148,9 +146,9 @@ export const createCommitPayload = ({
commit_message
:
state
.
commitMessage
||
getters
.
preBuiltCommitMessage
,
actions
:
getCommitFiles
(
rootState
.
stagedFiles
).
map
(
f
=>
({
action
:
commitActionForFile
(
f
),
file_path
:
f
.
moved
?
f
.
movedPath
:
f
.
path
,
previous_path
:
f
.
prevPath
===
''
?
undefined
:
f
.
prevPath
,
content
:
f
.
prevPath
?
null
:
f
.
content
||
undefined
,
file_path
:
f
.
path
,
previous_path
:
f
.
prevPath
||
undefined
,
content
:
f
.
prevPath
&&
!
f
.
changed
?
null
:
f
.
content
||
undefined
,
encoding
:
f
.
base64
?
'
base64
'
:
'
text
'
,
last_commit_id
:
newBranch
||
f
.
deleted
||
f
.
prevPath
||
f
.
replaces
?
undefined
:
f
.
lastCommitSha
,
...
...
@@ -213,3 +211,61 @@ export const mergeTrees = (fromTree, toTree) => {
return
toTree
;
};
export
const
escapeFileUrl
=
fileUrl
=>
encodeURIComponent
(
fileUrl
).
replace
(
/%2F/g
,
'
/
'
);
export
const
replaceFileUrl
=
(
url
,
oldPath
,
newPath
)
=>
{
// Add `/-/` so that we don't accidentally replace project path
const
result
=
url
.
replace
(
`/-/
${
escapeFileUrl
(
oldPath
)}
`
,
`/-/
${
escapeFileUrl
(
newPath
)}
`
);
return
result
;
};
export
const
swapInStateArray
=
(
state
,
arr
,
key
,
entryPath
)
=>
Object
.
assign
(
state
,
{
[
arr
]:
state
[
arr
].
map
(
f
=>
(
f
.
key
===
key
?
state
.
entries
[
entryPath
]
:
f
)),
});
export
const
getEntryOrRoot
=
(
state
,
path
)
=>
path
?
state
.
entries
[
path
]
:
state
.
trees
[
`
${
state
.
currentProjectId
}
/
${
state
.
currentBranchId
}
`
];
export
const
swapInParentTreeWithSorting
=
(
state
,
oldKey
,
newPath
,
parentPath
)
=>
{
if
(
!
newPath
)
{
return
;
}
const
parent
=
getEntryOrRoot
(
state
,
parentPath
);
if
(
parent
)
{
const
tree
=
parent
.
tree
// filter out old entry && new entry
.
filter
(({
key
,
path
})
=>
key
!==
oldKey
&&
path
!==
newPath
)
// concat new entry
.
concat
(
state
.
entries
[
newPath
]);
parent
.
tree
=
sortTree
(
tree
);
}
};
export
const
removeFromParentTree
=
(
state
,
oldKey
,
parentPath
)
=>
{
const
parent
=
getEntryOrRoot
(
state
,
parentPath
);
if
(
parent
)
{
parent
.
tree
=
sortTree
(
parent
.
tree
.
filter
(({
key
})
=>
key
!==
oldKey
));
}
};
export
const
updateFileCollections
=
(
state
,
key
,
entryPath
)
=>
{
[
'
openFiles
'
,
'
changedFiles
'
,
'
stagedFiles
'
].
forEach
(
fileCollection
=>
{
swapInStateArray
(
state
,
fileCollection
,
key
,
entryPath
);
});
};
export
const
cleanTrailingSlash
=
path
=>
path
.
replace
(
/
\/
$/
,
''
);
export
const
pathsAreEqual
=
(
a
,
b
)
=>
{
const
cleanA
=
a
?
cleanTrailingSlash
(
a
)
:
''
;
const
cleanB
=
b
?
cleanTrailingSlash
(
b
)
:
''
;
return
cleanA
===
cleanB
;
};
app/assets/javascripts/vue_shared/components/changed_file_icon.vue
View file @
5ecacec3
...
...
@@ -70,7 +70,13 @@ export default {
return
undefined
;
},
showIcon
()
{
return
this
.
file
.
changed
||
this
.
file
.
tempFile
||
this
.
file
.
staged
||
this
.
file
.
deleted
;
return
(
this
.
file
.
changed
||
this
.
file
.
tempFile
||
this
.
file
.
staged
||
this
.
file
.
deleted
||
this
.
file
.
prevPath
);
},
},
};
...
...
app/assets/javascripts/vue_shared/components/file_row.vue
View file @
5ecacec3
...
...
@@ -131,7 +131,7 @@ export default {
</
script
>
<
template
>
<div
v-if=
"!file.moved"
>
<div>
<file-header
v-if=
"file.isHeader"
:path=
"file.path"
/>
<div
v-else
...
...
app/assets/stylesheets/framework/animations.scss
View file @
5ecacec3
...
...
@@ -11,25 +11,10 @@
@include
webkit-prefix
(
animation-duration
,
1s
);
@include
webkit-prefix
(
animation-fill-mode
,
both
);
&
.infinite
{
@include
webkit-prefix
(
animation-iteration-count
,
infinite
);
}
&
.once
{
@include
webkit-prefix
(
animation-iteration-count
,
1
);
}
&
.hinge
{
@include
webkit-prefix
(
animation-duration
,
2s
);
}
&
.flipOutX
,
&
.flipOutY
,
&
.bounceIn
,
&
.bounceOut
{
@include
webkit-prefix
(
animation-duration
,
0
.75s
);
}
&
.short
{
@include
webkit-prefix
(
animation-duration
,
321ms
);
@include
webkit-prefix
(
animation-fill-mode
,
none
);
...
...
app/graphql/resolvers/issues_resolver.rb
View file @
5ecacec3
...
...
@@ -35,7 +35,7 @@ module Resolvers
description:
'Issues closed after this date'
argument
:search
,
GraphQL
::
STRING_TYPE
,
# rubocop:disable Graphql/Descriptions
required:
false
argument
:sort
,
Types
::
SortEnum
,
argument
:sort
,
Types
::
Issue
SortEnum
,
description:
'Sort issues by this criteria'
,
required:
false
,
default_value:
'created_desc'
...
...
app/graphql/types/issuable_sort_enum.rb
0 → 100644
View file @
5ecacec3
# frozen_string_literal: true
module
Types
# rubocop: disable Graphql/AuthorizeTypes
class
IssuableSortEnum
<
SortEnum
graphql_name
'IssuableSort'
description
'Values for sorting issuables'
end
# rubocop: enable Graphql/AuthorizeTypes
end
app/graphql/types/issue_sort_enum.rb
0 → 100644
View file @
5ecacec3
# frozen_string_literal: true
module
Types
# rubocop: disable Graphql/AuthorizeTypes
class
IssueSortEnum
<
IssuableSortEnum
graphql_name
'IssueSort'
description
'Values for sorting issues'
end
# rubocop: enable Graphql/AuthorizeTypes
end
changelogs/unreleased/17596-show-all-matching-labels-when-using-label-quick-action.yml
0 → 100644
View file @
5ecacec3
---
title
:
Show 20 labels in dropdown instead of
5
merge_request
:
17596
author
:
type
:
fixed
jest.config.js
View file @
5ecacec3
...
...
@@ -15,7 +15,10 @@ if (process.env.CI) {
]);
}
let
testMatch
=
[
'
<rootDir>/spec/frontend/**/*_spec.js
'
,
'
<rootDir>/ee/spec/frontend/**/*_spec.js
'
];
let
testMatch
=
[
'
<rootDir>/spec/frontend/**/*_spec.js
'
];
if
(
IS_EE
)
{
testMatch
.
push
(
'
<rootDir>/ee/spec/frontend/**/*_spec.js
'
);
}
// workaround for eslint-import-resolver-jest only resolving in test files
// see https://github.com/JoinColony/eslint-import-resolver-jest#note
...
...
lib/gitlab/import_export/project_tree_restorer.rb
View file @
5ecacec3
...
...
@@ -120,7 +120,7 @@ module Gitlab
end
end
def
remove_feature_dependent_sub_relations
(
_relation_item
)
def
remove_feature_dependent_sub_relations
!
(
_relation_item
)
# no-op
end
...
...
@@ -191,7 +191,7 @@ module Gitlab
# Avoid keeping a possible heavy object in memory once we are done with it
while
relation_item
=
tree_array
.
shift
remove_feature_dependent_sub_relations
(
relation_item
)
remove_feature_dependent_sub_relations
!
(
relation_item
)
# The transaction at this level is less speedy than one single transaction
# But we can't have it in the upper level or GC won't get rid of the AR objects
...
...
lib/gitlab/sidekiq_config.rb
View file @
5ecacec3
...
...
@@ -5,7 +5,11 @@ require 'set'
module
Gitlab
module
SidekiqConfig
QUEUE_CONFIG_PATHS
=
%w[app/workers/all_queues.yml ee/app/workers/all_queues.yml]
.
freeze
QUEUE_CONFIG_PATHS
=
begin
result
=
%w[app/workers/all_queues.yml]
result
<<
'ee/app/workers/all_queues.yml'
if
Gitlab
.
ee?
result
end
.
freeze
# This method is called by `ee/bin/sidekiq-cluster` in EE, which runs outside
# of bundler/Rails context, so we cannot use any gem or Rails methods.
...
...
@@ -48,9 +52,11 @@ module Gitlab
end
def
self
.
workers
@workers
||=
find_workers
(
Rails
.
root
.
join
(
'app'
,
'workers'
))
+
find_workers
(
Rails
.
root
.
join
(
'ee'
,
'app'
,
'workers'
))
@workers
||=
begin
result
=
find_workers
(
Rails
.
root
.
join
(
'app'
,
'workers'
))
result
.
concat
(
find_workers
(
Rails
.
root
.
join
(
'ee'
,
'app'
,
'workers'
)))
if
Gitlab
.
ee?
result
end
end
def
self
.
find_workers
(
root
)
...
...
lib/tasks/frontend.rake
View file @
5ecacec3
...
...
@@ -2,7 +2,10 @@ unless Rails.env.production?
namespace
:frontend
do
desc
'GitLab | Frontend | Generate fixtures for JavaScript tests'
RSpec
::
Core
::
RakeTask
.
new
(
:fixtures
,
[
:pattern
])
do
|
t
,
args
|
args
.
with_defaults
(
pattern:
'{spec,ee/spec}/frontend/fixtures/*.rb'
)
directories
=
%w[spec]
directories
<<
'ee/spec'
if
Gitlab
.
ee?
directory_glob
=
"{
#{
directories
.
join
(
','
)
}
}"
args
.
with_defaults
(
pattern:
"
#{
directory_glob
}
/frontend/fixtures/*.rb"
)
ENV
[
'NO_KNAPSACK'
]
=
'true'
t
.
pattern
=
args
[
:pattern
]
t
.
rspec_opts
=
'--format documentation'
...
...
spec/controllers/projects/environments_controller_spec.rb
View file @
5ecacec3
...
...
@@ -256,7 +256,7 @@ describe Projects::EnvironmentsController do
it
'loads the terminals for the environment'
do
# In EE we have to stub EE::Environment since it overwrites the
# "terminals" method.
expect_any_instance_of
(
defined?
(
EE
)
?
EE
::
Environment
:
Environment
)
expect_any_instance_of
(
Gitlab
.
ee?
?
EE
::
Environment
:
Environment
)
.
to
receive
(
:terminals
)
get
:terminal
,
params:
environment_params
...
...
@@ -282,7 +282,7 @@ describe Projects::EnvironmentsController do
it
'returns the first terminal for the environment'
do
# In EE we have to stub EE::Environment since it overwrites the
# "terminals" method.
expect_any_instance_of
(
defined?
(
EE
)
?
EE
::
Environment
:
Environment
)
expect_any_instance_of
(
Gitlab
.
ee?
?
EE
::
Environment
:
Environment
)
.
to
receive
(
:terminals
)
.
and_return
([
:fake_terminal
])
...
...
spec/frontend/fixtures/autocomplete_sources.rb
View file @
5ecacec3
...
...
@@ -24,6 +24,10 @@ describe Projects::AutocompleteSourcesController, '(JavaScript fixtures)', type:
create
(
:label
,
project:
project
,
title:
'feature'
)
create
(
:label
,
project:
project
,
title:
'documentation'
)
create
(
:label
,
project:
project
,
title:
'P1'
)
create
(
:label
,
project:
project
,
title:
'P2'
)
create
(
:label
,
project:
project
,
title:
'P3'
)
create
(
:label
,
project:
project
,
title:
'P4'
)
get
:labels
,
format: :json
,
...
...
spec/frontend/ide/lib/files_spec.js
View file @
5ecacec3
import
{
viewerInformationForPath
}
from
'
~/vue_shared/components/content_viewer/lib/viewer_utils
'
;
import
{
decorateFiles
,
splitParent
,
escapeFileUrl
}
from
'
~/ide/lib/files
'
;
import
{
decorateData
}
from
'
~/ide/stores/utils
'
;
import
{
decorateFiles
,
splitParent
}
from
'
~/ide/lib/files
'
;
import
{
decorateData
,
escapeFileUrl
}
from
'
~/ide/stores/utils
'
;
const
TEST_BRANCH_ID
=
'
lorem-ipsum
'
;
const
TEST_PROJECT_ID
=
10
;
...
...
spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
View file @
5ecacec3
...
...
@@ -2,12 +2,14 @@ import Vue from 'vue';
import
store
from
'
~/ide/stores
'
;
import
listItem
from
'
~/ide/components/commit_sidebar/list_item.vue
'
;
import
router
from
'
~/ide/ide_router
'
;
import
{
trimText
}
from
'
spec/helpers/text_helper
'
;
import
{
createComponentWithStore
}
from
'
spec/helpers/vue_mount_component_helper
'
;
import
{
file
,
resetStore
}
from
'
../../helpers
'
;
describe
(
'
Multi-file editor commit sidebar list item
'
,
()
=>
{
let
vm
;
let
f
;
let
findPathEl
;
beforeEach
(()
=>
{
const
Component
=
Vue
.
extend
(
listItem
);
...
...
@@ -21,6 +23,8 @@ describe('Multi-file editor commit sidebar list item', () => {
actionComponent
:
'
stage-button
'
,
activeFileKey
:
`staged-
${
f
.
key
}
`
,
}).
$mount
();
findPathEl
=
vm
.
$el
.
querySelector
(
'
.multi-file-commit-list-path
'
);
});
afterEach
(()
=>
{
...
...
@@ -29,15 +33,39 @@ describe('Multi-file editor commit sidebar list item', () => {
resetStore
(
store
);
});
const
findPathText
=
()
=>
trimText
(
findPathEl
.
textContent
);
it
(
'
renders file path
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.multi-file-commit-list-path
'
).
textContent
).
toContain
(
f
.
path
);
expect
(
findPathText
()).
toContain
(
f
.
path
);
});
it
(
'
correctly renders renamed entries
'
,
done
=>
{
Vue
.
set
(
vm
.
file
,
'
prevName
'
,
'
Old name
'
);
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
findPathText
()).
toEqual
(
`Old name →
${
f
.
name
}
`
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
correctly renders entry, the name of which did not change after rename (as within a folder)
'
,
done
=>
{
Vue
.
set
(
vm
.
file
,
'
prevName
'
,
f
.
name
);
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
findPathText
()).
toEqual
(
f
.
name
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
opens a closed file in the editor when clicking the file path
'
,
done
=>
{
spyOn
(
vm
,
'
openPendingTab
'
).
and
.
callThrough
();
spyOn
(
router
,
'
push
'
);
vm
.
$el
.
querySelector
(
'
.multi-file-commit-list-path
'
)
.
click
();
findPathEl
.
click
();
setTimeout
(()
=>
{
expect
(
vm
.
openPendingTab
).
toHaveBeenCalled
();
...
...
@@ -52,7 +80,7 @@ describe('Multi-file editor commit sidebar list item', () => {
spyOn
(
vm
,
'
updateViewer
'
).
and
.
callThrough
();
spyOn
(
router
,
'
push
'
);
vm
.
$el
.
querySelector
(
'
.multi-file-commit-list-path
'
)
.
click
();
findPathEl
.
click
();
setTimeout
(()
=>
{
expect
(
vm
.
updateViewer
).
toHaveBeenCalledWith
(
'
diff
'
);
...
...
spec/javascripts/ide/components/file_row_extra_spec.js
View file @
5ecacec3
...
...
@@ -139,6 +139,27 @@ describe('IDE extra file row component', () => {
done
();
});
});
it
(
'
shows when file is renamed
'
,
done
=>
{
vm
.
file
.
prevPath
=
'
original-file
'
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.file-changed-icon
'
)).
not
.
toBe
(
null
);
done
();
});
});
it
(
'
hides when file is renamed
'
,
done
=>
{
vm
.
file
.
prevPath
=
'
original-file
'
;
vm
.
file
.
type
=
'
tree
'
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.file-changed-icon
'
)).
toBe
(
null
);
done
();
});
});
});
describe
(
'
merge request icon
'
,
()
=>
{
...
...
spec/javascripts/ide/components/ide_tree_list_spec.js
View file @
5ecacec3
...
...
@@ -58,20 +58,6 @@ describe('IDE tree list', () => {
it
(
'
renders list of files
'
,
()
=>
{
expect
(
vm
.
$el
.
textContent
).
toContain
(
'
fileName
'
);
});
it
(
'
does not render moved entries
'
,
done
=>
{
const
tree
=
[
file
(
'
moved entry
'
),
file
(
'
normal entry
'
)];
tree
[
0
].
moved
=
true
;
store
.
state
.
trees
[
'
abcproject/master
'
].
tree
=
tree
;
const
container
=
vm
.
$el
.
querySelector
(
'
.ide-tree-body
'
);
vm
.
$nextTick
(()
=>
{
expect
(
container
.
children
.
length
).
toBe
(
1
);
expect
(
vm
.
$el
.
textContent
).
not
.
toContain
(
'
moved entry
'
);
expect
(
vm
.
$el
.
textContent
).
toContain
(
'
normal entry
'
);
done
();
});
});
});
describe
(
'
empty-branch state
'
,
()
=>
{
...
...
spec/javascripts/ide/components/repo_editor_spec.js
View file @
5ecacec3
...
...
@@ -410,10 +410,23 @@ describe('RepoEditor', () => {
describe
(
'
initEditor
'
,
()
=>
{
beforeEach
(()
=>
{
vm
.
file
.
tempFile
=
false
;
spyOn
(
vm
.
editor
,
'
createInstance
'
);
spyOnProperty
(
vm
,
'
shouldHideEditor
'
).
and
.
returnValue
(
true
);
});
it
(
'
does not fetch file information for temp entries
'
,
done
=>
{
vm
.
file
.
tempFile
=
true
;
vm
.
initEditor
();
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
vm
.
getFileData
).
not
.
toHaveBeenCalled
();
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
is being initialised for files without content even if shouldHideEditor is `true`
'
,
done
=>
{
vm
.
file
.
content
=
''
;
vm
.
file
.
raw
=
''
;
...
...
@@ -429,16 +442,13 @@ describe('RepoEditor', () => {
});
it
(
'
does not initialize editor for files already with content
'
,
done
=>
{
expect
(
vm
.
getFileData
.
calls
.
count
()).
toEqual
(
1
);
expect
(
vm
.
getRawFileData
.
calls
.
count
()).
toEqual
(
1
);
vm
.
file
.
content
=
'
foo
'
;
vm
.
initEditor
();
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
vm
.
getFileData
.
calls
.
count
()).
toEqual
(
1
);
expect
(
vm
.
getRawFileData
.
calls
.
count
()).
toEqual
(
1
);
expect
(
vm
.
getFileData
).
not
.
toHaveBeenCalled
(
);
expect
(
vm
.
getRawFileData
).
not
.
toHaveBeenCalled
(
);
expect
(
vm
.
editor
.
createInstance
).
not
.
toHaveBeenCalled
();
})
.
then
(
done
)
...
...
@@ -446,23 +456,56 @@ describe('RepoEditor', () => {
});
});
it
(
'
calls removePendingTab when old file is pending
'
,
done
=>
{
spyOnProperty
(
vm
,
'
shouldHideEditor
'
).
and
.
returnValue
(
true
);
spyOn
(
vm
,
'
removePendingTab
'
);
describe
(
'
updates on file changes
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
vm
,
'
initEditor
'
);
});
vm
.
file
.
pending
=
true
;
it
(
'
calls removePendingTab when old file is pending
'
,
done
=>
{
spyOnProperty
(
vm
,
'
shouldHideEditor
'
).
and
.
returnValue
(
true
);
spyOn
(
vm
,
'
removePendingTab
'
);
vm
.
$nextTick
()
.
then
(()
=>
{
vm
.
file
=
file
(
'
testing
'
);
vm
.
file
.
content
=
'
foo
'
;
// need to prevent full cycle of initEditor
vm
.
file
.
pending
=
true
;
vm
.
$nextTick
()
.
then
(()
=>
{
vm
.
file
=
file
(
'
testing
'
);
vm
.
file
.
content
=
'
foo
'
;
// need to prevent full cycle of initEditor
return
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
vm
.
removePendingTab
).
toHaveBeenCalled
();
})
.
then
(
done
)
.
catch
(
done
.
fail
);
return
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
vm
.
removePendingTab
).
toHaveBeenCalled
();
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
does not call initEditor if the file did not change
'
,
done
=>
{
Vue
.
set
(
vm
,
'
file
'
,
vm
.
file
);
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
vm
.
initEditor
).
not
.
toHaveBeenCalled
();
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
calls initEditor when file key is changed
'
,
done
=>
{
expect
(
vm
.
initEditor
).
not
.
toHaveBeenCalled
();
Vue
.
set
(
vm
,
'
file
'
,
{
...
vm
.
file
,
key
:
'
new
'
,
});
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
vm
.
initEditor
).
toHaveBeenCalled
();
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
});
spec/javascripts/ide/stores/actions/project_spec.js
View file @
5ecacec3
...
...
@@ -6,8 +6,10 @@ import {
createNewBranchFromDefault
,
showEmptyState
,
openBranch
,
loadFile
,
loadBranch
,
}
from
'
~/ide/stores/actions
'
;
import
store
from
'
~/ide/stores
'
;
import
{
createStore
}
from
'
~/ide/stores
'
;
import
service
from
'
~/ide/services
'
;
import
api
from
'
~/api
'
;
import
router
from
'
~/ide/ide_router
'
;
...
...
@@ -16,8 +18,10 @@ import testAction from '../../../helpers/vuex_action_helper';
describe
(
'
IDE store project actions
'
,
()
=>
{
let
mock
;
let
store
;
beforeEach
(()
=>
{
store
=
createStore
();
mock
=
new
MockAdapter
(
axios
);
store
.
state
.
projects
[
'
abc/def
'
]
=
{
...
...
@@ -231,28 +235,139 @@ describe('IDE store project actions', () => {
});
});
describe
(
'
loadFile
'
,
()
=>
{
beforeEach
(()
=>
{
Object
.
assign
(
store
.
state
,
{
entries
:
{
foo
:
{
pending
:
false
},
'
foo/bar-pending
'
:
{
pending
:
true
},
'
foo/bar
'
:
{
pending
:
false
},
},
});
spyOn
(
store
,
'
dispatch
'
);
});
it
(
'
does nothing, if basePath is not given
'
,
()
=>
{
loadFile
(
store
,
{
basePath
:
undefined
});
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalled
();
});
it
(
'
handles tree entry action, if basePath is given and the entry is not pending
'
,
()
=>
{
loadFile
(
store
,
{
basePath
:
'
foo/bar/
'
});
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
store
.
state
.
entries
[
'
foo/bar
'
],
);
});
it
(
'
does not handle tree entry action, if entry is pending
'
,
()
=>
{
loadFile
(
store
,
{
basePath
:
'
foo/bar-pending/
'
});
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
jasmine
.
anything
());
});
it
(
'
creates a new temp file supplied via URL if the file does not exist yet
'
,
()
=>
{
loadFile
(
store
,
{
basePath
:
'
not-existent.md
'
});
expect
(
store
.
dispatch
.
calls
.
count
()).
toBe
(
1
);
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
jasmine
.
anything
());
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
createTempEntry
'
,
{
name
:
'
not-existent.md
'
,
type
:
'
blob
'
,
});
});
});
describe
(
'
loadBranch
'
,
()
=>
{
const
projectId
=
'
abc/def
'
;
const
branchId
=
'
123-lorem
'
;
it
(
'
fetches branch data
'
,
done
=>
{
spyOn
(
store
,
'
dispatch
'
).
and
.
returnValue
(
Promise
.
resolve
());
loadBranch
(
store
,
{
projectId
,
branchId
})
.
then
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([
[
'
getBranchData
'
,
{
projectId
,
branchId
}],
[
'
getMergeRequestsForBranch
'
,
{
projectId
,
branchId
}],
[
'
getFiles
'
,
{
projectId
,
branchId
}],
]);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
shows an error if branch can not be fetched
'
,
done
=>
{
spyOn
(
store
,
'
dispatch
'
).
and
.
returnValue
(
Promise
.
reject
());
loadBranch
(
store
,
{
projectId
,
branchId
})
.
then
(
done
.
fail
)
.
catch
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([
[
'
getBranchData
'
,
{
projectId
,
branchId
}],
[
'
showBranchNotFoundError
'
,
branchId
],
]);
done
();
});
});
});
describe
(
'
openBranch
'
,
()
=>
{
const
projectId
=
'
abc/def
'
;
const
branchId
=
'
123-lorem
'
;
const
branch
=
{
projectId
:
'
abc/def
'
,
branchId
:
'
123-lorem
'
,
projectId
,
branchId
,
};
beforeEach
(()
=>
{
store
.
state
.
entries
=
{
foo
:
{
pending
:
false
},
'
foo/bar-pending
'
:
{
pending
:
true
},
'
foo/bar
'
:
{
pending
:
false
},
};
Object
.
assign
(
store
.
state
,
{
entries
:
{
foo
:
{
pending
:
false
},
'
foo/bar-pending
'
:
{
pending
:
true
},
'
foo/bar
'
:
{
pending
:
false
},
},
});
});
it
(
'
loads file right away if the branch has already been fetched
'
,
done
=>
{
spyOn
(
store
,
'
dispatch
'
);
Object
.
assign
(
store
.
state
,
{
projects
:
{
[
projectId
]:
{
branches
:
{
[
branchId
]:
{
foo
:
'
bar
'
},
},
},
},
});
openBranch
(
store
,
branch
)
.
then
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([[
'
loadFile
'
,
{
basePath
:
undefined
}]]);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
describe
(
'
empty repo
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
store
,
'
dispatch
'
).
and
.
returnValue
(
Promise
.
resolve
());
store
.
state
.
currentProjectId
=
'
abc/def
'
;
store
.
state
.
projects
[
'
abc/def
'
]
=
{
empty_repo
:
true
,
};
Object
.
assign
(
store
.
state
,
{
currentProjectId
:
'
abc/def
'
,
projects
:
{
'
abc/def
'
:
{
empty_repo
:
true
,
},
},
});
});
afterEach
(()
=>
{
...
...
@@ -262,10 +377,7 @@ describe('IDE store project actions', () => {
it
(
'
dispatches showEmptyState action right away
'
,
done
=>
{
openBranch
(
store
,
branch
)
.
then
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([
[
'
setCurrentBranchId
'
,
branch
.
branchId
],
[
'
showEmptyState
'
,
branch
],
]);
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([[
'
showEmptyState
'
,
branch
]]);
done
();
})
.
catch
(
done
.
fail
);
...
...
@@ -281,56 +393,14 @@ describe('IDE store project actions', () => {
openBranch
(
store
,
branch
)
.
then
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([
[
'
setCurrentBranchId
'
,
branch
.
branchId
],
[
'
getBranchData
'
,
branch
],
[
'
getMergeRequestsForBranch
'
,
branch
],
[
'
getFiles
'
,
branch
],
[
'
setCurrentBranchId
'
,
branchId
],
[
'
loadBranch
'
,
{
projectId
,
branchId
}],
[
'
loadFile
'
,
{
basePath
:
undefined
}],
]);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
handles tree entry action, if basePath is given
'
,
done
=>
{
openBranch
(
store
,
{
...
branch
,
basePath
:
'
foo/bar/
'
})
.
then
(()
=>
{
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
store
.
state
.
entries
[
'
foo/bar
'
],
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
does not handle tree entry action, if entry is pending
'
,
done
=>
{
openBranch
(
store
,
{
...
branch
,
basePath
:
'
foo/bar-pending
'
})
.
then
(()
=>
{
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
jasmine
.
anything
(),
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
creates a new file supplied via URL if the file does not exist yet
'
,
done
=>
{
openBranch
(
store
,
{
...
branch
,
basePath
:
'
not-existent.md
'
})
.
then
(()
=>
{
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
jasmine
.
anything
(),
);
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
createTempEntry
'
,
{
name
:
'
not-existent.md
'
,
type
:
'
blob
'
,
});
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
describe
(
'
non-existent branch
'
,
()
=>
{
...
...
@@ -342,9 +412,8 @@ describe('IDE store project actions', () => {
openBranch
(
store
,
branch
)
.
then
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([
[
'
setCurrentBranchId
'
,
branch
.
branchId
],
[
'
getBranchData
'
,
branch
],
[
'
showBranchNotFoundError
'
,
branch
.
branchId
],
[
'
setCurrentBranchId
'
,
branchId
],
[
'
loadBranch
'
,
{
projectId
,
branchId
}],
]);
})
.
then
(
done
)
...
...
spec/javascripts/ide/stores/actions_spec.js
View file @
5ecacec3
This diff is collapsed.
Click to expand it.
spec/javascripts/ide/stores/modules/commit/actions_spec.js
View file @
5ecacec3
import
rootActions
from
'
~/ide/stores/actions
'
;
import
store
from
'
~/ide/stores
'
;
import
{
createStore
}
from
'
~/ide/stores
'
;
import
service
from
'
~/ide/services
'
;
import
router
from
'
~/ide/ide_router
'
;
import
eventHub
from
'
~/ide/eventhub
'
;
...
...
@@ -11,6 +11,7 @@ import { resetStore, file } from 'spec/ide/helpers';
import
testAction
from
'
../../../../helpers/vuex_action_helper
'
;
const
TEST_COMMIT_SHA
=
'
123456789
'
;
const
store
=
createStore
();
describe
(
'
IDE commit module actions
'
,
()
=>
{
beforeEach
(()
=>
{
...
...
@@ -59,7 +60,9 @@ describe('IDE commit module actions', () => {
});
it
(
'
sets shouldCreateMR to true if "Create new MR" option is visible
'
,
done
=>
{
store
.
state
.
shouldHideNewMrOption
=
false
;
Object
.
assign
(
store
.
state
,
{
shouldHideNewMrOption
:
false
,
});
testAction
(
actions
.
updateCommitAction
,
...
...
@@ -78,7 +81,9 @@ describe('IDE commit module actions', () => {
});
it
(
'
sets shouldCreateMR to false if "Create new MR" option is hidden
'
,
done
=>
{
store
.
state
.
shouldHideNewMrOption
=
true
;
Object
.
assign
(
store
.
state
,
{
shouldHideNewMrOption
:
true
,
});
testAction
(
actions
.
updateCommitAction
,
...
...
@@ -172,24 +177,31 @@ describe('IDE commit module actions', () => {
content
:
'
file content
'
,
});
store
.
state
.
currentProjectId
=
'
abcproject
'
;
store
.
state
.
currentBranchId
=
'
master
'
;
store
.
state
.
projects
.
abcproject
=
{
web_url
:
'
web_url
'
,
branches
:
{
master
:
{
workingReference
:
''
,
commit
:
{
short_id
:
TEST_COMMIT_SHA
,
Object
.
assign
(
store
.
state
,
{
currentProjectId
:
'
abcproject
'
,
currentBranchId
:
'
master
'
,
projects
:
{
abcproject
:
{
web_url
:
'
web_url
'
,
branches
:
{
master
:
{
workingReference
:
''
,
commit
:
{
short_id
:
TEST_COMMIT_SHA
,
},
},
},
},
},
};
store
.
state
.
stagedFiles
.
push
(
f
,
{
...
file
(
'
changedFile2
'
),
changed
:
true
,
stagedFiles
:
[
f
,
{
...
file
(
'
changedFile2
'
),
changed
:
true
,
},
],
openFiles
:
store
.
state
.
stagedFiles
,
});
store
.
state
.
openFiles
=
store
.
state
.
stagedFiles
;
store
.
state
.
stagedFiles
.
forEach
(
stagedFile
=>
{
store
.
state
.
entries
[
stagedFile
.
path
]
=
stagedFile
;
...
...
@@ -275,40 +287,40 @@ describe('IDE commit module actions', () => {
document
.
body
.
innerHTML
+=
'
<div class="flash-container"></div>
'
;
store
.
state
.
currentProjectId
=
'
abcproject
'
;
store
.
state
.
currentBranchId
=
'
master
'
;
store
.
state
.
projects
.
abcproject
=
{
web_url
:
'
webUrl
'
,
branches
:
{
master
:
{
workingReference
:
'
1
'
,
commit
:
{
id
:
TEST_COMMIT_SHA
,
},
},
},
};
const
f
=
{
...
file
(
'
changed
'
),
type
:
'
blob
'
,
active
:
true
,
lastCommitSha
:
TEST_COMMIT_SHA
,
};
store
.
state
.
stagedFiles
.
push
(
f
);
store
.
state
.
changedFiles
=
[
{
...
f
,
},
];
store
.
state
.
openFiles
=
store
.
state
.
changedFiles
;
store
.
state
.
openFiles
.
forEach
(
localF
=>
{
store
.
state
.
entries
[
localF
.
path
]
=
localF
;
Object
.
assign
(
store
.
state
,
{
stagedFiles
:
[
f
],
changedFiles
:
[
f
],
openFiles
:
[
f
],
currentProjectId
:
'
abcproject
'
,
currentBranchId
:
'
master
'
,
projects
:
{
abcproject
:
{
web_url
:
'
webUrl
'
,
branches
:
{
master
:
{
workingReference
:
'
1
'
,
commit
:
{
id
:
TEST_COMMIT_SHA
,
},
},
},
},
},
});
store
.
state
.
commit
.
commitAction
=
'
2
'
;
store
.
state
.
commit
.
commitMessage
=
'
testing 123
'
;
store
.
state
.
openFiles
.
forEach
(
localF
=>
{
store
.
state
.
entries
[
localF
.
path
]
=
localF
;
});
});
afterEach
(()
=>
{
...
...
spec/javascripts/ide/stores/mutations/file_spec.js
View file @
5ecacec3
...
...
@@ -356,16 +356,16 @@ describe('IDE store file mutations', () => {
});
describe
(
'
STAGE_CHANGE
'
,
()
=>
{
it
(
'
adds file into stagedFiles array
'
,
()
=>
{
beforeEach
(
()
=>
{
mutations
.
STAGE_CHANGE
(
localState
,
localFile
.
path
);
});
it
(
'
adds file into stagedFiles array
'
,
()
=>
{
expect
(
localState
.
stagedFiles
.
length
).
toBe
(
1
);
expect
(
localState
.
stagedFiles
[
0
]).
toEqual
(
localFile
);
});
it
(
'
updates stagedFile if it is already staged
'
,
()
=>
{
mutations
.
STAGE_CHANGE
(
localState
,
localFile
.
path
);
localFile
.
raw
=
'
testing 123
'
;
mutations
.
STAGE_CHANGE
(
localState
,
localFile
.
path
);
...
...
@@ -373,19 +373,6 @@ describe('IDE store file mutations', () => {
expect
(
localState
.
stagedFiles
.
length
).
toBe
(
1
);
expect
(
localState
.
stagedFiles
[
0
].
raw
).
toEqual
(
'
testing 123
'
);
});
it
(
'
adds already-staged file to `replacedFiles`
'
,
()
=>
{
localFile
.
raw
=
'
already-staged
'
;
mutations
.
STAGE_CHANGE
(
localState
,
localFile
.
path
);
localFile
.
raw
=
'
testing 123
'
;
mutations
.
STAGE_CHANGE
(
localState
,
localFile
.
path
);
expect
(
localState
.
replacedFiles
.
length
).
toBe
(
1
);
expect
(
localState
.
replacedFiles
[
0
].
raw
).
toEqual
(
'
already-staged
'
);
});
});
describe
(
'
UNSTAGE_CHANGE
'
,
()
=>
{
...
...
spec/javascripts/ide/stores/mutations_spec.js
View file @
5ecacec3
This diff is collapsed.
Click to expand it.
spec/javascripts/ide/stores/utils_spec.js
View file @
5ecacec3
...
...
@@ -237,31 +237,6 @@ describe('Multi-file store utils', () => {
});
describe
(
'
getCommitFiles
'
,
()
=>
{
it
(
'
returns list of files excluding moved files
'
,
()
=>
{
const
files
=
[
{
path
:
'
a
'
,
type
:
'
blob
'
,
deleted
:
true
,
},
{
path
:
'
c
'
,
type
:
'
blob
'
,
moved
:
true
,
},
];
const
flattendFiles
=
utils
.
getCommitFiles
(
files
);
expect
(
flattendFiles
).
toEqual
([
{
path
:
'
a
'
,
type
:
'
blob
'
,
deleted
:
true
,
},
]);
});
it
(
'
filters out folders from the list
'
,
()
=>
{
const
files
=
[
{
...
...
@@ -422,4 +397,204 @@ describe('Multi-file store utils', () => {
expect
(
res
[
1
].
tree
[
0
].
opened
).
toEqual
(
true
);
});
});
describe
(
'
escapeFileUrl
'
,
()
=>
{
it
(
'
encodes URL excluding the slashes
'
,
()
=>
{
expect
(
utils
.
escapeFileUrl
(
'
/foo-bar/file.md
'
)).
toBe
(
'
/foo-bar/file.md
'
);
expect
(
utils
.
escapeFileUrl
(
'
foo bar/file.md
'
)).
toBe
(
'
foo%20bar/file.md
'
);
expect
(
utils
.
escapeFileUrl
(
'
foo/bar/file.md
'
)).
toBe
(
'
foo/bar/file.md
'
);
});
});
describe
(
'
swapInStateArray
'
,
()
=>
{
let
localState
;
beforeEach
(()
=>
{
localState
=
[];
});
it
(
'
swaps existing entry with a new one
'
,
()
=>
{
const
file1
=
{
...
file
(
'
old
'
),
key
:
'
foo
'
,
};
const
file2
=
file
(
'
new
'
);
const
arr
=
[
file1
];
Object
.
assign
(
localState
,
{
dummyArray
:
arr
,
entries
:
{
new
:
file2
,
},
});
utils
.
swapInStateArray
(
localState
,
'
dummyArray
'
,
'
foo
'
,
'
new
'
);
expect
(
localState
.
dummyArray
.
length
).
toBe
(
1
);
expect
(
localState
.
dummyArray
[
0
]).
toBe
(
file2
);
});
it
(
'
does not add an item if it does not exist yet in array
'
,
()
=>
{
const
file1
=
file
(
'
file
'
);
Object
.
assign
(
localState
,
{
dummyArray
:
[],
entries
:
{
file
:
file1
,
},
});
utils
.
swapInStateArray
(
localState
,
'
dummyArray
'
,
'
foo
'
,
'
file
'
);
expect
(
localState
.
dummyArray
.
length
).
toBe
(
0
);
});
});
describe
(
'
swapInParentTreeWithSorting
'
,
()
=>
{
let
localState
;
let
branchInfo
;
const
currentProjectId
=
'
123-foo
'
;
const
currentBranchId
=
'
master
'
;
beforeEach
(()
=>
{
localState
=
{
currentBranchId
,
currentProjectId
,
trees
:
{
[
`
${
currentProjectId
}
/
${
currentBranchId
}
`
]:
{
tree
:
[],
},
},
entries
:
{
oldPath
:
file
(
'
oldPath
'
,
'
oldPath
'
,
'
blob
'
),
newPath
:
file
(
'
newPath
'
,
'
newPath
'
,
'
blob
'
),
parentPath
:
file
(
'
parentPath
'
,
'
parentPath
'
,
'
tree
'
),
},
};
branchInfo
=
localState
.
trees
[
`
${
currentProjectId
}
/
${
currentBranchId
}
`
];
});
it
(
'
does not change tree if newPath is not supplied
'
,
()
=>
{
branchInfo
.
tree
=
[
localState
.
entries
.
oldPath
];
utils
.
swapInParentTreeWithSorting
(
localState
,
'
oldPath
'
,
undefined
,
undefined
);
expect
(
branchInfo
.
tree
).
toEqual
([
localState
.
entries
.
oldPath
]);
});
describe
(
'
oldPath to replace is not defined: simple addition to tree
'
,
()
=>
{
it
(
'
adds to tree on the state if there is no parent for the entry
'
,
()
=>
{
expect
(
branchInfo
.
tree
.
length
).
toBe
(
0
);
utils
.
swapInParentTreeWithSorting
(
localState
,
undefined
,
'
oldPath
'
,
undefined
);
expect
(
branchInfo
.
tree
.
length
).
toBe
(
1
);
expect
(
branchInfo
.
tree
[
0
].
name
).
toBe
(
'
oldPath
'
);
utils
.
swapInParentTreeWithSorting
(
localState
,
undefined
,
'
newPath
'
,
undefined
);
expect
(
branchInfo
.
tree
.
length
).
toBe
(
2
);
expect
(
branchInfo
.
tree
).
toEqual
([
jasmine
.
objectContaining
({
name
:
'
newPath
'
}),
jasmine
.
objectContaining
({
name
:
'
oldPath
'
}),
]);
});
it
(
'
adds to parent tree if it is supplied
'
,
()
=>
{
utils
.
swapInParentTreeWithSorting
(
localState
,
undefined
,
'
newPath
'
,
'
parentPath
'
);
expect
(
localState
.
entries
.
parentPath
.
tree
.
length
).
toBe
(
1
);
expect
(
localState
.
entries
.
parentPath
.
tree
).
toEqual
([
jasmine
.
objectContaining
({
name
:
'
newPath
'
}),
]);
localState
.
entries
.
parentPath
.
tree
=
[
localState
.
entries
.
oldPath
];
utils
.
swapInParentTreeWithSorting
(
localState
,
undefined
,
'
newPath
'
,
'
parentPath
'
);
expect
(
localState
.
entries
.
parentPath
.
tree
.
length
).
toBe
(
2
);
expect
(
localState
.
entries
.
parentPath
.
tree
).
toEqual
([
jasmine
.
objectContaining
({
name
:
'
newPath
'
}),
jasmine
.
objectContaining
({
name
:
'
oldPath
'
}),
]);
});
});
describe
(
'
swapping of the items
'
,
()
=>
{
it
(
'
swaps entries if both paths are supplied
'
,
()
=>
{
branchInfo
.
tree
=
[
localState
.
entries
.
oldPath
];
utils
.
swapInParentTreeWithSorting
(
localState
,
localState
.
entries
.
oldPath
.
key
,
'
newPath
'
);
expect
(
branchInfo
.
tree
).
toEqual
([
jasmine
.
objectContaining
({
name
:
'
newPath
'
})]);
utils
.
swapInParentTreeWithSorting
(
localState
,
localState
.
entries
.
newPath
.
key
,
'
oldPath
'
);
expect
(
branchInfo
.
tree
).
toEqual
([
jasmine
.
objectContaining
({
name
:
'
oldPath
'
})]);
});
it
(
'
sorts tree after swapping the entries
'
,
()
=>
{
const
alpha
=
file
(
'
alpha
'
,
'
alpha
'
,
'
blob
'
);
const
beta
=
file
(
'
beta
'
,
'
beta
'
,
'
blob
'
);
const
gamma
=
file
(
'
gamma
'
,
'
gamma
'
,
'
blob
'
);
const
theta
=
file
(
'
theta
'
,
'
theta
'
,
'
blob
'
);
localState
.
entries
=
{
alpha
,
beta
,
gamma
,
theta
};
branchInfo
.
tree
=
[
alpha
,
beta
,
gamma
];
utils
.
swapInParentTreeWithSorting
(
localState
,
alpha
.
key
,
'
theta
'
);
expect
(
branchInfo
.
tree
).
toEqual
([
jasmine
.
objectContaining
({
name
:
'
beta
'
}),
jasmine
.
objectContaining
({
name
:
'
gamma
'
}),
jasmine
.
objectContaining
({
name
:
'
theta
'
}),
]);
utils
.
swapInParentTreeWithSorting
(
localState
,
gamma
.
key
,
'
alpha
'
);
expect
(
branchInfo
.
tree
).
toEqual
([
jasmine
.
objectContaining
({
name
:
'
alpha
'
}),
jasmine
.
objectContaining
({
name
:
'
beta
'
}),
jasmine
.
objectContaining
({
name
:
'
theta
'
}),
]);
utils
.
swapInParentTreeWithSorting
(
localState
,
beta
.
key
,
'
gamma
'
);
expect
(
branchInfo
.
tree
).
toEqual
([
jasmine
.
objectContaining
({
name
:
'
alpha
'
}),
jasmine
.
objectContaining
({
name
:
'
gamma
'
}),
jasmine
.
objectContaining
({
name
:
'
theta
'
}),
]);
});
});
});
describe
(
'
cleanTrailingSlash
'
,
()
=>
{
[
{
input
:
''
,
output
:
''
},
{
input
:
'
abc
'
,
output
:
'
abc
'
},
{
input
:
'
abc/
'
,
output
:
'
abc
'
},
{
input
:
'
abc/def
'
,
output
:
'
abc/def
'
},
{
input
:
'
abc/def/
'
,
output
:
'
abc/def
'
},
].
forEach
(({
input
,
output
})
=>
{
it
(
`cleans trailing slash from string "
${
input
}
"`
,
()
=>
{
expect
(
utils
.
cleanTrailingSlash
(
input
)).
toEqual
(
output
);
});
});
});
describe
(
'
pathsAreEqual
'
,
()
=>
{
[
{
args
:
[
'
abc
'
,
'
abc
'
],
output
:
true
},
{
args
:
[
'
abc
'
,
'
def
'
],
output
:
false
},
{
args
:
[
'
abc/
'
,
'
abc
'
],
output
:
true
},
{
args
:
[
'
abc/abc
'
,
'
abc
'
],
output
:
false
},
{
args
:
[
'
/
'
,
''
],
output
:
true
},
{
args
:
[
''
,
'
/
'
],
output
:
true
},
{
args
:
[
false
,
'
/
'
],
output
:
true
},
].
forEach
(({
args
,
output
})
=>
{
it
(
`cleans and tests equality (
${
JSON
.
stringify
(
args
)}
)`
,
()
=>
{
expect
(
utils
.
pathsAreEqual
(...
args
)).
toEqual
(
output
);
});
});
});
});
spec/javascripts/lazy_loader_spec.js
View file @
5ecacec3
...
...
@@ -62,7 +62,7 @@ describe('LazyLoader', function() {
waitForAttributeChange
(
newImg
,
[
'
data-src
'
,
'
src
'
]),
])
.
then
(()
=>
{
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
(
);
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
With
(
newImg
);
expect
(
newImg
.
getAttribute
(
'
src
'
)).
toBe
(
testPath
);
expect
(
newImg
).
toHaveClass
(
'
js-lazy-loaded
'
);
done
();
...
...
@@ -79,7 +79,7 @@ describe('LazyLoader', function() {
scrollIntoViewPromise
(
newImg
)
.
then
(
waitForPromises
)
.
then
(()
=>
{
expect
(
LazyLoader
.
loadImage
).
not
.
toHaveBeenCalled
(
);
expect
(
LazyLoader
.
loadImage
).
not
.
toHaveBeenCalled
With
(
newImg
);
expect
(
newImg
).
not
.
toHaveClass
(
'
js-lazy-loaded
'
);
done
();
})
...
...
@@ -98,7 +98,7 @@ describe('LazyLoader', function() {
scrollIntoViewPromise
(
newImg
)
.
then
(
waitForPromises
)
.
then
(()
=>
{
expect
(
LazyLoader
.
loadImage
).
not
.
toHaveBeenCalled
(
);
expect
(
LazyLoader
.
loadImage
).
not
.
toHaveBeenCalled
With
(
newImg
);
expect
(
newImg
).
not
.
toHaveClass
(
'
js-lazy-loaded
'
);
done
();
})
...
...
@@ -121,7 +121,7 @@ describe('LazyLoader', function() {
])
.
then
(
waitForPromises
)
.
then
(()
=>
{
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
(
);
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
With
(
newImg
);
expect
(
newImg
).
toHaveClass
(
'
js-lazy-loaded
'
);
done
();
})
...
...
@@ -156,7 +156,7 @@ describe('LazyLoader', function() {
Promise
.
all
([
scrollIntoViewPromise
(
img
),
waitForAttributeChange
(
img
,
[
'
data-src
'
,
'
src
'
])])
.
then
(()
=>
{
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
(
);
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
With
(
img
);
expect
(
img
.
getAttribute
(
'
src
'
)).
toBe
(
originalDataSrc
);
expect
(
img
).
toHaveClass
(
'
js-lazy-loaded
'
);
done
();
...
...
@@ -176,7 +176,7 @@ describe('LazyLoader', function() {
waitForAttributeChange
(
newImg
,
[
'
data-src
'
,
'
src
'
]),
])
.
then
(()
=>
{
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
(
);
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
With
(
newImg
);
expect
(
newImg
.
getAttribute
(
'
src
'
)).
toBe
(
testPath
);
expect
(
newImg
).
toHaveClass
(
'
js-lazy-loaded
'
);
done
();
...
...
@@ -193,7 +193,7 @@ describe('LazyLoader', function() {
scrollIntoViewPromise
(
newImg
)
.
then
(
waitForPromises
)
.
then
(()
=>
{
expect
(
LazyLoader
.
loadImage
).
not
.
toHaveBeenCalled
(
);
expect
(
LazyLoader
.
loadImage
).
not
.
toHaveBeenCalled
With
(
newImg
);
expect
(
newImg
).
not
.
toHaveClass
(
'
js-lazy-loaded
'
);
done
();
})
...
...
@@ -212,7 +212,7 @@ describe('LazyLoader', function() {
scrollIntoViewPromise
(
newImg
)
.
then
(
waitForPromises
)
.
then
(()
=>
{
expect
(
LazyLoader
.
loadImage
).
not
.
toHaveBeenCalled
(
);
expect
(
LazyLoader
.
loadImage
).
not
.
toHaveBeenCalled
With
(
newImg
);
expect
(
newImg
).
not
.
toHaveClass
(
'
js-lazy-loaded
'
);
done
();
})
...
...
@@ -234,7 +234,7 @@ describe('LazyLoader', function() {
waitForAttributeChange
(
newImg
,
[
'
data-src
'
,
'
src
'
]),
])
.
then
(()
=>
{
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
(
);
expect
(
LazyLoader
.
loadImage
).
toHaveBeenCalled
With
(
newImg
);
expect
(
newImg
).
toHaveClass
(
'
js-lazy-loaded
'
);
done
();
})
...
...
spec/javascripts/vue_shared/components/file_row_spec.js
View file @
5ecacec3
...
...
@@ -90,19 +90,6 @@ describe('File row component', () => {
expect
(
vm
.
$el
.
querySelector
(
'
.js-file-row-header
'
)).
not
.
toBe
(
null
);
});
it
(
'
is not rendered for `moved` entries in subfolders
'
,
()
=>
{
createComponent
({
file
:
{
path
:
'
t5
'
,
moved
:
true
,
tree
:
[],
},
level
:
2
,
});
expect
(
vm
.
$el
.
nodeType
).
not
.
toEqual
(
1
);
});
describe
(
'
new dropdown
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
...
...
spec/lib/gitlab_spec.rb
View file @
5ecacec3
...
...
@@ -150,6 +150,7 @@ describe Gitlab do
describe
'.ee?'
do
before
do
stub_env
(
'IS_GITLAB_EE'
,
nil
)
# Make sure the ENV is clean
described_class
.
instance_variable_set
(
:@is_ee
,
nil
)
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