Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
5064bf8c
Commit
5064bf8c
authored
Mar 25, 2020
by
GitLab Bot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add latest changes from gitlab-org/gitlab@master
parent
9c83aadd
Changes
61
Show whitespace changes
Inline
Side-by-side
Showing
61 changed files
with
1042 additions
and
152 deletions
+1042
-152
.overcommit.yml.example
.overcommit.yml.example
+3
-1
app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
...scripts/blob/suggest_gitlab_ci_yml/components/popover.vue
+14
-5
app/assets/javascripts/blob_edit/blob_bundle.js
app/assets/javascripts/blob_edit/blob_bundle.js
+11
-0
app/assets/javascripts/environments/components/delete_environment_modal.vue
...ipts/environments/components/delete_environment_modal.vue
+66
-0
app/assets/javascripts/environments/components/environment_delete.vue
...avascripts/environments/components/environment_delete.vue
+70
-0
app/assets/javascripts/environments/components/environment_item.vue
.../javascripts/environments/components/environment_item.vue
+15
-1
app/assets/javascripts/environments/components/environments_app.vue
.../javascripts/environments/components/environments_app.vue
+3
-0
app/assets/javascripts/environments/components/stop_environment_modal.vue
...cripts/environments/components/stop_environment_modal.vue
+3
-4
app/assets/javascripts/environments/folder/environments_folder_view.vue
...ascripts/environments/folder/environments_folder_view.vue
+3
-0
app/assets/javascripts/environments/mixins/environments_mixin.js
...ets/javascripts/environments/mixins/environments_mixin.js
+65
-21
app/assets/javascripts/environments/mount_show.js
app/assets/javascripts/environments/mount_show.js
+32
-0
app/assets/javascripts/environments/services/environments_service.js
...javascripts/environments/services/environments_service.js
+5
-0
app/assets/javascripts/lib/utils/common_utils.js
app/assets/javascripts/lib/utils/common_utils.js
+8
-0
app/assets/javascripts/pages/projects/environments/show/index.js
...ets/javascripts/pages/projects/environments/show/index.js
+3
-0
app/controllers/projects/settings/operations_controller.rb
app/controllers/projects/settings/operations_controller.rb
+19
-0
app/helpers/environments_helper.rb
app/helpers/environments_helper.rb
+4
-0
app/helpers/gitlab_routing_helper.rb
app/helpers/gitlab_routing_helper.rb
+5
-0
app/models/commit_status.rb
app/models/commit_status.rb
+6
-3
app/models/concerns/noteable.rb
app/models/concerns/noteable.rb
+6
-0
app/models/project_services/prometheus_service.rb
app/models/project_services/prometheus_service.rb
+7
-2
app/models/snippet.rb
app/models/snippet.rb
+0
-2
app/policies/environment_policy.rb
app/policies/environment_policy.rb
+6
-0
app/policies/project_policy.rb
app/policies/project_policy.rb
+2
-0
app/serializers/environment_entity.rb
app/serializers/environment_entity.rb
+8
-0
app/services/projects/operations/update_service.rb
app/services/projects/operations/update_service.rb
+18
-0
app/views/projects/blob/_editor.html.haml
app/views/projects/blob/_editor.html.haml
+1
-1
app/views/projects/blob/new.html.haml
app/views/projects/blob/new.html.haml
+1
-1
app/views/projects/environments/show.html.haml
app/views/projects/environments/show.html.haml
+74
-67
app/views/shared/icons/_dev_ops_score_no_data.svg
app/views/shared/icons/_dev_ops_score_no_data.svg
+0
-1
app/views/shared/icons/_dev_ops_score_no_index.svg
app/views/shared/icons/_dev_ops_score_no_index.svg
+0
-3
changelogs/unreleased/32455-merge-request-discussions-api-degrades-with-comments-count.yml
...-request-discussions-api-degrades-with-comments-count.yml
+5
-0
changelogs/unreleased/41845-delete-environment.yml
changelogs/unreleased/41845-delete-environment.yml
+5
-0
changelogs/unreleased/osw-allow-custom-term-timeout-sk-cluster.yml
...s/unreleased/osw-allow-custom-term-timeout-sk-cluster.yml
+5
-0
changelogs/unreleased/rp-allow-local-prom-queries-self-monitoring.yml
...nreleased/rp-allow-local-prom-queries-self-monitoring.yml
+5
-0
config/routes/project.rb
config/routes/project.rb
+6
-1
db/fixtures/development/17_cycle_analytics.rb
db/fixtures/development/17_cycle_analytics.rb
+2
-2
doc/ci/environments.md
doc/ci/environments.md
+27
-0
lib/api/discussions.rb
lib/api/discussions.rb
+5
-6
lib/api/environments.rb
lib/api/environments.rb
+2
-1
lib/gitlab/cleanup/orphan_lfs_file_references.rb
lib/gitlab/cleanup/orphan_lfs_file_references.rb
+1
-1
lib/gitlab/git/lfs_changes.rb
lib/gitlab/git/lfs_changes.rb
+1
-1
lib/gitlab/gitaly_client/blob_service.rb
lib/gitlab/gitaly_client/blob_service.rb
+3
-4
lib/gitlab/sidekiq_cluster.rb
lib/gitlab/sidekiq_cluster.rb
+10
-3
lib/gitlab/sidekiq_cluster/cli.rb
lib/gitlab/sidekiq_cluster/cli.rb
+27
-5
locale/gitlab.pot
locale/gitlab.pot
+12
-0
spec/controllers/projects/settings/operations_controller_spec.rb
...ntrollers/projects/settings/operations_controller_spec.rb
+88
-0
spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
...rojects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
+8
-0
spec/fixtures/api/schemas/environment.json
spec/fixtures/api/schemas/environment.json
+4
-1
spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
...end/blob/suggest_gitlab_ci_yml/components/popover_spec.js
+6
-4
spec/frontend/environments/environment_delete_spec.js
spec/frontend/environments/environment_delete_spec.js
+38
-0
spec/frontend/environments/environment_item_spec.js
spec/frontend/environments/environment_item_spec.js
+24
-1
spec/lib/gitlab/gitaly_client/blob_service_spec.rb
spec/lib/gitlab/gitaly_client/blob_service_spec.rb
+2
-4
spec/lib/gitlab/sidekiq_cluster/cli_spec.rb
spec/lib/gitlab/sidekiq_cluster/cli_spec.rb
+22
-3
spec/lib/gitlab/sidekiq_cluster_spec.rb
spec/lib/gitlab/sidekiq_cluster_spec.rb
+4
-2
spec/models/commit_status_spec.rb
spec/models/commit_status_spec.rb
+13
-0
spec/models/concerns/noteable_spec.rb
spec/models/concerns/noteable_spec.rb
+15
-0
spec/models/project_services/prometheus_service_spec.rb
spec/models/project_services/prometheus_service_spec.rb
+60
-0
spec/policies/environment_policy_spec.rb
spec/policies/environment_policy_spec.rb
+44
-0
spec/policies/project_policy_spec.rb
spec/policies/project_policy_spec.rb
+46
-0
spec/requests/api/environments_spec.rb
spec/requests/api/environments_spec.rb
+13
-1
spec/services/projects/operations/update_service_spec.rb
spec/services/projects/operations/update_service_spec.rb
+81
-0
No files found.
.overcommit.yml.example
View file @
5064bf8c
...
...
@@ -28,7 +28,9 @@ PreCommit:
EsLint:
enabled: true
# https://github.com/sds/overcommit/issues/338
command: './node_modules/eslint/bin/eslint.js'
required_executable: 'yarn'
command: ['yarn', 'eslint']
flags: []
HamlLint:
enabled: true
MergeConflicts:
...
...
app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
View file @
5064bf8c
<
script
>
import
{
GlPopover
,
GlSprintf
,
GlButton
,
GlIcon
}
from
'
@gitlab/ui
'
;
import
Cookies
from
'
js-cookie
'
;
import
{
parseBoolean
,
scrollToElement
}
from
'
~/lib/utils/common_utils
'
;
import
{
parseBoolean
,
scrollToElement
,
setCookie
,
getCookie
}
from
'
~/lib/utils/common_utils
'
;
import
{
s__
}
from
'
~/locale
'
;
import
{
glEmojiTag
}
from
'
~/emoji
'
;
import
Tracking
from
'
~/tracking
'
;
...
...
@@ -51,7 +50,7 @@ export default {
},
data
()
{
return
{
popoverDismissed
:
parseBoolean
(
Cookies
.
get
(
this
.
dismissKey
)),
popoverDismissed
:
parseBoolean
(
getCookie
(
`
${
this
.
trackLabel
}
_
${
this
.
dismissKey
}
`
)),
tracking
:
{
label
:
this
.
trackLabel
,
property
:
this
.
humanAccess
,
...
...
@@ -68,17 +67,27 @@ export default {
emoji
()
{
return
popoverStates
[
this
.
trackLabel
].
emoji
||
''
;
},
dismissCookieName
()
{
return
`
${
this
.
trackLabel
}
_
${
this
.
dismissKey
}
`
;
},
commitCookieName
()
{
return
`suggest_gitlab_ci_yml_commit_
${
this
.
dismissKey
}
`
;
},
},
mounted
()
{
if
(
this
.
trackLabel
===
'
suggest_commit_first_project_gitlab_ci_yml
'
&&
!
this
.
popoverDismissed
)
if
(
this
.
trackLabel
===
'
suggest_commit_first_project_gitlab_ci_yml
'
&&
!
this
.
popoverDismissed
)
{
scrollToElement
(
document
.
querySelector
(
this
.
target
));
}
this
.
trackOnShow
();
},
methods
:
{
onDismiss
()
{
this
.
popoverDismissed
=
true
;
Cookies
.
set
(
this
.
dismissKey
,
this
.
popoverDismissed
,
{
expires
:
365
}
);
setCookie
(
this
.
dismissCookieName
,
this
.
popoverDismissed
);
},
trackOnShow
()
{
if
(
!
this
.
popoverDismissed
)
this
.
track
();
...
...
app/assets/javascripts/blob_edit/blob_bundle.js
View file @
5064bf8c
...
...
@@ -5,6 +5,7 @@ import NewCommitForm from '../new_commit_form';
import
EditBlob
from
'
./edit_blob
'
;
import
BlobFileDropzone
from
'
../blob/blob_file_dropzone
'
;
import
initPopover
from
'
~/blob/suggest_gitlab_ci_yml
'
;
import
{
setCookie
}
from
'
~/lib/utils/common_utils
'
;
export
default
()
=>
{
const
editBlobForm
=
$
(
'
.js-edit-blob-form
'
);
...
...
@@ -60,6 +61,16 @@ export default () => {
}
if
(
suggestEl
)
{
const
commitButton
=
document
.
querySelector
(
'
#commit-changes
'
);
initPopover
(
suggestEl
);
if
(
commitButton
)
{
const
commitCookieName
=
`suggest_gitlab_ci_yml_commit_
${
suggestEl
.
dataset
.
dismissKey
}
`
;
commitButton
.
addEventListener
(
'
click
'
,
()
=>
{
setCookie
(
commitCookieName
,
true
);
});
}
}
};
app/assets/javascripts/environments/components/delete_environment_modal.vue
0 → 100644
View file @
5064bf8c
<
script
>
import
{
GlTooltipDirective
}
from
'
@gitlab/ui
'
;
import
GlModal
from
'
~/vue_shared/components/gl_modal.vue
'
;
import
{
s__
,
sprintf
}
from
'
~/locale
'
;
import
eventHub
from
'
../event_hub
'
;
export
default
{
id
:
'
delete-environment-modal
'
,
name
:
'
DeleteEnvironmentModal
'
,
components
:
{
GlModal
,
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
props
:
{
environment
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
confirmDeleteMessage
()
{
return
sprintf
(
s__
(
`Environments|Deleting the '%{environmentName}' environment cannot be undone. Do you want to delete it anyway?`
,
),
{
environmentName
:
this
.
environment
.
name
,
},
false
,
);
},
},
methods
:
{
onSubmit
()
{
eventHub
.
$emit
(
'
deleteEnvironment
'
,
this
.
environment
);
},
},
};
</
script
>
<
template
>
<gl-modal
:id=
"$options.id"
:footer-primary-button-text=
"s__('Environments|Delete environment')"
footer-primary-button-variant=
"danger"
@
submit=
"onSubmit"
>
<template
slot=
"header"
>
<h4
class=
"modal-title d-flex mw-100"
>
{{
__
(
'
Delete
'
)
}}
<span
v-gl-tooltip
:title=
"environment.name"
class=
"text-truncate mx-1 flex-fill"
>
{{
environment
.
name
}}
?
</span>
</h4>
</
template
>
<p>
{{ confirmDeleteMessage }}
</p>
</gl-modal>
</template>
app/assets/javascripts/environments/components/environment_delete.vue
0 → 100644
View file @
5064bf8c
<
script
>
/**
* Renders the delete button that allows deleting a stopped environment.
* Used in the environments table and the environment detail view.
*/
import
$
from
'
jquery
'
;
import
{
GlTooltipDirective
}
from
'
@gitlab/ui
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
{
s__
}
from
'
~/locale
'
;
import
eventHub
from
'
../event_hub
'
;
import
LoadingButton
from
'
../../vue_shared/components/loading_button.vue
'
;
export
default
{
components
:
{
Icon
,
LoadingButton
,
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
props
:
{
environment
:
{
type
:
Object
,
required
:
true
,
},
},
data
()
{
return
{
isLoading
:
false
,
};
},
computed
:
{
title
()
{
return
s__
(
'
Environments|Delete environment
'
);
},
},
mounted
()
{
eventHub
.
$on
(
'
deleteEnvironment
'
,
this
.
onDeleteEnvironment
);
},
beforeDestroy
()
{
eventHub
.
$off
(
'
deleteEnvironment
'
,
this
.
onDeleteEnvironment
);
},
methods
:
{
onClick
()
{
$
(
this
.
$el
).
tooltip
(
'
dispose
'
);
eventHub
.
$emit
(
'
requestDeleteEnvironment
'
,
this
.
environment
);
},
onDeleteEnvironment
(
environment
)
{
if
(
this
.
environment
.
id
===
environment
.
id
)
{
this
.
isLoading
=
true
;
}
},
},
};
</
script
>
<
template
>
<loading-button
v-gl-tooltip
:loading=
"isLoading"
:title=
"title"
:aria-label=
"title"
container-class=
"btn btn-danger d-none d-sm-none d-md-block"
data-toggle=
"modal"
data-target=
"#delete-environment-modal"
@
click=
"onClick"
>
<icon
name=
"remove"
/>
</loading-button>
</
template
>
app/assets/javascripts/environments/components/environment_item.vue
View file @
5064bf8c
...
...
@@ -15,8 +15,9 @@ import ActionsComponent from './environment_actions.vue';
import
ExternalUrlComponent
from
'
./environment_external_url.vue
'
;
import
MonitoringButtonComponent
from
'
./environment_monitoring.vue
'
;
import
PinComponent
from
'
./environment_pin.vue
'
;
import
RollbackComponent
from
'
./environment_rollback
.vue
'
;
import
DeleteComponent
from
'
./environment_delete
.vue
'
;
import
StopComponent
from
'
./environment_stop.vue
'
;
import
RollbackComponent
from
'
./environment_rollback.vue
'
;
import
TerminalButtonComponent
from
'
./environment_terminal_button.vue
'
;
/**
...
...
@@ -33,6 +34,7 @@ export default {
Icon
,
MonitoringButtonComponent
,
PinComponent
,
DeleteComponent
,
RollbackComponent
,
StopComponent
,
TerminalButtonComponent
,
...
...
@@ -112,6 +114,15 @@ export default {
return
this
.
model
&&
this
.
model
.
can_stop
;
},
/**
* Returns whether the environment can be deleted.
*
* @returns {Boolean}
*/
canDeleteEnvironment
()
{
return
Boolean
(
this
.
model
&&
this
.
model
.
can_delete
&&
this
.
model
.
delete_path
);
},
/**
* Verifies if the `deployable` key is present in `last_deployment` key.
* Used to verify whether we should or not render the rollback partial.
...
...
@@ -485,6 +496,7 @@ export default {
this
.
externalURL
||
this
.
monitoringUrl
||
this
.
canStopEnvironment
||
this
.
canDeleteEnvironment
||
this
.
canRetry
);
},
...
...
@@ -680,6 +692,8 @@ export default {
/>
<stop-component
v-if=
"canStopEnvironment"
:environment=
"model"
/>
<delete-component
v-if=
"canDeleteEnvironment"
:environment=
"model"
/>
</div>
</div>
</div>
...
...
app/assets/javascripts/environments/components/environments_app.vue
View file @
5064bf8c
...
...
@@ -9,6 +9,7 @@ import environmentsMixin from '../mixins/environments_mixin';
import
CIPaginationMixin
from
'
~/vue_shared/mixins/ci_pagination_api_mixin
'
;
import
EnableReviewAppButton
from
'
./enable_review_app_button.vue
'
;
import
StopEnvironmentModal
from
'
./stop_environment_modal.vue
'
;
import
DeleteEnvironmentModal
from
'
./delete_environment_modal.vue
'
;
import
ConfirmRollbackModal
from
'
./confirm_rollback_modal.vue
'
;
export
default
{
...
...
@@ -18,6 +19,7 @@ export default {
EnableReviewAppButton
,
GlButton
,
StopEnvironmentModal
,
DeleteEnvironmentModal
,
},
mixins
:
[
CIPaginationMixin
,
environmentsMixin
,
envrionmentsAppMixin
],
...
...
@@ -95,6 +97,7 @@ export default {
<
template
>
<div>
<stop-environment-modal
:environment=
"environmentInStopModal"
/>
<delete-environment-modal
:environment=
"environmentInDeleteModal"
/>
<confirm-rollback-modal
:environment=
"environmentInRollbackModal"
/>
<div
class=
"top-area"
>
...
...
app/assets/javascripts/environments/components/stop_environment_modal.vue
View file @
5064bf8c
...
...
@@ -63,10 +63,9 @@ export default {
<template
slot=
"header"
>
<h4
class=
"modal-title d-flex mw-100"
>
Stopping
<span
v-gl-tooltip
:title=
"environment.name"
class=
"text-truncate ml-1 mr-1 flex-fill"
>
{{
environment
.
name
}}
</span>
?
<span
v-gl-tooltip
:title=
"environment.name"
class=
"text-truncate ml-1 mr-1 flex-fill"
>
{{
environment
.
name
}}
?
</span>
</h4>
</
template
>
...
...
app/assets/javascripts/environments/folder/environments_folder_view.vue
View file @
5064bf8c
...
...
@@ -3,10 +3,12 @@ import folderMixin from 'ee_else_ce/environments/mixins/environments_folder_view
import
environmentsMixin
from
'
../mixins/environments_mixin
'
;
import
CIPaginationMixin
from
'
../../vue_shared/mixins/ci_pagination_api_mixin
'
;
import
StopEnvironmentModal
from
'
../components/stop_environment_modal.vue
'
;
import
DeleteEnvironmentModal
from
'
../components/delete_environment_modal.vue
'
;
export
default
{
components
:
{
StopEnvironmentModal
,
DeleteEnvironmentModal
,
},
mixins
:
[
environmentsMixin
,
CIPaginationMixin
,
folderMixin
],
...
...
@@ -39,6 +41,7 @@ export default {
<
template
>
<div
:class=
"cssContainerClass"
>
<stop-environment-modal
:environment=
"environmentInStopModal"
/>
<delete-environment-modal
:environment=
"environmentInDeleteModal"
/>
<h4
class=
"js-folder-name environments-folder-name"
>
{{
s__
(
'
Environments|Environments
'
)
}}
/
...
...
app/assets/javascripts/environments/mixins/environments_mixin.js
View file @
5064bf8c
...
...
@@ -27,6 +27,10 @@ export default {
data
()
{
const
store
=
new
EnvironmentsStore
();
const
isDetailView
=
document
.
body
.
contains
(
document
.
getElementById
(
'
environments-detail-view
'
),
);
return
{
store
,
state
:
store
.
state
,
...
...
@@ -36,7 +40,9 @@ export default {
page
:
getParameterByName
(
'
page
'
)
||
'
1
'
,
requestData
:
{},
environmentInStopModal
:
{},
environmentInDeleteModal
:
{},
environmentInRollbackModal
:
{},
isDetailView
,
};
},
...
...
@@ -121,6 +127,10 @@ export default {
this
.
environmentInStopModal
=
environment
;
},
updateDeleteModal
(
environment
)
{
this
.
environmentInDeleteModal
=
environment
;
},
updateRollbackModal
(
environment
)
{
this
.
environmentInRollbackModal
=
environment
;
},
...
...
@@ -133,6 +143,30 @@ export default {
this
.
postAction
({
endpoint
,
errorMessage
});
},
deleteEnvironment
(
environment
)
{
const
endpoint
=
environment
.
delete_path
;
const
mountedToShow
=
environment
.
mounted_to_show
;
const
errorMessage
=
s__
(
'
Environments|An error occurred while deleting the environment. Check if the environment stopped; if not, stop it and try again.
'
,
);
this
.
service
.
deleteAction
(
endpoint
)
.
then
(()
=>
{
if
(
!
mountedToShow
)
{
// Reload as a first solution to bust the ETag cache
window
.
location
.
reload
();
return
;
}
const
url
=
window
.
location
.
href
.
split
(
'
/
'
);
url
.
pop
();
window
.
location
.
href
=
url
.
join
(
'
/
'
);
})
.
catch
(()
=>
{
Flash
(
errorMessage
);
});
},
rollbackEnvironment
(
environment
)
{
const
{
retryUrl
,
isLastDeployment
}
=
environment
;
const
errorMessage
=
isLastDeployment
...
...
@@ -178,6 +212,7 @@ export default {
this
.
service
=
new
EnvironmentsService
(
this
.
endpoint
);
this
.
requestData
=
{
page
:
this
.
page
,
scope
:
this
.
scope
,
nested
:
true
};
if
(
!
this
.
isDetailView
)
{
this
.
poll
=
new
Poll
({
resource
:
this
.
service
,
method
:
'
fetchEnvironments
'
,
...
...
@@ -203,11 +238,16 @@ export default {
this
.
poll
.
stop
();
}
});
}
eventHub
.
$on
(
'
postAction
'
,
this
.
postAction
);
eventHub
.
$on
(
'
requestStopEnvironment
'
,
this
.
updateStopModal
);
eventHub
.
$on
(
'
stopEnvironment
'
,
this
.
stopEnvironment
);
eventHub
.
$on
(
'
requestDeleteEnvironment
'
,
this
.
updateDeleteModal
);
eventHub
.
$on
(
'
deleteEnvironment
'
,
this
.
deleteEnvironment
);
eventHub
.
$on
(
'
requestRollbackEnvironment
'
,
this
.
updateRollbackModal
);
eventHub
.
$on
(
'
rollbackEnvironment
'
,
this
.
rollbackEnvironment
);
...
...
@@ -216,9 +256,13 @@ export default {
beforeDestroy
()
{
eventHub
.
$off
(
'
postAction
'
,
this
.
postAction
);
eventHub
.
$off
(
'
requestStopEnvironment
'
,
this
.
updateStopModal
);
eventHub
.
$off
(
'
stopEnvironment
'
,
this
.
stopEnvironment
);
eventHub
.
$off
(
'
requestDeleteEnvironment
'
,
this
.
updateDeleteModal
);
eventHub
.
$off
(
'
deleteEnvironment
'
,
this
.
deleteEnvironment
);
eventHub
.
$off
(
'
requestRollbackEnvironment
'
,
this
.
updateRollbackModal
);
eventHub
.
$off
(
'
rollbackEnvironment
'
,
this
.
rollbackEnvironment
);
...
...
app/assets/javascripts/environments/mount_show.js
0 → 100644
View file @
5064bf8c
import
Vue
from
'
vue
'
;
import
DeleteEnvironmentModal
from
'
./components/delete_environment_modal.vue
'
;
import
environmentsMixin
from
'
./mixins/environments_mixin
'
;
export
default
()
=>
{
const
el
=
document
.
getElementById
(
'
delete-environment-modal
'
);
const
container
=
document
.
getElementById
(
'
environments-detail-view
'
);
return
new
Vue
({
el
,
components
:
{
DeleteEnvironmentModal
,
},
mixins
:
[
environmentsMixin
],
data
()
{
const
environment
=
JSON
.
parse
(
JSON
.
stringify
(
container
.
dataset
));
environment
.
delete_path
=
environment
.
deletePath
;
environment
.
mounted_to_show
=
true
;
return
{
environment
,
};
},
render
(
createElement
)
{
return
createElement
(
'
delete-environment-modal
'
,
{
props
:
{
environment
:
this
.
environment
,
},
});
},
});
};
app/assets/javascripts/environments/services/environments_service.js
View file @
5064bf8c
...
...
@@ -16,6 +16,11 @@ export default class EnvironmentsService {
return
axios
.
post
(
endpoint
,
{});
}
// eslint-disable-next-line class-methods-use-this
deleteAction
(
endpoint
)
{
return
axios
.
delete
(
endpoint
,
{});
}
getFolderContent
(
folderUrl
)
{
return
axios
.
get
(
`
${
folderUrl
}
.json?per_page=
${
this
.
folderResults
}
`
);
}
...
...
app/assets/javascripts/lib/utils/common_utils.js
View file @
5064bf8c
...
...
@@ -9,6 +9,7 @@ import { getLocationHash } from './url_utility';
import
{
convertToCamelCase
,
convertToSnakeCase
}
from
'
./text_utility
'
;
import
{
isObject
}
from
'
./type_utility
'
;
import
{
isFunction
}
from
'
lodash
'
;
import
Cookies
from
'
js-cookie
'
;
export
const
getPagePath
=
(
index
=
0
)
=>
{
const
page
=
$
(
'
body
'
).
attr
(
'
data-page
'
)
||
''
;
...
...
@@ -902,3 +903,10 @@ window.gl.utils = {
spriteIcon
,
imagePath
,
};
// Methods to set and get Cookie
export
const
setCookie
=
(
name
,
value
)
=>
Cookies
.
set
(
name
,
value
,
{
expires
:
365
});
export
const
getCookie
=
name
=>
Cookies
.
get
(
name
);
export
const
removeCookie
=
name
=>
Cookies
.
remove
(
name
);
app/assets/javascripts/pages/projects/environments/show/index.js
0 → 100644
View file @
5064bf8c
import
initShowEnvironment
from
'
~/environments/mount_show
'
;
document
.
addEventListener
(
'
DOMContentLoaded
'
,
()
=>
initShowEnvironment
());
app/controllers/projects/settings/operations_controller.rb
View file @
5064bf8c
...
...
@@ -4,6 +4,9 @@ module Projects
module
Settings
class
OperationsController
<
Projects
::
ApplicationController
before_action
:authorize_admin_operations!
before_action
:authorize_read_prometheus_alerts!
,
only:
[
:reset_alerting_token
]
respond_to
:json
,
only:
[
:reset_alerting_token
]
helper_method
:error_tracking_setting
...
...
@@ -27,8 +30,24 @@ module Projects
end
end
def
reset_alerting_token
result
=
::
Projects
::
Operations
::
UpdateService
.
new
(
project
,
current_user
,
alerting_params
)
.
execute
if
result
[
:status
]
==
:success
render
json:
{
token:
project
.
alerting_setting
.
token
}
else
render
json:
{},
status: :unprocessable_entity
end
end
private
def
alerting_params
{
alerting_setting_attributes:
{
regenerate_token:
true
}
}
end
def
prometheus_service
project
.
find_or_initialize_service
(
::
PrometheusService
.
to_param
)
end
...
...
app/helpers/environments_helper.rb
View file @
5064bf8c
...
...
@@ -50,4 +50,8 @@ module EnvironmentsHelper
"cluster-applications-documentation-path"
=>
help_page_path
(
'user/clusters/applications.md'
,
anchor:
'elastic-stack'
)
}
end
def
can_destroy_environment?
(
environment
)
can?
(
current_user
,
:destroy_environment
,
environment
)
end
end
app/helpers/gitlab_routing_helper.rb
View file @
5064bf8c
...
...
@@ -4,6 +4,7 @@
module
GitlabRoutingHelper
extend
ActiveSupport
::
Concern
include
API
::
Helpers
::
RelatedResourcesHelpers
included
do
Gitlab
::
Routing
.
includes_helpers
(
self
)
end
...
...
@@ -29,6 +30,10 @@ module GitlabRoutingHelper
metrics_project_environment_path
(
environment
.
project
,
environment
,
*
args
)
end
def
environment_delete_path
(
environment
,
*
args
)
expose_path
(
api_v4_projects_environments_path
(
id:
environment
.
project
.
id
,
environment_id:
environment
.
id
))
end
def
issue_path
(
entity
,
*
args
)
project_issue_path
(
entity
.
project
,
entity
,
*
args
)
end
...
...
app/models/commit_status.rb
View file @
5064bf8c
...
...
@@ -62,13 +62,16 @@ class CommitStatus < ApplicationRecord
preload
(
project: :namespace
)
end
scope
:match_id_and_lock_version
,
->
(
slice
)
do
scope
:match_id_and_lock_version
,
->
(
items
)
do
# it expects that items are an array of attributes to match
# each hash needs to have `id` and `lock_version`
slice
.
inject
(
self
)
do
|
relation
,
item
|
match
=
CommitStatus
.
where
(
item
.
slice
(
:id
,
:lock_version
))
or_conditions
=
items
.
inject
(
none
)
do
|
relation
,
item
|
match
=
CommitStatus
.
default_scoped
.
where
(
item
.
slice
(
:id
,
:lock_version
))
relation
.
or
(
match
)
end
merge
(
or_conditions
)
end
# We use `CommitStatusEnums.failure_reasons` here so that EE can more easily
...
...
app/models/concerns/noteable.rb
View file @
5064bf8c
...
...
@@ -79,6 +79,12 @@ module Noteable
.
discussions
(
self
)
end
def
discussion_ids_relation
notes
.
select
(
:discussion_id
)
.
group
(
:discussion_id
)
.
order
(
'MIN(created_at), MIN(id)'
)
end
def
capped_notes_count
(
max
)
notes
.
limit
(
max
).
count
end
...
...
app/models/project_services/prometheus_service.rb
View file @
5064bf8c
...
...
@@ -81,7 +81,7 @@ class PrometheusService < MonitoringService
def
prometheus_client
return
unless
should_return_client?
Gitlab
::
PrometheusClient
.
new
(
api_url
)
Gitlab
::
PrometheusClient
.
new
(
api_url
,
allow_local_requests:
allow_local_api_url?
)
end
def
prometheus_available?
...
...
@@ -94,7 +94,8 @@ class PrometheusService < MonitoringService
end
def
allow_local_api_url?
self_monitoring_project?
&&
internal_prometheus_url?
allow_local_requests_from_web_hooks_and_services?
||
(
self_monitoring_project?
&&
internal_prometheus_url?
)
end
def
configured?
...
...
@@ -111,6 +112,10 @@ class PrometheusService < MonitoringService
api_url
.
present?
&&
api_url
==
::
Gitlab
::
Prometheus
::
Internal
.
uri
end
def
allow_local_requests_from_web_hooks_and_services?
current_settings
.
allow_local_requests_from_web_hooks_and_services?
end
def
should_return_client?
api_url
.
present?
&&
manual_configuration?
&&
active?
&&
valid?
end
...
...
app/models/snippet.rb
View file @
5064bf8c
...
...
@@ -19,8 +19,6 @@ class Snippet < ApplicationRecord
MAX_FILE_COUNT
=
1
ignore_column
:repository_storage
,
remove_with:
'12.10'
,
remove_after:
'2020-03-22'
cache_markdown_field
:title
,
pipeline: :single_line
cache_markdown_field
:description
cache_markdown_field
:content
...
...
app/policies/environment_policy.rb
View file @
5064bf8c
...
...
@@ -12,7 +12,13 @@ class EnvironmentPolicy < BasePolicy
!
@subject
.
stop_action_available?
&&
can?
(
:update_environment
,
@subject
)
end
condition
(
:stopped
)
do
@subject
.
stopped?
end
rule
{
stop_with_deployment_allowed
|
stop_with_update_allowed
}.
enable
:stop_environment
rule
{
~
stopped
}.
prevent
(
:destroy_environment
)
end
EnvironmentPolicy
.
prepend_if_ee
(
'EE::EnvironmentPolicy'
)
app/policies/project_policy.rb
View file @
5064bf8c
...
...
@@ -271,6 +271,7 @@ class ProjectPolicy < BasePolicy
enable
:destroy_container_image
enable
:create_environment
enable
:update_environment
enable
:destroy_environment
enable
:create_deployment
enable
:update_deployment
enable
:create_release
...
...
@@ -316,6 +317,7 @@ class ProjectPolicy < BasePolicy
enable
:create_deploy_token
enable
:read_pod_logs
enable
:destroy_deploy_token
enable
:read_prometheus_alerts
end
rule
{
(
mirror_available
&
can?
(
:admin_project
))
|
admin
}.
enable
:admin_remote_mirror
...
...
app/serializers/environment_entity.rb
View file @
5064bf8c
...
...
@@ -28,6 +28,10 @@ class EnvironmentEntity < Grape::Entity
cancel_auto_stop_project_environment_path
(
environment
.
project
,
environment
)
end
expose
:delete_path
do
|
environment
|
environment_delete_path
(
environment
)
end
expose
:cluster_type
,
if:
->
(
environment
,
_
)
{
cluster_platform_kubernetes?
}
do
|
environment
|
cluster
.
cluster_type
end
...
...
@@ -63,6 +67,10 @@ class EnvironmentEntity < Grape::Entity
environment
.
elastic_stack_available?
end
expose
:can_delete
do
|
environment
|
can?
(
current_user
,
:destroy_environment
,
environment
)
end
private
alias_method
:environment
,
:object
...
...
app/services/projects/operations/update_service.rb
View file @
5064bf8c
...
...
@@ -13,12 +13,30 @@ module Projects
def
project_update_params
error_tracking_params
.
merge
(
alerting_setting_params
)
.
merge
(
metrics_setting_params
)
.
merge
(
grafana_integration_params
)
.
merge
(
prometheus_integration_params
)
.
merge
(
incident_management_setting_params
)
end
def
alerting_setting_params
return
{}
unless
can?
(
current_user
,
:read_prometheus_alerts
,
project
)
attr
=
params
[
:alerting_setting_attributes
]
return
{}
unless
attr
regenerate_token
=
attr
.
delete
(
:regenerate_token
)
if
regenerate_token
attr
[
:token
]
=
nil
else
attr
=
attr
.
except
(
:token
)
end
{
alerting_setting_attributes:
attr
}
end
def
metrics_setting_params
attribs
=
params
[
:metrics_setting_attributes
]
return
{}
unless
attribs
...
...
app/views/projects/blob/_editor.html.haml
View file @
5064bf8c
...
...
@@ -23,7 +23,7 @@
.js-suggest-gitlab-ci-yml
{
data:
{
toggle:
'popover'
,
target:
'#gitlab-ci-yml-selector'
,
track_label:
'suggest_gitlab_ci_yml'
,
dismiss_key:
"suggest_gitlab_ci_yml_#{@project.id}"
,
dismiss_key:
@project
.
id
,
human_access:
human_access
}
}
.file-buttons
...
...
app/views/projects/blob/new.html.haml
View file @
5064bf8c
...
...
@@ -17,5 +17,5 @@
.js-suggest-gitlab-ci-yml-commit-changes
{
data:
{
toggle:
'popover'
,
target:
'#commit-changes'
,
track_label:
'suggest_commit_first_project_gitlab_ci_yml'
,
dismiss_key:
"suggest_commit_first_project_gitlab_ci_yml_#{@project.id}"
,
dismiss_key:
@project
.
id
,
human_access:
human_access
}
}
app/views/projects/environments/show.html.haml
View file @
5064bf8c
...
...
@@ -5,7 +5,8 @@
-
content_for
:page_specific_javascripts
do
=
stylesheet_link_tag
'page_bundles/xterm'
-
if
@environment
.
available?
&&
can?
(
current_user
,
:stop_environment
,
@environment
)
#environments-detail-view
{
data:
{
name:
@environment
.
name
,
id:
@environment
.
id
,
delete_path:
environment_delete_path
(
@environment
)}
}
-
if
@environment
.
available?
&&
can?
(
current_user
,
:stop_environment
,
@environment
)
#stop-environment-modal
.modal.fade
{
tabindex:
-
1
}
.modal-dialog
.modal-content
...
...
@@ -13,8 +14,7 @@
%h4
.modal-title.d-flex.mw-100
=
s_
(
"Environments|Stopping"
)
%span
.has-tooltip.text-truncate.ml-1.mr-1.flex-fill
{
title:
@environment
.
name
,
data:
{
container:
'#stop-environment-modal'
}
}
=
@environment
.
name
?
#{
@environment
.
name
}
?
.modal-body
%p
=
s_
(
'Environments|Are you sure you want to stop this environment?'
)
-
unless
@environment
.
stop_action_available?
...
...
@@ -32,7 +32,10 @@
=
button_to
stop_project_environment_path
(
@project
,
@environment
),
class:
'btn btn-danger has-tooltip'
,
method: :post
do
=
s_
(
'Environments|Stop environment'
)
.top-area.justify-content-between
-
if
can_destroy_environment?
(
@environment
)
#delete-environment-modal
.top-area.justify-content-between
.d-flex
%h3
.page-title
=
@environment
.
name
-
if
@environment
.
auto_stop_at?
...
...
@@ -50,8 +53,12 @@
target:
'#stop-environment-modal'
}
do
=
sprite_icon
(
'stop'
)
=
s_
(
'Environments|Stop'
)
-
if
can_destroy_environment?
(
@environment
)
=
button_tag
class:
'btn btn-danger'
,
type:
'button'
,
data:
{
toggle:
'modal'
,
target:
'#delete-environment-modal'
}
do
=
s_
(
'Environments|Delete'
)
.environments-container
.environments-container
-
if
@deployments
.
blank?
.empty-state
.text-content
...
...
app/views/shared/icons/_dev_ops_score_no_data.svg
View file @
5064bf8c
...
...
@@ -34,7 +34,6 @@
<rect
width=
"38"
height=
"4"
y=
"12"
fill=
"#FB722E"
rx=
"2"
/>
</g>
<path
fill=
"#EEE"
d=
"M4 14h106v4H4z"
/>
<path
fill=
"#333"
d=
"M35.724 138h9.696v-2.856h-2.856V122.76h-2.592c-1.08.648-2.136 1.08-3.792 1.392v2.184h2.856v8.808h-3.312V138zm17.736.288c-2.952 0-5.76-2.208-5.76-7.56 0-5.688 2.952-8.256 6.168-8.256 2.016 0 3.48.84 4.44 1.824l-1.848 2.112c-.528-.576-1.488-1.08-2.376-1.08-1.68 0-3.024 1.2-3.144 4.752.792-1.008 2.112-1.608 3.048-1.608 2.616 0 4.536 1.488 4.536 4.704 0 3.168-2.304 5.112-5.064 5.112zm-.072-2.64c1.056 0 1.92-.744 1.92-2.472 0-1.608-.84-2.208-1.992-2.208-.792 0-1.68.432-2.304 1.512.312 2.4 1.32 3.168 2.376 3.168zM63.9 132c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024zm.528 8.256l8.448-16.224h2.04l-8.448 16.224h-2.04zm11.016 0c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024z"
/>
</g>
</g>
</svg>
app/views/shared/icons/_dev_ops_score_no_index.svg
View file @
5064bf8c
...
...
@@ -17,7 +17,6 @@
<rect
width=
"38"
height=
"4"
y=
"12"
fill=
"#FB722E"
rx=
"2"
/>
</g>
<path
fill=
"#EEE"
d=
"M2 12h106v4H2z"
/>
<path
fill=
"#333"
d=
"M38.048 127.792c.792 0 1.68-.432 2.28-1.512-.312-2.4-1.296-3.168-2.376-3.168-1.032 0-1.92.744-1.92 2.472 0 1.608.864 2.208 2.016 2.208zm-.552 8.496c-2.016 0-3.504-.864-4.464-1.824l1.872-2.112c.504.576 1.464 1.08 2.352 1.08 1.704 0 3.024-1.2 3.144-4.752-.792 1.008-2.112 1.608-3.048 1.608-2.592 0-4.536-1.488-4.536-4.704 0-3.168 2.304-5.112 5.064-5.112 2.952 0 5.784 2.208 5.784 7.56 0 5.688-2.976 8.256-6.168 8.256zm13.488 0c-3.048 0-5.304-1.704-5.304-4.176 0-1.848 1.152-2.976 2.592-3.744v-.096c-1.176-.888-2.04-1.992-2.04-3.6 0-2.592 2.04-4.2 4.872-4.2 2.784 0 4.632 1.656 4.632 4.176 0 1.464-.936 2.64-1.992 3.336v.096c1.464.792 2.64 1.968 2.64 3.984 0 2.4-2.16 4.224-5.4 4.224zm.96-9.168c.6-.696.936-1.44.936-2.232 0-1.176-.696-1.968-1.848-1.968-.936 0-1.704.576-1.704 1.752 0 1.248 1.056 1.848 2.616 2.448zm-.888 6.72c1.176 0 2.04-.624 2.04-1.896 0-1.344-1.296-1.848-3.216-2.664-.672.624-1.176 1.488-1.176 2.424 0 1.344 1.08 2.136 2.352 2.136zm10.8-3.84c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024zm.528 8.256l8.448-16.224h2.04l-8.448 16.224h-2.04zm11.016 0c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024z"
/>
</g>
<g
transform=
"translate(122)"
>
<rect
width=
"110"
height=
"168"
x=
"2"
y=
"2"
fill=
"#FFF"
rx=
"10"
/>
...
...
@@ -39,7 +38,6 @@
<rect
width=
"8"
height=
"4"
x=
"73"
y=
"14"
fill=
"#EEE"
rx=
"2"
/>
<rect
width=
"8"
height=
"4"
x=
"86"
y=
"14"
fill=
"#EEE"
rx=
"2"
/>
<rect
width=
"8"
height=
"4"
x=
"99"
y=
"14"
fill=
"#EEE"
rx=
"2"
/>
<path
fill=
"#EEE"
d=
"M46.716 138.288c-3.264 0-5.448-2.784-5.448-7.968s2.184-7.848 5.448-7.848c3.264 0 5.448 2.664 5.448 7.848 0 5.184-2.184 7.968-5.448 7.968zm0-2.736c1.2 0 2.112-1.08 2.112-5.232 0-4.176-.912-5.112-2.112-5.112-1.176 0-2.112.936-2.112 5.112 0 4.152.936 5.232 2.112 5.232zM57.564 132c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024zm.528 8.256l8.448-16.224h2.04l-8.448 16.224h-2.04zm11.016 0c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024z"
/>
</g>
<g
transform=
"translate(243)"
>
<rect
width=
"110"
height=
"168"
x=
"2"
y=
"2"
fill=
"#FFF"
rx=
"10"
/>
...
...
@@ -61,7 +59,6 @@
<rect
width=
"8"
height=
"4"
x=
"73"
y=
"14"
fill=
"#EEE"
rx=
"2"
/>
<rect
width=
"8"
height=
"4"
x=
"86"
y=
"14"
fill=
"#EEE"
rx=
"2"
/>
<rect
width=
"8"
height=
"4"
x=
"99"
y=
"14"
fill=
"#EEE"
rx=
"2"
/>
<path
fill=
"#EEE"
d=
"M46.716 138.288c-3.264 0-5.448-2.784-5.448-7.968s2.184-7.848 5.448-7.848c3.264 0 5.448 2.664 5.448 7.848 0 5.184-2.184 7.968-5.448 7.968zm0-2.736c1.2 0 2.112-1.08 2.112-5.232 0-4.176-.912-5.112-2.112-5.112-1.176 0-2.112.936-2.112 5.112 0 4.152.936 5.232 2.112 5.232zM57.564 132c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024zm.528 8.256l8.448-16.224h2.04l-8.448 16.224h-2.04zm11.016 0c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024z"
/>
</g>
</g>
</svg>
changelogs/unreleased/32455-merge-request-discussions-api-degrades-with-comments-count.yml
0 → 100644
View file @
5064bf8c
---
title
:
Improve pagination in discussions API
merge_request
:
27697
author
:
type
:
performance
changelogs/unreleased/41845-delete-environment.yml
0 → 100644
View file @
5064bf8c
---
title
:
Adds features to delete stopped environments
merge_request
:
22629
author
:
type
:
added
changelogs/unreleased/osw-allow-custom-term-timeout-sk-cluster.yml
0 → 100644
View file @
5064bf8c
---
title
:
Support custom graceful timeout for Sidekiq Cluster processes
merge_request
:
27710
author
:
type
:
added
changelogs/unreleased/rp-allow-local-prom-queries-self-monitoring.yml
0 → 100644
View file @
5064bf8c
---
title
:
Allow self monitoring project to query internal Prometheus even when "Allow local requests in webhooks and services" setting is
false
merge_request
:
27865
author
:
type
:
fixed
config/routes/project.rb
View file @
5064bf8c
...
...
@@ -75,7 +75,12 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
put
:reset_registration_token
end
resource
:operations
,
only:
[
:show
,
:update
]
resource
:operations
,
only:
[
:show
,
:update
]
do
member
do
post
:reset_alerting_token
end
end
resource
:integrations
,
only:
[
:show
]
resource
:repository
,
only:
[
:show
],
controller: :repository
do
...
...
db/fixtures/development/17_cycle_analytics.rb
View file @
5064bf8c
...
...
@@ -30,7 +30,7 @@ class Gitlab::Seeder::CycleAnalytics
REVIEW_STAGE_MAX_DURATION_IN_HOURS
=
72
DEPLOYMENT_MAX_DURATION_IN_HOURS
=
48
def
self
.
seeder_base_on_env
(
project
)
def
self
.
seeder_base
d
_on_env
(
project
)
if
ENV
[
FLAG
]
self
.
new
(
project:
project
)
elsif
ENV
[
PERF_TEST
]
...
...
@@ -194,7 +194,7 @@ Gitlab::Seeder.quiet do
project_id
=
ENV
[
'CYCLE_ANALYTICS_SEED_PROJECT_ID'
]
project
=
Project
.
find
(
project_id
)
if
project_id
seeder
=
Gitlab
::
Seeder
::
CycleAnalytics
.
seeder_base_on_env
(
project
)
seeder
=
Gitlab
::
Seeder
::
CycleAnalytics
.
seeder_base
d
_on_env
(
project
)
if
seeder
seeder
.
seed!
...
...
doc/ci/environments.md
View file @
5064bf8c
...
...
@@ -761,6 +761,33 @@ runs once every hour. This means environments will not be stopped at the exact
timestamp as the specified period, but will be stopped when the hourly cron worker
detects expired environments.
#### Delete a stopped environment
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22629) in GitLab 12.9.
You can delete
[
stopped environments
](
#stopping-an-environment
)
in one of two
ways: through the GitLab UI or through the API.
##### Delete environments through the UI
To view the list of
**Stopped**
environments, navigate to
**Operations > Environments**
and click the
**Stopped**
tab.
From there, you can click the
**Delete**
button directly, or you can click the
environment name to see its details and
**Delete**
it from there.
You can also delete environments by viewing the details for a
stopped environment:
1.
Navigate to
**Operations > Environments**
.
1.
Click on the name of an environment within the
**Stopped**
environments list.
1.
Click on the
**Delete**
button that appears at the top for all stopped environments.
1.
Finally, confirm your chosen environment in the modal that appears to delete it.
##### Delete environments through the API
Environments can also be deleted by using the
[
Environments API
](
../api/environments.md#delete-an-environment
)
.
### Grouping similar environments
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/7015) in GitLab 8.14.
...
...
lib/api/discussions.rb
View file @
5064bf8c
...
...
@@ -28,10 +28,10 @@ module API
get
":id/
#{
noteables_path
}
/:noteable_id/discussions"
do
noteable
=
find_noteable
(
noteable_type
,
params
[
:noteable_id
])
notes
=
readable_discussion_notes
(
noteable
)
discussions
=
Kaminari
.
paginate_array
(
Discussion
.
build_collection
(
notes
,
noteable
)
)
discussion_ids
=
paginate
(
noteable
.
discussion_ids_relation
)
notes
=
readable_discussion_notes
(
noteable
,
discussion_ids
)
present
paginate
(
discussions
),
with:
Entities
::
Discussion
present
Discussion
.
build_collection
(
notes
,
noteable
),
with:
Entities
::
Discussion
end
desc
"Get a single
#{
noteable_type
.
to_s
.
downcase
}
discussion"
do
...
...
@@ -221,10 +221,9 @@ module API
helpers
do
# rubocop: disable CodeReuse/ActiveRecord
def
readable_discussion_notes
(
noteable
,
discussion_id
=
nil
)
def
readable_discussion_notes
(
noteable
,
discussion_id
s
)
notes
=
noteable
.
notes
notes
=
notes
.
where
(
discussion_id:
discussion_id
)
if
discussion_id
notes
=
notes
.
where
(
discussion_id:
discussion_ids
)
.
inc_relations_for_view
.
includes
(
:noteable
)
.
fresh
...
...
lib/api/environments.rb
View file @
5064bf8c
...
...
@@ -82,9 +82,10 @@ module API
requires
:environment_id
,
type:
Integer
,
desc:
'The environment ID'
end
delete
':id/environments/:environment_id'
do
authorize!
:
update
_environment
,
user_project
authorize!
:
read
_environment
,
user_project
environment
=
user_project
.
environments
.
find
(
params
[
:environment_id
])
authorize!
:destroy_environment
,
environment
destroy_conditionally!
(
environment
)
end
...
...
lib/gitlab/cleanup/orphan_lfs_file_references.rb
View file @
5064bf8c
...
...
@@ -40,7 +40,7 @@ module Gitlab
end
def
lfs_oids_from_repository
project
.
repository
.
gitaly_blob_client
.
get_all_lfs_pointers
(
nil
)
.
map
(
&
:lfs_oid
)
project
.
repository
.
gitaly_blob_client
.
get_all_lfs_pointers
.
map
(
&
:lfs_oid
)
end
def
orphan_oids
...
...
lib/gitlab/git/lfs_changes.rb
View file @
5064bf8c
...
...
@@ -13,7 +13,7 @@ module Gitlab
end
def
all_pointers
@repository
.
gitaly_blob_client
.
get_all_lfs_pointers
(
@newrev
)
@repository
.
gitaly_blob_client
.
get_all_lfs_pointers
end
end
end
...
...
lib/gitlab/gitaly_client/blob_service.rb
View file @
5064bf8c
...
...
@@ -131,10 +131,9 @@ module Gitlab
map_lfs_pointers
(
response
)
end
def
get_all_lfs_pointers
(
revision
)
request
=
Gitaly
::
GetNewLFSPointersRequest
.
new
(
repository:
@gitaly_repo
,
revision:
encode_binary
(
revision
)
def
get_all_lfs_pointers
request
=
Gitaly
::
GetAllLFSPointersRequest
.
new
(
repository:
@gitaly_repo
)
response
=
GitalyClient
.
call
(
@gitaly_repo
.
storage_name
,
:blob_service
,
:get_all_lfs_pointers
,
request
,
timeout:
GitalyClient
.
medium_timeout
)
...
...
lib/gitlab/sidekiq_cluster.rb
View file @
5064bf8c
...
...
@@ -62,21 +62,28 @@ module Gitlab
# directory - The directory of the Rails application.
#
# Returns an Array containing the PIDs of the started processes.
def
self
.
start
(
queues
,
env: :development
,
directory:
Dir
.
pwd
,
max_concurrency:
50
,
min_concurrency:
0
,
dryrun:
false
)
def
self
.
start
(
queues
,
env: :development
,
directory:
Dir
.
pwd
,
max_concurrency:
50
,
min_concurrency:
0
,
timeout:
CLI
::
DEFAULT_SOFT_TIMEOUT_SECONDS
,
dryrun:
false
)
queues
.
map
.
with_index
do
|
pair
,
index
|
start_sidekiq
(
pair
,
env:
env
,
directory:
directory
,
max_concurrency:
max_concurrency
,
min_concurrency:
min_concurrency
,
worker_id:
index
,
dryrun:
dryrun
)
start_sidekiq
(
pair
,
env:
env
,
directory:
directory
,
max_concurrency:
max_concurrency
,
min_concurrency:
min_concurrency
,
worker_id:
index
,
timeout:
timeout
,
dryrun:
dryrun
)
end
end
# Starts a Sidekiq process that processes _only_ the given queues.
#
# Returns the PID of the started process.
def
self
.
start_sidekiq
(
queues
,
env
:,
directory
:,
max_concurrency
:,
min_concurrency
:,
worker_id
:,
dryrun
:)
def
self
.
start_sidekiq
(
queues
,
env
:,
directory
:,
max_concurrency
:,
min_concurrency
:,
worker_id
:,
timeout
:,
dryrun
:)
counts
=
count_by_queue
(
queues
)
cmd
=
%w[bundle exec sidekiq]
cmd
<<
"-c
#{
self
.
concurrency
(
queues
,
min_concurrency
,
max_concurrency
)
}
"
cmd
<<
"-e
#{
env
}
"
cmd
<<
"-t
#{
timeout
}
"
cmd
<<
"-gqueues:
#{
proc_details
(
counts
)
}
"
cmd
<<
"-r
#{
directory
}
"
...
...
lib/gitlab/sidekiq_cluster/cli.rb
View file @
5064bf8c
...
...
@@ -8,9 +8,17 @@ module Gitlab
module
SidekiqCluster
class
CLI
CHECK_TERMINATE_INTERVAL_SECONDS
=
1
# How long to wait in total when asking for a clean termination
# Sidekiq default to self-terminate is 25s
TERMINATE_TIMEOUT_SECONDS
=
30
# How long to wait when asking for a clean termination.
# It maps the Sidekiq default timeout:
# https://github.com/mperham/sidekiq/wiki/Signals#term
#
# This value is passed to Sidekiq's `-t` if none
# is given through arguments.
DEFAULT_SOFT_TIMEOUT_SECONDS
=
25
# After surpassing the soft timeout.
DEFAULT_HARD_TIMEOUT_SECONDS
=
5
CommandError
=
Class
.
new
(
StandardError
)
...
...
@@ -74,7 +82,8 @@ module Gitlab
directory:
@rails_path
,
max_concurrency:
@max_concurrency
,
min_concurrency:
@min_concurrency
,
dryrun:
@dryrun
dryrun:
@dryrun
,
timeout:
soft_timeout_seconds
)
return
if
@dryrun
...
...
@@ -88,6 +97,15 @@ module Gitlab
SidekiqCluster
.
write_pid
(
@pid
)
if
@pid
end
def
soft_timeout_seconds
@soft_timeout_seconds
||
DEFAULT_SOFT_TIMEOUT_SECONDS
end
# The amount of time it'll wait for killing the alive Sidekiq processes.
def
hard_timeout_seconds
soft_timeout_seconds
+
DEFAULT_HARD_TIMEOUT_SECONDS
end
def
monotonic_time
Process
.
clock_gettime
(
Process
::
CLOCK_MONOTONIC
,
:float_second
)
end
...
...
@@ -101,7 +119,7 @@ module Gitlab
end
def
wait_for_termination
deadline
=
monotonic_time
+
TERMINATE_TIMEOUT_SECONDS
deadline
=
monotonic_time
+
hard_timeout_seconds
sleep
(
CHECK_TERMINATE_INTERVAL_SECONDS
)
while
continue_waiting?
(
deadline
)
hard_stop_stuck_pids
...
...
@@ -176,6 +194,10 @@ module Gitlab
@interval
=
int
.
to_i
end
opt
.
on
(
'-t'
,
'--timeout INT'
,
'Graceful timeout for all running processes'
)
do
|
timeout
|
@soft_timeout_seconds
=
timeout
.
to_i
end
opt
.
on
(
'-d'
,
'--dryrun'
,
'Print commands that would be run without this flag, and quit'
)
do
|
int
|
@dryrun
=
true
end
...
...
locale/gitlab.pot
View file @
5064bf8c
...
...
@@ -7695,6 +7695,9 @@ msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
msgstr ""
msgid "Environments|An error occurred while deleting the environment. Check if the environment stopped; if not, stop it and try again."
msgstr ""
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
...
...
@@ -7728,6 +7731,15 @@ msgstr ""
msgid "Environments|Currently showing all results."
msgstr ""
msgid "Environments|Delete"
msgstr ""
msgid "Environments|Delete environment"
msgstr ""
msgid "Environments|Deleting the '%{environmentName}' environment cannot be undone. Do you want to delete it anyway?"
msgstr ""
msgid "Environments|Deploy to..."
msgstr ""
...
...
spec/controllers/projects/settings/operations_controller_spec.rb
View file @
5064bf8c
...
...
@@ -295,6 +295,94 @@ describe Projects::Settings::OperationsController do
end
end
end
describe
'POST reset_alerting_token'
do
let
(
:project
)
{
create
(
:project
)
}
before
do
project
.
add_maintainer
(
user
)
end
context
'with existing alerting setting'
do
let!
(
:alerting_setting
)
do
create
(
:project_alerting_setting
,
project:
project
)
end
let!
(
:old_token
)
{
alerting_setting
.
token
}
it
'returns newly reset token'
do
reset_alerting_token
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
[
'token'
]).
to
eq
(
alerting_setting
.
reload
.
token
)
expect
(
old_token
).
not_to
eq
(
alerting_setting
.
token
)
end
end
context
'without existing alerting setting'
do
it
'creates a token'
do
reset_alerting_token
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
project
.
alerting_setting
).
not_to
be_nil
expect
(
json_response
[
'token'
]).
to
eq
(
project
.
alerting_setting
.
token
)
end
end
context
'when update fails'
do
let
(
:operations_update_service
)
{
spy
(
:operations_update_service
)
}
let
(
:alerting_params
)
do
{
alerting_setting_attributes:
{
regenerate_token:
true
}
}
end
before
do
expect
(
::
Projects
::
Operations
::
UpdateService
)
.
to
receive
(
:new
).
with
(
project
,
user
,
alerting_params
)
.
and_return
(
operations_update_service
)
expect
(
operations_update_service
).
to
receive
(
:execute
)
.
and_return
(
status: :error
)
end
it
'returns unprocessable_entity'
do
reset_alerting_token
expect
(
response
).
to
have_gitlab_http_status
(
:unprocessable_entity
)
expect
(
json_response
).
to
be_empty
end
end
context
'with insufficient permissions'
do
before
do
project
.
add_reporter
(
user
)
end
it
'returns 404'
do
reset_alerting_token
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
context
'as an anonymous user'
do
before
do
sign_out
(
user
)
end
it
'returns a redirect'
do
reset_alerting_token
expect
(
response
).
to
have_gitlab_http_status
(
:redirect
)
end
end
private
def
reset_alerting_token
post
:reset_alerting_token
,
params:
project_params
(
project
),
format: :json
end
end
end
private
...
...
spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
View file @
5064bf8c
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
'User follows pipeline suggest nudge spec when feature is enabled'
,
:js
do
include
CookieHelper
let
(
:user
)
{
create
(
:user
,
:admin
)
}
let
(
:project
)
{
create
(
:project
,
:empty_repo
)
}
...
...
@@ -38,6 +40,12 @@ describe 'User follows pipeline suggest nudge spec when feature is enabled', :js
expect
(
page
).
to
have_content
(
'1/2: Choose a template'
)
end
end
it
'sets the commit cookie when the Commit button is clicked'
do
click_button
'Commit changes'
expect
(
get_cookie
(
"suggest_gitlab_ci_yml_commit_
#{
project
.
id
}
"
)).
to
be_present
end
end
context
'when the page is visited without the param'
do
...
...
spec/fixtures/api/schemas/environment.json
View file @
5064bf8c
...
...
@@ -44,7 +44,10 @@
"build_path"
:
{
"type"
:
"string"
}
}
]
}
},
"can_delete"
:
{
"type"
:
"boolean"
}
,
"delete_path"
:
{
"type"
:
"string"
}
},
"additionalProperties"
:
false
}
spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
View file @
5064bf8c
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
Popover
from
'
~/blob/suggest_gitlab_ci_yml/components/popover.vue
'
;
import
Cookies
from
'
js-cookie
'
;
import
{
mockTracking
,
unmockTracking
}
from
'
helpers/tracking_helper
'
;
import
*
as
utils
from
'
~/lib/utils/common_utils
'
;
...
...
@@ -10,9 +9,11 @@ jest.mock('~/lib/utils/common_utils', () => ({
}));
const
target
=
'
gitlab-ci-yml-selector
'
;
const
dismissKey
=
'
suggest_gitlab_ci_yml_
99
'
;
const
dismissKey
=
'
99
'
;
const
defaultTrackLabel
=
'
suggest_gitlab_ci_yml
'
;
const
commitTrackLabel
=
'
suggest_commit_first_project_gitlab_ci_yml
'
;
const
dismissCookie
=
'
suggest_gitlab_ci_yml_99
'
;
const
humanAccess
=
'
owner
'
;
describe
(
'
Suggest gitlab-ci.yml Popover
'
,
()
=>
{
...
...
@@ -46,7 +47,8 @@ describe('Suggest gitlab-ci.yml Popover', () => {
describe
(
'
when the dismiss cookie is set
'
,
()
=>
{
beforeEach
(()
=>
{
Cookies
.
set
(
dismissKey
,
true
);
utils
.
setCookie
(
dismissCookie
,
true
);
createWrapper
(
defaultTrackLabel
);
});
...
...
@@ -55,7 +57,7 @@ describe('Suggest gitlab-ci.yml Popover', () => {
});
afterEach
(()
=>
{
Cookies
.
remove
(
dismissKey
);
utils
.
removeCookie
(
dismissCookie
);
});
});
...
...
spec/frontend/environments/environment_delete_spec.js
0 → 100644
View file @
5064bf8c
import
$
from
'
jquery
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
DeleteComponent
from
'
~/environments/components/environment_delete.vue
'
;
import
LoadingButton
from
'
~/vue_shared/components/loading_button.vue
'
;
import
eventHub
from
'
~/environments/event_hub
'
;
$
.
fn
.
tooltip
=
()
=>
{};
describe
(
'
External URL Component
'
,
()
=>
{
let
wrapper
;
const
createWrapper
=
()
=>
{
wrapper
=
shallowMount
(
DeleteComponent
,
{
propsData
:
{
environment
:
{},
},
});
};
const
findButton
=
()
=>
wrapper
.
find
(
LoadingButton
);
beforeEach
(()
=>
{
jest
.
spyOn
(
window
,
'
confirm
'
);
createWrapper
();
});
it
(
'
should render a button to delete the environment
'
,
()
=>
{
expect
(
findButton
().
exists
()).
toBe
(
true
);
expect
(
wrapper
.
attributes
(
'
title
'
)).
toEqual
(
'
Delete environment
'
);
});
it
(
'
emits requestDeleteEnvironment in the event hub when button is clicked
'
,
()
=>
{
jest
.
spyOn
(
eventHub
,
'
$emit
'
);
findButton
().
vm
.
$emit
(
'
click
'
);
expect
(
eventHub
.
$emit
).
toHaveBeenCalledWith
(
'
requestDeleteEnvironment
'
,
wrapper
.
vm
.
environment
);
});
});
spec/frontend/environments/environment_item_spec.js
View file @
5064bf8c
...
...
@@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils';
import
{
format
}
from
'
timeago.js
'
;
import
EnvironmentItem
from
'
~/environments/components/environment_item.vue
'
;
import
PinComponent
from
'
~/environments/components/environment_pin.vue
'
;
import
DeleteComponent
from
'
~/environments/components/environment_delete.vue
'
;
import
{
environment
,
folder
,
tableData
}
from
'
./mock_data
'
;
...
...
@@ -54,6 +55,10 @@ describe('Environment item', () => {
expect
(
wrapper
.
find
(
'
.environment-created-date-timeago
'
).
text
()).
toContain
(
formattedDate
);
});
it
(
'
should not render the delete button
'
,
()
=>
{
expect
(
wrapper
.
find
(
DeleteComponent
).
exists
()).
toBe
(
false
);
});
describe
(
'
With user information
'
,
()
=>
{
it
(
'
should render user avatar with link to profile
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.js-deploy-user-container
'
).
attributes
(
'
href
'
)).
toEqual
(
...
...
@@ -98,7 +103,7 @@ describe('Environment item', () => {
expect
(
findAutoStop
().
exists
()).
toBe
(
false
);
});
it
(
'
should not render the
s
uto-stop button
'
,
()
=>
{
it
(
'
should not render the
a
uto-stop button
'
,
()
=>
{
expect
(
wrapper
.
find
(
PinComponent
).
exists
()).
toBe
(
false
);
});
});
...
...
@@ -205,4 +210,22 @@ describe('Environment item', () => {
expect
(
wrapper
.
find
(
'
.folder-name .badge
'
).
text
()).
toContain
(
folder
.
size
);
});
});
describe
(
'
When environment can be deleted
'
,
()
=>
{
beforeEach
(()
=>
{
factory
({
propsData
:
{
model
:
{
can_delete
:
true
,
delete_path
:
'
http://0.0.0.0:3000/api/v4/projects/8/environments/45
'
,
},
tableData
,
},
});
});
it
(
'
should render the delete button
'
,
()
=>
{
expect
(
wrapper
.
find
(
DeleteComponent
).
exists
()).
toBe
(
true
);
});
});
});
spec/lib/gitlab/gitaly_client/blob_service_spec.rb
View file @
5064bf8c
...
...
@@ -46,14 +46,12 @@ describe Gitlab::GitalyClient::BlobService do
end
describe
'#get_all_lfs_pointers'
do
let
(
:revision
)
{
'master'
}
subject
{
client
.
get_all_lfs_pointers
(
revision
)
}
subject
{
client
.
get_all_lfs_pointers
}
it
'sends a get_all_lfs_pointers message'
do
expect_any_instance_of
(
Gitaly
::
BlobService
::
Stub
)
.
to
receive
(
:get_all_lfs_pointers
)
.
with
(
gitaly_request_with_params
(
revision:
revision
),
kind_of
(
Hash
))
.
with
(
gitaly_request_with_params
(
{}
),
kind_of
(
Hash
))
.
and_return
([])
subject
...
...
spec/lib/gitlab/sidekiq_cluster/cli_spec.rb
View file @
5064bf8c
...
...
@@ -5,8 +5,9 @@ require 'rspec-parameterized'
describe
Gitlab
::
SidekiqCluster
::
CLI
do
let
(
:cli
)
{
described_class
.
new
(
'/dev/null'
)
}
let
(
:timeout
)
{
described_class
::
DEFAULT_SOFT_TIMEOUT_SECONDS
}
let
(
:default_options
)
do
{
env:
'test'
,
directory:
Dir
.
pwd
,
max_concurrency:
50
,
min_concurrency:
0
,
dryrun:
false
}
{
env:
'test'
,
directory:
Dir
.
pwd
,
max_concurrency:
50
,
min_concurrency:
0
,
dryrun:
false
,
timeout:
timeout
}
end
before
do
...
...
@@ -80,6 +81,22 @@ describe Gitlab::SidekiqCluster::CLI do
end
end
context
'-timeout flag'
do
it
'when given'
,
'starts Sidekiq workers with given timeout'
do
expect
(
Gitlab
::
SidekiqCluster
).
to
receive
(
:start
)
.
with
([[
'foo'
]],
default_options
.
merge
(
timeout:
10
))
cli
.
run
(
%w(foo --timeout 10)
)
end
it
'when not given'
,
'starts Sidekiq workers with default timeout'
do
expect
(
Gitlab
::
SidekiqCluster
).
to
receive
(
:start
)
.
with
([[
'foo'
]],
default_options
.
merge
(
timeout:
described_class
::
DEFAULT_SOFT_TIMEOUT_SECONDS
))
cli
.
run
(
%w(foo)
)
end
end
context
'queue namespace expansion'
do
it
'starts Sidekiq workers for all queues in all_queues.yml with a namespace in argv'
do
expect
(
Gitlab
::
SidekiqConfig
::
CliMethods
).
to
receive
(
:worker_queues
).
and_return
([
'cronjob:foo'
,
'cronjob:bar'
])
...
...
@@ -222,7 +239,8 @@ describe Gitlab::SidekiqCluster::CLI do
.
with
([],
:KILL
)
stub_const
(
"Gitlab::SidekiqCluster::CLI::CHECK_TERMINATE_INTERVAL_SECONDS"
,
0.1
)
stub_const
(
"Gitlab::SidekiqCluster::CLI::TERMINATE_TIMEOUT_SECONDS"
,
1
)
allow
(
cli
).
to
receive
(
:terminate_timeout_seconds
)
{
1
}
cli
.
wait_for_termination
end
...
...
@@ -251,7 +269,8 @@ describe Gitlab::SidekiqCluster::CLI do
cli
.
run
(
%w(foo)
)
stub_const
(
"Gitlab::SidekiqCluster::CLI::CHECK_TERMINATE_INTERVAL_SECONDS"
,
0.1
)
stub_const
(
"Gitlab::SidekiqCluster::CLI::TERMINATE_TIMEOUT_SECONDS"
,
1
)
allow
(
cli
).
to
receive
(
:terminate_timeout_seconds
)
{
1
}
cli
.
wait_for_termination
end
end
...
...
spec/lib/gitlab/sidekiq_cluster_spec.rb
View file @
5064bf8c
...
...
@@ -58,6 +58,7 @@ describe Gitlab::SidekiqCluster do
directory:
'foo/bar'
,
max_concurrency:
20
,
min_concurrency:
10
,
timeout:
25
,
dryrun:
true
}
...
...
@@ -74,6 +75,7 @@ describe Gitlab::SidekiqCluster do
max_concurrency:
50
,
min_concurrency:
0
,
worker_id:
an_instance_of
(
Integer
),
timeout:
25
,
dryrun:
false
}
...
...
@@ -87,10 +89,10 @@ describe Gitlab::SidekiqCluster do
describe
'.start_sidekiq'
do
let
(
:first_worker_id
)
{
0
}
let
(
:options
)
do
{
env: :production
,
directory:
'foo/bar'
,
max_concurrency:
20
,
min_concurrency:
0
,
worker_id:
first_worker_id
,
dryrun:
false
}
{
env: :production
,
directory:
'foo/bar'
,
max_concurrency:
20
,
min_concurrency:
0
,
worker_id:
first_worker_id
,
timeout:
10
,
dryrun:
false
}
end
let
(
:env
)
{
{
"ENABLE_SIDEKIQ_CLUSTER"
=>
"1"
,
"SIDEKIQ_WORKER_ID"
=>
first_worker_id
.
to_s
}
}
let
(
:args
)
{
[
'bundle'
,
'exec'
,
'sidekiq'
,
anything
,
'-eproduction'
,
*
([
anything
]
*
5
)]
}
let
(
:args
)
{
[
'bundle'
,
'exec'
,
'sidekiq'
,
anything
,
'-eproduction'
,
'-t10'
,
*
([
anything
]
*
5
)]
}
it
'starts a Sidekiq process'
do
allow
(
Process
).
to
receive
(
:spawn
).
and_return
(
1
)
...
...
spec/models/commit_status_spec.rb
View file @
5064bf8c
...
...
@@ -449,6 +449,19 @@ describe CommitStatus do
end
end
describe
'.match_id_and_lock_version'
do
let
(
:status_1
)
{
create_status
(
lock_version:
1
)
}
let
(
:status_2
)
{
create_status
(
lock_version:
2
)
}
it
'returns statuses that match the given id and lock versions'
do
params
=
[
{
id:
status_1
.
id
,
lock_version:
1
},
{
id:
status_2
.
id
,
lock_version:
3
}
]
expect
(
described_class
.
match_id_and_lock_version
(
params
)).
to
contain_exactly
(
status_1
)
end
end
describe
'#before_sha'
do
subject
{
commit_status
.
before_sha
}
...
...
spec/models/concerns/noteable_spec.rb
View file @
5064bf8c
...
...
@@ -62,6 +62,21 @@ describe Noteable do
end
end
describe
'#discussion_ids_relation'
do
it
'returns ordered discussion_ids'
do
discussion_ids
=
subject
.
discussion_ids_relation
.
pluck
(
:discussion_id
)
expect
(
discussion_ids
).
to
eq
([
active_diff_note1
,
active_diff_note3
,
outdated_diff_note1
,
discussion_note1
,
note1
,
note2
].
map
(
&
:discussion_id
))
end
end
describe
'#grouped_diff_discussions'
do
let
(
:grouped_diff_discussions
)
{
subject
.
grouped_diff_discussions
}
...
...
spec/models/project_services/prometheus_service_spec.rb
View file @
5064bf8c
...
...
@@ -66,6 +66,18 @@ describe PrometheusService, :use_clean_rails_memory_store_caching do
end
end
it
'can query when local requests are allowed'
do
stub_application_setting
(
allow_local_requests_from_web_hooks_and_services:
true
)
aggregate_failures
do
[
'127.0.0.1'
,
'192.168.2.3'
].
each
do
|
url
|
allow
(
Addrinfo
).
to
receive
(
:getaddrinfo
).
with
(
domain
,
any_args
).
and_return
([
Addrinfo
.
tcp
(
url
,
80
)])
expect
(
service
.
can_query?
).
to
be
true
end
end
end
context
'with self-monitoring project and internal Prometheus'
do
before
do
service
.
api_url
=
'http://localhost:9090'
...
...
@@ -152,6 +164,54 @@ describe PrometheusService, :use_clean_rails_memory_store_caching do
expect
(
service
.
prometheus_client
).
to
be_nil
end
end
context
'when local requests are allowed'
do
let
(
:manual_configuration
)
{
true
}
let
(
:api_url
)
{
'http://192.168.1.1:9090'
}
before
do
stub_application_setting
(
allow_local_requests_from_web_hooks_and_services:
true
)
stub_prometheus_request
(
"
#{
api_url
}
/api/v1/query?query=1"
)
end
it
'allows local requests'
do
expect
(
service
.
prometheus_client
).
not_to
be_nil
expect
{
service
.
prometheus_client
.
ping
}.
not_to
raise_error
end
end
context
'when local requests are blocked'
do
let
(
:manual_configuration
)
{
true
}
let
(
:api_url
)
{
'http://192.168.1.1:9090'
}
before
do
stub_application_setting
(
allow_local_requests_from_web_hooks_and_services:
false
)
stub_prometheus_request
(
"
#{
api_url
}
/api/v1/query?query=1"
)
end
it
'blocks local requests'
do
expect
(
service
.
prometheus_client
).
to
be_nil
end
context
'with self monitoring project and internal Prometheus URL'
do
before
do
stub_application_setting
(
allow_local_requests_from_web_hooks_and_services:
false
)
stub_application_setting
(
self_monitoring_project_id:
project
.
id
)
stub_config
(
prometheus:
{
enable:
true
,
listen_address:
api_url
})
end
it
'allows local requests'
do
expect
(
service
.
prometheus_client
).
not_to
be_nil
expect
{
service
.
prometheus_client
.
ping
}.
not_to
raise_error
end
end
end
end
describe
'#prometheus_available?'
do
...
...
spec/policies/environment_policy_spec.rb
View file @
5064bf8c
...
...
@@ -86,6 +86,50 @@ describe EnvironmentPolicy do
it
{
expect
(
policy
).
to
be_allowed
:stop_environment
}
end
end
describe
'#destroy_environment'
do
let
(
:environment
)
do
create
(
:environment
,
project:
project
)
end
where
(
:access_level
,
:allowed?
)
do
nil
|
false
:guest
|
false
:reporter
|
false
:developer
|
true
:maintainer
|
true
end
with_them
do
before
do
project
.
add_user
(
user
,
access_level
)
unless
access_level
.
nil?
end
it
{
expect
(
policy
).
to
be_disallowed
:destroy_environment
}
context
'when environment is stopped'
do
before
do
environment
.
stop!
end
it
{
expect
(
policy
.
allowed?
(
:destroy_environment
)).
to
be
allowed?
}
end
end
context
'when an admin user'
do
let
(
:user
)
{
create
(
:user
,
:admin
)
}
it
{
expect
(
policy
).
to
be_disallowed
:destroy_environment
}
context
'when environment is stopped'
do
before
do
environment
.
stop!
end
it
{
expect
(
policy
).
to
be_allowed
:destroy_environment
}
end
end
end
end
context
'when project is public'
do
...
...
spec/policies/project_policy_spec.rb
View file @
5064bf8c
...
...
@@ -573,4 +573,50 @@ describe ProjectPolicy do
it
{
is_expected
.
to
be_allowed
(
:admin_issue
)
}
end
end
describe
'read_prometheus_alerts'
do
subject
{
described_class
.
new
(
current_user
,
project
)
}
context
'with admin'
do
let
(
:current_user
)
{
admin
}
it
{
is_expected
.
to
be_allowed
(
:read_prometheus_alerts
)
}
end
context
'with owner'
do
let
(
:current_user
)
{
owner
}
it
{
is_expected
.
to
be_allowed
(
:read_prometheus_alerts
)
}
end
context
'with maintainer'
do
let
(
:current_user
)
{
maintainer
}
it
{
is_expected
.
to
be_allowed
(
:read_prometheus_alerts
)
}
end
context
'with developer'
do
let
(
:current_user
)
{
developer
}
it
{
is_expected
.
to
be_disallowed
(
:read_prometheus_alerts
)
}
end
context
'with reporter'
do
let
(
:current_user
)
{
reporter
}
it
{
is_expected
.
to
be_disallowed
(
:read_prometheus_alerts
)
}
end
context
'with guest'
do
let
(
:current_user
)
{
guest
}
it
{
is_expected
.
to
be_disallowed
(
:read_prometheus_alerts
)
}
end
context
'with anonymous'
do
let
(
:current_user
)
{
nil
}
it
{
is_expected
.
to
be_disallowed
(
:read_prometheus_alerts
)
}
end
end
end
spec/requests/api/environments_spec.rb
View file @
5064bf8c
...
...
@@ -171,7 +171,15 @@ describe API::Environments do
describe
'DELETE /projects/:id/environments/:environment_id'
do
context
'as a maintainer'
do
it
'returns a 200 for an existing environment'
do
it
"rejects the requests in environment isn't stopped"
do
delete
api
(
"/projects/
#{
project
.
id
}
/environments/
#{
environment
.
id
}
"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
:forbidden
)
end
it
'returns a 200 for stopped environment'
do
environment
.
stop
delete
api
(
"/projects/
#{
project
.
id
}
/environments/
#{
environment
.
id
}
"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
:no_content
)
...
...
@@ -185,6 +193,10 @@ describe API::Environments do
end
it_behaves_like
'412 response'
do
before
do
environment
.
stop
end
let
(
:request
)
{
api
(
"/projects/
#{
project
.
id
}
/environments/
#{
environment
.
id
}
"
,
user
)
}
end
end
...
...
spec/services/projects/operations/update_service_spec.rb
View file @
5064bf8c
...
...
@@ -11,6 +11,87 @@ describe Projects::Operations::UpdateService do
subject
{
described_class
.
new
(
project
,
user
,
params
)
}
describe
'#execute'
do
context
'alerting setting'
do
before
do
project
.
add_maintainer
(
user
)
end
shared_examples
'no operation'
do
it
'does nothing'
do
expect
(
result
[
:status
]).
to
eq
(
:success
)
expect
(
project
.
reload
.
alerting_setting
).
to
be_nil
end
end
context
'with valid params'
do
let
(
:params
)
{
{
alerting_setting_attributes:
alerting_params
}
}
shared_examples
'setting creation'
do
it
'creates a setting'
do
expect
(
project
.
alerting_setting
).
to
be_nil
expect
(
result
[
:status
]).
to
eq
(
:success
)
expect
(
project
.
reload
.
alerting_setting
).
not_to
be_nil
end
end
context
'when regenerate_token is not set'
do
let
(
:alerting_params
)
{
{
token:
'some token'
}
}
context
'with an existing setting'
do
let!
(
:alerting_setting
)
do
create
(
:project_alerting_setting
,
project:
project
)
end
it
'ignores provided token'
do
expect
(
result
[
:status
]).
to
eq
(
:success
)
expect
(
project
.
reload
.
alerting_setting
.
token
)
.
to
eq
(
alerting_setting
.
token
)
end
end
context
'without an existing setting'
do
it_behaves_like
'setting creation'
end
end
context
'when regenerate_token is set'
do
let
(
:alerting_params
)
{
{
regenerate_token:
true
}
}
context
'with an existing setting'
do
let
(
:token
)
{
'some token'
}
let!
(
:alerting_setting
)
do
create
(
:project_alerting_setting
,
project:
project
,
token:
token
)
end
it
'regenerates token'
do
expect
(
result
[
:status
]).
to
eq
(
:success
)
expect
(
project
.
reload
.
alerting_setting
.
token
).
not_to
eq
(
token
)
end
end
context
'without an existing setting'
do
it_behaves_like
'setting creation'
context
'with insufficient permissions'
do
before
do
project
.
add_reporter
(
user
)
end
it_behaves_like
'no operation'
end
end
end
end
context
'with empty params'
do
let
(
:params
)
{
{}
}
it_behaves_like
'no operation'
end
end
context
'metrics dashboard setting'
do
let
(
:params
)
do
{
...
...
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