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
53ae6b7e
Commit
53ae6b7e
authored
Feb 17, 2020
by
GitLab Bot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add latest changes from gitlab-org/gitlab@master
parent
cfe63cce
Changes
49
Show whitespace changes
Inline
Side-by-side
Showing
49 changed files
with
583 additions
and
216 deletions
+583
-216
app/assets/javascripts/behaviors/markdown/render_mermaid.js
app/assets/javascripts/behaviors/markdown/render_mermaid.js
+18
-1
app/assets/javascripts/behaviors/shortcuts/shortcuts.js
app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+22
-1
app/assets/javascripts/behaviors/shortcuts/shortcuts_toggle.js
...ssets/javascripts/behaviors/shortcuts/shortcuts_toggle.js
+22
-0
app/assets/javascripts/behaviors/shortcuts/shortcuts_toggle.vue
...sets/javascripts/behaviors/shortcuts/shortcuts_toggle.vue
+60
-0
app/assets/javascripts/blob/pdf/index.js
app/assets/javascripts/blob/pdf/index.js
+3
-5
app/assets/javascripts/filtered_search/filtered_search_dropdown.js
...s/javascripts/filtered_search/filtered_search_dropdown.js
+1
-1
app/assets/javascripts/notes/constants.js
app/assets/javascripts/notes/constants.js
+1
-0
app/assets/javascripts/notes/mixins/description_version_history.js
...s/javascripts/notes/mixins/description_version_history.js
+2
-0
app/assets/javascripts/notes/stores/actions.js
app/assets/javascripts/notes/stores/actions.js
+48
-5
app/assets/javascripts/notes/stores/collapse_utils.js
app/assets/javascripts/notes/stores/collapse_utils.js
+6
-2
app/assets/javascripts/notes/stores/modules/index.js
app/assets/javascripts/notes/stores/modules/index.js
+2
-0
app/assets/javascripts/notes/stores/mutation_types.js
app/assets/javascripts/notes/stores/mutation_types.js
+8
-0
app/assets/javascripts/notes/stores/mutations.js
app/assets/javascripts/notes/stores/mutations.js
+21
-0
app/assets/javascripts/pipelines/pipeline_details_bundle.js
app/assets/javascripts/pipelines/pipeline_details_bundle.js
+1
-1
app/assets/javascripts/vue_shared/components/notes/system_note.vue
...s/javascripts/vue_shared/components/notes/system_note.vue
+20
-4
app/assets/stylesheets/pages/notes.scss
app/assets/stylesheets/pages/notes.scss
+9
-4
app/models/commit_status_enums.rb
app/models/commit_status_enums.rb
+1
-0
app/models/deployment.rb
app/models/deployment.rb
+11
-0
app/models/environment.rb
app/models/environment.rb
+1
-0
app/models/member.rb
app/models/member.rb
+1
-0
app/models/project.rb
app/models/project.rb
+1
-0
app/models/project_ci_cd_setting.rb
app/models/project_ci_cd_setting.rb
+6
-0
app/presenters/commit_status_presenter.rb
app/presenters/commit_status_presenter.rb
+1
-0
app/services/deployments/older_deployments_drop_service.rb
app/services/deployments/older_deployments_drop_service.rb
+31
-0
app/views/help/_shortcuts.html.haml
app/views/help/_shortcuts.html.haml
+1
-0
app/views/layouts/header/_help_dropdown.html.haml
app/views/layouts/header/_help_dropdown.html.haml
+4
-0
app/views/projects/pipelines/show.html.haml
app/views/projects/pipelines/show.html.haml
+2
-1
app/workers/all_queues.yml
app/workers/all_queues.yml
+6
-0
app/workers/deployments/forward_deployment_worker.rb
app/workers/deployments/forward_deployment_worker.rb
+14
-0
changelogs/unreleased/22113-improve-keyboard-shortcuts-or-allow-them-to-be-disabled.yml
...prove-keyboard-shortcuts-or-allow-them-to-be-disabled.yml
+5
-0
changelogs/unreleased/25276-allow-forward-deploys-only.yml
changelogs/unreleased/25276-allow-forward-deploys-only.yml
+5
-0
changelogs/unreleased/psi-mermaid-details.yml
changelogs/unreleased/psi-mermaid-details.yml
+5
-0
db/migrate/20200124143014_add_restrict_deployment_order_to_project_ci_cd_settings.rb
...dd_restrict_deployment_order_to_project_ci_cd_settings.rb
+9
-0
db/post_migrate/20200210062432_schedule_link_lfs_objects.rb
db/post_migrate/20200210062432_schedule_link_lfs_objects.rb
+1
-22
db/schema.rb
db/schema.rb
+1
-0
doc/user/shortcuts.md
doc/user/shortcuts.md
+4
-1
lib/gitlab/background_migration/link_lfs_objects.rb
lib/gitlab/background_migration/link_lfs_objects.rb
+1
-18
lib/gitlab/ci/status/build/failed.rb
lib/gitlab/ci/status/build/failed.rb
+1
-0
lib/quality/kubernetes_client.rb
lib/quality/kubernetes_client.rb
+1
-1
locale/gitlab.pot
locale/gitlab.pot
+18
-0
spec/factories/projects.rb
spec/factories/projects.rb
+1
-0
spec/features/markdown/mermaid_spec.rb
spec/features/markdown/mermaid_spec.rb
+30
-0
spec/features/projects/user_uses_shortcuts_spec.rb
spec/features/projects/user_uses_shortcuts_spec.rb
+53
-0
spec/lib/gitlab/background_migration/link_lfs_objects_spec.rb
.../lib/gitlab/background_migration/link_lfs_objects_spec.rb
+0
-66
spec/lib/quality/kubernetes_client_spec.rb
spec/lib/quality/kubernetes_client_spec.rb
+1
-1
spec/migrations/schedule_link_lfs_objects_spec.rb
spec/migrations/schedule_link_lfs_objects_spec.rb
+0
-82
spec/models/deployment_spec.rb
spec/models/deployment_spec.rb
+39
-0
spec/models/project_ci_cd_setting_spec.rb
spec/models/project_ci_cd_setting_spec.rb
+6
-0
spec/services/deployments/older_deployments_drop_service_spec.rb
...rvices/deployments/older_deployments_drop_service_spec.rb
+78
-0
No files found.
app/assets/javascripts/behaviors/markdown/render_mermaid.js
View file @
53ae6b7e
import
flash
from
'
~/flash
'
;
import
$
from
'
jquery
'
;
import
{
sprintf
,
__
}
from
'
../../locale
'
;
// Renders diagrams and flowcharts from text using Mermaid in any element with the
...
...
@@ -18,7 +19,7 @@ import { sprintf, __ } from '../../locale';
// This is an arbitrary number; Can be iterated upon when suitable.
const
MAX_CHAR_LIMIT
=
5000
;
export
default
function
renderMermaid
(
$els
)
{
function
renderMermaids
(
$els
)
{
if
(
!
$els
.
length
)
return
;
// A diagram may have been truncated in search results which will cause errors, so abort the render.
...
...
@@ -95,3 +96,19 @@ export default function renderMermaid($els) {
flash
(
`Can't load mermaid module:
${
err
}
`
);
});
}
export
default
function
renderMermaid
(
$els
)
{
if
(
!
$els
.
length
)
return
;
const
visibleMermaids
=
$els
.
filter
(
function
filter
()
{
return
$
(
this
).
closest
(
'
details
'
).
length
===
0
;
});
renderMermaids
(
visibleMermaids
);
$els
.
closest
(
'
details
'
).
one
(
'
toggle
'
,
function
toggle
()
{
if
(
this
.
open
)
{
renderMermaids
(
$
(
this
).
find
(
'
.js-render-mermaid
'
));
}
});
}
app/assets/javascripts/behaviors/shortcuts/shortcuts.js
View file @
53ae6b7e
import
$
from
'
jquery
'
;
import
Cookies
from
'
js-cookie
'
;
import
Mousetrap
from
'
mousetrap
'
;
import
Vue
from
'
vue
'
;
import
{
disableShortcuts
,
shouldDisableShortcuts
}
from
'
./shortcuts_toggle
'
;
import
ShortcutsToggle
from
'
./shortcuts_toggle.vue
'
;
import
axios
from
'
../../lib/utils/axios_utils
'
;
import
{
refreshCurrentPage
,
visitUrl
}
from
'
../../lib/utils/url_utility
'
;
import
findAndFollowLink
from
'
../../lib/utils/navigation_utility
'
;
...
...
@@ -15,6 +18,15 @@ Mousetrap.stopCallback = (e, element, combo) => {
return
defaultStopCallback
(
e
,
element
,
combo
);
};
function
initToggleButton
()
{
return
new
Vue
({
el
:
document
.
querySelector
(
'
.js-toggle-shortcuts
'
),
render
(
createElement
)
{
return
createElement
(
ShortcutsToggle
);
},
});
}
export
default
class
Shortcuts
{
constructor
()
{
this
.
onToggleHelp
=
this
.
onToggleHelp
.
bind
(
this
);
...
...
@@ -48,6 +60,14 @@ export default class Shortcuts {
$
(
this
).
remove
();
e
.
preventDefault
();
});
$
(
'
.js-shortcuts-modal-trigger
'
)
.
off
(
'
click
'
)
.
on
(
'
click
'
,
this
.
onToggleHelp
);
if
(
shouldDisableShortcuts
())
{
disableShortcuts
();
}
}
onToggleHelp
(
e
)
{
...
...
@@ -104,7 +124,8 @@ export default class Shortcuts {
}
return
$
(
'
.js-more-help-button
'
).
remove
();
});
})
.
then
(
initToggleButton
);
}
focusFilter
(
e
)
{
...
...
app/assets/javascripts/behaviors/shortcuts/shortcuts_toggle.js
0 → 100644
View file @
53ae6b7e
import
Mousetrap
from
'
mousetrap
'
;
import
'
mousetrap/plugins/pause/mousetrap-pause
'
;
const
shorcutsDisabledKey
=
'
shortcutsDisabled
'
;
export
const
shouldDisableShortcuts
=
()
=>
{
try
{
return
localStorage
.
getItem
(
shorcutsDisabledKey
)
===
'
true
'
;
}
catch
(
e
)
{
return
false
;
}
};
export
function
enableShortcuts
()
{
localStorage
.
setItem
(
shorcutsDisabledKey
,
false
);
Mousetrap
.
unpause
();
}
export
function
disableShortcuts
()
{
localStorage
.
setItem
(
shorcutsDisabledKey
,
true
);
Mousetrap
.
pause
();
}
app/assets/javascripts/behaviors/shortcuts/shortcuts_toggle.vue
0 → 100644
View file @
53ae6b7e
<
script
>
import
{
GlToggle
,
GlSprintf
}
from
'
@gitlab/ui
'
;
import
AccessorUtilities
from
'
~/lib/utils/accessor
'
;
import
{
disableShortcuts
,
enableShortcuts
,
shouldDisableShortcuts
}
from
'
./shortcuts_toggle
'
;
export
default
{
components
:
{
GlSprintf
,
GlToggle
,
},
data
()
{
return
{
localStorageUsable
:
AccessorUtilities
.
isLocalStorageAccessSafe
(),
shortcutsEnabled
:
!
shouldDisableShortcuts
(),
};
},
methods
:
{
onChange
(
value
)
{
this
.
shortcutsEnabled
=
value
;
if
(
value
)
{
enableShortcuts
();
}
else
{
disableShortcuts
();
}
},
},
};
</
script
>
<
template
>
<div
v-if=
"localStorageUsable"
class=
"d-inline-flex align-items-center js-toggle-shortcuts"
>
<gl-toggle
v-model=
"shortcutsEnabled"
aria-describedby=
"shortcutsToggle"
class=
"prepend-left-10 mb-0"
label-position=
"right"
@
change=
"onChange"
>
<template
#labelOn
>
<gl-sprintf
:message=
"__('%
{screenreaderOnlyStart}Keyboard shorcuts%{screenreaderOnlyEnd} Enabled')"
>
<template
#screenreaderOnly
="
{ content }">
<span
class=
"sr-only"
>
{{
content
}}
</span>
</
template
>
</gl-sprintf>
</template>
<
template
#labelOff
>
<gl-sprintf
:message=
"__('%
{screenreaderOnlyStart}Keyboard shorcuts%{screenreaderOnlyEnd} Disabled')"
>
<template
#screenreaderOnly
="
{ content }">
<span
class=
"sr-only"
>
{{
content
}}
</span>
</
template
>
</gl-sprintf>
</template>
</gl-toggle>
<div
id=
"shortcutsToggle"
class=
"sr-only"
>
{{ __('Enable or disable keyboard shortcuts') }}
</div>
</div>
</template>
app/assets/javascripts/blob/pdf/index.js
View file @
53ae6b7e
import
Vue
from
'
vue
'
;
import
pdfLab
from
'
../../pdf/index.vue
'
;
import
{
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
export
default
()
=>
{
const
el
=
document
.
getElementById
(
'
js-pdf-viewer
'
);
...
...
@@ -8,6 +9,7 @@ export default () => {
el
,
components
:
{
pdfLab
,
GlLoadingIcon
,
},
data
()
{
return
{
...
...
@@ -32,11 +34,7 @@ export default () => {
<div
class="text-center loading"
v-if="loading && !error">
<i
class="fa fa-spinner fa-spin"
aria-hidden="true"
aria-label="PDF loading">
</i>
<gl-loading-icon class="mt-5" size="lg"/>
</div>
<pdf-lab
v-if="!loadError"
...
...
app/assets/javascripts/filtered_search/filtered_search_dropdown.js
View file @
53ae6b7e
...
...
@@ -12,7 +12,7 @@ export default class FilteredSearchDropdown {
this
.
filter
=
filter
;
this
.
dropdown
=
dropdown
;
this
.
loadingTemplate
=
`<div class="filter-dropdown-loading">
<
i class="fa fa-spinner fa-spin"></i
>
<
span class="spinner"></span
>
</div>`
;
this
.
bindEvents
();
}
...
...
app/assets/javascripts/notes/constants.js
View file @
53ae6b7e
...
...
@@ -18,6 +18,7 @@ export const HISTORY_ONLY_FILTER_VALUE = 2;
export
const
DISCUSSION_FILTERS_DEFAULT_VALUE
=
0
;
export
const
DISCUSSION_TAB_LABEL
=
'
show
'
;
export
const
NOTE_UNDERSCORE
=
'
note_
'
;
export
const
TIME_DIFFERENCE_VALUE
=
10
;
export
const
NOTEABLE_TYPE_MAPPING
=
{
Issue
:
ISSUE_NOTEABLE_TYPE
,
...
...
app/assets/javascripts/notes/mixins/description_version_history.js
View file @
53ae6b7e
...
...
@@ -3,10 +3,12 @@
export
default
{
computed
:
{
canSeeDescriptionVersion
()
{},
canDeleteDescriptionVersion
()
{},
shouldShowDescriptionVersion
()
{},
descriptionVersionToggleIcon
()
{},
},
methods
:
{
toggleDescriptionVersion
()
{},
deleteDescriptionVersion
()
{},
},
};
app/assets/javascripts/notes/stores/actions.js
View file @
53ae6b7e
...
...
@@ -491,23 +491,66 @@ export const convertToDiscussion = ({ commit }, noteId) =>
export
const
removeConvertedDiscussion
=
({
commit
},
noteId
)
=>
commit
(
types
.
REMOVE_CONVERTED_DISCUSSION
,
noteId
);
export
const
fetchDescriptionVersion
=
(
_
,
{
endpoint
,
startingVersion
})
=>
{
export
const
setCurrentDiscussionId
=
({
commit
},
discussionId
)
=>
commit
(
types
.
SET_CURRENT_DISCUSSION_ID
,
discussionId
);
export
const
fetchDescriptionVersion
=
({
dispatch
},
{
endpoint
,
startingVersion
})
=>
{
let
requestUrl
=
endpoint
;
if
(
startingVersion
)
{
requestUrl
=
mergeUrlParams
({
start_version_id
:
startingVersion
},
requestUrl
);
}
dispatch
(
'
requestDescriptionVersion
'
);
return
axios
.
get
(
requestUrl
)
.
then
(
res
=>
res
.
data
)
.
catch
(()
=>
{
.
then
(
res
=>
{
dispatch
(
'
receiveDescriptionVersion
'
,
res
.
data
);
})
.
catch
(
error
=>
{
dispatch
(
'
receiveDescriptionVersionError
'
,
error
);
Flash
(
__
(
'
Something went wrong while fetching description changes. Please try again.
'
));
});
};
export
const
setCurrentDiscussionId
=
({
commit
},
discussionId
)
=>
commit
(
types
.
SET_CURRENT_DISCUSSION_ID
,
discussionId
);
export
const
requestDescriptionVersion
=
({
commit
})
=>
{
commit
(
types
.
REQUEST_DESCRIPTION_VERSION
);
};
export
const
receiveDescriptionVersion
=
({
commit
},
descriptionVersion
)
=>
{
commit
(
types
.
RECEIVE_DESCRIPTION_VERSION
,
descriptionVersion
);
};
export
const
receiveDescriptionVersionError
=
({
commit
},
error
)
=>
{
commit
(
types
.
RECEIVE_DESCRIPTION_VERSION_ERROR
,
error
);
};
export
const
softDeleteDescriptionVersion
=
({
dispatch
},
{
endpoint
,
startingVersion
})
=>
{
let
requestUrl
=
endpoint
;
if
(
startingVersion
)
{
requestUrl
=
mergeUrlParams
({
start_version_id
:
startingVersion
},
requestUrl
);
}
dispatch
(
'
requestDeleteDescriptionVersion
'
);
return
axios
.
delete
(
requestUrl
)
.
then
(()
=>
{
dispatch
(
'
receiveDeleteDescriptionVersion
'
);
})
.
catch
(
error
=>
{
dispatch
(
'
receiveDeleteDescriptionVersionError
'
,
error
);
Flash
(
__
(
'
Something went wrong while deleting description changes. Please try again.
'
));
});
};
export
const
requestDeleteDescriptionVersion
=
({
commit
})
=>
{
commit
(
types
.
REQUEST_DELETE_DESCRIPTION_VERSION
);
};
export
const
receiveDeleteDescriptionVersion
=
({
commit
})
=>
{
commit
(
types
.
RECEIVE_DELETE_DESCRIPTION_VERSION
,
__
(
'
Deleted
'
));
};
export
const
receiveDeleteDescriptionVersionError
=
({
commit
},
error
)
=>
{
commit
(
types
.
RECEIVE_DELETE_DESCRIPTION_VERSION_ERROR
,
error
);
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export
default
()
=>
{};
app/assets/javascripts/notes/stores/collapse_utils.js
View file @
53ae6b7e
import
{
DESCRIPTION_TYPE
}
from
'
../constants
'
;
import
{
DESCRIPTION_TYPE
,
TIME_DIFFERENCE_VALUE
}
from
'
../constants
'
;
/**
* Checks the time difference between two notes from their 'created_at' dates
...
...
@@ -45,7 +45,11 @@ export const collapseSystemNotes = notes => {
const
timeDifferenceMinutes
=
getTimeDifferenceMinutes
(
lastDescriptionSystemNote
,
note
);
// are they less than 10 minutes apart from the same user?
if
(
timeDifferenceMinutes
>
10
||
note
.
author
.
id
!==
lastDescriptionSystemNote
.
author
.
id
)
{
if
(
timeDifferenceMinutes
>
TIME_DIFFERENCE_VALUE
||
note
.
author
.
id
!==
lastDescriptionSystemNote
.
author
.
id
||
lastDescriptionSystemNote
.
description_version_deleted
)
{
// update the previous system note
lastDescriptionSystemNote
=
note
;
lastDescriptionSystemNoteIndex
=
acc
.
length
;
...
...
app/assets/javascripts/notes/stores/modules/index.js
View file @
53ae6b7e
...
...
@@ -14,6 +14,7 @@ export default () => ({
isToggleStateButtonLoading
:
false
,
isNotesFetched
:
false
,
isLoading
:
true
,
isLoadingDescriptionVersion
:
false
,
// holds endpoints and permissions provided through haml
notesData
:
{
...
...
@@ -27,6 +28,7 @@ export default () => ({
commentsDisabled
:
false
,
resolvableDiscussionsCount
:
0
,
unresolvedDiscussionsCount
:
0
,
descriptionVersion
:
null
,
},
actions
,
getters
,
...
...
app/assets/javascripts/notes/stores/mutation_types.js
View file @
53ae6b7e
...
...
@@ -31,3 +31,11 @@ export const SET_CURRENT_DISCUSSION_ID = 'SET_CURRENT_DISCUSSION_ID';
export
const
CLOSE_ISSUE
=
'
CLOSE_ISSUE
'
;
export
const
REOPEN_ISSUE
=
'
REOPEN_ISSUE
'
;
export
const
TOGGLE_STATE_BUTTON_LOADING
=
'
TOGGLE_STATE_BUTTON_LOADING
'
;
// Description version
export
const
REQUEST_DESCRIPTION_VERSION
=
'
REQUEST_DESCRIPTION_VERSION
'
;
export
const
RECEIVE_DESCRIPTION_VERSION
=
'
RECEIVE_DESCRIPTION_VERSION
'
;
export
const
RECEIVE_DESCRIPTION_VERSION_ERROR
=
'
RECEIVE_DESCRIPTION_VERSION_ERROR
'
;
export
const
REQUEST_DELETE_DESCRIPTION_VERSION
=
'
REQUEST_DELETE_DESCRIPTION_VERSION
'
;
export
const
RECEIVE_DELETE_DESCRIPTION_VERSION
=
'
RECEIVE_DELETE_DESCRIPTION_VERSION
'
;
export
const
RECEIVE_DELETE_DESCRIPTION_VERSION_ERROR
=
'
RECEIVE_DELETE_DESCRIPTION_VERSION_ERROR
'
;
app/assets/javascripts/notes/stores/mutations.js
View file @
53ae6b7e
...
...
@@ -284,4 +284,25 @@ export default {
[
types
.
SET_CURRENT_DISCUSSION_ID
](
state
,
discussionId
)
{
state
.
currentDiscussionId
=
discussionId
;
},
[
types
.
REQUEST_DESCRIPTION_VERSION
](
state
)
{
state
.
isLoadingDescriptionVersion
=
true
;
},
[
types
.
RECEIVE_DESCRIPTION_VERSION
](
state
,
descriptionVersion
)
{
state
.
isLoadingDescriptionVersion
=
false
;
state
.
descriptionVersion
=
descriptionVersion
;
},
[
types
.
RECEIVE_DESCRIPTION_VERSION_ERROR
](
state
)
{
state
.
isLoadingDescriptionVersion
=
false
;
},
[
types
.
REQUEST_DELETE_DESCRIPTION_VERSION
](
state
)
{
state
.
isLoadingDescriptionVersion
=
true
;
},
[
types
.
RECEIVE_DELETE_DESCRIPTION_VERSION
](
state
,
descriptionVersion
)
{
state
.
isLoadingDescriptionVersion
=
false
;
state
.
descriptionVersion
=
descriptionVersion
;
},
[
types
.
RECEIVE_DELETE_DESCRIPTION_VERSION_ERROR
](
state
)
{
state
.
isLoadingDescriptionVersion
=
false
;
},
};
app/assets/javascripts/pipelines/pipeline_details_bundle.js
View file @
53ae6b7e
...
...
@@ -132,7 +132,7 @@ export default () => {
});
axios
.
get
(
dataset
.
testReportEndpoint
)
.
get
(
dataset
.
testReport
sCount
Endpoint
)
.
then
(({
data
})
=>
{
document
.
querySelector
(
'
.js-test-report-badge-counter
'
).
innerHTML
=
data
.
total_count
;
})
...
...
app/assets/javascripts/vue_shared/components/notes/system_note.vue
View file @
53ae6b7e
...
...
@@ -17,11 +17,12 @@
* />
*/
import
$
from
'
jquery
'
;
import
{
mapGetters
,
mapActions
}
from
'
vuex
'
;
import
{
Gl
SkeletonLoading
}
from
'
@gitlab/ui
'
;
import
{
mapGetters
,
mapActions
,
mapState
}
from
'
vuex
'
;
import
{
Gl
Button
,
GlSkeletonLoading
,
GlTooltipDirective
}
from
'
@gitlab/ui
'
;
import
descriptionVersionHistoryMixin
from
'
ee_else_ce/notes/mixins/description_version_history
'
;
import
noteHeader
from
'
~/notes/components/note_header.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
glFeatureFlagsMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
TimelineEntryItem
from
'
./timeline_entry_item.vue
'
;
import
{
spriteIcon
}
from
'
../../../lib/utils/common_utils
'
;
import
initMRPopovers
from
'
~/mr_popover/
'
;
...
...
@@ -34,9 +35,13 @@ export default {
Icon
,
noteHeader
,
TimelineEntryItem
,
GlButton
,
GlSkeletonLoading
,
},
mixins
:
[
descriptionVersionHistoryMixin
],
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
mixins
:
[
descriptionVersionHistoryMixin
,
glFeatureFlagsMixin
()],
props
:
{
note
:
{
type
:
Object
,
...
...
@@ -50,6 +55,7 @@ export default {
},
computed
:
{
...
mapGetters
([
'
targetNoteHash
'
]),
...
mapState
([
'
descriptionVersion
'
,
'
isLoadingDescriptionVersion
'
]),
noteAnchorId
()
{
return
`note_
${
this
.
note
.
id
}
`
;
},
...
...
@@ -80,7 +86,7 @@ export default {
initMRPopovers
(
this
.
$el
.
querySelectorAll
(
'
.gfm-merge_request
'
));
},
methods
:
{
...
mapActions
([
'
fetchDescriptionVersion
'
]),
...
mapActions
([
'
fetchDescriptionVersion
'
,
'
softDeleteDescriptionVersion
'
]),
},
};
</
script
>
...
...
@@ -122,6 +128,16 @@ export default {
<gl-skeleton-loading
/>
</pre>
<pre
v-else
class=
"wrapper mt-2"
v-html=
"descriptionVersion"
></pre>
<gl-button
v-if=
"canDeleteDescriptionVersion"
ref=
"deleteDescriptionVersionButton"
v-gl-tooltip
:title=
"__('Remove description history')"
class=
"btn-transparent delete-description-history"
@
click=
"deleteDescriptionVersion"
>
<icon
name=
"remove"
/>
</gl-button>
</div>
</div>
</div>
...
...
app/assets/stylesheets/pages/notes.scss
View file @
53ae6b7e
...
...
@@ -311,13 +311,18 @@ $note-form-margin-left: 72px;
overflow
:
hidden
;
.description-version
{
position
:
relative
;
.btn.delete-description-history
{
position
:
absolute
;
top
:
18px
;
right
:
0
;
}
pre
{
max-height
:
$dropdown-max-height-lg
;
white-space
:
pre-wrap
;
&
.loading-state
{
height
:
94px
;
}
padding-right
:
30px
;
}
}
...
...
app/models/commit_status_enums.rb
View file @
53ae6b7e
...
...
@@ -18,6 +18,7 @@ module CommitStatusEnums
unmet_prerequisites:
10
,
scheduler_failure:
11
,
data_integrity_failure:
12
,
forward_deployment_failure:
13
,
insufficient_bridge_permissions:
1_001
,
downstream_bridge_project_not_found:
1_002
,
invalid_bridge_trigger:
1_003
,
...
...
app/models/deployment.rb
View file @
53ae6b7e
...
...
@@ -41,6 +41,9 @@ class Deployment < ApplicationRecord
scope
:visible
,
->
{
where
(
status:
%i[running success failed canceled]
)
}
scope
:stoppable
,
->
{
where
.
not
(
on_stop:
nil
).
where
.
not
(
deployable_id:
nil
).
success
}
scope
:active
,
->
{
where
(
status:
%i[created running]
)
}
scope
:older_than
,
->
(
deployment
)
{
where
(
'id < ?'
,
deployment
.
id
)
}
scope
:with_deployable
,
->
{
includes
(
:deployable
).
where
(
'deployable_id IS NOT NULL'
)
}
state_machine
:status
,
initial: :created
do
event
:run
do
...
...
@@ -74,6 +77,14 @@ class Deployment < ApplicationRecord
Deployments
::
FinishedWorker
.
perform_async
(
id
)
end
end
after_transition
any
=>
:running
do
|
deployment
|
next
unless
deployment
.
project
.
forward_deployment_enabled?
deployment
.
run_after_commit
do
Deployments
::
ForwardDeploymentWorker
.
perform_async
(
id
)
end
end
end
enum
status:
{
...
...
app/models/environment.rb
View file @
53ae6b7e
...
...
@@ -12,6 +12,7 @@ class Environment < ApplicationRecord
has_many
:deployments
,
->
{
visible
},
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
has_many
:successful_deployments
,
->
{
success
},
class_name:
'Deployment'
has_many
:active_deployments
,
->
{
active
},
class_name:
'Deployment'
has_many
:prometheus_alerts
,
inverse_of: :environment
has_one
:last_deployment
,
->
{
success
.
order
(
'deployments.id DESC'
)
},
class_name:
'Deployment'
...
...
app/models/member.rb
View file @
53ae6b7e
...
...
@@ -75,6 +75,7 @@ class Member < ApplicationRecord
scope
:reporters
,
->
{
active
.
where
(
access_level:
REPORTER
)
}
scope
:developers
,
->
{
active
.
where
(
access_level:
DEVELOPER
)
}
scope
:maintainers
,
->
{
active
.
where
(
access_level:
MAINTAINER
)
}
scope
:non_guests
,
->
{
where
(
'members.access_level > ?'
,
GUEST
)
}
scope
:masters
,
->
{
maintainers
}
# @deprecated
scope
:owners
,
->
{
active
.
where
(
access_level:
OWNER
)
}
scope
:owners_and_maintainers
,
->
{
active
.
where
(
access_level:
[
OWNER
,
MAINTAINER
])
}
...
...
app/models/project.rb
View file @
53ae6b7e
...
...
@@ -343,6 +343,7 @@ class Project < ApplicationRecord
delegate
:last_pipeline
,
to: :commit
,
allow_nil:
true
delegate
:external_dashboard_url
,
to: :metrics_setting
,
allow_nil:
true
,
prefix:
true
delegate
:default_git_depth
,
:default_git_depth
=
,
to: :ci_cd_settings
,
prefix: :ci
delegate
:forward_deployment_enabled
,
:forward_deployment_enabled
=
,
:forward_deployment_enabled?
,
to: :ci_cd_settings
# Validations
validates
:creator
,
presence:
true
,
on: :create
...
...
app/models/project_ci_cd_setting.rb
View file @
53ae6b7e
...
...
@@ -18,6 +18,8 @@ class ProjectCiCdSetting < ApplicationRecord
},
allow_nil:
true
default_value_for
:forward_deployment_enabled
,
true
def
self
.
available?
@available
||=
ActiveRecord
::
Migrator
.
current_version
>=
MINIMUM_SCHEMA_VERSION
...
...
@@ -28,6 +30,10 @@ class ProjectCiCdSetting < ApplicationRecord
super
end
def
forward_deployment_enabled?
super
&&
::
Feature
.
enabled?
(
:forward_deployment_enabled
,
project
)
end
private
def
set_default_git_depth
...
...
app/presenters/commit_status_presenter.rb
View file @
53ae6b7e
...
...
@@ -14,6 +14,7 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
unmet_prerequisites:
'The job failed to complete prerequisite tasks'
,
scheduler_failure:
'The scheduler failed to assign job to the runner, please try again or contact system administrator'
,
data_integrity_failure:
'There has been a structural integrity problem detected, please contact system administrator'
,
forward_deployment_failure:
'The deployment job is older than the previously succeeded deployment job, and therefore cannot be run'
,
invalid_bridge_trigger:
'This job could not be executed because downstream pipeline trigger definition is invalid'
,
downstream_bridge_project_not_found:
'This job could not be executed because downstream bridge project could not be found'
,
insufficient_bridge_permissions:
'This job could not be executed because of insufficient permissions to create a downstream pipeline'
,
...
...
app/services/deployments/older_deployments_drop_service.rb
0 → 100644
View file @
53ae6b7e
# frozen_string_literal: true
module
Deployments
class
OlderDeploymentsDropService
attr_reader
:deployment
def
initialize
(
deployment_id
)
@deployment
=
Deployment
.
find_by_id
(
deployment_id
)
end
def
execute
return
unless
@deployment
&
.
running?
older_deployments
.
find_each
do
|
older_deployment
|
older_deployment
.
deployable
&
.
drop!
(
:forward_deployment_failure
)
rescue
=>
e
Gitlab
::
ErrorTracking
.
track_exception
(
e
,
subject_id:
@deployment
.
id
,
deployment_id:
older_deployment
.
id
)
end
end
private
def
older_deployments
@deployment
.
environment
.
active_deployments
.
older_than
(
@deployment
)
.
with_deployable
end
end
end
app/views/help/_shortcuts.html.haml
View file @
53ae6b7e
...
...
@@ -6,6 +6,7 @@
=
_
(
'Keyboard Shortcuts'
)
%small
=
link_to
_
(
'(Show all)'
),
'#'
,
class:
'js-more-help-button'
.js-toggle-shortcuts
%button
.close
{
type:
"button"
,
"data-dismiss"
:
"modal"
,
"aria-label"
=>
_
(
'Close'
)
}
%span
{
"aria-hidden"
:
true
}
×
.modal-body
...
...
app/views/layouts/header/_help_dropdown.html.haml
View file @
53ae6b7e
...
...
@@ -4,6 +4,10 @@
=
link_to
_
(
"Help"
),
help_path
%li
=
link_to
_
(
"Support"
),
support_url
%li
%button
.js-shortcuts-modal-trigger
{
type:
"button"
}
=
_
(
"Keyboard shortcuts"
)
%span
.text-secondary.float-right
{
"aria-hidden"
:
true
}=
'?'
.
html_safe
=
render_if_exists
"shared/learn_gitlab_menu_item"
%li
.divider
%li
...
...
app/views/projects/pipelines/show.html.haml
View file @
53ae6b7e
...
...
@@ -21,4 +21,5 @@
=
render
"projects/pipelines/with_tabs"
,
pipeline:
@pipeline
.js-pipeline-details-vue
{
data:
{
endpoint:
project_pipeline_path
(
@project
,
@pipeline
,
format: :json
),
test_report_endpoint:
test_report_project_pipeline_path
(
@project
,
@pipeline
,
format: :json
)
}
}
test_report_endpoint:
test_report_project_pipeline_path
(
@project
,
@pipeline
,
format: :json
),
test_reports_count_endpoint:
test_reports_count_project_pipeline_path
(
@project
,
@pipeline
,
format: :json
)
}
}
app/workers/all_queues.yml
View file @
53ae6b7e
...
...
@@ -225,6 +225,12 @@
:latency_sensitive:
:resource_boundary: :cpu
:weight:
3
-
:name: deployment:deployments_forward_deployment
:feature_category: :continuous_delivery
:has_external_dependencies:
:latency_sensitive:
:resource_boundary: :unknown
:weight:
3
-
:name: deployment:deployments_success
:feature_category: :continuous_delivery
:has_external_dependencies:
...
...
app/workers/deployments/forward_deployment_worker.rb
0 → 100644
View file @
53ae6b7e
# frozen_string_literal: true
module
Deployments
class
ForwardDeploymentWorker
include
ApplicationWorker
queue_namespace
:deployment
feature_category
:continuous_delivery
def
perform
(
deployment_id
)
Deployments
::
OlderDeploymentsDropService
.
new
(
deployment_id
).
execute
end
end
end
changelogs/unreleased/22113-improve-keyboard-shortcuts-or-allow-them-to-be-disabled.yml
0 → 100644
View file @
53ae6b7e
---
title
:
Allow keyboard shortcuts to be disabled
merge_request
:
18782
author
:
type
:
added
changelogs/unreleased/25276-allow-forward-deploys-only.yml
0 → 100644
View file @
53ae6b7e
---
title
:
Allow to deploy only forward deployments
merge_request
:
22959
author
:
type
:
changed
changelogs/unreleased/psi-mermaid-details.yml
0 → 100644
View file @
53ae6b7e
---
title
:
Correctly render mermaid digrams inside details blocks
merge_request
:
23662
author
:
type
:
fixed
db/migrate/20200124143014_add_restrict_deployment_order_to_project_ci_cd_settings.rb
0 → 100644
View file @
53ae6b7e
# frozen_string_literal: true
class
AddRestrictDeploymentOrderToProjectCiCdSettings
<
ActiveRecord
::
Migration
[
5.2
]
DOWNTIME
=
false
def
change
add_column
:project_ci_cd_settings
,
:forward_deployment_enabled
,
:boolean
end
end
db/post_migrate/20200210062432_schedule_link_lfs_objects.rb
View file @
53ae6b7e
...
...
@@ -4,32 +4,11 @@ class ScheduleLinkLfsObjects < ActiveRecord::Migration[6.0]
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
MIGRATION
=
'LinkLfsObjects'
BATCH_SIZE
=
1_000
disable_ddl_transaction!
class
Project
<
ActiveRecord
::
Base
include
EachBatch
self
.
table_name
=
'projects'
end
def
up
fork_network_members
=
Gitlab
::
BackgroundMigration
::
LinkLfsObjects
::
ForkNetworkMember
.
select
(
1
)
.
with_non_existing_lfs_objects
.
where
(
'fork_network_members.project_id = projects.id'
)
forks
=
Project
.
where
(
'EXISTS (?)'
,
fork_network_members
)
queue_background_migration_jobs_by_range_at_intervals
(
forks
,
MIGRATION
,
BackgroundMigrationWorker
.
minimum_interval
,
batch_size:
BATCH_SIZE
)
# no-op as background migration being schedule times out in some instances
end
def
down
...
...
db/schema.rb
View file @
53ae6b7e
...
...
@@ -3166,6 +3166,7 @@ ActiveRecord::Schema.define(version: 2020_02_13_204737) do
t
.
boolean
"group_runners_enabled"
,
default:
true
,
null:
false
t
.
boolean
"merge_pipelines_enabled"
t
.
integer
"default_git_depth"
t
.
boolean
"forward_deployment_enabled"
t
.
index
[
"project_id"
],
name:
"index_project_ci_cd_settings_on_project_id"
,
unique:
true
end
...
...
doc/user/shortcuts.md
View file @
53ae6b7e
...
...
@@ -6,7 +6,10 @@ disqus_identifier: 'https://docs.gitlab.com/ee/workflow/shortcuts.html'
# GitLab keyboard shortcuts
GitLab has many useful keyboard shortcuts to make it easier to access different features.
You can see the quick reference sheet within GitLab itself with
<kbd>
Shift
</kbd>
+
<kbd>
?
</kbd>
.
You can see a modal listing keyboard shortcuts within GitLab itself by pressing
<kbd>
?
</kbd>
,
or clicking
**Keyboard shortcuts**
in the Help menu at the top right.
From
[
GitLab 12.8 onwards
](
https://gitlab.com/gitlab-org/gitlab/issues/22113
)
,
keyboard shortcuts can be disabled using the
**Enable**
/
**Disable**
toggle in this modal window.
The
[
Global Shortcuts
](
#global-shortcuts
)
work from any area of GitLab, but you must
be in specific pages for the other shortcuts to be available, as explained in each
...
...
lib/gitlab/background_migration/link_lfs_objects.rb
View file @
53ae6b7e
...
...
@@ -24,24 +24,7 @@ module Gitlab
end
def
perform
(
start_id
,
end_id
)
select_query
=
ForkNetworkMember
.
select
(
'lop.lfs_object_id, fork_network_members.project_id'
)
.
with_non_existing_lfs_objects
.
where
(
project_id:
start_id
..
end_id
)
return
if
select_query
.
empty?
execute
<<-
SQL
INSERT INTO lfs_objects_projects (lfs_object_id, project_id)
#{
select_query
.
to_sql
}
SQL
end
private
def
execute
(
sql
)
::
ActiveRecord
::
Base
.
connection
.
execute
(
sql
)
# no-op as some queries times out
end
end
end
...
...
lib/gitlab/ci/status/build/failed.rb
View file @
53ae6b7e
...
...
@@ -19,6 +19,7 @@ module Gitlab
unmet_prerequisites:
'unmet prerequisites'
,
scheduler_failure:
'scheduler failure'
,
data_integrity_failure:
'data integrity failure'
,
forward_deployment_failure:
'forward deployment failure'
,
invalid_bridge_trigger:
'downstream pipeline trigger definition is invalid'
,
downstream_bridge_project_not_found:
'downstream project could not be found'
,
insufficient_bridge_permissions:
'no permissions to trigger downstream pipeline'
,
...
...
lib/quality/kubernetes_client.rb
View file @
53ae6b7e
...
...
@@ -63,7 +63,7 @@ module Quality
'get'
,
RESOURCE_LIST
,
%(--namespace "#{namespace}")
,
'-o
custom-columns=NAME:.metadata.
name'
'-o name'
]
run_command
(
command
).
lines
.
map
(
&
:strip
)
end
...
...
locale/gitlab.pot
View file @
53ae6b7e
...
...
@@ -375,6 +375,12 @@ msgid_plural "%{releases} releases"
msgstr[0] ""
msgstr[1] ""
msgid "%{screenreaderOnlyStart}Keyboard shorcuts%{screenreaderOnlyEnd} Disabled"
msgstr ""
msgid "%{screenreaderOnlyStart}Keyboard shorcuts%{screenreaderOnlyEnd} Enabled"
msgstr ""
msgid "%{service_title} activated."
msgstr ""
...
...
@@ -7155,6 +7161,9 @@ msgstr ""
msgid "Enable mirror configuration"
msgstr ""
msgid "Enable or disable keyboard shortcuts"
msgstr ""
msgid "Enable or disable the Pseudonymizer data collection."
msgstr ""
...
...
@@ -10945,6 +10954,9 @@ msgstr ""
msgid "Keyboard Shortcuts"
msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
msgid "Kubernetes"
msgstr ""
...
...
@@ -15857,6 +15869,9 @@ msgstr ""
msgid "Remove child epic from an epic"
msgstr ""
msgid "Remove description history"
msgstr ""
msgid "Remove due date"
msgstr ""
...
...
@@ -17780,6 +17795,9 @@ msgstr ""
msgid "Something went wrong while closing the %{issuable}. Please try again later"
msgstr ""
msgid "Something went wrong while deleting description changes. Please try again."
msgstr ""
msgid "Something went wrong while deleting the image."
msgstr ""
...
...
spec/factories/projects.rb
View file @
53ae6b7e
...
...
@@ -37,6 +37,7 @@ FactoryBot.define do
group_runners_enabled
{
nil
}
import_status
{
nil
}
import_jid
{
nil
}
forward_deployment_enabled
{
nil
}
end
after
(
:create
)
do
|
project
,
evaluator
|
...
...
spec/features/markdown/mermaid_spec.rb
View file @
53ae6b7e
...
...
@@ -68,4 +68,34 @@ describe 'Mermaid rendering', :js do
expect
(
page
).
to
have_selector
(
'pre.mermaid'
)
end
end
it
'correctly sizes mermaid diagram inside <details> block'
,
:js
do
description
=
<<~
MERMAID
<details>
<summary>Click to show diagram</summary>
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
</details>
MERMAID
project
=
create
(
:project
,
:public
)
issue
=
create
(
:issue
,
project:
project
,
description:
description
)
visit
project_issue_path
(
project
,
issue
)
page
.
within
(
'.description'
)
do
page
.
find
(
'summary'
).
click
svg
=
page
.
find
(
'svg.mermaid'
)
expect
(
svg
[
:width
].
to_i
).
to
be_within
(
5
).
of
(
120
)
expect
(
svg
[
:height
].
to_i
).
to
be_within
(
5
).
of
(
220
)
end
end
end
spec/features/projects/user_uses_shortcuts_spec.rb
View file @
53ae6b7e
...
...
@@ -17,6 +17,59 @@ describe 'User uses shortcuts', :js do
wait_for_requests
end
context
'disabling shortcuts'
do
before
do
page
.
evaluate_script
(
"localStorage.removeItem('shortcutsDisabled')"
)
end
it
'can disable shortcuts from help menu'
do
open_modal_shortcut_keys
click_toggle_button
close_modal
open_modal_shortcut_keys
# modal-shortcuts still in the DOM, but hidden
expect
(
find
(
'#modal-shortcuts'
,
visible:
false
)).
not_to
be_visible
page
.
refresh
open_modal_shortcut_keys
# after reload, shortcuts modal doesn't exist at all until we add it
expect
(
page
).
not_to
have_selector
(
'#modal-shortcuts'
)
end
it
're-enables shortcuts'
do
open_modal_shortcut_keys
click_toggle_button
close_modal
open_modal_from_help_menu
click_toggle_button
close_modal
open_modal_shortcut_keys
expect
(
find
(
'#modal-shortcuts'
)).
to
be_visible
end
def
open_modal_shortcut_keys
find
(
'body'
).
native
.
send_key
(
'?'
)
end
def
open_modal_from_help_menu
find
(
'.header-help-dropdown-toggle'
).
click
find
(
'button'
,
text:
'Keyboard shortcuts'
).
click
end
def
click_toggle_button
find
(
'.js-toggle-shortcuts .gl-toggle'
).
click
end
def
close_modal
find
(
'.modal button[aria-label="Close"]'
).
click
end
end
context
'when navigating to the Project pages'
do
it
'redirects to the details page'
do
visit
project_issues_path
(
project
)
...
...
spec/lib/gitlab/background_migration/link_lfs_objects_spec.rb
deleted
100644 → 0
View file @
cfe63cce
# frozen_string_literal: true
require
'spec_helper'
describe
Gitlab
::
BackgroundMigration
::
LinkLfsObjects
,
:migration
,
schema:
2020_02_10_062432
do
let
(
:namespaces
)
{
table
(
:namespaces
)
}
let
(
:projects
)
{
table
(
:projects
)
}
let
(
:fork_networks
)
{
table
(
:fork_networks
)
}
let
(
:fork_network_members
)
{
table
(
:fork_network_members
)
}
let
(
:lfs_objects
)
{
table
(
:lfs_objects
)
}
let
(
:lfs_objects_projects
)
{
table
(
:lfs_objects_projects
)
}
let
(
:namespace
)
{
namespaces
.
create
(
name:
'GitLab'
,
path:
'gitlab'
)
}
let
(
:source_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:another_source_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:another_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:other_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:linked_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:fork_network
)
{
fork_networks
.
create
(
root_project_id:
source_project
.
id
)
}
let
(
:another_fork_network
)
{
fork_networks
.
create
(
root_project_id:
another_source_project
.
id
)
}
let
(
:lfs_object
)
{
lfs_objects
.
create
(
oid:
'abc123'
,
size:
100
)
}
let
(
:another_lfs_object
)
{
lfs_objects
.
create
(
oid:
'def456'
,
size:
200
)
}
before
do
# Create links between projects
fork_network_members
.
create
(
fork_network_id:
fork_network
.
id
,
project_id:
source_project
.
id
,
forked_from_project_id:
nil
)
[
project
,
another_project
,
linked_project
].
each
do
|
p
|
fork_network_members
.
create
(
fork_network_id:
fork_network
.
id
,
project_id:
p
.
id
,
forked_from_project_id:
fork_network
.
root_project_id
)
end
fork_network_members
.
create
(
fork_network_id:
another_fork_network
.
id
,
project_id:
another_source_project
.
id
,
forked_from_project_id:
nil
)
fork_network_members
.
create
(
fork_network_id:
another_fork_network
.
id
,
project_id:
other_project
.
id
,
forked_from_project_id:
another_fork_network
.
root_project_id
)
# Links LFS objects to some projects
[
source_project
,
another_source_project
,
linked_project
].
each
do
|
p
|
lfs_objects_projects
.
create
(
lfs_object_id:
lfs_object
.
id
,
project_id:
p
.
id
)
lfs_objects_projects
.
create
(
lfs_object_id:
another_lfs_object
.
id
,
project_id:
p
.
id
)
end
end
it
'creates LfsObjectsProject records for forks within the specified range of project IDs'
do
expect
{
subject
.
perform
(
project
.
id
,
other_project
.
id
)
}.
to
change
{
lfs_objects_projects
.
count
}.
by
(
6
)
expect
(
lfs_object_ids_for
(
project
)).
to
match_array
(
lfs_object_ids_for
(
source_project
))
expect
(
lfs_object_ids_for
(
another_project
)).
to
match_array
(
lfs_object_ids_for
(
source_project
))
expect
(
lfs_object_ids_for
(
other_project
)).
to
match_array
(
lfs_object_ids_for
(
another_source_project
))
expect
{
subject
.
perform
(
project
.
id
,
other_project
.
id
)
}.
not_to
change
{
lfs_objects_projects
.
count
}
end
context
'when it is not necessary to create LfsObjectProject records'
do
it
'does not create LfsObjectProject records'
do
expect
{
subject
.
perform
(
linked_project
.
id
,
linked_project
.
id
)
}
.
not_to
change
{
lfs_objects_projects
.
count
}
end
end
def
lfs_object_ids_for
(
project
)
lfs_objects_projects
.
where
(
project_id:
project
.
id
).
pluck
(
:lfs_object_id
)
end
end
spec/lib/quality/kubernetes_client_spec.rb
View file @
53ae6b7e
...
...
@@ -102,7 +102,7 @@ RSpec.describe Quality::KubernetesClient do
it
'calls kubectl to retrieve the resource names'
do
expect
(
Gitlab
::
Popen
).
to
receive
(
:popen_with_detail
)
.
with
([
"kubectl get
#{
described_class
::
RESOURCE_LIST
}
"
+
%(--namespace "#{namespace}" -o
custom-columns=NAME:.metadata.
name)
])
%(--namespace "#{namespace}" -o name)
])
.
and_return
(
Gitlab
::
Popen
::
Result
.
new
([],
raw_resource_names_str
,
''
,
double
(
success?:
true
)))
expect
(
subject
.
__send__
(
:raw_resource_names
)).
to
eq
(
raw_resource_names
)
...
...
spec/migrations/schedule_link_lfs_objects_spec.rb
deleted
100644 → 0
View file @
cfe63cce
# frozen_string_literal: true
require
'spec_helper'
require
Rails
.
root
.
join
(
'db'
,
'post_migrate'
,
'20200210062432_schedule_link_lfs_objects.rb'
)
describe
ScheduleLinkLfsObjects
,
:migration
,
:sidekiq
do
let
(
:namespaces
)
{
table
(
:namespaces
)
}
let
(
:projects
)
{
table
(
:projects
)
}
let
(
:fork_networks
)
{
table
(
:fork_networks
)
}
let
(
:fork_network_members
)
{
table
(
:fork_network_members
)
}
let
(
:lfs_objects
)
{
table
(
:lfs_objects
)
}
let
(
:lfs_objects_projects
)
{
table
(
:lfs_objects_projects
)
}
let
(
:namespace
)
{
namespaces
.
create
(
name:
'GitLab'
,
path:
'gitlab'
)
}
let
(
:fork_network
)
{
fork_networks
.
create
(
root_project_id:
source_project
.
id
)
}
let
(
:another_fork_network
)
{
fork_networks
.
create
(
root_project_id:
another_source_project
.
id
)
}
let
(
:source_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:another_source_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:another_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:other_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:linked_project
)
{
projects
.
create
(
namespace_id:
namespace
.
id
)
}
let
(
:lfs_object
)
{
lfs_objects
.
create
(
oid:
'abc123'
,
size:
100
)
}
let
(
:another_lfs_object
)
{
lfs_objects
.
create
(
oid:
'def456'
,
size:
200
)
}
before
do
# Create links between projects
fork_network_members
.
create
(
fork_network_id:
fork_network
.
id
,
project_id:
source_project
.
id
,
forked_from_project_id:
nil
)
[
project
,
another_project
,
linked_project
].
each
do
|
p
|
fork_network_members
.
create
(
fork_network_id:
fork_network
.
id
,
project_id:
p
.
id
,
forked_from_project_id:
fork_network
.
root_project_id
)
end
fork_network_members
.
create
(
fork_network_id:
another_fork_network
.
id
,
project_id:
another_source_project
.
id
,
forked_from_project_id:
nil
)
fork_network_members
.
create
(
fork_network_id:
another_fork_network
.
id
,
project_id:
other_project
.
id
,
forked_from_project_id:
another_fork_network
.
root_project_id
)
end
context
'when there are forks to be backfilled'
do
before
do
stub_const
(
"
#{
described_class
.
name
}
::BATCH_SIZE"
,
2
)
# Links LFS objects to some projects
[
source_project
,
another_source_project
,
linked_project
].
each
do
|
p
|
lfs_objects_projects
.
create
(
lfs_object_id:
lfs_object
.
id
,
project_id:
p
.
id
)
lfs_objects_projects
.
create
(
lfs_object_id:
another_lfs_object
.
id
,
project_id:
p
.
id
)
end
end
it
'schedules background migration to link LFS objects'
do
Sidekiq
::
Testing
.
fake!
do
migrate!
expect
(
BackgroundMigrationWorker
.
jobs
.
size
).
to
eq
(
2
)
expect
(
described_class
::
MIGRATION
)
.
to
be_scheduled_delayed_migration
(
2
.
minutes
,
project
.
id
,
another_project
.
id
)
expect
(
described_class
::
MIGRATION
)
.
to
be_scheduled_delayed_migration
(
4
.
minutes
,
other_project
.
id
,
other_project
.
id
)
end
end
end
context
'when there are no forks to be backfilled'
do
before
do
# Links LFS objects to all projects
projects
.
all
.
each
do
|
p
|
lfs_objects_projects
.
create
(
lfs_object_id:
lfs_object
.
id
,
project_id:
p
.
id
)
lfs_objects_projects
.
create
(
lfs_object_id:
another_lfs_object
.
id
,
project_id:
p
.
id
)
end
end
it
'does not schedule any job'
do
Sidekiq
::
Testing
.
fake!
do
migrate!
expect
(
BackgroundMigrationWorker
.
jobs
.
size
).
to
eq
(
0
)
end
end
end
end
spec/models/deployment_spec.rb
View file @
53ae6b7e
...
...
@@ -281,6 +281,45 @@ describe Deployment do
expect
(
last_deployments
).
to
match_array
(
deployments
.
last
(
2
))
end
end
describe
'active'
do
subject
{
described_class
.
active
}
it
'retrieves the active deployments'
do
deployment1
=
create
(
:deployment
,
status: :created
)
deployment2
=
create
(
:deployment
,
status: :running
)
create
(
:deployment
,
status: :failed
)
create
(
:deployment
,
status: :canceled
)
is_expected
.
to
contain_exactly
(
deployment1
,
deployment2
)
end
end
describe
'older_than'
do
let
(
:deployment
)
{
create
(
:deployment
)
}
subject
{
described_class
.
older_than
(
deployment
)
}
it
'retrives the correct older deployments'
do
older_deployment1
=
create
(
:deployment
)
older_deployment2
=
create
(
:deployment
)
deployment
create
(
:deployment
)
is_expected
.
to
contain_exactly
(
older_deployment1
,
older_deployment2
)
end
end
describe
'with_deployable'
do
subject
{
described_class
.
with_deployable
}
it
'retrieves deployments with deployable builds'
do
with_deployable
=
create
(
:deployment
)
create
(
:deployment
,
deployable:
nil
)
is_expected
.
to
contain_exactly
(
with_deployable
)
end
end
end
describe
'#includes_commit?'
do
...
...
spec/models/project_ci_cd_setting_spec.rb
View file @
53ae6b7e
...
...
@@ -32,6 +32,12 @@ describe ProjectCiCdSetting do
end
end
describe
'#forward_deployment_enabled'
do
it
'is true by default'
do
expect
(
described_class
.
new
.
forward_deployment_enabled
).
to
be_truthy
end
end
describe
'#default_git_depth'
do
let
(
:default_value
)
{
described_class
::
DEFAULT_GIT_DEPTH
}
...
...
spec/services/deployments/older_deployments_drop_service_spec.rb
0 → 100644
View file @
53ae6b7e
# frozen_string_literal: true
require
'spec_helper'
describe
Deployments
::
OlderDeploymentsDropService
do
let
(
:environment
)
{
create
(
:environment
)
}
let
(
:deployment
)
{
create
(
:deployment
,
environment:
environment
)
}
let
(
:service
)
{
described_class
.
new
(
deployment
)
}
describe
'#execute'
do
subject
{
service
.
execute
}
shared_examples
'it does not drop any build'
do
it
do
expect
{
subject
}.
to
not_change
(
Ci
::
Build
.
failed
,
:count
)
end
end
context
'when deployment is nil'
do
let
(
:deployment
)
{
nil
}
it_behaves_like
'it does not drop any build'
end
context
'when a deployment is passed in'
do
context
'and there is no active deployment for the related environment'
do
let
(
:deployment
)
{
create
(
:deployment
,
:canceled
,
environment:
environment
)
}
let
(
:deployment2
)
{
create
(
:deployment
,
:canceled
,
environment:
environment
)
}
before
do
deployment
deployment2
end
it_behaves_like
'it does not drop any build'
end
context
'and there are active deployment for the related environment'
do
let
(
:deployment
)
{
create
(
:deployment
,
:running
,
environment:
environment
)
}
let
(
:deployment2
)
{
create
(
:deployment
,
:running
,
environment:
environment
)
}
context
'and there is no older deployment than "deployment"'
do
before
do
deployment
deployment2
end
it_behaves_like
'it does not drop any build'
end
context
'and there is an older deployment than "deployment"'
do
let
(
:older_deployment
)
{
create
(
:deployment
,
:running
,
environment:
environment
)
}
before
do
older_deployment
deployment
deployment2
end
it
'drops that older deployment'
do
deployable
=
older_deployment
.
deployable
expect
(
deployable
.
failed?
).
to
be_falsey
subject
expect
(
deployable
.
reload
.
failed?
).
to
be_truthy
end
context
'and there is no deployable for that older deployment'
do
let
(
:older_deployment
)
{
create
(
:deployment
,
:running
,
environment:
environment
,
deployable:
nil
)
}
it_behaves_like
'it does not drop any build'
end
end
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment